diff options
author | Linnnus <[email protected]> | 2024-04-08 11:49:56 +0200 |
---|---|---|
committer | Linnnus <[email protected]> | 2024-04-08 11:53:40 +0200 |
commit | 1930c167863f6e427c7d778d9295148ef9f3f57e (patch) | |
tree | 4207ab2bd7b18098429f11aaf9195ef40569bce4 /hosts/ahmed/torrenting | |
parent | 65440e54ac8a8374a504a5dd5e5e1577a6a5a09a (diff) |
hosts/ahmed/torrenting: Split into aspects, add portal
Diffstat (limited to 'hosts/ahmed/torrenting')
-rw-r--r-- | hosts/ahmed/torrenting/default.nix | 155 | ||||
-rw-r--r-- | hosts/ahmed/torrenting/portal/anime.jpg | bin | 0 -> 82170 bytes | |||
-rw-r--r-- | hosts/ahmed/torrenting/portal/index.css | 68 | ||||
-rw-r--r-- | hosts/ahmed/torrenting/portal/index.html | 26 | ||||
-rw-r--r-- | hosts/ahmed/torrenting/portal/movie.jpg | bin | 0 -> 76334 bytes | |||
-rw-r--r-- | hosts/ahmed/torrenting/portal/thief.webp | bin | 0 -> 7568 bytes | |||
-rw-r--r-- | hosts/ahmed/torrenting/portal/watching-tv.jpg | bin | 0 -> 9137 bytes | |||
-rw-r--r-- | hosts/ahmed/torrenting/reverse-proxy.nix | 89 | ||||
-rw-r--r-- | hosts/ahmed/torrenting/wireguard.nix | 103 |
9 files changed, 297 insertions, 144 deletions
diff --git a/hosts/ahmed/torrenting/default.nix b/hosts/ahmed/torrenting/default.nix index 9b7a9c5..9fc3fb1 100644 --- a/hosts/ahmed/torrenting/default.nix +++ b/hosts/ahmed/torrenting/default.nix @@ -1,4 +1,5 @@ # This module configures the my torrenting setup. It uses qBittorrent over a VPN. + { pkgs, options, @@ -6,174 +7,40 @@ ... }: let downloadPath = "/srv/media/"; - - qbWebUiPort = 8082; - qbListeningPort = 52916; - - wgInterface = "wg0"; - wgPort = 51820; - - qbDomain = "qbittorrent.ulovlighacker.download"; - jellyfinDomain = "ulovlighacker.download"; - useACME = true; in { + imports = [ + ./wireguard.nix + ./reverse-proxy.nix + ]; + # Configure the actual qBittorrent service. services.qbittorrent = { enable = true; - # We will use a reverse proxy in front of qBittorrent. - openFirewall = false; - port = qbWebUiPort; - settings = { BitTorrent = { # Use the specified download path for finished torrents. "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; }; Preferences = { + # Again?? "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"]; + # WARNING: Jellyfin has been manually configured to serve from the correct download path. + services.jellyfin.enable = true; - # Create the directory to which media will be downloaded. - # This is also used by Jellyfin to serve the files. + # Create the directory to which media will be downloaded. This will be used + # by qBittorent to hold files and Jellyfin will serve from it. systemd.tmpfiles.rules = let 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 - - 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/hosts/ahmed/torrenting/portal/anime.jpg b/hosts/ahmed/torrenting/portal/anime.jpg Binary files differnew file mode 100644 index 0000000..9361510 --- /dev/null +++ b/hosts/ahmed/torrenting/portal/anime.jpg diff --git a/hosts/ahmed/torrenting/portal/index.css b/hosts/ahmed/torrenting/portal/index.css new file mode 100644 index 0000000..8132a1f --- /dev/null +++ b/hosts/ahmed/torrenting/portal/index.css @@ -0,0 +1,68 @@ +body { + font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + box-sizing: border-box; + + max-width: 600px; + margin: 1rem auto; + padding: 0 1rem; +} + +.title { + text-align: center; +} + +.actions { + list-style: none; + padding: 0; + margin: 0; +} + +.actions__item { + display: flex; + align-items: center; + justify-content: center; + + margin-bottom: 1rem; + + aspect-ratio: 4 / 1; + background-position-x: center; + background-repeat: no-repeat; +} + +.actions__item--watch { + background-image: + radial-gradient(rgba(0, 0, 0, 10%), black), + url(/watching-tv.jpg); + background-position-y: 40%; +} + +.actions__item--fetch { + background-image: + radial-gradient(rgba(0, 0, 0, 10%), black), + url(/thief.webp); + background-position-y: 20%; +} + +.actions__item--find-anime { + background-image: + radial-gradient(rgba(0, 0, 0, 10%), black), + url(/anime.jpg); + background-position-y: 38%; +} + +.actions__item--find-movies { + background-image: + radial-gradient(rgba(0, 0, 0, 10%), black), + url(/movie.jpg); + background-position-y: center; +} + +.actions__link { + /* Remove link styling */ + text-decoration: none; + color: white; + + font-size: xx-large; + font-weight: bold; +} + diff --git a/hosts/ahmed/torrenting/portal/index.html b/hosts/ahmed/torrenting/portal/index.html new file mode 100644 index 0000000..46226c2 --- /dev/null +++ b/hosts/ahmed/torrenting/portal/index.html @@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html lang="da"> + <head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Ulovlig hacker download</title> + <link rel="stylesheet" href="/index.css"> + </head> + <body> + <h1 class="title">Ulovlig hacker portalen</h1> + <ul class="actions"> + <li class="actions__item actions__item--watch"> + <a class="actions__link" href="//@jellyfinDomain@">Se film</a> + </li> + <li class="actions__item actions__item--fetch"> + <a class="actions__link" rel="noreferrer" href="//@qbDomain@">Styr torrents</a> + </li> + <li class="actions__item actions__item--find-anime"> + <a class="actions__link" rel="noreferrer" href="https://nyaa.si">Find animé</a> + </li> + <li class="actions__item actions__item--find-movies"> + <a class="actions__link" rel="noreferrer" href="https://1337x.to">Find film</a> + </li> + </ul> + </body> +</html> diff --git a/hosts/ahmed/torrenting/portal/movie.jpg b/hosts/ahmed/torrenting/portal/movie.jpg Binary files differnew file mode 100644 index 0000000..5b57faa --- /dev/null +++ b/hosts/ahmed/torrenting/portal/movie.jpg diff --git a/hosts/ahmed/torrenting/portal/thief.webp b/hosts/ahmed/torrenting/portal/thief.webp Binary files differnew file mode 100644 index 0000000..11f0060 --- /dev/null +++ b/hosts/ahmed/torrenting/portal/thief.webp diff --git a/hosts/ahmed/torrenting/portal/watching-tv.jpg b/hosts/ahmed/torrenting/portal/watching-tv.jpg Binary files differnew file mode 100644 index 0000000..f268099 --- /dev/null +++ b/hosts/ahmed/torrenting/portal/watching-tv.jpg diff --git a/hosts/ahmed/torrenting/reverse-proxy.nix b/hosts/ahmed/torrenting/reverse-proxy.nix new file mode 100644 index 0000000..fb141ed --- /dev/null +++ b/hosts/ahmed/torrenting/reverse-proxy.nix @@ -0,0 +1,89 @@ +# This module configures a reverse proxy for the various services that are +# exposed to the internet. + +{ + pkgs, + config, + lib, + ... +}: let + baseDomain = "ulovlighacker.download"; + wwwDomain = "www.${baseDomain}"; + qbDomain = "qbittorrent.${baseDomain}"; + jellyfinDomain = "jellyfin.${baseDomain}"; + + # The internal port where qBittorrents web UI will be served. + qbWebUiPort = 8082; + + # Whether to use ACME/Letsencrypt to get free certificates. + useACME = true; +in { + services.qbittorrent = { + openFirewall = false; + port = qbWebUiPort; + + settings = { + Preferences = { + # Used in conjunction with the --webui-port flag (via services.qbittorrent.port) + # We do NOT want qBittorrent to open the webui's port on the router, + # since all trafic will be going through the reverse proxy anyways. + "WebUI\\UseUPnP" = false; + }; + }; + }; + + services.jellyfin.openFirewall = false; + + # Use NGINX as a reverse proxy. + services.nginx = { + virtualHosts."${baseDomain}" = { + enableACME = useACME; + forceSSL = useACME; + + serverAliases = [wwwDomain]; + + locations."/" = { + index = "index.html"; + root = pkgs.runCommand "${baseDomain}-portal" { inherit qbDomain jellyfinDomain; } '' + mkdir $out + + ${pkgs.xorg.lndir}/bin/lndir ${./portal} $out + + rm $out/index.html + substituteAll ${./portal/index.html} $out/index.html + ''; + }; + }; + + 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; + }; + }; + }; + + # Register the domains with the DDNS client. + services.cloudflare-dyndns.domains = [ + baseDomain + wwwDomain + qbDomain + jellyfinDomain + ]; +} diff --git a/hosts/ahmed/torrenting/wireguard.nix b/hosts/ahmed/torrenting/wireguard.nix new file mode 100644 index 0000000..22d3f9c --- /dev/null +++ b/hosts/ahmed/torrenting/wireguard.nix @@ -0,0 +1,103 @@ +# This module configures a WireGuard for qBittorrent to use. + +{ + config, + ... +}: let + wgInterface = "wg0"; + wgPort = 51820; +in { + # TODO: Use Peer as DNS server: https://arc.net/l/quote/axlprdca + + # 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; + + 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"; + }; + + # Configure qBittorrent to only torrent through the wireguard interface. + services.qbittorrent.settings = { + Bittorrent = { + "Session\\Interface" = wgInterface; + "Session\\InterfaceName" = wgInterface; + }; + }; + + # We also instruct qBittorrent to wait for the wireguard interface to come + # online. This lets us avoid an awkward interim where qBittorrent is live + # but can't torrent anything. + # + # FIXME: Maybe not strictly necessary. + systemd.services.qbittorrent.unitConfig.After = ["wireguard-${wgInterface}.target"]; +} |