diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index aba4d3d72d1df..45bc518b04ea4 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -41,6 +41,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable). +- Systemd's service for [qbittorrent-nox](https://github.com/qbittorrent/qBittorrent), a headless version of `qbittorrent`, the bittorrent client. Available as [`services.qbittorrent-nox.enable`](#opt-services.qbittorrent-nox.enable), please refer to other configurations under [`services.qbittorrent-nox`](#opt-services.qbittorrent-nox). + - [TuxClocker](https://github.com/Lurkki14/tuxclocker), a hardware control and monitoring program. Available as [programs.tuxclocker](#opt-programs.tuxclocker.enable). ## Backward Incompatibilities {#sec-release-24.05-incompatibilities} diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 5af7284ac71af..6abf04ed10fa2 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -356,6 +356,7 @@ in rstudio-server = 324; localtimed = 325; automatic-timezoned = 326; + qbittorrent-nox = 327; # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399! @@ -666,6 +667,7 @@ in rstudio-server = 324; localtimed = 325; automatic-timezoned = 326; + qbittorrent-nox = 327; # When adding a gid, make sure it doesn't match an existing # uid. Users and groups with the same name should have equal diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4e3ce4d088968..aa2e4bef48c9a 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1237,6 +1237,7 @@ ./services/torrent/magnetico.nix ./services/torrent/opentracker.nix ./services/torrent/peerflix.nix + ./services/torrent/qbittorrent-nox.nix ./services/torrent/rtorrent.nix ./services/torrent/transmission.nix ./services/torrent/torrentstream.nix diff --git a/nixos/modules/services/torrent/qbittorrent-nox.nix b/nixos/modules/services/torrent/qbittorrent-nox.nix new file mode 100644 index 0000000000000..6d9ed8b50c4b4 --- /dev/null +++ b/nixos/modules/services/torrent/qbittorrent-nox.nix @@ -0,0 +1,141 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.qbittorrent-nox; +in { + options = { + services = { + qbittorrent-nox = { + enable = mkEnableOption (lib.mdDoc "qbittorrent-nox daemon"); + + web = { + port = mkOption { + type = types.port; + default = 8080; + description = lib.mdDoc '' + qbittorrent-nox web UI port. + ''; + }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + Whether to open the firewall for the ports in + {option}`services.qbittorrent-nox.web.port`. + ''; + }; + }; + + torrenting = { + port = mkOption { + type = types.port; + default = 48197; + description = lib.mdDoc '' + qbittorrent-nox web UI port. + ''; + }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = lib.mdDoc '' + Whether to open the firewall for the ports in + {option}`services.qbittorrent-nox.torrenting.port`. + ''; + }; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/qbittorrent-nox"; + description = lib.mdDoc '' + The directory where qbittorrent-nox will create files. + ''; + }; + + user = mkOption { + type = types.str; + default = "qbittorrent"; + description = lib.mdDoc '' + User account under which qbittorrent-nox runs. + ''; + }; + + group = mkOption { + type = types.str; + default = "qbittorrent"; + description = lib.mdDoc '' + Group under which qbittorrent-nox runs. + ''; + }; + + package = mkPackageOption pkgs "qbittorrent-nox" { }; + }; + }; + }; + + config = mkIf cfg.enable { + + services.qbittorrent-nox.package = mkDefault (pkgs.qbittorrent-nox); + + systemd.tmpfiles.rules = [ + "d '${cfg.dataDir}' 0770 ${cfg.user} ${cfg.group}" + "d '${cfg.dataDir}/.config' 0770 ${cfg.user} ${cfg.group}" + "d '${cfg.dataDir}/.config/qBittorrent' 0770 ${cfg.user} ${cfg.group}" + ]; + + systemd.services.qbittorrent-nox = { + after = [ "network.target" "local-fs.target" "network-online.target" "nss-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ cfg.package ]; + unitConfig = { + Description = "qBittorrent-nox Daemon"; + Documentation = "man:qbittorrent-nox(1)"; + }; + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/qbittorrent-nox \ + --profile=${cfg.dataDir} \ + --webui-port=${toString cfg.web.port} \ + --torrenting-port=${toString cfg.torrenting.port} + ''; + Type = "exec"; + User = cfg.user; + Group = cfg.group; + UMask = "0002"; + PrivateTmp = "false"; + TimeoutStopSec = 1800; + }; + # preStart = preStart; + }; + + networking.firewall = mkMerge [ + (mkIf (cfg.torrenting.openFirewall) { + allowedTCPPorts = [ cfg.torrenting.port ]; + allowedUDPPorts = [ cfg.torrenting.port ]; + }) + (mkIf (cfg.web.openFirewall) { + allowedTCPPorts = [ cfg.web.port ]; + }) + ]; + + environment.systemPackages = [ cfg.package ]; + + users.users = mkIf (cfg.user == "qbittorrent") { + qbittorrent = { + group = cfg.group; + uid = config.ids.uids.qbittorrent-nox; + home = cfg.dataDir; + description = "qbittorrent daemon user"; + }; + }; + + users.groups = mkIf (cfg.group == "qbittorrent") { + qbittorrent = { + gid = config.ids.gids.qbittorrent-nox; + }; + }; + }; +} diff --git a/nixos/tests/qbittorrent-nox.nix b/nixos/tests/qbittorrent-nox.nix new file mode 100644 index 0000000000000..4a7efc0c6849f --- /dev/null +++ b/nixos/tests/qbittorrent-nox.nix @@ -0,0 +1,29 @@ +import ./make-test-python.nix ({ pkgs, ...} : { + name = "qbittorrent-nox"; + meta = with pkgs.lib.maintainers; { + maintainers = [ camilosampedro ]; + }; + + nodes = { + simple = { + services.qbittorrent-nox = { + enable = true; + package = pkgs.qbittorrent-nox; + port = 8091; + web = { + enable = true; + openFirewall = true; + }; + }; + }; + + }; + + testScript = '' + start_all() + + simple.wait_for_unit("qbittorrent-nox") + simple.wait_for_open_port(8091) + simple.wait_until_succeeds("curl --fail http://simple:8091") + ''; +})