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 /modules/nixos | |
parent | 7dac2d7245bc475ac0e8aa0ad4b41f3aa98f39f6 (diff) |
hosts/ahmed: Add qBittorrent
Diffstat (limited to 'modules/nixos')
-rw-r--r-- | modules/nixos/default.nix | 1 | ||||
-rw-r--r-- | modules/nixos/qbittorrent/default.nix | 166 |
2 files changed, 167 insertions, 0 deletions
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]; + }; + }; +} |