summaryrefslogtreecommitdiff
path: root/hosts/ahmed/torrenting
diff options
context:
space:
mode:
Diffstat (limited to 'hosts/ahmed/torrenting')
-rw-r--r--hosts/ahmed/torrenting/default.nix155
-rw-r--r--hosts/ahmed/torrenting/portal/anime.jpgbin0 -> 82170 bytes
-rw-r--r--hosts/ahmed/torrenting/portal/index.css68
-rw-r--r--hosts/ahmed/torrenting/portal/index.html26
-rw-r--r--hosts/ahmed/torrenting/portal/movie.jpgbin0 -> 76334 bytes
-rw-r--r--hosts/ahmed/torrenting/portal/thief.webpbin0 -> 7568 bytes
-rw-r--r--hosts/ahmed/torrenting/portal/watching-tv.jpgbin0 -> 9137 bytes
-rw-r--r--hosts/ahmed/torrenting/reverse-proxy.nix89
-rw-r--r--hosts/ahmed/torrenting/wireguard.nix103
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
new file mode 100644
index 0000000..9361510
--- /dev/null
+++ b/hosts/ahmed/torrenting/portal/anime.jpg
Binary files differ
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
new file mode 100644
index 0000000..5b57faa
--- /dev/null
+++ b/hosts/ahmed/torrenting/portal/movie.jpg
Binary files differ
diff --git a/hosts/ahmed/torrenting/portal/thief.webp b/hosts/ahmed/torrenting/portal/thief.webp
new file mode 100644
index 0000000..11f0060
--- /dev/null
+++ b/hosts/ahmed/torrenting/portal/thief.webp
Binary files differ
diff --git a/hosts/ahmed/torrenting/portal/watching-tv.jpg b/hosts/ahmed/torrenting/portal/watching-tv.jpg
new file mode 100644
index 0000000..f268099
--- /dev/null
+++ b/hosts/ahmed/torrenting/portal/watching-tv.jpg
Binary files differ
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"];
+}