diff options
author | Linnnus <[email protected]> | 2024-04-07 13:35:48 +0200 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-04-07 13:41:38 +0200 |
commit | 65440e54ac8a8374a504a5dd5e5e1577a6a5a09a (patch) | |
tree | 34ce5c1edc09791585d9e53be49a8ee333f5d048 | |
parent | 4c95d6f14be1bde2ae9e33d2318bf8e1c8ff8134 (diff) |
hosts/ahmed: Add WireGuard + Jellyfin
-rw-r--r-- | hosts/ahmed/torrenting/default.nix | 156 | ||||
-rw-r--r-- | secrets/mullvad-wg.key.age | 20 | ||||
-rw-r--r-- | secrets/mullvad-wg.key.example | 1 | ||||
-rw-r--r-- | secrets/secrets.nix | 10 |
4 files changed, 176 insertions, 11 deletions
diff --git a/hosts/ahmed/torrenting/default.nix b/hosts/ahmed/torrenting/default.nix index c49baa6..9b7a9c5 100644 --- a/hosts/ahmed/torrenting/default.nix +++ b/hosts/ahmed/torrenting/default.nix @@ -1,14 +1,29 @@ # This module configures the my torrenting setup. It uses qBittorrent over a VPN. -{pkgs, options, config, ...}: let +{ + pkgs, + options, + config, + ... +}: let downloadPath = "/srv/media/"; - interface = "tun0"; + qbWebUiPort = 8082; + qbListeningPort = 52916; + + wgInterface = "wg0"; + wgPort = 51820; + + qbDomain = "qbittorrent.ulovlighacker.download"; + jellyfinDomain = "ulovlighacker.download"; + useACME = true; in { # Configure the actual qBittorrent service. services.qbittorrent = { enable = true; - openFirewall = true; # TEMP: reverse proxy will cover this instead + # We will use a reverse proxy in front of qBittorrent. + openFirewall = false; + port = qbWebUiPort; settings = { BitTorrent = { @@ -16,22 +31,149 @@ in { "Session\\DefaultSavePath" = downloadPath; "Session\\TempPath" = "${config.services.qbittorrent.profile}/qBittorrent/temp"; "Session\\TempPathEnabled" = true; + + # Instruct qBittorrent to only use VPN interface. + "Session\\Interface" = wgInterface; + "Session\\InterfaceName" = wgInterface; + + "Session\\Port" = qbListeningPort; }; - # Instruct qBittorrent to only use VPN interface. + Preferences = { + "Downloads\\SavePath" = downloadPath; + "General\\Locale" = "da"; + + # Used in conjunction with the --webui-port flag (via services.qbittorrent.port) + # since we'll be using a reverse proxy. + "WebUI\\UseUPnP" = false; + }; }; }; + systemd.services.qbittorrent.unitConfig.After = ["wireguard-${wgInterface}.target"]; + # Create the directory to which media will be downloaded. # This is also used by Jellyfin to serve the files. systemd.tmpfiles.rules = let - user = options.services.qbittorrent.user.default; - group = options.services.qbittorrent.group.default; + user = config.services.qbittorrent.user; + group = config.services.qbittorrent.group; in [ "d ${downloadPath} 0755 ${user} ${group}" ]; # Create a connection to Mullvad's WireGuard server. + networking.wireguard.interfaces = { + ${wgInterface} = { + # The port to use for communication. This should also be opened in the firewall. + ips = ["10.70.101.133/32" "fc00:bbbb:bbbb:bb01::7:6584/128"]; + privateKeyFile = config.age.secrets.mullvad-wg-key.path; + allowedIPsAsRoutes = false; + listenPort = wgPort; + + # Create a differente networking namespace to isolate the qBittorent + # process. I decided not to do this because connecting the WebUI to NGINX + # becomes a bit tricky then. I will keep it around just in case I take up + # this issue again sometime later. + # + # Remember, you would also need to set NetworkNamespacePath= on + # qBittorrent [0]. The network namespace would when be located under + # /run/netns/${wgNamespace}. + # + # [0]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#NetworkNamespacePath= + # + # interfaceNamespace = wgNamespace; + # preSetup = '' + # echo "Setting up namespace: ${wgNamespace}" + # ${pkgs.iproute2}/bin/ip netns add ${wgNamespace} + # ${pkgs.iproute2}/bin/ip -n ${wgNamespace} link set lo up + # ''; + # postShutdown = '' + # echo "Tearing down namespace: ${wgNamespace}" + # ${pkgs.iproute2}/bin/ip netns del "${wgNamespace}" + # ''; + + # Since this is a client configuration, we only need a single peer: the Mullvad server. + peers = [ + { + # The public key of the server. + publicKey = "/iivwlyqWqxQ0BVWmJRhcXIFdJeo0WbHQ/hZwuXaN3g="; + + # The location of the server. + endpoint = "193.32.127.66:${toString wgPort}"; + + # Which destination IPs should be directed to this ip/pubkey pair. In + # this case, we send all packets to our only peer. + # + # NOTE: It is important the we either use a network namespace or set + # `allowedIPsAsRoutes = false` as otherwise we run into the loop + # routing problem. + # + # See: https://wiki.archlinux.org/title/WireGuard#Loop_routing + # See: https://cohost.org/linuwus/post/5040530-an-unexpected-soluti + allowedIPs = ["0.0.0.0/0" "::/0"]; + + # Send keepalives messages. Important to keep NAT tables alive. + persistentKeepalive = 25; + } + ]; + }; + }; + + # Here we load the secret file containing this clients private key. It is + # defined in the configuration file from Mullvad's website. + age.secrets.mullvad-wg-key.file = ../../../secrets/mullvad-wg.key.age; + + # TODO: Use Peer as DNS server: https://arc.net/l/quote/axlprdca - # Use NGINX as a reverse proxy for qBittorrent's WebUI. + services.jellyfin = { + enable = true; + # We use a reverse proxy. + openFirewall = false; + }; + + # Use NGINX as a reverse proxy for the various services that present web UIs. + services.nginx = { + virtualHosts.${qbDomain} = { + enableACME = useACME; + forceSSL = useACME; + + locations."/" = { + proxyPass = "http://localhost:${toString qbWebUiPort}"; + recommendedProxySettings = true; + }; + }; + + virtualHosts.${jellyfinDomain} = { + enableACME = useACME; + forceSSL = useACME; + + locations."/" = { + # This is the "static port" of the HTTP web interface. + # + # See: https://jellyfin.org/docs/general/networking/#port-bindings + proxyPass = "http://localhost:8096"; + recommendedProxySettings = true; + }; + }; + }; + + services.cloudflare-dyndns.domains = [ + qbDomain + jellyfinDomain + ]; + + networking.firewall = { + # Clients and peers use the same port. I'm actually not sure we need to + # accept incomming connections as clients participating in the wireguard + # protocol. + allowedUDPPorts = [wgPort]; + + # This is a weird fix. Apparently the rpfilter set up as part of + # nixos-rpfilter in the 'mangle' table will block WireGuard traffic. + # Setting this to "loose" somehow fixes that. + # + # See: https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577/2?u=linnnus + # See: https://github.com/NixOS/nixpkgs/issues/51258#issuecomment-448005659 + checkReversePath = "loose"; + }; } diff --git a/secrets/mullvad-wg.key.age b/secrets/mullvad-wg.key.age new file mode 100644 index 0000000..aa1b344 --- /dev/null +++ b/secrets/mullvad-wg.key.age @@ -0,0 +1,20 @@ +age-encryption.org/v1 +-> ssh-rsa 5MROTA +Ey8R/TdctoyamAZWhoUaTLAfWdja0g3tWBRYexyH/1hlnTgaz9KwkXpRW9desg7/ +IA0GaBVuRlmVx1kbA2KKbgpG8c/a34AwM7F2LnYoFkPV4VDZoN54fDEDa01TRG2o +qk96gjmCTS8l+AY2mlpUbsBzIYZLjtLQgPGOLpfKuyL9cw1IM+8Es3NHbkb5seLi +zGnvl/qGV2usetfd+Vdb8QycPtE29UJaQw/Qh2f4nvquVZgzxwPzVhEDtqzdj5X8 +bRJxOcsIf7kK14xHM+nT1S8dfSUN3Ztfcuyy6EbNX1/opIO0KOEEnnKs/wNZQq98 +26INpaB7rnCtdZNkblpmGvo6/QCqeRerIWNPdjAnvSWogQjtgVsL6OveAI4lKuQ/ +rq1+KtvOgZChLCOVxcI888IRnMDYxlTUJ6QlJmS7KYGWITejcnbL1kbKFvE/IJ1L +MSSJpK7FIM2YwY78NcrVmaJlc+K/VVzTms85bq5NNawGTyjWgZaHZSvlzGYMVgu5 +ze4P5jUjYCFON8Ohe20H4jvac8DlP64efH/EokTDEAaLO9Ye0Ew66tMoh4fbWEpw +mA1UVED8X3zejAhWRdwAmvpEWejOrIizmWEGZB5iOxWBfDz3UUBXM2x3Dgf068K0 +2hWli4GMn4Ls6v7oEVe4lYIV7PSaLqdc1MU4IjTmx2g +-> ssh-ed25519 LNzQIA awafDaYwRJjBEWAlOShvwSLTIPQDSYZsiJux4PlFOE4 +iQpj96oh9wta8wrxMewHAyNY99wEXiXOUt1bGO3paOI +-> jHn93"D-grease P{.i5 *<*l {Y:GM +ns4gUbJyOQnGDuqxKIAfjHhLMhXyTjT6BeUzPQasvoLvXvO3Bju3YN6FbR6LcMBz +Km8KE+iczuv4pfhILngj/Mv8wJBuWuAyi4DjnIRs38wF +--- QKAOhH8C9OLDT9hYvSnzmXut29OBZpSUwVpOPmqDTDs +W@X�\�� �1(�`y(U�`������h�:{��7��1� w/�kG)[S�a��qr�o�/���&��V���C�^ ��J�3�
\ No newline at end of file diff --git a/secrets/mullvad-wg.key.example b/secrets/mullvad-wg.key.example new file mode 100644 index 0000000..442f26a --- /dev/null +++ b/secrets/mullvad-wg.key.example @@ -0,0 +1 @@ +IMF/WbG/aJSKj0LkEkU/+88/f+bO+dQnYzKhKmazz0w= diff --git a/secrets/secrets.nix b/secrets/secrets.nix index e50f757..34fd87b 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -2,9 +2,11 @@ # imported into the system cofniguration. let metadata = builtins.fromTOML (builtins.readFile ../metadata.toml); - publicKeys = map (builtins.getAttr "sshPubKey") (builtins.attrValues metadata.hosts); + ahmedKey = metadata.hosts.ahmed.sshPubKey; + muhammedKey = metadata.hosts.muhammed.sshPubKey; in { - "cloudflare-ddns-token.env.age".publicKeys = publicKeys; - "duksebot.env.age".publicKeys = publicKeys; - "forsvarsarper.env.age".publicKeys = publicKeys; + "cloudflare-ddns-token.env.age".publicKeys = [muhammedKey ahmedKey]; + "duksebot.env.age".publicKeys = [muhammedKey ahmedKey]; + "forsvarsarper.env.age".publicKeys = [muhammedKey ahmedKey]; + "mullvad-wg.key.age".publicKeys = [muhammedKey ahmedKey]; } |