diff --git a/flake.nix b/flake.nix index 3adb74c7..b0a91d91 100644 --- a/flake.nix +++ b/flake.nix @@ -124,7 +124,7 @@ ./shared/bookmarks/options.nix ./shared/umami/options.nix ./shared/concourse/options.nix - ./shared/rtorrent/options.nix + ./shared/torrents/options.nix ./shared/oci-containers/options.nix ./shared/pleroma/options.nix ./shared/resolved/options.nix diff --git a/hosts/nyarlathotep/configuration.nix b/hosts/nyarlathotep/configuration.nix index 5842528e..19ea6ce7 100644 --- a/hosts/nyarlathotep/configuration.nix +++ b/hosts/nyarlathotep/configuration.nix @@ -245,7 +245,7 @@ in services.caddy.virtualHosts."flood.nyarlathotep.lan:80".extraConfig = '' import restrict_vlan encode gzip - reverse_proxy http://localhost:${toString config.nixfiles.rtorrent.flood.port} + reverse_proxy http://localhost:${toString config.nixfiles.torrents.rpcPort} ''; services.caddy.virtualHosts."finder.nyarlathotep.lan:80".extraConfig = '' @@ -337,13 +337,14 @@ in ############################################################################### - ## rTorrent + ## torrents ############################################################################### - nixfiles.rtorrent.enable = true; - nixfiles.rtorrent.downloadDir = "/mnt/nas/torrents/files/"; - nixfiles.rtorrent.watchDir = "/mnt/nas/torrents/watch/"; - nixfiles.rtorrent.user = "barrucadu"; + nixfiles.torrents.enable = true; + nixfiles.torrents.downloadDir = "/mnt/nas/torrents/files"; + nixfiles.torrents.watchDir = "/mnt/nas/torrents/watch"; + nixfiles.torrents.user = "barrucadu"; + nixfiles.torrents.group = "users"; ############################################################################### diff --git a/hosts/nyarlathotep/jobs/restic-prepare--hardlink-torrent-files.py b/hosts/nyarlathotep/jobs/restic-prepare--hardlink-torrent-files.py index 4a8f95ce..6891ed10 100644 --- a/hosts/nyarlathotep/jobs/restic-prepare--hardlink-torrent-files.py +++ b/hosts/nyarlathotep/jobs/restic-prepare--hardlink-torrent-files.py @@ -11,7 +11,7 @@ # Directories to link MEDIA_DIRS = ["/mnt/nas/anime", "/mnt/nas/movies", "/mnt/nas/tv"] -# Where rtorrent downloads its files to +# Where torrent files are downloaded to TORRENT_FILES_DIR = "/mnt/nas/torrents/files" # Where .torrent files are stored diff --git a/shared/default.nix b/shared/default.nix index 0db6771f..c145c598 100644 --- a/shared/default.nix +++ b/shared/default.nix @@ -36,7 +36,7 @@ in ./pleroma ./resolved ./restic-backups - ./rtorrent + ./torrents ./umami ]; diff --git a/shared/rtorrent/default.nix b/shared/rtorrent/default.nix deleted file mode 100644 index 791e7cfb..00000000 --- a/shared/rtorrent/default.nix +++ /dev/null @@ -1,97 +0,0 @@ -# [rTorrent][] is a bittorrent client. This module configures it in a way -# appropriate for private trackers. -# -# This module does not include a backup script. Torrented files must be backed -# up independently. -# -# **Erase your darlings:** transparently stores session data and logs on the -# persistent volume. -# -# [rTorrent]: https://github.com/rakshasa/rtorrent -{ config, lib, pkgs, ... }: - -with lib; -let - cfg = config.nixfiles.rtorrent; - - stateDir = "/var/lib/rtorrent"; - logDir = "/var/log/rtorrent"; - rpcSocketPath = "/run/rtorrent/rpc.sock"; - - rtorrentrc = pkgs.writeText "rtorrent.rc" '' - # Paths - directory.default.set = ${cfg.downloadDir} - session.path.set = ${stateDir}/session/ - - # Logging - method.insert = cfg.logfile, private|const|string, (cat,"${logDir}/",(system.time),".log") - log.open_file = "log", (cfg.logfile) - ${concatMapStringsSep "\n" (lvl: "log.add_output = \"${lvl}\", \"log\"") cfg.logLevels} - - # Listening port for incoming peer traffic - network.port_range.set = ${toString cfg.portRange.from}-${toString cfg.portRange.to} - network.port_random.set = no - - # Optimise for private trackers (disable DHT & UDP trackers) - dht.mode.set = disable - protocol.pex.set = no - trackers.use_udp.set = no - - # Force encryption - protocol.encryption.set = allow_incoming,try_outgoing,require,require_RC4 - - # Write filenames in UTF-8 - encoding.add = UTF-8 - - # File options - pieces.hash.on_completion.set = yes - pieces.sync.always_safe.set = yes - - # Monitor for new .torrent files - schedule2 = watch_directory,5,5,load.start=${cfg.watchDir}*.torrent - - # XMLRPC - network.scgi.open_local = ${rpcSocketPath} - ''; - -in -{ - imports = [ - ./erase-your-darlings.nix - ./options.nix - ]; - - config = mkIf cfg.enable { - networking.firewall.allowedTCPPortRanges = mkIf cfg.openFirewall [ cfg.portRange ]; - - systemd.services.rtorrent = { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - serviceConfig = { - ExecStart = "${pkgs.rtorrent}/bin/rtorrent -n -o system.daemon.set=true -o import=${rtorrentrc}"; - User = cfg.user; - Restart = "on-failure"; - LogsDirectory = "rtorrent"; - RuntimeDirectory = "rtorrent"; - StateDirectory = "rtorrent/session"; - # with a lot of torrents, rtorrent can take a while to shut down - TimeoutStopSec = 300; - }; - }; - - systemd.services.flood = mkIf cfg.flood.enable { - enable = true; - wantedBy = [ "multi-user.target" ]; - after = [ "rtorrent.service" ]; - requires = [ "rtorrent.service" ]; - serviceConfig = { - ExecStart = "${pkgs.flood}/bin/flood --noauth --port=${toString cfg.flood.port} --rundir=${stateDir}/flood --rtsocket=${rpcSocketPath}"; - User = cfg.user; - Restart = "on-failure"; - StateDirectory = "rtorrent/flood"; - }; - }; - }; -} diff --git a/shared/rtorrent/erase-your-darlings.nix b/shared/rtorrent/erase-your-darlings.nix deleted file mode 100644 index 1b7195c3..00000000 --- a/shared/rtorrent/erase-your-darlings.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ config, lib, ... }: - -with lib; -let - cfg = config.nixfiles.rtorrent; - eyd = config.nixfiles.eraseYourDarlings; - - logDir = "/var/log/rtorrent"; - stateDir = "/var/lib/rtorrent"; -in -{ - config = mkIf (cfg.enable && eyd.enable) { - systemd.services.rtorrent.serviceConfig.BindPaths = [ - "${toString eyd.persistDir}${logDir}:${logDir}" - "${toString eyd.persistDir}${stateDir}/session:${stateDir}/session" - ]; - systemd.services.flood.serviceConfig.BindPaths = [ - "${toString eyd.persistDir}${stateDir}/flood:${stateDir}/flood" - ]; - }; -} diff --git a/shared/rtorrent/options.nix b/shared/rtorrent/options.nix deleted file mode 100644 index e4c83a2d..00000000 --- a/shared/rtorrent/options.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ lib, ... }: - -with lib; - -{ - options.nixfiles.rtorrent = { - enable = mkOption { - type = types.bool; - default = false; - description = mdDoc '' - Enable the [rTorrent](https://github.com/rakshasa/rtorrent) service. - ''; - }; - - downloadDir = mkOption { - type = types.str; - example = "/mnt/nas/torrents/files/"; - description = mdDoc '' - Directory to download torrented files to. - ''; - }; - - watchDir = mkOption { - type = types.str; - example = "/mnt/nas/torrents/watch/"; - description = mdDoc '' - Directory to monitor for new .torrent files. - ''; - }; - - user = mkOption { - type = types.str; - description = mdDoc '' - The user to run rTorrent as. - ''; - }; - - logLevels = mkOption { - type = types.listOf types.str; - default = [ "info" ]; - description = mdDoc '' - Verbosity of the log messages. - ''; - }; - - openFirewall = mkOption { - type = types.bool; - default = true; - description = mdDoc '' - Allow connections from TCP and UDP ports `''${portRange.from}` to - `''${portRange.to}`. - ''; - }; - - portRange = { - from = mkOption { - type = types.int; - default = 50000; - description = mdDoc '' - Lower bound (inclusive) of the port range to accept connections on. - ''; - }; - to = mkOption { - type = types.int; - default = 50000; - description = mdDoc '' - Upper bound (inclusive) of the port range to accept connections on. - ''; - }; - }; - - flood = { - enable = mkOption { - type = types.bool; - default = true; - description = mdDoc '' - Enable the [Flood](https://flood.js.org/) web UI. - ''; - }; - port = mkOption { - type = types.int; - default = 45904; - description = mdDoc '' - Port (on 127.0.0.1) to expose Flood on. - ''; - }; - }; - }; -} diff --git a/shared/torrents/default.nix b/shared/torrents/default.nix new file mode 100644 index 00000000..c699474c --- /dev/null +++ b/shared/torrents/default.nix @@ -0,0 +1,60 @@ +# [Transmission][] is a bittorrent client. This module configures it along with +# a web UI. +# +# This module does not include a backup script. Torrented files must be backed +# up independently. +# +# **Erase your darlings:** transparently stores session data on the persistent +# volume. +# +# [Transmission]: https://transmissionbt.com/ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.nixfiles.torrents; +in +{ + imports = [ + ./erase-your-darlings.nix + ./options.nix + ]; + + config = mkIf cfg.enable { + services.transmission = { + enable = true; + user = cfg.user; + group = cfg.group; + home = "${cfg.stateDir}/transmission"; + openPeerPorts = cfg.openFirewall; + webHome = pkgs.flood-for-transmission; + settings = { + # paths + download-dir = cfg.downloadDir; + watch-dir = cfg.watchDir; + watch-dir-enabled = true; + incomplete-dir-enabled = false; + + # optimise for private trackers (disable DHT and PEX, force encryption) + encryption = 2; + dht-enabled = false; + pex-enabled = false; + + # peers + peer-port = cfg.peerPort; + peer-port-random-on-start = false; + + # rpc + rpc-bind-address = "127.0.0.1"; + rpc-port = cfg.rpcPort; + rpc-host-whitelist-enabled = false; + + # misc + message-level = cfg.logLevel; + rename-partial-files = false; + trash-can-enabled = false; + trash-original-torrent-files = false; + }; + }; + }; +} diff --git a/shared/torrents/erase-your-darlings.nix b/shared/torrents/erase-your-darlings.nix new file mode 100644 index 00000000..367490bc --- /dev/null +++ b/shared/torrents/erase-your-darlings.nix @@ -0,0 +1,12 @@ +{ config, lib, ... }: + +with lib; +let + cfg = config.nixfiles.torrents; + eyd = config.nixfiles.eraseYourDarlings; +in +{ + config = mkIf (cfg.enable && eyd.enable) { + nixfiles.torrents.stateDir = "${toString eyd.persistDir}/var/lib/torrents"; + }; +} diff --git a/shared/torrents/options.nix b/shared/torrents/options.nix new file mode 100644 index 00000000..13507afc --- /dev/null +++ b/shared/torrents/options.nix @@ -0,0 +1,86 @@ +{ lib, ... }: + +with lib; + +{ + options.nixfiles.torrents = { + enable = mkOption { + type = types.bool; + default = false; + description = mdDoc '' + Enable the [Transmission](https://transmissionbt.com/) service. + ''; + }; + + downloadDir = mkOption { + type = types.str; + example = "/mnt/nas/torrents/files"; + description = mdDoc '' + Directory to download torrented files to. + ''; + }; + + stateDir = mkOption { + type = types.str; + example = "/var/lib/torrents"; + description = mdDoc '' + Directory to store service state in. + ''; + }; + + watchDir = mkOption { + type = types.str; + example = "/mnt/nas/torrents/watch"; + description = mdDoc '' + Directory to monitor for new .torrent files. + ''; + }; + + user = mkOption { + type = types.str; + description = mdDoc '' + The user to run Transmission as. + ''; + }; + + group = mkOption { + type = types.str; + description = mdDoc '' + The group to run Transmission as. + ''; + }; + + logLevel = mkOption { + type = types.ints.between 0 6; + default = 2; + description = mdDoc '' + Verbosity of the log messages. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + default = true; + description = mdDoc '' + Allow connections from TCP and UDP ports `''${portRange.from}` to + `''${portRange.to}`. + ''; + }; + + peerPort = mkOption { + type = types.port; + default = 50000; + description = mdDoc '' + Port to accept peer connections on. + ''; + }; + + rpcPort = mkOption { + type = types.port; + default = 49528; + description = mdDoc '' + Port to accept RPC connections on. Bound on 127.0.0.1. + ''; + }; + }; +}