diff --git a/.sops.yaml b/.sops.yaml index 8b25638..3738238 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -39,3 +39,9 @@ creation_rules: - *joonas age: - *thebes + - path_regex: hosts/thebes/recyclarr_secrets$ + key_groups: + - pgp: + - *joonas + age: + - *thebes diff --git a/hosts/thebes/default.nix b/hosts/thebes/default.nix index a0d3ece..9574899 100644 --- a/hosts/thebes/default.nix +++ b/hosts/thebes/default.nix @@ -14,24 +14,32 @@ ]) (with self.nixosModules; [ locale - tailscale systemd-boot ]) inputs.disko.nixosModules.disko inputs.sops-nix.nixosModules.sops + inputs.nixarr.nixosModules.default ./disk-config.nix ]; networking.hostName = "thebes"; - networking.useDHCP = true; nixpkgs.hostPlatform = "x86_64-linux"; system.stateVersion = "24.11"; sops = { defaultSopsFile = ./secrets.yaml; - secrets = { }; + secrets = { + "wireguard.conf".owner = "root"; + recyclarr-secrets = { + format = "binary"; + sopsFile = ./recyclarr_secrets; + path = "/var/lib/recyclarr/secrets.yml"; + }; + }; }; + # HARDWARE + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" @@ -43,16 +51,34 @@ boot.kernelModules = [ "kvm-intel" ]; - environment.systemPackages = with pkgs; [ - mergerfs - smartmontools - ]; + networking.useDHCP = true; + + # enable vaapi on OS-level + nixpkgs.config.packageOverrides = pkgs: { + vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; + }; + + # hardware acceleration + hardware.graphics = { + enable = true; + extraPackages = with pkgs; [ + intel-media-driver + intel-vaapi-driver + vaapiVdpau + intel-compute-runtime # OpenCL filter support (hardware tonemapping and subtitle burn-in) + vpl-gpu-rt # QSV on 11th gen or newer + intel-media-sdk # QSV up to 11th gen + ]; + }; # MOUNTS systemd.tmpfiles.rules = [ "d /data 0755 root root" "d /srv/nfs 0775 nfs users" + "d '${config.nixarr.mediaDir}/torrents' 0755 torrenter media - -" + "d '${config.nixarr.mediaDir}/torrents/.incomplete' 0755 torrenter media - -" + "d '${config.nixarr.mediaDir}/torrents/.watch' 0755 torrenter media - -" ]; fileSystems = { @@ -73,16 +99,16 @@ device = "/mnt/disk*"; fsType = "fuse.mergerfs"; options = [ - "cache.files=partial" + "cache.files=full" # required for deluge to work "dropcacheonclose=true" "category.create=mfs" - "func.getattr=newest" + "func.getattr=newest" # required for jellyfin to find new files ]; }; - # Bind mount /data into /srv/nfs + # Bind mount /data/share into /srv/nfs "/srv/nfs" = { - device = "/data"; + device = "/data/share"; options = [ "bind" ]; }; }; @@ -128,4 +154,122 @@ }; services.vnstat.enable = true; + + # The *arr suite + nixarr = { + enable = true; + mediaDir = "/data/media"; + stateDir = "/var/lib/nixarr"; + + jellyfin.enable = true; # 8096 + # https://github.com/NixOS/nixpkgs/issues/353600 + jellyfin.package = inputs.nixpkgs-old.legacyPackages.${pkgs.system}.jellyfin; + + prowlarr.enable = true; # 9696 + radarr.enable = true; # 7878 + sonarr.enable = true; # 8989 + readarr.enable = true; # 8787 + bazarr.enable = true; # 6767 + }; + + users.groups = { + torrenter = { }; + cross-seed = { }; + }; + + users.users.torrenter = { + isSystemUser = true; + group = "torrenter"; + }; + + # set up vpn confinement namespace + vpnNamespaces.wg = { + enable = true; + wireguardConfigFile = config.sops.secrets."wireguard.conf".path; + + portMappings = [ + { + from = config.services.deluge.web.port; + to = config.services.deluge.web.port; + } + ]; + openVPNPorts = [ + { + port = 41886; + protocol = "both"; + } + ]; + accessibleFrom = [ + "192.168.1.0/24" + "10.0.0.0/8" + "127.0.0.1" + ]; + }; + + # map local port to the vpn port so it's accessible + services.nginx = { + enable = true; + virtualHosts."127.0.0.1:${toString config.services.deluge.web.port}" = { + listen = [ + { + addr = "0.0.0.0"; + inherit (config.services.deluge.web) port; + } + ]; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://${config.vpnNamespaces.wg.namespaceAddress}:${toString config.services.deluge.web.port}"; + }; + }; + }; + + # use deluge torrent client + services.deluge = { + enable = true; + user = "torrenter"; + group = "media"; + web = { + enable = true; + openFirewall = true; + port = 8112; + }; + }; + + # run deluge daemon inside the vpn + systemd.services.deluged.vpnConfinement = { + enable = true; + vpnNamespace = "wg"; + }; + + # run deluge web ui inside the vpn. + # while this doesn't matter for privacy, + # it's required so the web ui can find the daemon + systemd.services.delugeweb.vpnConfinement = { + enable = true; + vpnNamespace = "wg"; + }; + + # recyclarr is used to set up quality profiles + systemd.services.recyclarr = { + wantedBy = [ "multi-user.target" ]; + requires = [ + "radarr.service" + "sonarr.service" + ]; + serviceConfig = { + type = "oneshot"; + }; + script = "${lib.getExe pkgs.recyclarr} sync --config ${./recyclarr.yml} --app-data /var/lib/recyclarr"; + }; + + # PACKAGES + + environment.systemPackages = with pkgs; [ + mergerfs + smartmontools + wireguard-tools + intel-gpu-tools + qbittorrent-nox + ]; } diff --git a/hosts/thebes/recyclarr.yml b/hosts/thebes/recyclarr.yml new file mode 100644 index 0000000..59f688c --- /dev/null +++ b/hosts/thebes/recyclarr.yml @@ -0,0 +1,156 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/recyclarr/recyclarr/master/schemas/config-schema.json + +sonarr: + series: + base_url: http://localhost:8989 + api_key: !secret sonarr_apikey + + quality_definition: + type: series + include: + - template: sonarr-quality-definition-series + - template: sonarr-v4-quality-profile-anime + - template: sonarr-v4-custom-formats-anime + - template: sonarr-v4-quality-profile-web-2160p + - template: sonarr-v4-custom-formats-web-2160p + quality_profiles: + - name: WEB-2160p + qualities: + - name: WEB 2160p + qualities: + - WEBDL-2160p + - WEBRip-2160p + - name: WEB 1080p + qualities: + - WEBDL-1080p + - WEBRip-1080p + custom_formats: + # ================================= + # Remux-1080p - Anime + # ================================= + - trash_ids: + # Uncensored + - 026d5aadd1a6b4e550b134cb6c72b3ca + # 10bit + - b2550eb333d27b75833e25b8c2557b38 + # Anime Dual Audio + - 418f50b10f1907201b6cfdf881f467b7 + assign_scores_to: + - name: Remux-1080p - Anime + score: 10 + # ================================= + # WEB-2160p + # ================================= + # Optional + - trash_ids: + # Bad Dual Groups + - 32b367365729d530ca1c124a0b180c64 + # DV (WEBDL) + - 9b27ab6498ec0f31a3353992e19434ca + # No-RlsGroup + - 82d40da2bc6923f41e14394075dd4b03 + assign_scores_to: + - name: WEB-2160p + +radarr: + movies: + base_url: http://localhost:7878 + api_key: !secret radarr_apikey + + quality_profiles: + - name: SQP-1 (1080p) + min_format_score: 10 + - name: SQP-1 (2160p) + # Uncomment the below line if you don't have access to top-tier indexers + min_format_score: 10 + + include: + # Comment out any of the following includes to disable them + - template: radarr-quality-definition-sqp-streaming + + - template: radarr-quality-profile-sqp-1-1080p + - template: radarr-custom-formats-sqp-1-1080p + + - template: radarr-quality-profile-sqp-1-2160p-default + - template: radarr-custom-formats-sqp-1-2160p + + custom_formats: + # 1080p + - trash_ids: + # Uncomment any of the next six lines to prefer these movie versions + # - 570bc9ebecd92723d2d21500f4be314c # Remaster + # - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster + # - e0c07d59beb37348e975a930d5e50319 # Criterion Collection + # - 9d27d9d2181838f76dee150882bdc58c # Masters of Cinema + # - db9b4c4b53d312a3ca5f1378f6440fc9 # Vinegar Syndrome + # - 957d0f44b592285f26449575e8b1167e # Special Edition + # Uncomment the next line if you prefer WEBDL with IMAX Enhanced to BHDStudio + # - 9f6cbff8cfe4ebbc1bde14c7b7bec0de # IMAX Enhanced + + # Optional - uncomment any of the following if you want them added to your profile + # - b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups + # - 90cedc1fea7ea5d11298bebd3d1d3223 # EVO (no WEBDL) + # - ae9b7c9ebde1f3bd336a8cbd1ec4c5e5 # No-RlsGroup + # - 7357cf5161efbf8c4d5d0c30b4815ee2 # Obfuscated + # - 5c44f52a8714fdd79bb4d98e2673be1f # Retags + # - f537cf427b64c38c8e36298f657e4828 # Scene + assign_scores_to: + - name: SQP-1 (1080p) + - trash_ids: + - dc98083864ea246d05a42df0d05f81cc # x265 (HD) + assign_scores_to: + - name: SQP-1 (1080p) + + + # 4K + - trash_ids: + # Uncomment any of the next six lines to prefer these movie versions + # - 570bc9ebecd92723d2d21500f4be314c # Remaster + # - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster + # - e0c07d59beb37348e975a930d5e50319 # Criterion Collection + # - 9d27d9d2181838f76dee150882bdc58c # Masters of Cinema + # - db9b4c4b53d312a3ca5f1378f6440fc9 # Vinegar Syndrome + # - 957d0f44b592285f26449575e8b1167e # Special Edition + # Uncomment the next line if you prefer 1080p/2160p WEBDL with IMAX Enhanced + # - 9f6cbff8cfe4ebbc1bde14c7b7bec0de # IMAX Enhanced + assign_scores_to: + - name: SQP-1 (2160p) + + # Unwanted + - trash_ids: + # Uncomment the next six lines to block all x265 HD releases + # - 839bea857ed2c0a8e084f3cbdbd65ecb # x265 (no HDR/DV) + # assign_scores_to: + # - name: SQP-1 (2160p) + # score: 0 + # - trash_ids: + # - dc98083864ea246d05a42df0d05f81cc # x265 (HD) + assign_scores_to: + - name: SQP-1 (2160p) + + # Optional + - trash_ids: + # Uncomment the next two lines if you have a setup that supports HDR10+ + # - b17886cb4158d9fea189859409975758 # HDR10+ Boost + # - 55a5b50cb416dea5a50c4955896217ab # DV HDR10+ Boost + + # Uncomment any of the following optional custom formats if you want them to be added to + # the quality profile + # - b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups + # - 90cedc1fea7ea5d11298bebd3d1d3223 # EVO (no WEBDL) + # - ae9b7c9ebde1f3bd336a8cbd1ec4c5e5 # No-RlsGroup + # - 7357cf5161efbf8c4d5d0c30b4815ee2 # Obfuscated + # - 5c44f52a8714fdd79bb4d98e2673be1f # Retags + # - f537cf427b64c38c8e36298f657e4828 # Scene + assign_scores_to: + - name: SQP-1 (2160p) + + # Optional SDR + # Only ever use ONE of the following custom formats: + # SDR - block ALL SDR releases + # SDR (no WEBDL) - block UHD/4k Remux and Bluray encode SDR releases, but allow SDR WEB + - trash_ids: + - 9c38ebb7384dada637be8899efa68e6f # SDR + # - 25c12f78430a3a23413652cbd1d48d77 # SDR (no WEBDL) + assign_scores_to: + - name: SQP-1 (2160p) diff --git a/hosts/thebes/recyclarr_secrets b/hosts/thebes/recyclarr_secrets new file mode 100644 index 0000000..9924bc5 --- /dev/null +++ b/hosts/thebes/recyclarr_secrets @@ -0,0 +1,26 @@ +{ + "data": "ENC[AES256_GCM,data:mMKMKDLkUvoFFe2RqMo2yL8usq4WzahiLyStHL40DQOFzWtfxHfUR0WZnrBBVcyzHt8N4KDEMxDnl6yq6NA/F8/2hgXfBtrV9qqLILPUY+LAB8ZrVBgm2KqXdz4B+pla,iv:tC38lv/aQ8CdI9Z0YaXQXdwU5hs+6xyRqkL1Q4IUfYo=,tag:VQwaK2dLkV5+nYOEV7z6ug==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1kg6sf8x9vwu8nw3fx38z5swpy04k5mnt0nqm2t0wgqt6qjqpjd4qdmmhvk", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLa1Y3cFdxRlpNZmRjazJV\nbitrb09XWXNTbzNWZlFGd09WcTh0Q25iZ2xBCjVNZDAzUlBETndtaEJ4VFMybHVS\nVW45c1ZyY01HQk02NVZJT1dHZ09NU1EKLS0tIEljekFvTUdMb2RROTVWWmpNeWN5\nc0IyTDcvUkx0aWhEVjlUd203TWdmREkKpsB+rN9LEtq4KEeHGXENXos0leUthkUO\nY8v5JErIvPEBb9yWZ6jVwO4wIoO0l8tDesW42Nwv0PBEQgi/DzrGXg==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2024-11-05T20:19:27Z", + "mac": "ENC[AES256_GCM,data:5Sc4xne3+8Umw7aZ+wlc57TFvOFEMZZAnAyAEzk0/ZBPO5+PRQ9b16gSyjn9H1V24sHoa48qnuigW/JtfOLVQVn52sVZtjWT2Aiz5SULWB0MZ5wKYD829RJXxFHPrnjGZ5+Ca7u03JKySOvAapDbmbw71cn46dDpswTsl6MBsrA=,iv:qAYEnO1dp82xeVXShXJ9KODbZNKsc36to8hrAk8ozRU=,tag:02kGtOmuBVuJnP0UUoThgw==,type:str]", + "pgp": [ + { + "created_at": "2024-11-05T20:19:27Z", + "enc": "-----BEGIN PGP MESSAGE-----\n\nhQIMAwAAAAAAAAAAARAAgaHrOmGnkt9fY0ZfUcm4wy9/VlZF//8AmkbyZCCC5sCm\nznpQCrIYM+X5weZJSeNIg/aDjzCZq69UJV6MOnxntQC606SHJyBF6AH4kYrnN6as\nMalJqMBLkeNlHD/ETqJ2NDaGeSnNIh00zYv/9TZJ5mkvZY6ojUevi02mpQa5JzsP\nBVHNu0F0hQL1f0qzjT1KfRM5BodANCK2CDRVHxTgoCWuihlKGfItbP1sumtkHbfg\nI0d3osdIQmz7AHGxr5rz30ImPOgVHFwVF52OH9mw1KP7cdcDAlyLrSBci4/QstA7\nnAygS8undilvI81sF/h5XxC+ETTXMVl3YyHNEVTywyipLMugLXGZTnnN14KBQ45/\n8A+1vdlJvdQ5g/Pfn6BvSsCJDWIsZttdtHa7G2AEGxwkh76C1cdzv/fzsUNTqc7Y\nyUaVv4qi7lurMu0rEh/p9gBaUoCLv+ko9DpAbdhzLUI6Qnhb2DKhOAeiyF5HbXpA\n88ozCkEKN0Dz68aoXSGiFkRjBwts+L9xoGk8Af8zHFWEzTfuO96tSHn8paiNKSJZ\nhwOAv1iTrGJDmD8Tj0OeOmGBCHyS6tDtE/WX5VtivpG6xk1HqQxLOkFr2nw9EvLt\nFB8/c3JhWPRGDvxxo3c7xmd/Po6Ertn2jO2D/TJVKvyHYjJcz4F++RvSl72Se6SF\nAgwDAAAAAAAAAAABD/wKTn55nYaUi6vR8NMUemBDxjtiFzuXQvjkPUTsAjOVEyG/\nw9DmdguKQnfjHgPtZXIoOzVc175QYfWqB0veJ+hkdT4EGJBlDIDBsTgi+xXAAqoT\nG5K0vUNeqLKNA0v7aBe1kXq7PS+40zB9aSFmTSy6BR3uYLKFxlOQ40HLojENhFb9\nkakiNVCbUcsmXbl8SwvrXzfIdqLEbKmeUPeN9Ok4qKnB1R9CtI02EBAOuatPJAID\nS1h01ThSGDlDgJcgjlgRDh9dccDEbxWpJZ8QLV8gqp/OBYMUzyUUjsCBYTgSMVv3\n7hVJhXra8aGW5HogXrylcPVYfPSBhQKGy5W30xhkf6ScUT0wCKrc9FpvYSpfizwS\nrlLD83LTN9ceVOoKdZBtKkvXXT6nlWeWBx7zLOj8jrZYPS01bevH+DbN3dRlOxtV\nq839mvrjVfQRErgHARlyHOL+sBXR8Rt+h66U7/lXVrxeXi7w7zQl0Ql2+j0CSw9C\naXh6YEaKWmjUxiahUN9wZOcZMIx8QH8/znGSHtmfrziKH+NzSjVHmVCaaXIBpl4i\nVMxHLlkBtWKAZSz0K7tNNLp7C4cZ7MUIiopNcQLQkXsz0l2N+kLNlbNokx8jiwJ3\nNCQZgqR4RTHBasqKZ2yJeNZL7knE/KxLl9SB7gpCBIvuyG7EzRVPivo5fQ7lhdJe\nATOq6OLY15HilQjhWogSTsYh8Q5hkOPZsrXeQDhLsBBiO5VcQsz2DqUaC73RuFf7\nwCVBERwaZo+rvYkj3JGmHDusLSg/UO9vEFAEHTiFIm7UnQmotuYHOwF+1D03Ng==\n=zyGq\n-----END PGP MESSAGE-----", + "fp": "87ECDD306614E5105299F0D4090EB48A4669AA54" + } + ], + "unencrypted_suffix": "_unencrypted", + "version": "3.9.1" + } +} \ No newline at end of file diff --git a/hosts/thebes/secrets.yaml b/hosts/thebes/secrets.yaml index 7ad0206..29fc956 100644 --- a/hosts/thebes/secrets.yaml +++ b/hosts/thebes/secrets.yaml @@ -1,4 +1,5 @@ ssh_host_ed25519_key: ENC[AES256_GCM,data:cz4p88+FeCJj92KeWGPaSnBo8fRKcjVGzgvOg3YZE6kroQ6+MeNFhhhhdQxfjQ8M6FAFIuy/YN17x15TdpS14biebebwVeXiYU6Gu1PS+qkIcL0bDpoBdYqKPZbxW9xRSPEGCtM0dzH22HmN3ZOJDH1DeZS8WHRVKeMj0FngcBc7VwPdmRy7ZYQbbkpQXgq2h0ZjcERi4oBBRssuNeS8UpJrfNCtYdPKwHetjrF5DA93Mj2iqsSVdmvCVHjZu2NQXVdr/uhxkGhnsSMcXiQOlTqBnUwhAqfR00ZEaoZhjYWgcgQ60RS9LDA/7+N2rJMGM1d2WSdWhia+FLgyKIIuE3ny6ojepE5H61aFnEjfV3OChWZYxNRjmHYo9eDC986BasXYiLRd+hfN79PGm3qszZ0dqiy6uG8evTGy++85Kr0OKHSBldY/BgiDAtA3lGhMzZkO16ehvo5FxDQdRYC1mIS44/MPGRw7HJWWBibE+TA108t9folktuxAM6uvbDEnO5fvcB9Fp+nIPV/sEHIk,iv:sHBn6N7zmCa5IzEYQyV6OEwCdemKp5ZjRTNgGIxy/zA=,tag:9JFPqVfc6fTrtY44PEjLzw==,type:str] +wireguard.conf: ENC[AES256_GCM,data:dNBGJc86rOXTgXC2QNXvHumj6pv9id88wYdFh/ZgIgzk26MOf2SVGWJkuEyt+k2snQ+tHEOywzaMO3apl/FJ4qzx+IrI4/vTRnLPTZ1bqaw+P+Nx+EI4wk8FCGmBpaP55QTOSDa1Tz99lqit5/ppDrFm8MikfzOVGwe9OQgm45o/i0sD7I4HnOkkRTK7MCN4eqnw0hwRIf756W6RySLABsAZsqGrwbbKckxJxXY3v8NDDBNcaZOz6S30tI0dqc4eX/qjRFpoVHITuxYXyvMbyzW5OMVSwQeOyn1D6fsqsJxYrOOSK+stUiRRGBA9Iu1tI6CufVMzjB/fApv7gHYsB2O6XDnysFeSNpwj/jD0lL+sQrUIPsL9hcytsXwr5z4D2KzkGHn7lFrS2sHIbouoCzcN2Fnjz86WVDCjXqTMg9avwIKnfwTDnbMgI+bAIT9H+9bob0LIwjJLsyz3LOTigZlijJrj4IMNFn8JOSIGF1qAKaYByXKVEDL3iRGYow==,iv:epdurkZpvp+F3pkOgYxImcaei8RNCn1qP0cvcsZT5ds=,tag:gOoBKe4S1Z9L+hGjEE7l3A==,type:str] sops: kms: [] gcp_kms: [] @@ -14,8 +15,8 @@ sops: RnRPSndjSUV5R205VUFoc3BLbVRKRjQK2bO9F/cQD0PJmhiIfF36C1ca5Pr4miRY OGir48nhEwF7zPcuHhYUQkJjo4QJrm2sDgfjyiOPR9A3Wri/v0MoUw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-11-02T13:34:46Z" - mac: ENC[AES256_GCM,data:QVBI6JCipyOhznFKFviEBSbiyBoKYmhLsqIWKvoyVMsckgki/LpKy2Z4lDtPhElTJAe5DPuVccP5S2c+A/98QC16Z2/TIlG9i8ScpphmRgdqIgR/YHgkXRC2z4G/jP/KsXfEbrFZsYFR2pLccN1HFQhJ2uJ7IPV2gxpdI5Bvk4s=,iv:cV4x5CMVjwB7VGCPFJPOuQ0vyfc37HOvi46QQXTo/+I=,tag:eOh4PU0A3UpFkFduecrjxg==,type:str] + lastmodified: "2024-11-05T19:58:56Z" + mac: ENC[AES256_GCM,data:ABONPAOOfgJoIkMwWyO6FddMgh7e2ZAZ3P8TSCb8b9kZzWbtykiLoICVs3s+SJ1Ya0QymTnNcN3OJBhb0m6N7XUnNEA+UtGO1vzaVQJC2o9trHt+39QW+nw0Lbx24PxVKwWqRVenbLgK4Vj10f+HUAW8zpFMjpybmYOF30Ghd2o=,iv:0bFcg3pswEDznI/6HOD6igCKoQhVRXPgrMGPbYTcsHI=,tag:+FokO4J+Vmx45ppXHaS2+w==,type:str] pgp: - created_at: "2024-11-02T13:37:01Z" enc: |- diff --git a/hosts/thebes/ssh.pub b/hosts/thebes/ssh.pub deleted file mode 100644 index 116ff9e..0000000 --- a/hosts/thebes/ssh.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMiQi4E/cmLbFeWvWKNhp94g9MrySP5em6A3KPaQlZS