From d33b7b3faa9c296a3439dbe3a9d6132e7436e8b7 Mon Sep 17 00:00:00 2001 From: Mel Date: Thu, 4 Sep 2025 04:49:00 +0200 Subject: Add alternative BitTorrent client service (qBittorrent) Signed-off-by: Mel --- machines/corsac/default.nix | 2 +- services/torrent/default.nix | 145 +++++++++++++++++++++++++++++++ services/torrent/qbittorrent.nix | 49 +++++++++++ services/torrent/transmission.nix | 52 +++++++++++ services/transmission.nix | 176 -------------------------------------- 5 files changed, 247 insertions(+), 177 deletions(-) create mode 100644 services/torrent/default.nix create mode 100644 services/torrent/qbittorrent.nix create mode 100644 services/torrent/transmission.nix delete mode 100644 services/transmission.nix diff --git a/machines/corsac/default.nix b/machines/corsac/default.nix index c3d7d85..1eeb792 100644 --- a/machines/corsac/default.nix +++ b/machines/corsac/default.nix @@ -14,7 +14,7 @@ ../../services/home-assistant.nix ../../services/immich.nix - ../../services/transmission.nix + ../../services/torrent ]; foundation = { diff --git a/services/torrent/default.nix b/services/torrent/default.nix new file mode 100644 index 0000000..4e505ba --- /dev/null +++ b/services/torrent/default.nix @@ -0,0 +1,145 @@ +{ + me, + config, + lib, + pkgs, + auxiliaryPkgs, + ... +}: + +let + inherit (pkgs) dockerTools; + inherit (auxiliaryPkgs) common; + + torrentLocalPort = 2018; + torrentDir = "/srv/torrent"; + + mtu = 1280; + + # gluetun openvpn likes to ignore my mtu settings, + # so we set it forcefully every 15 seconds. + vpn-force-mtu = pkgs.writeTextFile { + name = "vpn-force-mtu"; + destination = "/scripts/vpn-force-mtu.sh"; + executable = true; + text = '' + #!/bin/ash + while true; do + /bin/sleep 15 + /sbin/ip link set dev tun0 mtu ${toString mtu} 2>/dev/null || true + done + ''; + }; + vpn-entry = pkgs.writeTextFile { + name = "vpn-entry"; + destination = "/scripts/vpn-entry.sh"; + executable = true; + text = '' + #!/bin/ash + /scripts/vpn-force-mtu.sh & + /gluetun-entrypoint + ''; + }; + + vpn-scripts = pkgs.symlinkJoin { + name = "vpn-scripts"; + paths = [ + vpn-entry + vpn-force-mtu + ]; + }; + + gluetunImage = common.pullImage { + name = "qmcgaw/gluetun"; + tag = "v3.39"; + digest = "sha256:6a8058e626763cbf735ac2f78c774dbb24fec2490bd9d9f7d67e22592cb4a991"; + x86.sha256 = "1cg43lmp3ql64zsfwp2f52kigijs30n3hnja12msr9npbgq8a8ga"; + }; + + vpnImage = dockerTools.streamLayeredImage { + name = "vpn"; + tag = "3.39.0-renard"; + fromImage = gluetunImage.base; + contents = [ vpn-scripts ]; + }; + + piaCountries = [ + "Albania" + "Austria" + "Belgium" + "Bosnia and Herzegovina" + "Bulgaria" + "Czech Republic" + "ES Madrid" + "ES Valencia" + "Estonia" + "Georgia" + "Greece" + "Hungary" + "IT Milano" + "Poland" + "Portugal" + "Romania" + "Serbia" + "Turkey" + "Ukraine" + ]; +in +{ + imports = [ + # pick current client through import + ./transmission.nix + #./qbittorrent.nix + ]; + + age.secrets.pia-login-secrets = { + file = ../../secrets/pia-login-secrets.age; + }; + + foundation = { + networks.vpn = { + enable = true; + driver = "bridge"; + # current vpn does not support ipv6! + ipv6.enable = false; + # lower MTU to prevent packet non-deliverability + inherit mtu; + }; + + services = { + vpn = { + network = "vpn"; + + image = vpnImage; + + ports = [ + (common.tailnetPort me [ + torrentLocalPort + torrentLocalPort + ]) + ]; + + volumes = [ + [ + "${torrentDir}/gluetun" + "/gluetun" + ] + ]; + + entrypoint = "/scripts/vpn-entry.sh"; + + capabilities = [ "NET_ADMIN" ]; + devices = [ "/dev/net/tun" ]; + + environment = { + VPN_SERVICE_PROVIDER = "private internet access"; + VPN_TYPE = "openvpn"; + OPENVPN_MSSFIX = toString mtu; + SERVER_REGIONS = lib.concatStringsSep "," piaCountries; + }; + + environmentFiles = [ config.age.secrets.pia-login-secrets.path ]; + }; + }; + }; +} diff --git a/services/torrent/qbittorrent.nix b/services/torrent/qbittorrent.nix new file mode 100644 index 0000000..88bacd9 --- /dev/null +++ b/services/torrent/qbittorrent.nix @@ -0,0 +1,49 @@ +{ + lib, + pkgs, + auxiliaryPkgs, + ... +}: + +let + inherit (pkgs) dockerTools; + inherit (auxiliaryPkgs) common; + + qbittorrent = pkgs.qbittorrent-nox; + + torrentLocalPort = 2018; + torrentDir = "/srv/torrent"; + + qbittorrentImage = dockerTools.streamLayeredImage { + name = "qbittorrent"; + tag = qbittorrent.version; + fromImage = common.alpine.base; + contents = [ qbittorrent ]; + }; +in +{ + foundation.services.torrent = { + image = qbittorrentImage; + + volumes = [ + [ + "${torrentDir}/qbittorrent" + "/qbittorrent/config" + ] + [ + "${torrentDir}/download" + "/qbittorrent/download" + ] + ]; + + entrypoint = lib.getExe qbittorrent; + cmd = [ + "--confirm-legal-notice" + "--profile=/qbittorrent/config" + + "--webui-port=${toString torrentLocalPort}" + ]; + + customNetworkOption = "container:vpn"; + }; +} diff --git a/services/torrent/transmission.nix b/services/torrent/transmission.nix new file mode 100644 index 0000000..e563e3f --- /dev/null +++ b/services/torrent/transmission.nix @@ -0,0 +1,52 @@ +{ + me, + config, + lib, + pkgs, + auxiliaryPkgs, + ... +}: + +let + inherit (pkgs) dockerTools; + inherit (auxiliaryPkgs) common; + + transmission = pkgs.transmission_4; + + torrentLocalPort = 2018; + torrentDir = "/srv/torrent"; + + transmissionImage = dockerTools.streamLayeredImage { + name = "transmission"; + tag = transmission.version; + fromImage = common.alpine.base; + contents = [ transmission ]; + }; +in +{ + foundation.services.torrent = { + image = transmissionImage; + + volumes = [ + [ + "${torrentDir}/transmission" + "/var/lib/transmission/config" + ] + [ + "${torrentDir}/download" + "/var/lib/transmission/download" + ] + ]; + + entrypoint = lib.getExe' transmission "transmission-daemon"; + cmd = [ + "--foreground" + "--port" + "${toString torrentLocalPort}" + "--config-dir" + "/var/lib/transmission/config" + ]; + + customNetworkOption = "container:vpn"; + }; +} diff --git a/services/transmission.nix b/services/transmission.nix deleted file mode 100644 index d761bc1..0000000 --- a/services/transmission.nix +++ /dev/null @@ -1,176 +0,0 @@ -{ - me, - config, - lib, - pkgs, - auxiliaryPkgs, - ... -}: - -let - inherit (pkgs) dockerTools; - inherit (auxiliaryPkgs) common; - - transmission = pkgs.transmission_4; - - transmissionLocalPort = 2018; - transmissionDir = "/srv/transmission"; - - mtu = 1280; - - # gluetun openvpn likes to ignore my mtu settings, - # so we set it forcefully every 15 seconds. - vpn-force-mtu = pkgs.writeTextFile { - name = "vpn-force-mtu"; - destination = "/scripts/vpn-force-mtu.sh"; - executable = true; - text = '' - #!/bin/ash - while true; do - /bin/sleep 15 - /sbin/ip link set dev tun0 mtu ${toString mtu} 2>/dev/null || true - done - ''; - }; - vpn-entry = pkgs.writeTextFile { - name = "vpn-entry"; - destination = "/scripts/vpn-entry.sh"; - executable = true; - text = '' - #!/bin/ash - /scripts/vpn-force-mtu.sh & - /gluetun-entrypoint - ''; - }; - - vpn-scripts = pkgs.symlinkJoin { - name = "vpn-scripts"; - paths = [ - vpn-entry - vpn-force-mtu - ]; - }; - - transmissionImage = dockerTools.streamLayeredImage { - name = "transmission"; - tag = transmission.version; - fromImage = common.alpine.base; - contents = [ transmission ]; - }; - - gluetunImage = common.pullImage { - name = "qmcgaw/gluetun"; - tag = "v3.39"; - digest = "sha256:6a8058e626763cbf735ac2f78c774dbb24fec2490bd9d9f7d67e22592cb4a991"; - x86.sha256 = "1cg43lmp3ql64zsfwp2f52kigijs30n3hnja12msr9npbgq8a8ga"; - }; - - vpnImage = dockerTools.streamLayeredImage { - name = "vpn"; - tag = "3.39.0-renard"; - fromImage = gluetunImage.base; - contents = [ vpn-scripts ]; - }; - - piaCountries = [ - "Albania" - "Austria" - "Belgium" - "Bosnia and Herzegovina" - "Bulgaria" - "Czech Republic" - "ES Madrid" - "ES Valencia" - "Estonia" - "Georgia" - "Greece" - "Hungary" - "IT Milano" - "Poland" - "Portugal" - "Romania" - "Serbia" - "Turkey" - "Ukraine" - ]; -in -{ - age.secrets.pia-login-secrets = { - file = ../secrets/pia-login-secrets.age; - }; - - foundation = { - networks.vpn = { - enable = true; - driver = "bridge"; - # current vpn does not support ipv6! - ipv6.enable = false; - # lower MTU to prevent packet non-deliverability - inherit mtu; - }; - - services = { - transmission = { - image = transmissionImage; - - volumes = [ - [ - "${transmissionDir}/config" - "/var/lib/transmission/config" - ] - [ - "${transmissionDir}/download" - "/var/lib/transmission/download" - ] - [ - "${transmissionDir}/torrents" - "/var/lib/transmission/torrents" - ] - ]; - - entrypoint = lib.getExe' transmission "transmission-daemon"; - cmd = [ - "--foreground" - "--config-dir" - "/var/lib/transmission/config" - ]; - - customNetworkOption = "container:vpn"; - }; - - vpn = { - network = "vpn"; - - image = vpnImage; - - ports = [ - (common.tailnetPort me [ - transmissionLocalPort - 9091 - ]) - ]; - - volumes = [ - [ - "${transmissionDir}/gluetun" - "/gluetun" - ] - ]; - - entrypoint = "/scripts/vpn-entry.sh"; - - capabilities = [ "NET_ADMIN" ]; - devices = [ "/dev/net/tun" ]; - - environment = { - VPN_SERVICE_PROVIDER = "private internet access"; - VPN_TYPE = "openvpn"; - OPENVPN_MSSFIX = toString mtu; - SERVER_REGIONS = lib.concatStringsSep "," piaCountries; - }; - - environmentFiles = [ config.age.secrets.pia-login-secrets.path ]; - }; - }; - }; -} -- cgit 1.4.1