diff options
author | Linnnus <[email protected]> | 2024-03-09 20:01:10 +0100 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-04-07 13:41:38 +0200 |
commit | 4c95d6f14be1bde2ae9e33d2318bf8e1c8ff8134 (patch) | |
tree | 5204448d084ddf28ea511c07d5785cf5b837742b | |
parent | 7dac2d7245bc475ac0e8aa0ad4b41f3aa98f39f6 (diff) |
hosts/ahmed: Add qBittorrent
-rw-r--r-- | hosts/ahmed/configuration.nix | 1 | ||||
-rw-r--r-- | hosts/ahmed/hellohtml.linus.onl/default.nix | 2 | ||||
-rw-r--r-- | hosts/ahmed/torrenting/default.nix | 37 | ||||
-rw-r--r-- | modules/nixos/default.nix | 1 | ||||
-rw-r--r-- | modules/nixos/qbittorrent/default.nix | 166 | ||||
-rw-r--r-- | overlays/default.nix | 14 |
6 files changed, 220 insertions, 1 deletions
diff --git a/hosts/ahmed/configuration.nix b/hosts/ahmed/configuration.nix index 27c35eb..9d49d32 100644 --- a/hosts/ahmed/configuration.nix +++ b/hosts/ahmed/configuration.nix @@ -17,6 +17,7 @@ ./linus.onl ./nofitications.linus.onl ./ssh + ./torrenting ./home ]; diff --git a/hosts/ahmed/hellohtml.linus.onl/default.nix b/hosts/ahmed/hellohtml.linus.onl/default.nix index 4859ed3..f973c11 100644 --- a/hosts/ahmed/hellohtml.linus.onl/default.nix +++ b/hosts/ahmed/hellohtml.linus.onl/default.nix @@ -20,7 +20,7 @@ in { ]; # Use NGINX as reverse proxy. - services.nginx.virtualHosts.${mainDomain}= { + services.nginx.virtualHosts.${mainDomain} = { # Set up secondary domain name to also point to this host. Only the # client (browser) should treat these as separate. On the server, they # are the same. diff --git a/hosts/ahmed/torrenting/default.nix b/hosts/ahmed/torrenting/default.nix new file mode 100644 index 0000000..c49baa6 --- /dev/null +++ b/hosts/ahmed/torrenting/default.nix @@ -0,0 +1,37 @@ +# This module configures the my torrenting setup. It uses qBittorrent over a VPN. +{pkgs, options, config, ...}: let + downloadPath = "/srv/media/"; + + interface = "tun0"; +in { + # Configure the actual qBittorrent service. + services.qbittorrent = { + enable = true; + + openFirewall = true; # TEMP: reverse proxy will cover this instead + + settings = { + BitTorrent = { + # Use the specified download path for finished torrents. + "Session\\DefaultSavePath" = downloadPath; + "Session\\TempPath" = "${config.services.qbittorrent.profile}/qBittorrent/temp"; + "Session\\TempPathEnabled" = true; + }; + + # Instruct qBittorrent to only use VPN interface. + }; + }; + + # Create the directory to which media will be downloaded. + # This is also used by Jellyfin to serve the files. + systemd.tmpfiles.rules = let + user = options.services.qbittorrent.user.default; + group = options.services.qbittorrent.group.default; + in [ + "d ${downloadPath} 0755 ${user} ${group}" + ]; + + # Create a connection to Mullvad's WireGuard server. + + # Use NGINX as a reverse proxy for qBittorrent's WebUI. +} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index b813155..77a5faa 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -1,4 +1,5 @@ { on-demand-minecraft = import ./on-demand-minecraft; hellohtml = import ./hellohtml; + qbittorrent = import ./qbittorrent; } diff --git a/modules/nixos/qbittorrent/default.nix b/modules/nixos/qbittorrent/default.nix new file mode 100644 index 0000000..2d2c591 --- /dev/null +++ b/modules/nixos/qbittorrent/default.nix @@ -0,0 +1,166 @@ +# This module defines a service which runs a headless qBittorrent instance +{ + config, + options, + lib, + pkgs, + ... +}: let + defaultUser = "qbittorrent"; + defaultGroup = "qbittorrent"; + + cfg = config.services.qbittorrent; +in { + options.services.qbittorrent = { + enable = lib.mkEnableOption "headless qBittorrent instance"; + + port = lib.mkOption { + description = "The port on which to serve the WebUI."; + type = lib.types.port; + default = 8080; + }; + + openFirewall = lib.mkOption { + description = '' + Open holes in the firewall so clients on LAN can connect to the web + interface. You must set up port forwarding if you want it accessable + from the wider internet. + ''; + type = lib.types.bool; + default = false; + }; + + profile = lib.mkOption { + description = '' + The directory where qBittorrent should store it's data files. Note that + these are for qBittorrent itself, not the files it downloads. Those are + controlled through the configuration option `XXX`. + ''; + type = lib.types.path; + default = "/var/lib/qBittorrent"; + }; + + user = lib.mkOption { + description = '' + The user to run the qBittorrent service as. + + The user is not automatically created if it is changed from the default value. + ''; + type = lib.types.str; + default = defaultUser; + }; + + group = lib.mkOption { + description = '' + The group to run the qBittorrent service as. + + The group is not automatically created if it is changed from the default value. + ''; + type = lib.types.str; + default = defaultGroup; + }; + + package = lib.mkOption { + description = "qBittorrent package to use"; + type = lib.types.package; + default = pkgs.qbittorrent-nox; + }; + + settings = lib.mkOption rec { + description = '' + An attribute set whose values overrides the ones specified in + `qBittorrent.conf`. + + These values are applied on top of the existing configuration when the + service starts. This is a necessary compromise between determinism and + usability, as qBittorrent also saves all kinds of gunk in the + configuration file. + ''; + type = lib.types.attrs; + default = { + LegalNotice = { + Accepted = false; + }; + }; + apply = lib.recursiveUpdate default; + example = { + LegalNotice = { + Accepted = true; + }; + Preferences = { + "Connection\\PortRangeMin" = 20082; + "Downloads\\SavePath" = "/mnt"; + "WebUI\\UseUPnP" = false; + }; + }; + }; + }; + + config = lib.mkIf cfg.enable { + # Create the user/group if required. + users.users = lib.mkIf (cfg.user == defaultUser) { + ${defaultUser} = { + description = "Runs ${options.services.qbittorrent.enable.description}"; + group = cfg.group; + isSystemUser = true; + }; + }; + users.groups = lib.mkIf (cfg.group == defaultGroup) { + ${defaultGroup} = {}; + }; + + # Set up a service to run qBittorrent + # See: https://github.com/qbittorrent/qBittorrent/blob/615b76f78c8ab92ad57bed42fc4266950c9f0251/dist/unix/systemd/qbittorrent-nox%40.service.in + systemd.services.qbittorrent = { + enable = true; + + unitConfig = { + Wants = ["network-online.target"]; + After = ["local-fs.target" "network-online.target" "nss-lookup.target"]; + }; + + serviceConfig = { + Type = "simple"; + + User = cfg.user; + Group = cfg.group; + PrivateTmp = false; + + ExecStartPre = let + format = pkgs.formats.ini {}; + settingsFile = format.generate "qBittorrent.conf" cfg.settings; + configPath = "${cfg.profile}/qBittorrent/config/qBittorrent.conf"; + + start-pre-script = pkgs.writeShellScript "qbittorrent-start-pre" '' + set -ue + + # Create data directory if it doesn't exist + if ! test -d ${cfg.profile}; then + echo "Creating initial qBittorrent data directory in: ${cfg.profile}" + install -d -m 0755 -o ${cfg.user} -g ${cfg.group} ${cfg.profile}/qBittorrent/config/ + fi + + # Force-apply configuration. + ${pkgs.crudini}/bin/crudini --ini-options=nospace --merge ${configPath} <${settingsFile} + ''; + in + # Requires full permissions to create data directory, hence the "!". + "!${start-pre-script}"; + ExecStart = pkgs.writeShellScript "qbittorrent-start" '' + exec ${cfg.package}/bin/qbittorrent-nox --webui-port=${toString cfg.port} --profile=${cfg.profile} + ''; + TimeoutStopSec = 1800; + + # Set as low-priority + IOSchedulingClass = "idle"; + IOSchedulingPriority = "7"; + }; + + wantedBy = ["multi-user.target"]; + }; + + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = [cfg.port]; + }; + }; +} diff --git a/overlays/default.nix b/overlays/default.nix index b87fbfb..438d924 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -19,6 +19,20 @@ + (final.lib.strings.optionalString (final.stdenv.cc.isGNU or false) " -Wno-maybe-uninitialized"); }); + # Use a slightly newer version of qBittorrent that doesn't include the password bug. + # + # See: https://old.reddit.com/r/qBittorrent/comments/1827zqn/locked_out_of_qbittorrent/kahat1u/?context=3 + # See: https://www.qbittorrent.org/news#mon-nov-27th-2023---qbittorrent-v4.6.2-release + qbittorrent-nox = prev.qbittorrent-nox.overrideAttrs (old: rec { + version = "4.6.2"; + src = final.fetchFromGitHub { + owner = "qbittorrent"; + repo = "qBittorrent"; + rev = "release-${version}"; + hash = "sha256-+leX0T+yJUG6F7WbHa3nCexQZmd7RRfK8Uc+suMJ+vI="; + }; + }); + # Use newest version. noweb = prev.noweb.overrideAttrs (old: rec { version = "2_13rc3"; |