diff --git a/hosts/tywin.storage.ts.hillion.co.uk/default.nix b/hosts/tywin.storage.ts.hillion.co.uk/default.nix index 4d4c75b..45a2661 100644 --- a/hosts/tywin.storage.ts.hillion.co.uk/default.nix +++ b/hosts/tywin.storage.ts.hillion.co.uk/default.nix @@ -16,6 +16,8 @@ boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; + custom.locations.autoServe = true; + ## Tailscale age.secrets."tailscale/tywin.storage.ts.hillion.co.uk".file = ../../secrets/tailscale/tywin.storage.ts.hillion.co.uk.age; custom.tailscale = { @@ -241,6 +243,15 @@ }; }; + ## Downloads + custom.services.downloads = { + metadataPath = "/data/downloads/metadata"; + downloadCachePath = "/data/downloads/torrents"; + filmsPath = "/data/media/films"; + tvPath = "/data/media/tv"; + }; + + ## Firewall networking.firewall.interfaces."tailscale0".allowedTCPPorts = [ 80 # Caddy (restic.tywin.storage.ts.) 14002 # Storj Dashboard (zfs.) diff --git a/modules/default.nix b/modules/default.nix index 1b8bf14..7ec228e 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,11 +8,13 @@ ./desktop/awesome/default.nix ./locations.nix ./resilio.nix + ./services/downloads.nix ./services/mastodon/default.nix ./services/matrix.nix ./services/version_tracker.nix ./storj.nix ./tailscale.nix + ./users.nix ./www/global.nix ./www/www-repo.nix ]; diff --git a/modules/locations.nix b/modules/locations.nix index 60aff5b..ff95c36 100644 --- a/modules/locations.nix +++ b/modules/locations.nix @@ -13,15 +13,17 @@ in locations = lib.mkOption { default = { services = { - matrix = "vm.strangervm.ts.hillion.co.uk"; + downloads = "tywin.storage.ts.hillion.co.uk"; mastodon = "vm.strangervm.ts.hillion.co.uk"; + matrix = "vm.strangervm.ts.hillion.co.uk"; }; }; }; }; config = lib.mkIf cfg.autoServe { - custom.services.matrix.enable = cfg.locations.services.matrix == config.networking.fqdn; + custom.services.downloads.enable = cfg.locations.services.downloads == config.networking.fqdn; custom.services.mastodon.enable = cfg.locations.services.mastodon == config.networking.fqdn; + custom.services.matrix.enable = cfg.locations.services.matrix == config.networking.fqdn; }; } diff --git a/modules/services/downloads.nix b/modules/services/downloads.nix new file mode 100644 index 0000000..f2bedd8 --- /dev/null +++ b/modules/services/downloads.nix @@ -0,0 +1,187 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.custom.services.downloads; +in +{ + options.custom.services.downloads = { + enable = lib.mkEnableOption "downloads"; + + metadataPath = lib.mkOption { + type = lib.types.str; + default = "/var/lib/downloads"; + }; + downloadCachePath = lib.mkOption { + type = lib.types.str; + default = "/var/cache/torrents"; + }; + filmsPath = lib.mkOption { + type = lib.types.str; + }; + tvPath = lib.mkOption { + type = lib.types.str; + }; + }; + + config = lib.mkIf cfg.enable { + services.caddy = { + enable = true; + + virtualHosts = builtins.listToAttrs (builtins.map + (x: { + name = "http://${x}.downloads.ts.hillion.co.uk"; + value = { + listenAddresses = [ config.custom.tailscale.ipv4Addr config.custom.tailscale.ipv6Addr ]; + extraConfig = "reverse_proxy unix//${cfg.metadataPath}/caddy/caddy.sock"; + }; + }) [ "prowlarr" "sonarr" "radarr" "deluge" ]); + }; + + + ## Wireguard + age.secrets."wireguard/downloads".file = ../../secrets/wireguard/downloads.age; + age.secrets."deluge/auth" = { + file = ../../secrets/deluge/auth.age; + owner = "deluge"; + }; + + networking.wireguard.interfaces."downloads" = { + privateKeyFile = config.age.secrets."wireguard/downloads".path; + ips = [ "10.2.0.2/32" ]; + peers = [ + { + publicKey = "9nrcUUgwvjNU5Z+EBB0C2cbrhQ3dsCz+zSU83/eqGFY="; + endpoint = "138.199.6.177:51820"; + allowedIPs = [ "0.0.0.0/0" ]; + } + ]; + interfaceNamespace = "downloads"; + preSetup = "test -f /run/netns/downloads || ip netns add downloads || test -f /run/netns/downloads"; + }; + + ## Host User/Directories + users.groups = { + radarr.gid = config.ids.gids.radarr; + deluge.gid = config.ids.gids.deluge; + sonarr.gid = config.ids.gids.sonarr; + mediaaccess = { + gid = config.ids.gids.mediaaccess; + members = [ "radarr" "sonarr" "deluge" config.custom.user ]; + }; + }; + users.users = + let + mkUser = user: { + name = user; + value = { + group = user; + home = "${cfg.metadataPath}/${user}"; + uid = config.ids.uids.${user}; + createHome = true; + }; + }; + users = [ "radarr" "deluge" "sonarr" ]; + in + builtins.listToAttrs (builtins.map mkUser users); + + systemd.tmpfiles.rules = [ + "d ${cfg.downloadCachePath} 0750 deluge mediaaccess - -" + "d ${cfg.filmsPath} 0770 radarr mediaaccess - -" + "d ${cfg.tvPath} 0770 sonarr mediaaccess - -" + ]; + + ## Container + containers."downloads" = { + autoStart = true; + ephemeral = true; + extraFlags = [ "--network-namespace-path=/run/netns/downloads" ]; + + bindMounts = { + "/var/lib/caddy" = { hostPath = "${cfg.metadataPath}/caddy"; isReadOnly = false; }; + "/var/lib/sonarr" = { hostPath = "${cfg.metadataPath}/sonarr"; isReadOnly = false; }; + "/var/lib/radarr" = { hostPath = "${cfg.metadataPath}/radarr"; isReadOnly = false; }; + "/var/lib/deluge" = { hostPath = "${cfg.metadataPath}/deluge"; isReadOnly = false; }; + "/var/lib/private/prowlarr" = { hostPath = "${cfg.metadataPath}/prowlarr"; isReadOnly = false; }; + + "/media/downloads" = { hostPath = cfg.downloadCachePath; isReadOnly = false; }; + "/media/films" = { hostPath = cfg.filmsPath; isReadOnly = false; }; + "/media/tv" = { hostPath = cfg.tvPath; isReadOnly = false; }; + + "/run/agenix/deluge/auth".hostPath = config.age.secrets."deluge/auth".path; + }; + + config = (hostConfig: ({ config, pkgs, ... }: { + config = { + system.stateVersion = "23.05"; + + ids = hostConfig.ids; + + users.groups.mediaaccess = { + gid = config.ids.gids.mediaaccess; + members = [ "radarr" "sonarr" "deluge" ]; + }; + + systemd.services.setup-loopback = { + description = "Setup container loopback adapter."; + + after = [ "network-pre.target" ]; + before = [ "network.target" ]; + + script = with pkgs; "${iproute2}/bin/ip link set up lo"; + }; + networking.hosts = { "127.0.0.1" = builtins.map (x: "${x}.downloads.ts.hillion.co.uk") [ "prowlarr" "sonarr" "radarr" "deluge" ]; }; + + services = { + prowlarr.enable = true; + + sonarr = { + enable = true; + dataDir = "/var/lib/sonarr"; + }; + radarr = { + enable = true; + dataDir = "/var/lib/radarr"; + }; + + deluge = { + enable = true; + web.enable = true; + + dataDir = "/var/lib/deluge"; + authFile = "/run/agenix/deluge/auth"; + + declarative = true; + config = { + download_location = "/media/downloads"; + max_connections_global = 1024; + max_upload_speed = 12500; + max_download_speed = 25000; + dont_count_slow_torrents = true; + stop_seed_ratio = 2; + share_ratio_limit = 2; + enabled_plugins = [ "Label" ]; + }; + }; + + caddy = { + enable = true; + virtualHosts = builtins.listToAttrs (builtins.map + (x: { + name = "http://${x.name}.downloads.ts.hillion.co.uk"; + value = { + listenAddresses = [ "127.0.0.1" "unix///var/lib/caddy/caddy.sock" ]; + extraConfig = "reverse_proxy http://localhost:${toString x.port}"; + }; + }) [ + { name = "radarr"; port = 7878; } + { name = "sonarr"; port = 8989; } + { name = "prowlarr"; port = 9696; } + { name = "deluge"; port = config.services.deluge.web.port; } + ]); + }; + }; + }; + })) config; + }; + }; +} diff --git a/modules/users.nix b/modules/users.nix new file mode 100644 index 0000000..3c9739e --- /dev/null +++ b/modules/users.nix @@ -0,0 +1,19 @@ +{ config, pkgs, lib, ... }: + +{ + config = { + ids.uids = { + ## Defined System Users (see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix) + + ## Consistent People + jake = 1000; + joseph = 1001; + }; + ids.gids = { + ## Defined System Groups (see https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix) + + ## Consistent Groups + mediaaccess = 1200; + }; + }; +} diff --git a/secrets/deluge/auth.age b/secrets/deluge/auth.age new file mode 100644 index 0000000..8d15935 --- /dev/null +++ b/secrets/deluge/auth.age @@ -0,0 +1,23 @@ +age-encryption.org/v1 +-> ssh-rsa GxPFJQ +F1+/Im3cdSzHDBn2W5LAV+ezO23nrjzaeVLQ0pFNYMt6v8XTA/WHHTPsImg/Nebi +noLNcxgjPu3fSnubXJuhsL5kQ6qHWvjQlQ0cRVSnMvV4UvrrPyp0066q1iMBL3PA +rh4hQ7sF4sHz3pm9jtxfdnWamGxqsowE793AjtNEvSU/i9/ZkFrKRj0LLAhHeIHJ +dWdYpnlZIrRjXFo6y+jdYpK0gyGQopy4SwoRwvDmQ/5paBRhpiXYUPtwRckiz/KE +iHA0WJhDO9a5OHLN9WPnKVRIutH/YHviy4twyPDjhHCDeJBQE02Lykd6wvJg9cWT +BkCeYhVdGp7VpWZEbLCtnw +-> ssh-rsa K9mW1w +Pm7esUbyDOoLdzxxrRkOXYxodhfKdK+X41nAT2AOR0bBcNHqGt8BSvL+HOK1vbOW +AquzA7+S91aNF7noV3JPIDrWZxDquqBp4z89YYyWNjpH9EIOYa2Sbp5xNFdgyAJw +C0uS3B/XKJcQi2np39szNzuR2h7uTKkKW5wMan+YUK1ODxmTJVibo0c0JUybMjXA +VS31BrkDb0LKRgvp/kNfn9aEaI7d78oca+6X0BDHk2zYRPwL1Q/MGw4tkx3pqI+x +i6frCSHlo715tHaYvxRQyimWthmUft/1etMasFINhLidx4ufdawLR6sbR09sCrMj +5NMeB1wc1XrGxwMumNDWyg +-> ssh-ed25519 nWv9MA CxCjLfbIfEn1voAr3jX+dRGnHmdAyylNuPn/2QfuphM +PS2cpu13uyPlo9PJIT+dybq4P2juNpiZY61sJq7DepQ +-> )ei-grease ,jk Bw +IucfaHwBWhzdMcTDXxOUyTy1kCUnSlsfAwVw8YKimsxHyvJS+wkyPXUzepHMZYId +SvebFA +--- q53LwYLjQ6p0yHStpDma4DYMpfFTpv7+MAzaHjM7Kaw +?0պ9S>h( Q>8;zLPYhJs@dґC׌9ڿ{r|taNv3'o +ֱd= Z`T62($HZ:Qh diff --git a/secrets/secrets.nix b/secrets/secrets.nix index 33b1c23..075dfcb 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -90,4 +90,10 @@ in # Home Automation secrets "mqtt/zigbee2mqtt.age".publicKeys = jake_users ++ [ ts.home.microserver ]; + + # Wireguard Secrets + "wireguard/downloads.age".publicKeys = jake_users ++ [ ts.storage.tywin ]; + + # Deluge Secrets + "deluge/auth.age".publicKeys = jake_users ++ [ ts.storage.tywin ]; } diff --git a/secrets/wireguard/downloads.age b/secrets/wireguard/downloads.age new file mode 100644 index 0000000..7c2541e --- /dev/null +++ b/secrets/wireguard/downloads.age @@ -0,0 +1,21 @@ +age-encryption.org/v1 +-> ssh-rsa GxPFJQ +qvr3798lXYpFKMBj6Kgt35E9FQFiTbNN6yGKvWO7Bm/2veZymVjW7zI/JZ6//WMi +OunOsnwCAINAB/30+ua40dvc8KaV/Mp2wLWrmm2H+8OgN9vxpwfe/PdBI8IQGyBa +8fR1YZU5W34CypwMczpzELede9ayhhKCadB+KbqYq4pFAMVpWa4noE8b9g9foNCQ +BdwrbQxp+iJVGx01Z5CRVsZ9q6YeuL7/rBzXKn59Ga6kfPzKVbXusJeAyR6K9hK1 +Nz5EKrKmfXjMsSGCckv64rPpOlJMfZX37Vtqf2B3K1VqDykh33yAjaOHDJjmRvkQ +K6r6/Us3L98/LsVZ20HMbw +-> ssh-rsa K9mW1w +IHp/1LLLavXAigGpU3kmflj9ijLBuskLM4gadTJ49S3iYQcbwtpoDEQVr9K52W3c +Sd71l4xLRw0AnlP2EV7DiUsdeQcRgJO2hq/hXhmy3KXzYaMCaBpHz/Y6y7+vmdHL +/b6lFwCWhxLLRVBA7tSlia7oneUEa9rjy9dHlbryL/yO4epB+kP5m0whe7zyPaNe +2wbfwnNpkcTeyqye6UQTGM/nBJJSTpBbU2xoPwCrhFf/TJAHOuh9AV6+U8+NkV04 +oZpC86fWPwWAWgdsA4jHuGidKpqlVrI30h8haZW7qbuFny90xUlOdqLQcPVHB8Ux +t9ZXKy6eN4gPHsbqWo5H+g +-> ssh-ed25519 nWv9MA zB9wtm2ydzVDrLuoHJUCFj0e6X+vr7lPKME4dRXbPTg +6XWXniYAW5+doJvSU0A3wiFIeZFF8nRkMO+qIbvOGMs +-> LZw/kad#-grease ^M+k i-~[#2]v +v/8FOljENf9K166hovY3DSO88KTIHmxUmU2fW+MSn8ZD +--- ythVTik09YoysBPv6MFuNgbHl70b9tCm4K97xxKXFWA +&0GXA|_Xr`O0oo@>?a9u|H> %]ب6wUF