summaryrefslogtreecommitdiff
path: root/modules/nixos/rtorrent.nix
diff options
context:
space:
mode:
authorAzat Bahawi <azat@bahawi.net>2022-12-17 16:39:09 +0300
committerAzat Bahawi <azat@bahawi.net>2022-12-17 16:39:09 +0300
commit8f137c28230623259a964484adcf31fe00756594 (patch)
tree82bce6a13fda125087cf6d9dc80aa91d9230d6c4 /modules/nixos/rtorrent.nix
parent3229e56e0d3620ddc735edcfbbefb167efa3b23f (diff)
2022-12-17
Diffstat (limited to 'modules/nixos/rtorrent.nix')
-rw-r--r--modules/nixos/rtorrent.nix297
1 files changed, 297 insertions, 0 deletions
diff --git a/modules/nixos/rtorrent.nix b/modules/nixos/rtorrent.nix
new file mode 100644
index 0000000..4014a3b
--- /dev/null
+++ b/modules/nixos/rtorrent.nix
@@ -0,0 +1,297 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.nixfiles.modules.rtorrent;
+in {
+ options.nixfiles.modules.rtorrent = {
+ enable = mkEnableOption "rTorrent";
+
+ flood = {
+ enable = mkEnableOption "Flood" // {default = cfg.enable;};
+
+ domain = mkOption {
+ description = "Domain name sans protocol scheme.";
+ type = with types; str;
+ default = "flood.${config.networking.domain}";
+ };
+ };
+ };
+
+ config = let
+ user = "rtorrent";
+ group = "rtorrent";
+ baseDir = "/var/lib/rtorrent";
+ rpcSocket = "${baseDir}/rpc.socket";
+ in
+ mkIf cfg.enable (mkMerge [
+ (let
+ port = 50000;
+ in {
+ systemd = {
+ services.rtorrent = {
+ description = "rTorrent";
+ after = ["network.target" "local-fs.target"];
+ serviceConfig = let
+ leechDir = "${baseDir}/leech";
+ seedDir = "${baseDir}/seed";
+ sessionDir = "${baseDir}/session";
+ logDir = "${baseDir}/log";
+ configFile = let
+ moveCompleted = let
+ pkg = pkgs.writeShellApplication {
+ name = "move-completed";
+ runtimeInputs = with pkgs; [
+ coreutils-full
+ gnused
+ findutils
+ ];
+ text = ''
+ set -x
+
+ leech_path="$1"
+ seed_path="$2"
+ # seed_path="$(echo "$2" | sed 's@+@ @g;s@%@\\x@g' | xargs -0 printf '%b')"
+
+ mkdir -pv "$seed_path"
+ mv -fv "$leech_path" "$seed_path"
+ '';
+ };
+ in "${pkg}/bin/move-completed";
+ in
+ pkgs.writeText "rtorrent.rc" ''
+ method.insert = cfg.leech, private|const|string, (cat, "${leechDir}")
+ method.insert = cfg.seed, private|const|string, (cat, "${seedDir}")
+ method.insert = cfg.session, private|const|string, (cat, "${sessionDir}")
+ method.insert = cfg.log, private|const|string, (cat, "${logDir}")
+ method.insert = cfg.rpcsocket, private|const|string, (cat, "${rpcSocket}")
+
+ directory.default.set = (cat, (cfg.leech))
+ session.path.set = (cat, (cfg.session))
+
+ network.port_range.set = ${toString port}-${toString port}
+ network.port_random.set = no
+
+ dht.mode.set = disable
+ protocol.pex.set = no
+
+ trackers.use_udp.set = no
+
+ protocol.encryption.set = allow_incoming,try_outgoing,enable_retry
+
+ pieces.memory.max.set = ${toString (pow 2 11)}M
+ pieces.preload.type.set = 2
+
+ network.xmlrpc.size_limit.set = ${toString (pow 2 17)}
+
+ network.max_open_files.set = ${toString (pow 2 10)}
+ network.max_open_sockets.set = ${toString (pow 2 10)}
+
+ network.http.max_open.set = ${toString (pow 2 8)}
+
+ throttle.global_down.max_rate.set_kb = 0
+ throttle.global_up.max_rate.set_kb = 0
+
+ encoding.add = UTF-8
+ system.umask.set = 0027
+ system.cwd.set = (directory.default)
+
+ network.scgi.open_local = (cat, (cfg.rpcsocket))
+
+ method.insert = d.move_completed, simple, "\
+ d.directory.set=$argument.1=;\
+ execute=${moveCompleted}, $argument.0=, $argument.1=;\
+ d.save_full_session=\
+ "
+ method.insert = d.leech_path, simple, "\
+ if=(d.is_multi_file),\
+ (cat, (d.directory), /),\
+ (cat, (d.directory), /, (d.name))\
+ "
+ method.insert = d.seed_path, simple, "\
+ cat=$cfg.seed=, /, $d.custom1=\
+ "
+ method.set_key = event.download.finished, move_complete, "\
+ d.move_completed=$d.leech_path=, $d.seed_path=\
+ "
+
+ log.open_file = "log", (cat, (cfg.log), "/", "default.log")
+ log.add_output = "info", "log"
+ log.execute = (cat, (cfg.log), "/", "execute.log")
+ '';
+ in {
+ Restart = "on-failure";
+ RestartSec = 3;
+
+ KillMode = "process";
+ KillSignal = "SIGHUP";
+
+ User = user;
+ Group = group;
+
+ ExecStartPre = concatStringsSep " " [
+ "${pkgs.coreutils-full}/bin/mkdir -p"
+ leechDir
+ seedDir
+ sessionDir
+ logDir
+ ];
+ ExecStart = concatStringsSep " " [
+ "${pkgs.rtorrent}/bin/rtorrent"
+ "-n"
+ "-o system.daemon.set=true"
+ "-o network.bind_address.set=0.0.0.0"
+ "-o import=${configFile}"
+ ];
+ ExecStop = concatStringsSep " " [
+ "${pkgs.coreutils-full}/bin/rm -rf"
+ rpcSocket
+ ];
+
+ RuntimeDirectory = "rtorrent";
+ RuntimeDirectoryMode = 0750;
+ UMask = 0027;
+ AmbientCapabilities = [""];
+ CapabilityBoundingSet = [""];
+ LockPersonality = true;
+ MemoryDenyWriteExecute = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProcSubset = "pid";
+ RemoveIPC = true;
+ RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = ["@system-service" "~@resources" "~@privileged"];
+ };
+ wantedBy = ["multi-user.target"];
+ };
+
+ tmpfiles.rules = ["d '${baseDir}' 0750 ${user} ${group} -"];
+ };
+
+ users = {
+ users.${user} = {
+ inherit group;
+ shell = pkgs.bashInteractive;
+ home = baseDir;
+ description = "rTorrent";
+ isSystemUser = true;
+ };
+ groups.${group} = {};
+ };
+ my.extraGroups = [group];
+
+ networking.firewall.allowedTCPPorts = [port];
+
+ boot.kernel.sysctl = {
+ "net.core.rmem_max" = mkOverride 500 (pow 2 24);
+ "net.core.wmem_max" = mkOverride 500 (pow 2 24);
+ "net.ipv4.tcp_fin_timeout" = mkOverride 500 30;
+ "net.ipv4.tcp_rmem" = mkOverride 500 (mkTcpMem 12 23 24);
+ "net.ipv4.tcp_slow_start_after_idle" = 0;
+ "net.ipv4.tcp_tw_recycle" = mkOverride 500 1;
+ "net.ipv4.tcp_tw_reuse" = mkOverride 500 1;
+ "net.ipv4.tcp_wmem" = mkOverride 500 (mkTcpMem 12 23 24);
+ };
+ })
+ (let
+ port = 50001;
+ pkg = pkgs.nodePackages.flood;
+ in
+ mkIf cfg.flood.enable {
+ nixfiles.modules.nginx = {
+ enable = true;
+ upstreams.flood.servers."127.0.0.1:${toString port}" = {};
+ virtualHosts.${cfg.flood.domain} = {
+ root = "${pkg}/lib/node_modules/flood/dist/assets";
+ locations = {
+ "/".tryFiles = "$uri /index.html";
+ "/api" = {
+ proxyPass = "http://flood";
+ extraConfig = ''
+ proxy_buffering off;
+ proxy_cache off;
+ '';
+ };
+ };
+ extraConfig = nginxInternalOnly;
+ };
+ };
+
+ systemd.services.flood = {
+ description = "Flood";
+ after = ["network.target" "rtorrent.service"];
+ path = with pkgs; [mediainfo];
+ serviceConfig = {
+ Restart = "on-failure";
+ RestartSec = 3;
+
+ User = user;
+ Group = group;
+
+ ExecStart = concatStringsSep " " [
+ "${pkg}/bin/flood"
+ "--allowedpath=${baseDir}"
+ "--baseuri=/"
+ "--rundir=${baseDir}/flood"
+ "--host=127.0.0.1"
+ "--port=${toString port}"
+ "--rtsocket=${rpcSocket}"
+ "--ssl=false"
+ "--auth=none"
+ ];
+
+ RuntimeDirectory = "rtorrent";
+ RuntimeDirectoryMode = 0750;
+ UMask = 0027;
+ AmbientCapabilities = [""];
+ CapabilityBoundingSet = [""];
+ LockPersonality = true;
+ NoNewPrivileges = true;
+ PrivateDevices = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProcSubset = "pid";
+ ProtectProc = "invisible";
+ RemoveIPC = true;
+ RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [
+ "~@cpu-emulation"
+ "~@debug"
+ "~@mount"
+ "~@obsolete"
+ "~@privileged"
+ "~@resources"
+ ];
+ };
+ wantedBy = ["multi-user.target"];
+ };
+ })
+ ]);
+}