nixformat + firewall rules to port forward qbittorrent
This commit is contained in:
@@ -59,7 +59,7 @@ in
|
|||||||
webcomix = prev.python3Packages.callPackage "${jawzScriptsSrc}/pkgs_pr/webcomix.nix" { };
|
webcomix = prev.python3Packages.callPackage "${jawzScriptsSrc}/pkgs_pr/webcomix.nix" { };
|
||||||
download = prev.python3Packages.callPackage "${jawzScriptsSrc}/pkgs/download.nix" {
|
download = prev.python3Packages.callPackage "${jawzScriptsSrc}/pkgs/download.nix" {
|
||||||
gallery-dl = final.gallery-dl-dev;
|
gallery-dl = final.gallery-dl-dev;
|
||||||
webcomix = pyfinal.webcomix;
|
inherit (pyfinal) webcomix;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -71,7 +71,7 @@ in
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
gallery-dl = final.gallery-dl-dev;
|
gallery-dl = final.gallery-dl-dev;
|
||||||
download = final.python3Packages.download;
|
inherit (final.python3Packages) download;
|
||||||
inherit (pkgsU)
|
inherit (pkgsU)
|
||||||
code-cursor
|
code-cursor
|
||||||
symbola
|
symbola
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
lidarrMbGapId = 968;
|
lidarrMbGapId = 968;
|
||||||
|
qbittorrentRouteTable = 200;
|
||||||
|
serverInterface = config.my.interfaces.server;
|
||||||
|
jawzUid = config.users.users.jawz.uid;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -70,7 +73,11 @@ in
|
|||||||
};
|
};
|
||||||
networking = {
|
networking = {
|
||||||
hostName = "server";
|
hostName = "server";
|
||||||
|
iproute2.rttablesExtraConfig = ''
|
||||||
|
${toString qbittorrentRouteTable} qbittorrent
|
||||||
|
'';
|
||||||
wireguard.interfaces.wg0 = lib.mkIf config.my.secureHost {
|
wireguard.interfaces.wg0 = lib.mkIf config.my.secureHost {
|
||||||
|
allowedIPsAsRoutes = false;
|
||||||
ips = [ "${config.my.ips.wg-server}/32" ];
|
ips = [ "${config.my.ips.wg-server}/32" ];
|
||||||
privateKeyFile = config.sops.secrets."server/private".path;
|
privateKeyFile = config.sops.secrets."server/private".path;
|
||||||
peers = [
|
peers = [
|
||||||
@@ -78,6 +85,7 @@ in
|
|||||||
publicKey = "dFbiSekBwnZomarcS31o5+w6imHjMPNCipkfc2fZ3GY=";
|
publicKey = "dFbiSekBwnZomarcS31o5+w6imHjMPNCipkfc2fZ3GY=";
|
||||||
endpoint = "${config.my.ips.vps}:51820";
|
endpoint = "${config.my.ips.vps}:51820";
|
||||||
allowedIPs = [
|
allowedIPs = [
|
||||||
|
"0.0.0.0/0"
|
||||||
"${config.my.ips.wg-vps}/32"
|
"${config.my.ips.wg-vps}/32"
|
||||||
config.my.subnets.wg-homelab
|
config.my.subnets.wg-homelab
|
||||||
config.my.subnets.wg-friends
|
config.my.subnets.wg-friends
|
||||||
@@ -92,6 +100,71 @@ in
|
|||||||
interfaces.wg0.allowedTCPPorts = [ config.my.servers.nextcloud.port ];
|
interfaces.wg0.allowedTCPPorts = [ config.my.servers.nextcloud.port ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
systemd.services.qbittorrent-vpn-routing = lib.mkIf config.my.secureHost {
|
||||||
|
description = "Route qBittorrent user traffic through the VPS WireGuard tunnel";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
path = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
gnugrep
|
||||||
|
iproute2
|
||||||
|
];
|
||||||
|
script = ''
|
||||||
|
for _ in $(seq 1 30); do
|
||||||
|
if ip -4 addr show dev wg0 >/dev/null 2>&1; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if ! ip -4 addr show dev wg0 >/dev/null 2>&1; then
|
||||||
|
echo "wg0 is not available"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip -4 route replace ${config.my.subnets.wg-homelab} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
ip -4 route replace ${config.my.subnets.wg-friends} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
ip -4 route replace ${config.my.subnets.wg-guests} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
|
||||||
|
ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-homelab} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-friends} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
ip -4 route replace table ${toString qbittorrentRouteTable} ${config.my.subnets.wg-guests} dev wg0 src ${config.my.ips.wg-server}
|
||||||
|
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 wg0 src ${config.my.ips.wg-server}
|
||||||
|
|
||||||
|
while ip -4 rule show | grep -q 'uidrange ${toString jawzUid}-${toString jawzUid} lookup ${toString qbittorrentRouteTable}'; do
|
||||||
|
ip -4 rule del uidrange ${toString jawzUid}-${toString jawzUid} lookup ${toString qbittorrentRouteTable}
|
||||||
|
done
|
||||||
|
|
||||||
|
while ip -4 rule show | grep -q 'from ${config.my.ips.wg-server} lookup ${toString qbittorrentRouteTable}'; do
|
||||||
|
ip -4 rule del from ${config.my.ips.wg-server}/32 lookup ${toString qbittorrentRouteTable}
|
||||||
|
done
|
||||||
|
|
||||||
|
ip -4 rule add from ${config.my.ips.wg-server}/32 lookup ${toString qbittorrentRouteTable} priority 9999
|
||||||
|
ip -4 rule add uidrange ${toString jawzUid}-${toString jawzUid} lookup ${toString qbittorrentRouteTable} priority 10000
|
||||||
|
'';
|
||||||
|
preStop = ''
|
||||||
|
while ip -4 rule show | grep -q 'from ${config.my.ips.wg-server} lookup ${toString qbittorrentRouteTable}'; do
|
||||||
|
ip -4 rule del from ${config.my.ips.wg-server}/32 lookup ${toString qbittorrentRouteTable} || true
|
||||||
|
done
|
||||||
|
|
||||||
|
while ip -4 rule show | grep -q 'uidrange ${toString jawzUid}-${toString jawzUid} lookup ${toString qbittorrentRouteTable}'; do
|
||||||
|
ip -4 rule del uidrange ${toString jawzUid}-${toString jawzUid} lookup ${toString qbittorrentRouteTable} || true
|
||||||
|
done
|
||||||
|
|
||||||
|
ip -4 route del ${config.my.subnets.wg-homelab} dev wg0 || true
|
||||||
|
ip -4 route del ${config.my.subnets.wg-friends} dev wg0 || true
|
||||||
|
ip -4 route del ${config.my.subnets.wg-guests} dev wg0 || true
|
||||||
|
ip -4 route flush table ${toString qbittorrentRouteTable} || true
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
RemainAfterExit = true;
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
};
|
||||||
users.users.jawz.packages = builtins.attrValues {
|
users.users.jawz.packages = builtins.attrValues {
|
||||||
inherit (pkgs) podman-compose attic-client;
|
inherit (pkgs) podman-compose attic-client;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ let
|
|||||||
};
|
};
|
||||||
ports = {
|
ports = {
|
||||||
inherit (config.my.ports) giteaSsh;
|
inherit (config.my.ports) giteaSsh;
|
||||||
|
inherit (config.my.ports) qbittorrent;
|
||||||
inherit (config.my.ports) ssh;
|
inherit (config.my.ports) ssh;
|
||||||
web = [
|
web = [
|
||||||
80
|
80
|
||||||
@@ -33,7 +34,6 @@ let
|
|||||||
synapseFederation = config.my.ports.synapseSsl;
|
synapseFederation = config.my.ports.synapseSsl;
|
||||||
};
|
};
|
||||||
portsStr = {
|
portsStr = {
|
||||||
giteaSsh = toString ports.giteaSsh;
|
|
||||||
syncthing = toString ports.syncthing;
|
syncthing = toString ports.syncthing;
|
||||||
synapseFederation = toString ports.synapseFederation;
|
synapseFederation = toString ports.synapseFederation;
|
||||||
synapseClient = toString config.my.servers.synapse.port;
|
synapseClient = toString config.my.servers.synapse.port;
|
||||||
@@ -48,6 +48,38 @@ let
|
|||||||
ollama = toString config.my.ports.ollama;
|
ollama = toString config.my.ports.ollama;
|
||||||
comfyui = toString config.my.ports.comfyui;
|
comfyui = toString config.my.ports.comfyui;
|
||||||
};
|
};
|
||||||
|
forwardedPorts = [
|
||||||
|
{
|
||||||
|
comment = "snat ssh forward";
|
||||||
|
port = ports.giteaSsh;
|
||||||
|
proto = "tcp";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
comment = "snat qbittorrent tcp forward";
|
||||||
|
port = ports.qbittorrent;
|
||||||
|
proto = "tcp";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
comment = "snat qbittorrent udp forward";
|
||||||
|
port = ports.qbittorrent;
|
||||||
|
proto = "udp";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
mkForwardPort =
|
||||||
|
{ port, proto, ... }:
|
||||||
|
{
|
||||||
|
sourcePort = port;
|
||||||
|
inherit proto;
|
||||||
|
destination = "${ips.homeServer}:${toString port}";
|
||||||
|
};
|
||||||
|
mkSnatRule =
|
||||||
|
{
|
||||||
|
comment,
|
||||||
|
port,
|
||||||
|
proto,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
''iifname "${externalInterface}" oifname "${wgInterface}" ip daddr ${ips.homeServer}/32 ${proto} dport ${toString port} masquerade comment "${comment}"'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
@@ -99,14 +131,8 @@ in
|
|||||||
nat = {
|
nat = {
|
||||||
inherit externalInterface;
|
inherit externalInterface;
|
||||||
enable = true;
|
enable = true;
|
||||||
internalInterfaces = [ "wg0" ];
|
internalInterfaces = [ wgInterface ];
|
||||||
forwardPorts = [
|
forwardPorts = map mkForwardPort forwardedPorts;
|
||||||
{
|
|
||||||
sourcePort = ports.giteaSsh;
|
|
||||||
proto = "tcp";
|
|
||||||
destination = "${ips.homeServer}:${portsStr.giteaSsh}";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
nftables = {
|
nftables = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -115,7 +141,8 @@ in
|
|||||||
content = ''
|
content = ''
|
||||||
chain postrouting {
|
chain postrouting {
|
||||||
type nat hook postrouting priority srcnat;
|
type nat hook postrouting priority srcnat;
|
||||||
iifname "${externalInterface}" oifname "${wgInterface}" ip daddr ${ips.homeServer}/32 tcp dport ${portsStr.giteaSsh} masquerade comment "snat ssh forward"
|
iifname "${wgInterface}" oifname "${externalInterface}" ip saddr ${subnets.wgHomelab} masquerade comment "snat homelab egress"
|
||||||
|
${lib.concatStringsSep "\n " (map mkSnatRule forwardedPorts)}
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -124,8 +151,15 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
filterForward = true;
|
filterForward = true;
|
||||||
checkReversePath = "loose";
|
checkReversePath = "loose";
|
||||||
allowedTCPPorts = [ ports.ssh ] ++ ports.web;
|
allowedTCPPorts = [
|
||||||
allowedUDPPorts = [ ports.wg ];
|
ports.ssh
|
||||||
|
ports.qbittorrent
|
||||||
|
]
|
||||||
|
++ ports.web;
|
||||||
|
allowedUDPPorts = [
|
||||||
|
ports.wg
|
||||||
|
ports.qbittorrent
|
||||||
|
];
|
||||||
extraForwardRules = ''
|
extraForwardRules = ''
|
||||||
iifname "${wgInterface}" ip saddr ${subnets.wgFriends} ip daddr ${ips.homeServer}/32 tcp dport ${portsStr.syncthing} accept
|
iifname "${wgInterface}" ip saddr ${subnets.wgFriends} ip daddr ${ips.homeServer}/32 tcp dport ${portsStr.syncthing} accept
|
||||||
iifname "${wgInterface}" ip saddr ${ips.homeServer}/32 ip daddr ${subnets.wgFriends} tcp dport ${portsStr.syncthing} accept
|
iifname "${wgInterface}" ip saddr ${ips.homeServer}/32 ip daddr ${subnets.wgFriends} tcp dport ${portsStr.syncthing} accept
|
||||||
@@ -142,6 +176,7 @@ in
|
|||||||
iifname "${wgInterface}" ip saddr ${subnets.wgHomelab} ip daddr ${ips.wgWorkstation}/32 tcp dport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept
|
iifname "${wgInterface}" ip saddr ${subnets.wgHomelab} ip daddr ${ips.wgWorkstation}/32 tcp dport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept
|
||||||
iifname "${wgInterface}" ip saddr ${ips.wgWorkstation}/32 ip daddr ${subnets.wgHomelab} tcp sport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept
|
iifname "${wgInterface}" ip saddr ${ips.wgWorkstation}/32 ip daddr ${subnets.wgHomelab} tcp sport { ${portsStr.openWebui}, ${portsStr.sillytavern}, ${portsStr.ollama}, ${portsStr.comfyui} } accept
|
||||||
|
|
||||||
|
iifname "${wgInterface}" ip saddr ${subnets.wgHomelab} oifname "${externalInterface}" accept
|
||||||
iifname "${wgInterface}" ip saddr ${subnets.wgFriends} oifname "${externalInterface}" accept
|
iifname "${wgInterface}" ip saddr ${subnets.wgFriends} oifname "${externalInterface}" accept
|
||||||
iifname "${wgInterface}" ip saddr ${subnets.wgGuests} oifname "${externalInterface}" accept
|
iifname "${wgInterface}" ip saddr ${subnets.wgGuests} oifname "${externalInterface}" accept
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
inputs,
|
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
download = pkgs.download;
|
inherit (pkgs) download;
|
||||||
gallerySecretsPath = lib.attrByPath [ "sops" "secrets" "gallery-dl/secrets" "path" ] null config;
|
gallerySecretsPath = lib.attrByPath [ "sops" "secrets" "gallery-dl/secrets" "path" ] null config;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ let
|
|||||||
inputs.self.lib.hmOnlyUser config osConfig "jawz"
|
inputs.self.lib.hmOnlyUser config osConfig "jawz"
|
||||||
&& (osConfig.my.units.download.enable || osConfig.my.units.downloadManga.enable);
|
&& (osConfig.my.units.download.enable || osConfig.my.units.downloadManga.enable);
|
||||||
download = import ./common.nix {
|
download = import ./common.nix {
|
||||||
inherit inputs lib pkgs;
|
inherit lib pkgs;
|
||||||
config = if osConfig == null then { } else osConfig;
|
config = if osConfig == null then { } else osConfig;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
inputs,
|
|
||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
@@ -9,7 +8,6 @@ let
|
|||||||
download = import ./common.nix {
|
download = import ./common.nix {
|
||||||
inherit
|
inherit
|
||||||
config
|
config
|
||||||
inputs
|
|
||||||
lib
|
lib
|
||||||
pkgs
|
pkgs
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -61,10 +61,10 @@
|
|||||||
packages =
|
packages =
|
||||||
(inputs.jawz-scripts.packages.${system} or { })
|
(inputs.jawz-scripts.packages.${system} or { })
|
||||||
// {
|
// {
|
||||||
download = pkgs.download;
|
inherit (pkgs) download;
|
||||||
doom-emacs = portableEmacs.package;
|
doom-emacs = portableEmacs.package;
|
||||||
gallery-dl = pkgs.gallery-dl;
|
inherit (pkgs) gallery-dl;
|
||||||
gallery-dl-dev = pkgs.gallery-dl-dev;
|
inherit (pkgs) gallery-dl-dev;
|
||||||
mcp-tests = mcpTests;
|
mcp-tests = mcpTests;
|
||||||
nixos-mcp = nixosMcp;
|
nixos-mcp = nixosMcp;
|
||||||
nixos-mcp-server = mcpServerPkg;
|
nixos-mcp-server = mcpServerPkg;
|
||||||
|
|||||||
Reference in New Issue
Block a user