mirror of
https://github.com/nickolaj-jepsen/nixos.git
synced 2026-01-22 16:16:50 +01:00
fix: qbittorrent
This commit is contained in:
parent
41906e75fb
commit
d769b830a2
8 changed files with 72 additions and 66 deletions
12
flake.lock
generated
12
flake.lock
generated
|
|
@ -58,11 +58,11 @@
|
||||||
"quickshell": "quickshell"
|
"quickshell": "quickshell"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765865292,
|
"lastModified": 1765916864,
|
||||||
"narHash": "sha256-BmL32FIn6YtjFG/5Z+BcApTc5Z8mKNLv9wnAU0aRYIE=",
|
"narHash": "sha256-mXKYRVK5YndrvgbIKCyz4BRuLkyEqgceF/djXmA6cD8=",
|
||||||
"owner": "AvengeMedia",
|
"owner": "AvengeMedia",
|
||||||
"repo": "DankMaterialShell",
|
"repo": "DankMaterialShell",
|
||||||
"rev": "2947ff41313566c4eb77fbddf085176141eb337a",
|
"rev": "672754b0b5efd9e61ea8080c40614ad3b4fd5dbf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -770,11 +770,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765874996,
|
"lastModified": 1765918270,
|
||||||
"narHash": "sha256-qQjl+fX5ySQzzx+Cc8oua3CSsZA5lK6Ev6XEmjxKbHs=",
|
"narHash": "sha256-TbNcuaNCIRp4ZcZBQ1lyXW6GMyHhY5+gWCHqKTLZ3So=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "1d585f45ed47164867626b03b7f192f2cddaa606",
|
"rev": "e62aaff51af4cbc43149a71b67931005416d1138",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
_: {
|
_: {
|
||||||
monitors = [
|
monitors = [
|
||||||
{
|
{
|
||||||
name = "DP-1";
|
name = "DP-3";
|
||||||
resolution = {
|
resolution = {
|
||||||
width = 2560;
|
width = 2560;
|
||||||
height = 1440;
|
height = 1440;
|
||||||
|
|
@ -14,7 +14,7 @@ _: {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "DP-3";
|
name = "DP-2";
|
||||||
resolution = {
|
resolution = {
|
||||||
width = 2560;
|
width = 2560;
|
||||||
height = 1440;
|
height = 1440;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ lib.mkIf config.fireproof.homelab.enable (let
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "nickolaj-jepsen";
|
owner = "nickolaj-jepsen";
|
||||||
repo = "glance";
|
repo = "glance";
|
||||||
rev = "7ea37f329e17908cdcc306f0fbb23a62e7c50584";
|
rev = "c490067f87186cac9084a76010a646119b7793e1";
|
||||||
hash = "sha256-ZU9iswhgQPeMZeQmzgNhFBcO2TzWYrmIWPnKSAA0fFM=";
|
hash = "sha256-zsanWSWO/gY4ZuYssdcoGKVw/Yk29qaF5Gn5XUYKQhk=";
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,31 +5,13 @@
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
lib.mkIf config.fireproof.homelab.enable (let
|
lib.mkIf config.fireproof.homelab.enable (let
|
||||||
inherit (config.fireproof) username;
|
|
||||||
user = "media";
|
|
||||||
group = "media";
|
|
||||||
|
|
||||||
# VPN namespace configuration
|
# VPN namespace configuration
|
||||||
vpnNamespace = "vpn";
|
vpnNamespace = "qbittorrent-vpn";
|
||||||
vpnInterface = "wg0";
|
vpnInterface = "qbt-wg0";
|
||||||
|
|
||||||
# Ports
|
# Ports
|
||||||
webUiPort = 8082;
|
webUiPort = 8082;
|
||||||
torrentPort = 51413;
|
torrentPort = 51413;
|
||||||
|
|
||||||
mkVirtualHost = port: {
|
|
||||||
enableACME = true;
|
|
||||||
forceSSL = true;
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://localhost:${toString port}";
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
# Secrets for Mullvad WireGuard config
|
# Secrets for Mullvad WireGuard config
|
||||||
# mullvad-wg.age should contain just the WireGuard config (not the Address line):
|
# mullvad-wg.age should contain just the WireGuard config (not the Address line):
|
||||||
|
|
@ -66,30 +48,11 @@ in {
|
||||||
# Create network namespace if it doesn't exist
|
# Create network namespace if it doesn't exist
|
||||||
ip netns add ${vpnNamespace} || true
|
ip netns add ${vpnNamespace} || true
|
||||||
|
|
||||||
# Create veth pair for communication between namespaces
|
# Set up loopback interface in namespace
|
||||||
ip link add veth-vpn type veth peer name veth-vpn-br || true
|
|
||||||
ip link set veth-vpn-br netns ${vpnNamespace} || true
|
|
||||||
|
|
||||||
# Configure host side
|
|
||||||
ip addr add 10.200.200.1/24 dev veth-vpn || true
|
|
||||||
ip link set veth-vpn up
|
|
||||||
|
|
||||||
# Configure namespace side
|
|
||||||
ip netns exec ${vpnNamespace} ip addr add 10.200.200.2/24 dev veth-vpn-br || true
|
|
||||||
ip netns exec ${vpnNamespace} ip link set veth-vpn-br up
|
|
||||||
ip netns exec ${vpnNamespace} ip link set lo up
|
ip netns exec ${vpnNamespace} ip link set lo up
|
||||||
|
|
||||||
# Enable IP forwarding for the veth bridge
|
|
||||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
|
||||||
iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o veth-vpn -j MASQUERADE || true
|
|
||||||
|
|
||||||
# Allow traffic from namespace to host for web UI
|
|
||||||
iptables -A FORWARD -i veth-vpn -o veth-vpn -j ACCEPT || true
|
|
||||||
'';
|
'';
|
||||||
ExecStop = pkgs.writeShellScript "destroy-vpn-netns" ''
|
ExecStop = pkgs.writeShellScript "destroy-vpn-netns" ''
|
||||||
ip link del veth-vpn || true
|
|
||||||
ip netns del ${vpnNamespace} || true
|
ip netns del ${vpnNamespace} || true
|
||||||
iptables -t nat -D POSTROUTING -s 10.200.200.0/24 -o veth-vpn -j MASQUERADE || true
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -107,8 +70,12 @@ in {
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
ExecStart = pkgs.writeShellScript "setup-wg-vpn" ''
|
ExecStart = pkgs.writeShellScript "setup-wg-vpn" ''
|
||||||
set -ex
|
set -ex
|
||||||
# Create WireGuard interface in namespace
|
# Clean up any existing WireGuard interface first
|
||||||
ip link add ${vpnInterface} type wireguard || true
|
ip link del ${vpnInterface} 2>/dev/null || true
|
||||||
|
ip netns exec ${vpnNamespace} ip link del ${vpnInterface} 2>/dev/null || true
|
||||||
|
|
||||||
|
# Create WireGuard interface
|
||||||
|
ip link add ${vpnInterface} type wireguard
|
||||||
ip link set ${vpnInterface} netns ${vpnNamespace}
|
ip link set ${vpnInterface} netns ${vpnNamespace}
|
||||||
|
|
||||||
# Configure WireGuard with Mullvad config
|
# Configure WireGuard with Mullvad config
|
||||||
|
|
@ -116,7 +83,7 @@ in {
|
||||||
|
|
||||||
# Set the interface address from secret file
|
# Set the interface address from secret file
|
||||||
WG_ADDR=$(cat ${config.age.secrets.mullvad-wg-address.path})
|
WG_ADDR=$(cat ${config.age.secrets.mullvad-wg-address.path})
|
||||||
ip netns exec ${vpnNamespace} ip addr add "$WG_ADDR" dev ${vpnInterface} || true
|
ip netns exec ${vpnNamespace} ip addr add "$WG_ADDR" dev ${vpnInterface}
|
||||||
ip netns exec ${vpnNamespace} ip link set ${vpnInterface} up
|
ip netns exec ${vpnNamespace} ip link set ${vpnInterface} up
|
||||||
|
|
||||||
# Route all traffic through WireGuard (default route)
|
# Route all traffic through WireGuard (default route)
|
||||||
|
|
@ -134,25 +101,43 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
# qBittorrent service running inside the VPN namespace
|
# qBittorrent service running inside the VPN namespace
|
||||||
|
services.qbittorrent = {
|
||||||
|
enable = true;
|
||||||
|
user = "media";
|
||||||
|
group = "media";
|
||||||
|
webuiPort = webUiPort;
|
||||||
|
torrentingPort = torrentPort;
|
||||||
|
serverConfig = {
|
||||||
|
LegalNotice.Accepted = true;
|
||||||
|
Preferences = {
|
||||||
|
WebUI = {
|
||||||
|
Address = "*";
|
||||||
|
Port = webUiPort;
|
||||||
|
};
|
||||||
|
Connection = {
|
||||||
|
PortRangeMin = torrentPort;
|
||||||
|
};
|
||||||
|
Downloads = {
|
||||||
|
SavePath = "/mnt/data/torrent";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Override the qbittorrent service to run in VPN namespace
|
||||||
systemd.services.qbittorrent = {
|
systemd.services.qbittorrent = {
|
||||||
description = "qBittorrent-nox service";
|
|
||||||
documentation = ["man:qbittorrent-nox(1)"];
|
|
||||||
after = [
|
after = [
|
||||||
"network.target"
|
"network.target"
|
||||||
"wg-${vpnNamespace}.service"
|
"wg-${vpnNamespace}.service"
|
||||||
];
|
];
|
||||||
requires = ["wg-${vpnNamespace}.service"];
|
requires = ["wg-${vpnNamespace}.service"];
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
|
||||||
User = user;
|
|
||||||
Group = group;
|
|
||||||
StateDirectory = "qbittorrent";
|
|
||||||
# Run in the VPN namespace
|
# Run in the VPN namespace
|
||||||
NetworkNamespacePath = "/var/run/netns/${vpnNamespace}";
|
NetworkNamespacePath = "/var/run/netns/${vpnNamespace}";
|
||||||
ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox --webui-port=${toString webUiPort}";
|
# Bind mount the DNS config into the namespace
|
||||||
Restart = "on-failure";
|
BindReadOnlyPaths = [
|
||||||
TimeoutStopSec = 1800;
|
"/etc/netns/${vpnNamespace}/resolv.conf:/etc/resolv.conf"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -162,14 +147,15 @@ in {
|
||||||
after = ["qbittorrent.service"];
|
after = ["qbittorrent.service"];
|
||||||
requires = ["qbittorrent.service"];
|
requires = ["qbittorrent.service"];
|
||||||
wantedBy = ["multi-user.target"];
|
wantedBy = ["multi-user.target"];
|
||||||
|
path = with pkgs; [iproute2 socat];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "simple";
|
Type = "simple";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
ExecStart = "${pkgs.socat}/bin/socat TCP-LISTEN:${toString webUiPort},fork,reuseaddr EXEC:'${pkgs.iproute2}/bin/ip netns exec ${vpnNamespace} ${pkgs.socat}/bin/socat STDIO TCP\\:127.0.0.1\\:${toString webUiPort}'";
|
ExecStart = "${pkgs.socat}/bin/socat TCP-LISTEN:${toString webUiPort},fork,reuseaddr,bind=0.0.0.0 EXEC:'${pkgs.iproute2}/bin/ip netns exec ${vpnNamespace} ${pkgs.socat}/bin/socat STDIO TCP\\:127.0.0.1\\:${toString webUiPort}'";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# Firewall rules for torrent port (forwarded through VPN)
|
# Firewall rules
|
||||||
networking.firewall.allowedTCPPorts = [webUiPort];
|
networking.firewall.allowedTCPPorts = [webUiPort];
|
||||||
networking.firewall.allowedUDPPorts = [torrentPort];
|
networking.firewall.allowedUDPPorts = [torrentPort];
|
||||||
|
|
||||||
|
|
@ -178,7 +164,19 @@ in {
|
||||||
"qbittorrent.nickolaj.com".allowed_groups = ["arr"];
|
"qbittorrent.nickolaj.com".allowed_groups = ["arr"];
|
||||||
};
|
};
|
||||||
nginx.virtualHosts = {
|
nginx.virtualHosts = {
|
||||||
"qbittorrent.nickolaj.com" = mkVirtualHost webUiPort;
|
"qbittorrent.nickolaj.com" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://localhost:${toString webUiPort}";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
restic.backups.homelab.paths = [
|
restic.backups.homelab.paths = [
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> ssh-ed25519 uxq+Zw 5GTpmg1JYdchll7KGFza4+Wr2HUrspkUy263EjosImI
|
||||||
|
FI/rKWr8SRFjX46ABgBAtOfF+tm5Si1T6uWC5K0EXmQ
|
||||||
|
-> 1\y>D-grease b s$Uo}
|
||||||
|
rw0Ut3iYFuMxeoj+6/VBi5qrKioY/Es
|
||||||
|
--- 7hpSVWwDE2aWWdKs60R94/87gI3IcqVY9z8PV4SlTpg
|
||||||
|
ü»0úŒµ ‘”äÍH
|
||||||
|
Ã,l±$°)^È)ѨÖ
¹£iˆFà¨pŸ™Øåì¾s‰7Á
|
||||||
Binary file not shown.
BIN
secrets/hosts/homelab/mullvad-wg-address.age
Normal file
BIN
secrets/hosts/homelab/mullvad-wg-address.age
Normal file
Binary file not shown.
BIN
secrets/hosts/homelab/mullvad-wg.age
Normal file
BIN
secrets/hosts/homelab/mullvad-wg.age
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue