{ config, lib, pkgs, ... }: let qbittorrentRouteTable = 200; qbitUser = config.services.qbittorrent.user; serverInterface = config.my.interfaces.server; wgInterface = "wg0"; wgServerIp = config.my.ips.wg-server; in { my.network.firewall = { enabledServicePorts = true; additionalPorts = [ 2049 config.my.ports.syncthingGui config.my.ports.syncthingRelay config.my.ports.sonarqube config.my.ports.synapseSsl config.my.ports.tdarr config.my.ports.mediaMap config.my.ports.qbittorrent ]; }; networking = { iproute2.rttablesExtraConfig = '' ${toString qbittorrentRouteTable} qbittorrent ''; wireguard.interfaces.${wgInterface} = lib.mkIf config.my.secureHost { allowedIPsAsRoutes = false; ips = [ "${wgServerIp}/32" ]; privateKeyFile = config.sops.secrets."server/private".path; peers = [ { publicKey = "dFbiSekBwnZomarcS31o5+w6imHjMPNCipkfc2fZ3GY="; endpoint = "${config.my.ips.vps}:51820"; allowedIPs = [ "0.0.0.0/0" "${config.my.ips.wg-vps}/32" config.my.subnets.wg-homelab config.my.subnets.wg-friends config.my.subnets.wg-guests ]; persistentKeepalive = 25; } ]; }; firewall = { allowedUDPPorts = config.networking.firewall.allowedTCPPorts; interfaces.${wgInterface}.allowedTCPPorts = [ config.my.servers.nextcloud.port ]; }; }; systemd.services.qbittorrent-vpn-routing = lib.mkIf (config.my.secureHost && config.services.qbittorrent.enable) { description = "Route qBittorrent user traffic through the VPS WireGuard tunnel"; before = [ "qbittorrent.service" ]; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" "wireguard-${wgInterface}.service" ]; wants = [ "network-online.target" "wireguard-${wgInterface}.service" ]; path = with pkgs; [ coreutils gnugrep iproute2 shadow ]; script = '' qbit_uid="$(id -u ${qbitUser})" for _ in $(seq 1 30); do if ip -4 addr show dev ${wgInterface} >/dev/null 2>&1; then break fi sleep 1 done if ! ip -4 addr show dev ${wgInterface} >/dev/null 2>&1; then echo "${wgInterface} is not available" exit 1 fi ip -4 route replace ${config.my.subnets.wg-homelab} dev ${wgInterface} src ${wgServerIp} ip -4 route replace ${config.my.subnets.wg-friends} dev ${wgInterface} src ${wgServerIp} ip -4 route replace ${config.my.subnets.wg-guests} dev ${wgInterface} src ${wgServerIp} ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-homelab} dev ${wgInterface} src ${wgServerIp} ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-friends} dev ${wgInterface} src ${wgServerIp} ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-guests} dev ${wgInterface} src ${wgServerIp} ip -4 route replace table ${toString qbittorrentRouteTable} 10.88.0.0/16 dev podman0 src 10.88.0.1 ip -4 route replace table ${toString qbittorrentRouteTable} 192.168.100.0/24 dev ${serverInterface} src ${config.my.ips.server} ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.ips.vps}/32 via ${config.my.ips.router} dev ${serverInterface} src ${config.my.ips.server} ip -4 route replace table ${toString qbittorrentRouteTable} default via ${config.my.ips.wg-vps} dev ${wgInterface} src ${wgServerIp} while ip -4 rule show | grep -q "uidrange ''${qbit_uid}-''${qbit_uid} lookup ${toString qbittorrentRouteTable}"; do ip -4 rule del uidrange "''${qbit_uid}-''${qbit_uid}" lookup ${toString qbittorrentRouteTable} done while ip -4 rule show | grep -q 'from ${wgServerIp} lookup ${toString qbittorrentRouteTable}'; do ip -4 rule del from ${wgServerIp}/32 lookup ${toString qbittorrentRouteTable} done ip -4 rule add from ${wgServerIp}/32 lookup ${toString qbittorrentRouteTable} priority 9999 ip -4 rule add uidrange "''${qbit_uid}-''${qbit_uid}" lookup ${toString qbittorrentRouteTable} priority 10000 ''; preStop = '' qbit_uid="$(id -u ${qbitUser})" while ip -4 rule show | grep -q 'from ${wgServerIp} lookup ${toString qbittorrentRouteTable}'; do ip -4 rule del from ${wgServerIp}/32 lookup ${toString qbittorrentRouteTable} || true done while ip -4 rule show | grep -q "uidrange ''${qbit_uid}-''${qbit_uid} lookup ${toString qbittorrentRouteTable}"; do ip -4 rule del uidrange "''${qbit_uid}-''${qbit_uid}" lookup ${toString qbittorrentRouteTable} || true done ip -4 route del ${config.my.subnets.wg-homelab} dev ${wgInterface} || true ip -4 route del ${config.my.subnets.wg-friends} dev ${wgInterface} || true ip -4 route del ${config.my.subnets.wg-guests} dev ${wgInterface} || true ip -4 route flush table ${toString qbittorrentRouteTable} || true ''; serviceConfig = { RemainAfterExit = true; Type = "oneshot"; }; }; }