diff --git a/modules/nixos/guests/torrent/default.nix b/modules/nixos/guests/torrent/default.nix index 3ce323b..fe7f6a5 100755 --- a/modules/nixos/guests/torrent/default.nix +++ b/modules/nixos/guests/torrent/default.nix @@ -12,8 +12,6 @@ let dns0 = instances.web.dns.provider0; dns0Path = "dns/${dns0}"; torrentPort = 51820; - vpnEndpoint = "185.111.110.1"; - localNet = "192.168.50.0/24"; in { microvm.vms.${serviceCfg.name} = { @@ -21,25 +19,18 @@ in config = { system.stateVersion = "25.05"; - # VPN Killswitch - configured BEFORE networking starts - boot.kernel.sysctl = { - "net.ipv4.ip_forward" = 1; - }; - networking = { - # Disable default firewall - we're doing it manually - firewall.enable = false; - wg-quick.interfaces = { wg0 = { - address = [ "10.2.0.2/32" ]; + address = [ + "10.2.0.2/32" + ]; dns = [ "10.2.0.1" ]; privateKeyFile = "/run/secrets/wireguard-pass"; - peers = [ { publicKey = "QPfiwJQmt5VLEOh1ufLbi1lj6LUnwQY0tgDSh3pWx1k="; - endpoint = "${vpnEndpoint}:${toString torrentPort}"; + endpoint = "185.111.110.1:${builtins.toString torrentPort}"; allowedIPs = [ "0.0.0.0/0" "::/0" @@ -47,62 +38,33 @@ in persistentKeepalive = 25; } ]; - - # Now we can safely open the VPN tunnel for all traffic - postUp = '' - echo "VPN UP: Opening network for VPN and local traffic" - - # Allow ALL traffic through VPN interface - ${pkgs.iptables}/bin/iptables -A INPUT -i wg0 -j ACCEPT - ${pkgs.iptables}/bin/iptables -A OUTPUT -o wg0 -j ACCEPT - - # Allow local network traffic (WebUI, management) - ${pkgs.iptables}/bin/iptables -A INPUT -i enp0s5 -s ${localNet} -j ACCEPT - ${pkgs.iptables}/bin/iptables -A OUTPUT -o enp0s5 -d ${localNet} -j ACCEPT - - # NAT for VPN - ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE - - # Allow forwarding through VPN (for port forwarding) - ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT - ${pkgs.iptables}/bin/iptables -A FORWARD -o wg0 -j ACCEPT - ${pkgs.iptables}/bin/iptables -A FORWARD -i enp0s5 -o wg0 -j ACCEPT - ${pkgs.iptables}/bin/iptables -A FORWARD -o enp0s5 -i wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - - echo "VPN UP: Network opened for VPN and local traffic" - ''; - - preDown = '' - echo "VPN DOWN: Removing VPN rules, killswitch remains active" - ${pkgs.iptables}/bin/iptables -D INPUT -i wg0 -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D OUTPUT -o wg0 -j ACCEPT 2>/dev/null || true - - ${pkgs.iptables}/bin/iptables -D INPUT -i enp0s5 -s ${localNet} -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D OUTPUT -o enp0s5 -d ${localNet} -j ACCEPT 2>/dev/null || true - - ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE 2>/dev/null || true - - ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -o wg0 -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -i enp0s5 -o wg0 -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -o enp0s5 -i wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true - - echo "VPN DOWN: Killswitch rules remain - no internet access" - ''; }; }; - + firewall = { + enable = true; + allowedTCPPorts = [ + 22 + torrentPort + serviceCfg.ports.port0 + ]; + allowedUDPPorts = [ + torrentPort + ]; + }; dhcpcd.enable = false; useNetworkd = true; }; + # imports = [ + # ./rqbit.nix + # ]; + services = { qbittorrent = { enable = true; webuiPort = serviceCfg.ports.port0; torrentingPort = torrentPort; - openFirewall = false; # We're managing firewall manually - + openFirewall = true; serverConfig = { LegalNotice.Accepted = true; @@ -114,20 +76,23 @@ in Port = torrentPort; MaxConnectionsPerTorrent = -1; MaxUploads = -1; - QueueingSystemEnabled = false; + MaxActiveDownloads = 999; + MaxActiveUploads = 999; + MaxActiveTorrents = 999; }; }; Preferences = { WebUI = { Username = "user"; + # generate new passwords with this: + # https://codeberg.org/feathecutie/qbittorrent_password Password_PBKDF2 = "@ByteArray(1bJKXLVSLU6kgCHbCS2lDg==:BmyrMaod6dbJqEe7Ud/JgKAxRMqzsAuEjHcTvLzIBgc5rc5Z7J2X9mbH0cDEAhXqc+O3gQxrckt8S2Gf+zlO9w==)"; }; General = { Locale = "en"; }; - Downloads = { SavePath = "${serviceCfg.varPaths.path0}/downloads"; TempPathEnabled = false; @@ -160,151 +125,9 @@ in "d ${serviceCfg.varPaths.path0}/downloads 755 ${serviceCfg.name} ${serviceCfg.name} -" ]; - services = { - # Ensure qBittorrent ONLY starts after VPN is up - qbittorrent = { - after = [ - "wg-quick-wg0.service" - "network-online.target" - ]; - requires = [ "wg-quick-wg0.service" ]; - wants = [ "network-online.target" ]; - bindsTo = [ "wg-quick-wg0.service" ]; # Stop if VPN stops - - serviceConfig = { - Restart = "on-failure"; - RestartSec = "10s"; - }; - }; - - natpmp-portforward = { - description = "NAT-PMP Port Forwarding for VPN"; - after = [ - "wg-quick-wg0.service" - "qbittorrent.service" - ]; - requires = [ - "wg-quick-wg0.service" - "qbittorrent.service" - ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - Type = "simple"; - Restart = "always"; - RestartSec = "10s"; - }; - - script = '' - PASSWORD=$(cat /run/secrets/qbittorrent-pass) - echo "Waiting for qBittorrent to start..." - sleep 10 - - while true; do - echo "Requesting port forwarding from VPN..." - - UDP_OUTPUT=$(${pkgs.libnatpmp}/bin/natpmpc -a 1 0 udp 60 -g 10.2.0.1 2>&1) - UDP_PORT=$(echo "$UDP_OUTPUT" | ${pkgs.gnugrep}/bin/grep "Mapped public port" | ${pkgs.gawk}/bin/awk '{print $4}' | head -1) - - TCP_OUTPUT=$(${pkgs.libnatpmp}/bin/natpmpc -a 1 0 tcp 60 -g 10.2.0.1 2>&1) - TCP_PORT=$(echo "$TCP_OUTPUT" | ${pkgs.gnugrep}/bin/grep "Mapped public port" | ${pkgs.gawk}/bin/awk '{print $4}' | head -1) - - if [ -n "$UDP_PORT" ] && [ -n "$TCP_PORT" ]; then - echo "Port forwarding successful: UDP=$UDP_PORT, TCP=$TCP_PORT" - - # Clean up old dynamic rules - ${pkgs.iptables}/bin/iptables -t nat -D PREROUTING -i enp0s5 -s ${localNet} -p tcp -j DNAT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -t nat -D PREROUTING -i enp0s5 -s ${localNet} -p udp -j DNAT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -i enp0s5 -o wg0 -p tcp -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -i enp0s5 -o wg0 -p udp -j ACCEPT 2>/dev/null || true - ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -o enp0s5 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true - - # DNAT: Forward LAN traffic to qBittorrent on WireGuard interface - ${pkgs.iptables}/bin/iptables -t nat -A PREROUTING -i enp0s5 -s ${localNet} -p tcp --dport "$TCP_PORT" -j DNAT --to-destination 10.2.0.2:"$TCP_PORT" - ${pkgs.iptables}/bin/iptables -t nat -A PREROUTING -i enp0s5 -s ${localNet} -p udp --dport "$UDP_PORT" -j DNAT --to-destination 10.2.0.2:"$UDP_PORT" - - # Allow forwarding for these specific ports - ${pkgs.iptables}/bin/iptables -A FORWARD -i enp0s5 -o wg0 -d 10.2.0.2 -p tcp --dport "$TCP_PORT" -j ACCEPT - ${pkgs.iptables}/bin/iptables -A FORWARD -i enp0s5 -o wg0 -d 10.2.0.2 -p udp --dport "$UDP_PORT" -j ACCEPT - ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -o enp0s5 -s 10.2.0.2 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT - - echo "Firewall forwarding rules updated for ports: UDP=$UDP_PORT, TCP=$TCP_PORT" - - # Update qBittorrent listening port via API - echo "Logging into qBittorrent API..." - COOKIE=$(${pkgs.curl}/bin/curl -s -i \ - --header "Referer: http://localhost:${toString serviceCfg.ports.port0}" \ - --data "username=user&password=$PASSWORD" \ - "http://localhost:${toString serviceCfg.ports.port0}/api/v2/auth/login" | \ - ${pkgs.gnugrep}/bin/grep -i "set-cookie" | ${pkgs.gawk}/bin/awk -F'SID=|;' '{print $2}') - - if [ -n "$COOKIE" ]; then - echo "Authentication successful, updating port..." - ${pkgs.curl}/bin/curl -s \ - --cookie "SID=$COOKIE" \ - --data "json={\"listen_port\":$UDP_PORT}" \ - "http://localhost:${toString serviceCfg.ports.port0}/api/v2/app/setPreferences" - - echo "Updated qBittorrent listening port to $UDP_PORT" - else - echo "WARNING: Failed to authenticate with qBittorrent API" - fi - else - echo "ERROR: Failed to get forwarded ports" - echo "UDP output: $UDP_OUTPUT" - echo "TCP output: $TCP_OUTPUT" - fi - - sleep 45 - done - ''; - }; - killswitch-init = { - description = "Initialize VPN Killswitch Before Network"; - wantedBy = [ "network-pre.target" ]; - before = [ - "network-pre.target" - "network.target" - ]; - after = [ "systemd-modules-load.service" ]; - - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - - script = '' - echo "KILLSWITCH: Setting up firewall rules BEFORE network services" - - # Default DROP everything - ${pkgs.iptables}/bin/iptables -P INPUT DROP - ${pkgs.iptables}/bin/iptables -P OUTPUT DROP - ${pkgs.iptables}/bin/iptables -P FORWARD DROP - - ${pkgs.iptables}/bin/iptables -F - ${pkgs.iptables}/bin/iptables -t nat -F - ${pkgs.iptables}/bin/iptables -X - - # Allow loopback - ${pkgs.iptables}/bin/iptables -A INPUT -i lo -j ACCEPT - ${pkgs.iptables}/bin/iptables -A OUTPUT -o lo -j ACCEPT - - # CRITICAL: Only allow WireGuard endpoint traffic before VPN is up - ${pkgs.iptables}/bin/iptables -A OUTPUT -o enp0s5 -p udp --dport ${toString torrentPort} -d ${vpnEndpoint} -j ACCEPT - ${pkgs.iptables}/bin/iptables -A INPUT -i enp0s5 -p udp --sport ${toString torrentPort} -s ${vpnEndpoint} -j ACCEPT - - # Allow SSH from local network (for management) - ${pkgs.iptables}/bin/iptables -A INPUT -i enp0s5 -s ${localNet} -p tcp --dport 22 -j ACCEPT - ${pkgs.iptables}/bin/iptables -A OUTPUT -o enp0s5 -d ${localNet} -p tcp --sport 22 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT - - # Block IPv6 completely - ${pkgs.iptables}/bin/ip6tables -P INPUT DROP 2>/dev/null || true - ${pkgs.iptables}/bin/ip6tables -P OUTPUT DROP 2>/dev/null || true - ${pkgs.iptables}/bin/ip6tables -P FORWARD DROP 2>/dev/null || true - - echo "KILLSWITCH: Initialized - Network locked down" - ''; - }; + services.qbittorrent = { + after = [ "wg-quick-wg0.service" ]; + requires = [ "wg-quick-wg0.service" ]; }; }; @@ -350,7 +173,7 @@ in { mountPoint = "/run/secrets"; proto = "virtiofs"; - source = "/run/secrets/torrent"; + source = "/run/secrets/proton"; tag = "host_secrets"; } ]; @@ -358,19 +181,14 @@ in environment.systemPackages = builtins.attrValues { inherit (pkgs) - bottom - conntrack-tools - gawk - iptables - libnatpmp - speedtest-go wireguard-tools + speedtest-go + bottom ; }; }; }; - # Host configuration remains the same services = { caddy = { virtualHosts = { @@ -396,11 +214,7 @@ in group = "caddy"; mode = "0400"; }; - "torrent/wireguard-pass" = { - owner = "root"; - mode = "0400"; - }; - "torrent/qbittorrent-pass" = { + "proton/wireguard-pass" = { owner = "root"; mode = "0400"; }; @@ -420,22 +234,10 @@ in EnvironmentFile = config.sops.secrets."caddy/share-auth".path; }; }; - tmpfiles.rules = [ "d ${serviceCfg.mntPaths.path0} 0755 microvm wheel - -" "d ${serviceCfg.secretPaths.path0}/caddy 755 caddy caddy -" "d /var/log/caddy 755 caddy caddy -" ]; }; - - networking.firewall = { - allowedTCPPorts = [ - 38834 - torrentPort - ]; - allowedUDPPorts = [ - 38834 - torrentPort - ]; - }; } diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index b410887..db9465f 100755 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -55,9 +55,8 @@ firefly-iii: pass: ENC[AES256_GCM,data:WjHcoTuEzEq9pfw4QoqRjI4jhu5VPEMOXlHL0olg9dqUj4EGa1Shv5T/kIxdRFuao0y3zQ==,iv:4/fmFOxxDLzplsNGpSJMQOeoNviZw2c2pFlB1ZkRu+o=,tag:7TQ2q/kEFDU4tZxPx53ebw==,type:str] data: ENC[AES256_GCM,data:921LhcRTWVk24eEAQoDMV+RllSP3PbSXCCIDXlQA80Mq,iv:YXEgas77DgdyPTnBZa/ySjcERBIwmdDZJbijeNKNF24=,tag:Wj25wA7tLJ2bZ/faG9DUhg==,type:str] smtp: ENC[AES256_GCM,data:+e4MiRZ2WOZyWYpMf+By1Eb45ih4TA+svLI2+00yQk82,iv:+52+kJouMwkOSDEaOCA8V80+wT/VzNxgtCkOO68SCdk=,tag:YrtrJAXIhQpsUTEeYvrVwQ==,type:str] -torrent: - wireguard-pass: ENC[AES256_GCM,data:fNNHuOvaRRpiS7c9n/l6lB0A1J4VboJxIh+hrMrTfjFS2grpgRATLHhjZ/wo,iv:CVZIG3Gq+O1/qPqu0XBH/5XsTpAe9xe52/CtBHaIOPI=,tag:8RfoFjz0Ecmx8O7Bt/90ig==,type:str] - qbittorrent-pass: ENC[AES256_GCM,data:W1p7cYWbBNeAtEEL7Tb0pG27TSniqTrNMN6gxFFlli27,iv:seiWOr6V8pyjioBkKKEtCXC17RctDScA37E7uFbnmzk=,tag:KYz92O6XUvJob74LnGlYNg==,type:str] +proton: + wireguard-pass: ENC[AES256_GCM,data:u3riHMDyK+DxFAGpdP7zTqZMfp//W3pb3WRp/iS/pAf6ItY9PNFClm7Gh4Dn,iv:8jfPQALR+J3VZVL+a2XHwuL8P8yhZ4OcjhVbCTBADwE=,tag:H42pKD/tlDXUlIVVzdv+DQ==,type:str] backblaze: env: ENC[AES256_GCM,data:cdOYt77KocuGB3aqYz13oBokoLkEIgI1AW+cYC5uutgZYujG3PqoLEh6Gvbpzn3O+0OWg1/4UAYr4f2v7oCsgwFzPWS3HrhqC5+kIBjrPCyAnxDxlu2xaQ9hR+ogFh5UTDo=,iv:6+jx4Dj5CNV72DAss6NNYm44f9gSHco/EUBvL2o2CNI=,tag:6/cx84MgTDqQJxu/zINEeA==,type:str] repo: ENC[AES256_GCM,data:sRae9XELIfkWPaXelCdgEXIDbLTHVqGcRO0o+WA9aBfB8MUw92JjRCYgMgGXT0Apy38eszyuEHFB3XPpRmtQ7g==,iv:EilVA9zdHm6B9pTIhNxyj6Th1248nXvh0kpnEqZJ5HI=,tag:q9ASAgx5vgY0IePws4rT5Q==,type:str] @@ -74,7 +73,7 @@ sops: bXBOa1VSakoyaWxpODJEOU11QUZCaUEK8Ch9Ten3DdrPHF1DTH2qei85AlHUOaLD aNfzakake7ej+MxJYdKEU0bcWofNMKzIlZa2uM10KZSENDP8d8qlig== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-11-27T18:54:52Z" - mac: ENC[AES256_GCM,data:ZxkJZUJJ1AfDlmxAy8Botu73EPt+1prsdbX7RhU9bVNaEhpPzrvqlO74D8ek/OqFG51k1K4mdW5SWXWs/D5oR34i/yA+329j4jHNAe3Yajkx1gn/xDEa/kgiVGkc7dE3dnzmy5zr4X8U06khJl9rg+qLujke0GCgIv+82xkFFRI=,iv:0UYNIZTxXdPqrZsjVYNGfSlt6UH3+Q102EF6XeC5yh4=,tag:3oj0X73xRnGBXWdGsUv2xg==,type:str] + lastmodified: "2025-11-27T09:53:41Z" + mac: ENC[AES256_GCM,data:fV10gBOFgCTTMWAKv8tGnCz3TG0t0G19di4N4wEi2lsHeYDBk8ijumOM/wLY6Zds80y5u6s6hGwFpCcY5pChjQ/E/pOURHAY7rIqQmGm9yQnpECCfWLDJVgsQjliYRPD76WTEKlsevz/XCGfdITNuRAlU7tuWEEEgXvIKt+0Z/8=,iv:dA/zt7WQA5w+dZM53VunucZAQTBKRyzLaWaShhTMWzI=,tag:CUD7KGes5pNquMJfCm6dYQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 diff --git a/systems/ceres/config/networking.nix b/systems/ceres/config/networking.nix index c9c3cf8..2b58aba 100755 --- a/systems/ceres/config/networking.nix +++ b/systems/ceres/config/networking.nix @@ -10,37 +10,35 @@ in { microvm.host.enable = true; - systemd.network = { - enable = true; - netdevs."10-br-vms" = { - netdevConfig = { - Name = "br-vms"; - Kind = "bridge"; - }; - }; + systemd.network.enable = true; - networks = { - "20-lan" = { - matchConfig.Name = [ - "enp10s0" - "vm-*" - ]; - networkConfig = { - Bridge = "br-vms"; - }; - }; - "30-br-vms" = { - matchConfig.Name = "br-vms"; - networkConfig = { - Address = "192.168.50.240/24"; - Gateway = "192.168.50.1"; - DNS = [ "192.168.50.1" ]; - }; - linkConfig.RequiredForOnline = "routable"; - }; + systemd.network.netdevs."10-br-vms" = { + netdevConfig = { + Name = "br-vms"; + Kind = "bridge"; }; }; + systemd.network.networks."20-lan" = { + matchConfig.Name = [ + "enp10s0" + "vm-*" + ]; + networkConfig = { + Bridge = "br-vms"; + }; + }; + + systemd.network.networks."30-br-vms" = { + matchConfig.Name = "br-vms"; + networkConfig = { + Address = "192.168.50.240/24"; + Gateway = "192.168.50.1"; + DNS = [ "192.168.50.1" ]; + }; + linkConfig.RequiredForOnline = "routable"; + }; + networking = { hostName = ceres.name; networkmanager.enable = false; @@ -61,19 +59,6 @@ in wireguardService.ports.port0 # WireGuard wireguardService.ports.port1 # WireGuard ]; - # Add port ranges for VPN dynamic port forwarding - allowedTCPPortRanges = [ - { - from = 30000; - to = 65535; - } - ]; - allowedUDPPortRanges = [ - { - from = 30000; - to = 65535; - } - ]; }; };