Simon Bruder
10b8d432d5
This applies the REUSE specification to the repository, so the licensing information can be tracked for every file individually.
198 lines
6.4 KiB
Nix
198 lines
6.4 KiB
Nix
# SPDX-FileCopyrightText: 2022-2023 Simon Bruder <simon@sbruder.de>
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
{ config, inputs, lib, pkgs, ... }:
|
|
let
|
|
cfg = config.sbruder.qbittorrent;
|
|
in
|
|
{
|
|
options.sbruder.qbittorrent = {
|
|
enable = lib.mkEnableOption "the qbittorrent service";
|
|
homeDir = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = "/var/lib/qbittorrent";
|
|
};
|
|
configDir = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = "${cfg.homeDir}/config";
|
|
};
|
|
downloadDir = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = "${cfg.homeDir}/download";
|
|
};
|
|
webuiPort = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 8099;
|
|
};
|
|
sopsFile = lib.mkOption {
|
|
type = lib.types.path;
|
|
default = ../../machines/${config.networking.hostName}/secrets.yaml;
|
|
description = ''
|
|
The sops secret file that includes the wireguard private key (wg-qbittorrent-private-key).
|
|
'';
|
|
};
|
|
wireguardConnectionDetails = lib.mkOption {
|
|
type = lib.types.attrs;
|
|
default = import ../../machines/${config.networking.hostName}/secrets/wireguard-qbittorrent.nix;
|
|
example = {
|
|
ips = [ "10.0.0.1/32" "fd00::1/128" ];
|
|
|
|
peers = lib.singleton {
|
|
publicKey = "MbLFO7MIFSdwVmZWQG//IUxVxwSHprRkhr/NWl2gils=";
|
|
allowedIPs = [ "0.0.0.0/0" "::0/0" ];
|
|
endpoint = "192.0.2.1:51820";
|
|
};
|
|
};
|
|
description = "The connection details for the WireGuard tunnel.";
|
|
};
|
|
fqdn = lib.mkOption {
|
|
type = lib.types.str;
|
|
description = "The fqdn nginx should listen on. It must not be used for anything else.";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable
|
|
{
|
|
users.users.qbittorrent = {
|
|
group = "qbittorrent";
|
|
home = cfg.homeDir;
|
|
isSystemUser = true;
|
|
};
|
|
users.groups.qbittorrent = { };
|
|
|
|
systemd.tmpfiles.rules = [
|
|
"d '${cfg.downloadDir}' 0775 qbittorrent users - -"
|
|
"d '${cfg.homeDir}' 0771 qbittorrent qbittorrent - -"
|
|
];
|
|
|
|
sops.secrets.wg-qbittorrent-private-key.sopsFile = cfg.sopsFile;
|
|
|
|
networking.wireguard.interfaces.wg-qbittorrent = {
|
|
interfaceNamespace = "qbittorrent";
|
|
preSetup = "ip netns add qbittorrent && ip -n qbittorrent link set lo up";
|
|
postShutdown = "ip netns del qbittorrent";
|
|
|
|
privateKeyFile = config.sops.secrets.wg-qbittorrent-private-key.path;
|
|
} // (builtins.removeAttrs cfg.wireguardConnectionDetails [ "nameserver" ]);
|
|
|
|
environment.etc."netns/qbittorrent/resolv.conf".text = ''
|
|
nameserver ${cfg.wireguardConnectionDetails.nameserver}
|
|
'';
|
|
|
|
systemd.services.qbittorrent = {
|
|
description = "qBittorrent Service";
|
|
after = [ "wireguard-wg-qbittorrent.service" ];
|
|
requires = [ "wireguard-wg-qbittorrent.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
serviceConfig = {
|
|
PrivateNetwork = true;
|
|
NetworkNamespacePath = "/run/netns/qbittorrent";
|
|
|
|
Restart = "always";
|
|
ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox --profile=${cfg.configDir} --webui-port=${toString cfg.webuiPort}";
|
|
User = "qbittorrent";
|
|
Group = "qbittorrent";
|
|
|
|
# Increase number of open file descriptors (default: 1024)
|
|
LimitNOFILE = 65536;
|
|
|
|
# Avoid using nscd (leaks dns)
|
|
InaccessiblePaths = [
|
|
"/run/nscd"
|
|
"/etc/nsswitch.conf"
|
|
];
|
|
# Make correct resolv.conf available for unit
|
|
BindReadOnlyPaths = [
|
|
"/etc/netns/qbittorrent/resolv.conf:/etc/resolv.conf"
|
|
];
|
|
|
|
|
|
# systemd-analyze --no-pager security qbittorrent.service
|
|
CapabilityBoundingSet = null;
|
|
PrivateDevices = true;
|
|
PrivateTmp = true;
|
|
PrivateUsers = true;
|
|
ProtectHome = true;
|
|
RestrictNamespaces = true;
|
|
SystemCallFilter = "@system-service";
|
|
};
|
|
};
|
|
|
|
systemd.services.qbittorrent-webui-proxy = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "wireguard-wg-qbittorrent.service" ];
|
|
partOf = [ "wireguard-wg-qbittorrent.service" ];
|
|
|
|
serviceConfig = {
|
|
PrivateNetwork = true;
|
|
NetworkNamespacePath = "/run/netns/qbittorrent";
|
|
|
|
Restart = "always";
|
|
ExecStart = "${pkgs.socat}/bin/socat UNIX-LISTEN:${cfg.homeDir}/webui.sock,fork,reuseaddr,mode=660,unlink-early TCP:127.0.0.1:${toString cfg.webuiPort}";
|
|
User = "qbittorrent";
|
|
Group = "nginx";
|
|
|
|
# systemd-analyze --no-pager security qbittorrent-webui-proxy.service
|
|
CapabilityBoundingSet = null;
|
|
PrivateDevices = true;
|
|
PrivateTmp = true;
|
|
PrivateUsers = true;
|
|
ProtectHome = true;
|
|
RestrictNamespaces = true;
|
|
SystemCallFilter = "@system-service";
|
|
};
|
|
};
|
|
|
|
systemd.services.qbittorrent_exporter = {
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" ];
|
|
environment = {
|
|
QBITTORRENT_API_SOCKET = "${cfg.homeDir}/webui.sock";
|
|
QBITTORRENT_EXPORTER_LISTEN_ADDRESS = ":9561";
|
|
};
|
|
serviceConfig = {
|
|
ExecStart = "${pkgs.callPackage ./exporter { }}/bin/qbittorrent_exporter";
|
|
Restart = "always";
|
|
User = "qbittorrent";
|
|
Group = "qbittorrent";
|
|
|
|
# systemd-analyze --no-pager security qbittorrent_exporter.service
|
|
CapabilityBoundingSet = null;
|
|
PrivateDevices = true;
|
|
PrivateUsers = true;
|
|
ProtectHome = true;
|
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
|
|
RestrictNamespaces = true;
|
|
SystemCallArchitectures = "native";
|
|
SystemCallFilter = "@system-service";
|
|
};
|
|
};
|
|
|
|
services.nginx.virtualHosts."${cfg.fqdn}" = {
|
|
enableACME = lib.mkDefault true;
|
|
forceSSL = lib.mkDefault true;
|
|
|
|
# treated as state
|
|
basicAuthFile = "${cfg.homeDir}/htpasswd";
|
|
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://unix:${cfg.homeDir}/webui.sock";
|
|
proxyWebsockets = true;
|
|
};
|
|
"/download/" = {
|
|
alias = "${cfg.downloadDir}/";
|
|
extraConfig = ''
|
|
autoindex on;
|
|
'';
|
|
};
|
|
"=/metrics" = {
|
|
proxyPass = "http://127.0.0.1:9561/metrics";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|