diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 485dee6..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.idea diff --git a/.sops.yaml b/.sops.yaml deleted file mode 100644 index 02cc451..0000000 --- a/.sops.yaml +++ /dev/null @@ -1,10 +0,0 @@ -keys: - - &tdpeuter_Tibo-NixFatDesk age1fva6s64s884z0q2w7de024sp69ucvqu0pg9shrhhqsn3ewlpjfpsh6md7y - - &tdpeuter_Tibo-NixTop age1qzutny0mqpcccqw6myyfntu6wcskruu9ghzvt6r4te7afkqwnguq05ex37 - -creation_rules: - - path_regex: secrets/[^/]+\.(yaml|json|env|ini)$ - key_groups: - - age: - - *tdpeuter_Tibo-NixFatDesk - - *tdpeuter_Tibo-NixTop diff --git a/flake.lock b/flake.lock index ca6e418..8df2f99 100644 --- a/flake.lock +++ b/flake.lock @@ -5,11 +5,11 @@ "systems": "systems" }, "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "owner": "numtide", "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "type": "github" }, "original": { @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1759381078, - "narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=", + "lastModified": 1730785428, + "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee", + "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", "type": "github" }, "original": { @@ -37,30 +37,9 @@ "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", - "sops-nix": "sops-nix", "utils": "utils" } }, - "sops-nix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1759188042, - "narHash": "sha256-f9QC2KKiNReZDG2yyKAtDZh0rSK2Xp1wkPzKbHeQVRU=", - "owner": "Mic92", - "repo": "sops-nix", - "rev": "9fcfabe085281dd793589bdc770a2e577a3caa5d", - "type": "github" - }, - "original": { - "owner": "Mic92", - "repo": "sops-nix", - "type": "github" - } - }, "systems": { "locked": { "lastModified": 1681028828, @@ -83,11 +62,11 @@ ] }, "locked": { - "lastModified": 1738591040, - "narHash": "sha256-4WNeriUToshQ/L5J+dTSWC5OJIwT39SEP7V7oylndi8=", + "lastModified": 1722363685, + "narHash": "sha256-XCf2PIAT6lH7BwytgioPmVf/wkzXjSKScC4KzcZgb64=", "owner": "gytis-ivaskevicius", "repo": "flake-utils-plus", - "rev": "afcb15b845e74ac5e998358709b2b5fe42a948d1", + "rev": "6b10f51ff73a66bb29f3bc8151a59d217713f496", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 446f4ce..57bbff8 100644 --- a/flake.nix +++ b/flake.nix @@ -5,10 +5,6 @@ nixpkgs.url = "nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; - sops-nix = { - url = "github:Mic92/sops-nix"; - inputs.nixpkgs.follows = "nixpkgs"; - }; utils = { url = "github:gytis-ivaskevicius/flake-utils-plus"; inputs.flake-utils.follows = "flake-utils"; @@ -17,11 +13,11 @@ outputs = inputs@{ self, nixpkgs, - flake-utils, sops-nix, utils, + flake-utils, utils, ... }: let - system = utils.lib.system.x86_64-linux; + system = "x86_64-linux"; in utils.lib.mkFlake { inherit self inputs; @@ -32,30 +28,20 @@ modules = [ ./modules ./users - - sops-nix.nixosModules.sops ]; }; hosts = { - # Physical hosts - Niko.modules = [ ./hosts/Niko ]; + Niko.modules = [ ./hosts/Niko ]; - # Virtual machines - - # Single-service Ingress.modules = [ ./hosts/Ingress ]; Gitea.modules = [ ./hosts/Gitea ]; Vaultwarden.modules = [ ./hosts/Vaultwarden ]; - # Production multi-service Binnenpost.modules = [ ./hosts/Binnenpost ]; - Production.modules = [ ./hosts/Production ]; ProductionGPU.modules = [ ./hosts/ProductionGPU ]; - ProductionArr.modules = [ ./hosts/ProductionArr ]; ACE.modules = [ ./hosts/ACE ]; - # Others Template.modules = [ ./hosts/Template ]; Development.modules = [ ./hosts/Development ]; Testing.modules = [ ./hosts/Testing ]; diff --git a/hosts/Binnenpost/default.nix b/hosts/Binnenpost/default.nix index 561fbe1..d78e2da 100644 --- a/hosts/Binnenpost/default.nix +++ b/hosts/Binnenpost/default.nix @@ -16,7 +16,6 @@ apps = { speedtest.enable = true; technitiumDNS.enable = true; - traefik.enable = true; }; virtualisation.guest.enable = true; }; @@ -77,14 +76,6 @@ }; }; - virtualisation.oci-containers.containers.traefik.labels = { - "traefik.http.routers.roxanne.rule" = "Host(`roxanne.depeuter.dev`)"; - "traefik.http.services.roxanne.loadbalancer.server.url" = "https://192.168.0.13:8006"; - - "traefik.http.routers.hugo.rule" = "Host(`hugo.depeuter.dev`)"; - "traefik.http.services.hugo.loadbalancer.server.url" = "https://192.168.0.11:444"; - }; - system.stateVersion = "24.05"; }; } diff --git a/hosts/Development/default.nix b/hosts/Development/default.nix index b2237b7..40983c9 100644 --- a/hosts/Development/default.nix +++ b/hosts/Development/default.nix @@ -3,10 +3,8 @@ { config = { homelab = { - apps = { - bind9.enable = true; - traefik.enable = true; - plex.enable = true; + apps.arr = { + qbittorrent.enable = true; }; virtualisation.guest.enable = true; }; diff --git a/hosts/Ingress/default.nix b/hosts/Ingress/default.nix index 68cdcfe..63e3ced 100644 --- a/hosts/Ingress/default.nix +++ b/hosts/Ingress/default.nix @@ -59,7 +59,6 @@ prefixLength = 24; }; "cloud.depeuter.dev" = { }; "git.depeuter.dev" = { }; - "home.depeuter.dev" = { }; "jelly.depeuter.dev" = { }; "vault.depeuter.dev" = { }; }; @@ -137,27 +136,10 @@ prefixLength = 24; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ''; }; - "calendar.depeuter.dev" = { - useACMEHost = "depeuter.dev"; - locations."/".return = "301 https://cloud.depeuter.dev/apps/calendar"; - }; + "calendar.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/calendar"; "tasks.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/tasks"; "notes.depeuter.dev".locations."/".return = "301 https://cloud.depeuter.dev/apps/notes"; - "home.depeuter.dev" = { - enableACME = true; - forceSSL = true; - locations."/" = { - proxyPass = "http://192.168.0.21:8123"; - extraConfig = '' - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - ''; - }; - }; - "jelly.depeuter.dev" = { enableACME = true; forceSSL = true; @@ -194,7 +176,7 @@ prefixLength = 24; }; }; extraConfig = '' - client_max_body_size 512M; + client_max_body_size 20M; # Security / XSS Mitigation Headers # NOTE: X-Frame-Options may cause issues with the webOS app @@ -224,7 +206,7 @@ prefixLength = 24; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - client_max_body_size 10G; + client_max_body_size 512M; keepalive_timeout 600s; proxy_buffers 4 256k; # Number and size of buffers for reading response proxy_buffer_size 256k; # Buffer for the first part of the response @@ -238,18 +220,10 @@ prefixLength = 24; enableACME = true; forceSSL = true; locations = { - "/" = { - proxyPass = "http://192.168.0.22:10102"; - proxyWebSockets = true; - }; + "/".proxyPass = "http://192.168.0.22:10102"; "~ ^/admin".return = 403; }; }; - "rss.depeuter.dev" = { - enableACME = true; - forceSSL = true; - locations."/".proxyPass = "http://192.168.92:${toString config.homelab.apps.freshrss.port}"; - }; }; }; }; diff --git a/hosts/Niko/default.nix b/hosts/Niko/default.nix index 910f325..57dbc27 100644 --- a/hosts/Niko/default.nix +++ b/hosts/Niko/default.nix @@ -7,10 +7,7 @@ ]; homelab = { - apps = { - technitiumDNS.enable = true; - traefik.enable = true; - }; + apps.technitiumDNS.enable = true; users.deploy.enable = true; }; @@ -37,11 +34,12 @@ hardware = { enableRedistributableFirmware = true; enableAllFirmware = true; - graphics.enable = true; + pulseaudio.enable = true; + opengl.enable = true; }; # Select internationalisation properties. - i18n.defaultLocale = "en_GB.UTF-8"; + i18n.defaultLocale = "en_GB.utf8"; networking = { hostName = "Niko"; @@ -81,8 +79,6 @@ user = config.users.users.jellyfin-mpv-shim.name; }; - pulseaudio.enable = true; - tailscale = { enable = true; useRoutingFeatures = "server"; @@ -98,6 +94,8 @@ # resolved.enable = true; }; + sound.enable = true; + # Define a user account. Don't forget to set a password with 'passwd'. users.users.jellyfin-mpv-shim = { description = "Jellyfin MPV Shim User"; @@ -116,4 +114,67 @@ systemd.services."cage-tty1".serviceConfig.Restart = "always"; system.stateVersion = "24.05"; + + virtualisation = { + # Enable Android emulator + # waydroid.enable = true; + + docker = { + enable = true; + autoPrune.enable = true; + }; + + oci-containers = { + backend = "docker"; + containers = { + reverse-proxy = { + hostname = "traefik"; + image = "traefik:v3.0"; + cmd = [ + "--api.insecure=true" + # Add Docker provider + "--providers.docker=true" + "--providers.docker.exposedByDefault=false" + # Add web entrypoint + "--entrypoints.web.address=:80/tcp" + "--entrypoints.web.http.redirections.entrypoint.to=websecure" + "--entrypoints.web.http.redirections.entrypoint.scheme=https" + # Add websecure entrypoint + "--entrypoints.websecure.address=:443/tcp" + "--entrypoints.websecure.http.tls=true" + "--entrypoints.websecure.http.tls.certResolver=letsencrypt" + "--entrypoints.websecure.http.tls.domains[0].main=depeuter.dev" + "--entrypoints.websecure.http.tls.domains[0].sans=*.depeuter.dev" + "--entrypoints.websecure.http.tls.domains[1].sans=*.niko.depeuter.dev" + # Certificates + "--certificatesresolvers.letsencrypt.acme.dnschallenge=true" + "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare" + "--certificatesresolvers.letsencrypt.acme.email=tibo.depeuter@telenet.be" + "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" + ]; + ports = [ + "80:80/tcp" + "443:443/tcp" + # "8080:8080/tcp" # The Web UI (enabled by --api.insecure=true) + ]; + environment = { + # TODO Hide this! + "CLOUDFLARE_DNS_API_TOKEN" = "6Vz64Op_a6Ls1ljGeBxFoOVfQ-yB-svRbf6OyPv2"; + }; + environmentFiles = [ + ]; + volumes = [ + "/var/run/docker.sock:/var/run/docker.sock:ro" # So that Traefik can listen to the Docker events + "letsencrypt:/letsencrypt" + ]; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.traefik.rule" = "Host(`traefik.niko.depeuter.dev`)"; + "traefik.http.services.traefik.loadbalancer.server.port" = "8080"; + }; + autoStart = true; + }; + }; + }; + }; } diff --git a/hosts/Production/default.nix b/hosts/Production/default.nix deleted file mode 100644 index 9bb565d..0000000 --- a/hosts/Production/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ config, pkgs, lib, system, ... }: - -{ - config = { - homelab = { - apps = { - calibre.enable = true; - traefik.enable = true; - }; - virtualisation.guest.enable = true; - }; - - networking = { - hostId = "aaaa2100"; - domain = "roxanne.depeuter.dev"; - - useDHCP = false; - - enableIPv6 = true; - - defaultGateway = { - address = "192.168.0.1"; - interface = "ens18"; - }; - - # Open ports in the firewall. - firewall = { - enable = true; - }; - - interfaces.ens18 = { - ipv4.addresses = [ - { - address = "192.168.0.31"; - prefixLength = 24; - } - ]; - }; - - nameservers = [ - "1.1.1.1" # Cloudflare - "1.0.0.1" # Cloudflare - ]; - }; - - system.stateVersion = "24.05"; - }; -} diff --git a/hosts/ProductionArr/default.nix b/hosts/ProductionArr/default.nix deleted file mode 100644 index ff4f4c2..0000000 --- a/hosts/ProductionArr/default.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ config, pkgs, lib, system, ... }: - -{ - config = { - homelab = { - apps = { - arr.enable = true; - traefik.enable = true; - }; - virtualisation.guest.enable = true; - }; - - networking = { - hostId = "aaaa2300"; - domain = "roxanne.depeuter.dev"; - - useDHCP = false; - - enableIPv6 = true; - - defaultGateway = { - address = "192.168.0.1"; - interface = "ens18"; - }; - - # Open ports in the firewall. - firewall = { - enable = true; - }; - - interfaces.ens18 = { - ipv4.addresses = [ - { - address = "192.168.0.33"; - prefixLength = 24; - } - ]; - }; - - nameservers = [ - "1.1.1.1" # Cloudflare - "1.0.0.1" # Cloudflare - ]; - }; - - system.stateVersion = "24.05"; - }; -} diff --git a/hosts/ProductionGPU/default.nix b/hosts/ProductionGPU/default.nix index fa9ca8c..75e48e7 100644 --- a/hosts/ProductionGPU/default.nix +++ b/hosts/ProductionGPU/default.nix @@ -17,7 +17,7 @@ defaultGateway = { address = "192.168.0.1"; - interface = "ens18"; + interface = "enp6s18"; }; # Open ports in the firewall. @@ -25,7 +25,7 @@ enable = true; }; - interfaces.ens18 = { + interfaces.enp6s18 = { ipv4.addresses = [ { address = "192.168.0.94"; @@ -40,7 +40,7 @@ ]; }; - system.stateVersion = "24.11"; + system.stateVersion = "unstable"; ### Nvidia GPU support ### @@ -64,7 +64,7 @@ }; hardware = { - graphics = { + opengl = { enable = true; # driSupport = true; # driSupport32Bit = true; diff --git a/hosts/Testing/default.nix b/hosts/Testing/default.nix index cc353f6..78abc58 100644 --- a/hosts/Testing/default.nix +++ b/hosts/Testing/default.nix @@ -3,11 +3,10 @@ { config = { homelab = { - apps = { - freshrss.enable = true; - traefik.enable = true; + virtualisation = { + containers.enable = true; + guest.enable = true; }; - virtualisation.guest.enable = true; }; networking = { diff --git a/hosts/Vaultwarden/default.nix b/hosts/Vaultwarden/default.nix index d8115bc..9f98d84 100644 --- a/hosts/Vaultwarden/default.nix +++ b/hosts/Vaultwarden/default.nix @@ -3,11 +3,7 @@ { config = { homelab = { - apps.vaultwarden = { - enable = true; - domain = "https://vault.depeuter.dev"; - name = "Hugo's Vault"; - }; + apps.vaultwarden.enable = true; virtualisation.guest.enable = true; }; diff --git a/modules/apps/arr/default.nix b/modules/apps/arr/default.nix index 7b530c3..8be935f 100644 --- a/modules/apps/arr/default.nix +++ b/modules/apps/arr/default.nix @@ -4,86 +4,61 @@ let cfg = config.homelab.apps.arr; networkName = "arrStack"; - proxyNet = config.homelab.apps.traefik.sharedNetworkName; - - appNames = [ "bazarr" "prowlarr" "qbittorrent" "radarr" "sonarr" ]; + appNames = [ "bazarr" "lidarr" "prowlarr" "qbittorrent" "radarr" "sonarr" ]; inUse = builtins.any (app: cfg.${app}.enable) appNames; PGID = toString config.users.groups.media.gid; UMASK = "002"; in { - options.homelab.apps.arr = let - mkAppOption = appName: { - enable = lib.mkEnableOption "${appName} using Docker"; - exposePorts = lib.mkOption { - type = lib.types.bool; - description = "Expose ${appName} port"; - default = cfg.exposePorts; - }; - }; - in { + options.homelab.apps.arr = { enable = lib.mkEnableOption "Arr Stack using Docker"; - exposePorts = lib.mkOption { - type = lib.types.bool; - description = "Expose all app ports"; - # Only expose ports by default if Traefik is not in use. - default = ! config.homelab.apps.traefik.enable; - }; - bazarr = mkAppOption "Bazarr"; - prowlarr = mkAppOption "Prowlarr"; - qbittorrent = mkAppOption "qBittorrent"; - radarr = mkAppOption "Radarr"; - sonarr = mkAppOption "Sonarr"; + bazarr.enable = lib.mkEnableOption "Bazarr using Docker"; + lidarr.enable = lib.mkEnableOption "Lidarr using Docker"; + prowlarr.enable = lib.mkEnableOption "Prowlarr using Docker"; + qbittorrent.enable = lib.mkEnableOption "qBittorrent using Docker"; + radarr.enable = lib.mkEnableOption "Radarr using Docker"; + sonarr.enable = lib.mkEnableOption "Sonarr using Docker"; }; config = { homelab = { - users = lib.mkIf inUse { - apps.enable = true; - media.enable = true; - }; + users.media.enable = lib.mkIf inUse true; # "Master switch": Enable all apps. - apps.arr = lib.mkIf cfg.enable { - bazarr.enable = true; - prowlarr.enable = true; - qbittorrent.enable = true; - radarr.enable = true; - sonarr.enable = true; + apps.arr = { + bazarr.enable = lib.mkIf cfg.enable true; + lidarr.enable = lib.mkIf cfg.enable true; + prowlarr.enable = lib.mkIf cfg.enable true; + qbittorrent.enable = lib.mkIf cfg.enable true; + radarr.enable = lib.mkIf cfg.enable true; + sonarr.enable = lib.mkIf cfg.enable true; }; - - fileSystems.media.video = { - enable = true; - permissions = [ "read" "write" ]; - }; - - virtualisation.containers.enable = lib.mkIf inUse true; }; - fileSystems = let - mkFileSystem = device: { - inherit device; + fileSystems = lib.mkIf inUse { + "/srv/video" = { + device = "192.168.0.11:/mnt/SMALL/MEDIA/VIDEO"; fsType = "nfs"; options = [ "rw" - "auto" "nfsvers=4.2" - "rsize=1048576" "wsize=1048576" - "hard" - "timeo=600" "retrans=2" - "_netdev" "nosuid" "tcp" + "async" "soft" + "timeo=100" "retry=50" "actimeo=1800" "lookupcache=all" + "nosuid" "tcp" ]; }; - hugoBackup = "192.168.0.11:/mnt/BIG/BACKUP"; - in lib.mkIf inUse { - "/srv/bazarr-backup" = lib.mkIf cfg.bazarr.enable (mkFileSystem "${hugoBackup}/BAZARR"); - "/srv/prowlarr-backup" = lib.mkIf cfg.bazarr.enable (mkFileSystem "${hugoBackup}/PROWLARR"); - "/srv/qbittorrent" = lib.mkIf cfg.qbittorrent.enable (mkFileSystem "192.168.0.11:/mnt/SMALL/CONFIG/QBITTORRENT"); - "/srv/radarr-backup" = lib.mkIf cfg.radarr.enable (mkFileSystem "${hugoBackup}/RADARR"); - "/srv/sonarr-backup" = lib.mkIf cfg.sonarr.enable (mkFileSystem "${hugoBackup}/SONARR"); - "/srv/torrent" = mkFileSystem "192.168.0.11:/mnt/SMALL/MEDIA/TORRENT"; + "/srv/qbittorrent" = { + device = "192.168.0.11:/mnt/SMALL/CONFIG/QBITTORRENT/qBittorrent"; + fsType = "nfs"; + options = [ + "rw" + "nfsvers=4.2" + "async" "soft" + "nosuid" "tcp" + ]; + }; }; # Make sure the Docker network exists. @@ -91,6 +66,7 @@ in { description = "Create Docker network for ${networkName}"; requiredBy = [ "docker-bazarr.service" + "docker-lidarr.service" "docker-prowlarr.service" "docker-qbittorrent.service" "docker-radarr.service" @@ -108,77 +84,109 @@ in { }; # Create a user for each app. - users.users = let - mkUser = uid: { - uid = lib.mkForce uid; + users.users = { + bazarr = lib.mkIf cfg.bazarr.enable { + uid = lib.mkForce 3003; isSystemUser = true; group = config.users.groups.media.name; home = "/var/empty"; shell = null; }; - in { - bazarr = lib.mkIf cfg.bazarr.enable (mkUser 3003); - prowlarr = lib.mkIf cfg.prowlarr.enable (mkUser 3004); - qbittorrent = lib.mkIf cfg.qbittorrent.enable (mkUser 3005) // { - extraGroups = [ - config.users.groups.apps.name - ]; + lidarr = lib.mkIf cfg.lidarr.enable { + uid = lib.mkForce 3002; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; + }; + prowlarr = lib.mkIf cfg.prowlarr.enable { + uid = lib.mkForce 3004; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; + }; + qbittorrent = lib.mkIf cfg.qbittorrent.enable { + uid = lib.mkForce 3005; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; + }; + radarr = lib.mkIf cfg.radarr.enable { + uid = lib.mkForce 3006; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; + }; + sonarr = lib.mkIf cfg.sonarr.enable { + uid = lib.mkForce 3007; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; }; - radarr = lib.mkIf cfg.radarr.enable (mkUser 3006); - sonarr = lib.mkIf cfg.sonarr.enable (mkUser 3007); }; - virtualisation.oci-containers.containers = let - videoHostPath = config.homelab.fileSystems.media.video.hostPath; - in { - bazarr = let - port = 6767; - in lib.mkIf cfg.bazarr.enable { + virtualisation.oci-containers.containers = { + bazarr = lib.mkIf cfg.bazarr.enable { hostname = "bazarr"; - image = "ghcr.io/hotio/bazarr:release-1.5.2"; + image = "ghcr.io/hotio/bazarr:release-1.4.4"; autoStart = true; - ports = lib.mkIf cfg.bazarr.exposePorts [ - "${toString port}:${toString port}/tcp" - "${toString port}:${toString port}/udp" + ports = [ + "6767:6767/tcp" + "6767:6767/udp" ]; extraOptions = [ "--network=${networkName}" - "--network=${proxyNet}" + + "--mount" ''type=volume,source=bazarr-backup,target=/backup,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/mnt/BIG/BACKUP/BAZARR,"volume-opt=o=addr=192.168.0.11,rw,nfsvers=4.2,async,nosuid"'' ]; environment = { PUID = toString config.users.users.bazarr.uid; inherit PGID UMASK; TZ = config.time.timeZone; - WEBUI_PORTS = "${toString port}/tcp,${toString port}/udp"; + WEBUI_PORTS = "6767/tcp,6767/udp"; }; volumes = [ "bazarr-config:/config" - - "/srv/bazarr-backup:/config/backup" - - "${videoHostPath}/Films:/media/movies" - "${videoHostPath}/Series:/media/series" + "/srv/video:/data" ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.bazarr.rule" = "Host(`bazarr.depeuter.dev`)"; - "traefik.http.services.bazarr.loadbalancer.server.port" = toString port; - }; }; - prowlarr = let - port = 9696; - in lib.mkIf cfg.prowlarr.enable { - hostname = "prowlarr"; - image = "ghcr.io/hotio/prowlarr:release-2.0.5.5160"; + lidarr = lib.mkIf cfg.lidarr.enable { + hostname = "lidarr"; + image = "ghcr.io/hotio/lidarr:release-2.5.3.4341"; autoStart = true; - ports = lib.mkIf cfg.prowlarr.exposePorts [ - "${toString port}:${toString port}/tcp" + ports = [ + "8686:8686/tcp" + ]; + extraOptions = [ + "--network=${networkName}" + + "--mount" ''type=volume,source=lidarr-backup,target=/backup,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/mnt/BIG/BACKUP/LIDARR,"volume-opt=o=addr=192.168.0.11,rw,nfsvers=4.2,async,nosuid"'' + ]; + environment = { + PUID = toString config.users.users.lidarr.uid; + inherit PGID UMASK; + TZ = config.time.timeZone; + }; + volumes = [ + "lidarr-config:/config" + # TODO "data:/data" + ]; + }; + + prowlarr = lib.mkIf cfg.prowlarr.enable { + hostname = "prowlarr"; + image = "ghcr.io/hotio/prowlarr:release-1.23.1.4708"; + autoStart = true; + ports = [ + "9696:9696/tcp" ]; extraOptions = [ "--network=${networkName}" - "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.prowlarr.uid; @@ -186,63 +194,44 @@ in { TZ = config.time.timeZone; }; volumes = [ - "prowlarr-config:/config" - - "/srv/prowlarr-backup:/config/Backups" + # TODO "config:/config" ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.prowlarr.rule" = "Host(`prowlarr.depeuter.dev`)"; - "traefik.http.services.prowlarr.loadbalancer.server.port" = toString port; - }; }; - qbittorrent = let - port = 10095; - in lib.mkIf cfg.qbittorrent.enable { + qbittorrent = lib.mkIf cfg.qbittorrent.enable { hostname = "qbittorrent"; - image = "ghcr.io/hotio/qbittorrent:release-5.1.2"; + image = "ghcr.io/hotio/qbittorrent:release-4.6.7"; autoStart = true; - ports = lib.mkIf cfg.qbittorrent.exposePorts [ - "${toString port}:${toString port}/tcp" - "${toString port}:${toString port}/udp" + ports = [ + "10095:10095/udp" + "10095:10095/tcp" ]; extraOptions = [ "--network=${networkName}" - "--network=${proxyNet}" + + "--mount" ''type=volume,source=torrents,target=/data,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/mnt/SMALL/MEDIA/TORRENT,"volume-opt=o=addr=192.168.0.11,rw,nfsvers=4.2,async,nosuid"'' ]; environment = { PUID = toString config.users.users.qbittorrent.uid; inherit PGID UMASK; TZ = config.time.timeZone; - WEBUI_PORTS = "${toString port}/tcp,${toString port}/udp"; + WEBUI_PORTS = "10095/tcp,10095/udp"; }; volumes = [ - "/srv/qbittorrent:/config" - - "/srv/torrent:/media/cache" + "/srv/qbittorrent:/config/config" + "/srv/video:/media/video" ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.qbittorrent.rule" = "Host(`qb.depeuter.dev`)"; - "traefik.http.services.qbittorrent.loadbalancer.server.port" = toString port; - }; }; - radarr = let - port = 7878; - in lib.mkIf cfg.radarr.enable { + radarr = lib.mkIf cfg.radarr.enable { hostname = "radarr"; - image = "ghcr.io/hotio/radarr:testing-5.28.0.10205"; + image = "ghcr.io/hotio/radarr:release-5.9.1.9070"; autoStart = true; - ports = lib.mkIf cfg.radarr.exposePorts [ - "${toString port}:${toString port}/tcp" + ports = [ + "7878:7878/tcp" ]; extraOptions = [ "--network=${networkName}" - "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.radarr.uid; @@ -250,33 +239,20 @@ in { TZ = config.time.timeZone; }; volumes = [ - "radarr-config:/config" - - "/srv/radarr-backup:/config/Backups" - - "/srv/torrent:/media/cache" - "${videoHostPath}/Films:/media/movies" + # TODO "config:/config" + # TODO "data:/data" ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.radarr.rule" = "Host(`radarr.depeuter.dev`)"; - "traefik.http.services.radarr.loadbalancer.server.port" = toString port; - }; }; - sonarr = let - port = 8989; - in lib.mkIf cfg.sonarr.enable { + sonarr = lib.mkIf cfg.sonarr.enable { hostname = "sonarr"; - image = "ghcr.io/hotio/sonarr:release-4.0.15.2941"; + image = "ghcr.io/hotio/sonarr:release-4.0.9.2244"; autoStart = true; - ports = lib.mkIf cfg.sonarr.exposePorts [ - "${toString port}:${toString port}/tcp" + ports = [ + "8989:8989/tcp" ]; extraOptions = [ "--network=${networkName}" - "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.sonarr.uid; @@ -284,19 +260,9 @@ in { TZ = config.time.timeZone; }; volumes = [ - "sonarr-config:/config" - - "/srv/sonarr-backup:/config/Backups" - - "/srv/torrent:/media/cache" - "${videoHostPath}/Series:/media/series" + # TODO "config:/config" + # TODO "data:/data" ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.sonarr.rule" = "Host(`sonarr.depeuter.dev`)"; - "traefik.http.services.sonarr.loadbalancer.server.port" = toString port; - }; }; }; }; diff --git a/modules/apps/bind9/db.depeuter.dev b/modules/apps/bind9/db.depeuter.dev deleted file mode 100644 index 72f3825..0000000 --- a/modules/apps/bind9/db.depeuter.dev +++ /dev/null @@ -1,45 +0,0 @@ -$TTL 604800 -@ IN SOA ns1 admin ( - 15 ; Serial - 604800 ; Refresh - 86400 ; Retry - 2419200 ; Expire - 604800 ) ; Negative Cache TTL - -; Name servers - NS records - IN NS ns1 -; IN NS ns2 - -ns1 IN A 192.168.0.91 -;ns2 IN A 192.158.0.X - -; Hostnames -hugo.kmtl IN A 192.168.0.11 - -ingress.kmtl IN A 192.168.0.10 -ingress.kmtl IN AAAA fe80::be24:11ff:fed6:842a - -; Core services -cloud IN A 192.168.0.10 -git IN A 78.23.37.117 -home IN A 192.168.0.10 -jelly IN CNAME ingress.kmtl -vault IN A 192.168.0.10 - -; Production VM -books IN A 192.168.0.31 -calibre IN A 192.168.0.31 - -; Production VM - Arr -bazarr IN A 192.168.0.33 -prowlarr IN A 192.168.0.33 -qb IN A 192.168.0.33 -radarr IN A 192.168.0.33 -sonarr IN A 192.168.0.33 - -; Development VM -plex IN A 192.168.0.91 - -; Catchalls -*.production IN A 192.168.0.31 -*.development IN A 192.168.0.91 diff --git a/modules/apps/bind9/default.nix b/modules/apps/bind9/default.nix deleted file mode 100644 index a2346c1..0000000 --- a/modules/apps/bind9/default.nix +++ /dev/null @@ -1,54 +0,0 @@ -{ config, lib, ... }: - -let - cfg = config.homelab.apps.bind9; -in { - options.homelab.apps.bind9.enable = lib.mkEnableOption "ISC BIND 9 (Docker)"; - - config = lib.mkIf cfg.enable { - homelab.virtualisation.containers.enable = true; - - environment.etc = { - "bind/named.conf" = { - source = ./named.conf; - mode = "0555"; - }; - "bind/named.conf.options" = { - source = ./named.conf.options; - mode = "0555"; - }; - "bind/named.conf.local" = { - source = ./named.conf.local; - mode = "0555"; - }; - "bind/zones/db.depeuter.dev" = { - source = ./db.depeuter.dev; - mode = "0555"; - }; - }; - - virtualisation.oci-containers.containers.bind9 = { - hostname = "bind9"; - #image = "internetsystemsconsortium/bind9:9.20"; # Current stable - image = "ubuntu/bind9"; # Current stable - autoStart = true; - ports = [ - "53:53/udp" - "53:53/tcp" - "953:953/tcp" - ]; - extraOptions = [ - ]; - environment = { - }; - volumes = [ - "/etc/bind:/etc/bind" # For configuration, your `named.conf` lives here - "bind9-cache:/var/cache/bind" - #"...:/var/lib/bind" # Secondary zones - "bind9-logs:/var/log" # Logfiles - ]; - labels = { - }; - }; - }; -} diff --git a/modules/apps/bind9/named.conf b/modules/apps/bind9/named.conf deleted file mode 100644 index d301bd7..0000000 --- a/modules/apps/bind9/named.conf +++ /dev/null @@ -1,2 +0,0 @@ -include "/etc/bind/named.conf.options"; -include "/etc/bind/named.conf.local"; diff --git a/modules/apps/bind9/named.conf.local b/modules/apps/bind9/named.conf.local deleted file mode 100644 index 442eca9..0000000 --- a/modules/apps/bind9/named.conf.local +++ /dev/null @@ -1,4 +0,0 @@ -zone "depeuter.dev" { - type primary; - file "/etc/bind/zones/db.depeuter.dev"; -}; diff --git a/modules/apps/bind9/named.conf.options b/modules/apps/bind9/named.conf.options deleted file mode 100644 index b05f4bf..0000000 --- a/modules/apps/bind9/named.conf.options +++ /dev/null @@ -1,35 +0,0 @@ -http local { - endpoints { "/dns-query"; }; -}; - -acl bogusnets { -}; - -acl trusted { - 192.168.0.0/16; -}; - -options { - directory "/var/cache/bind"; - - version "not currently available"; - - listen-on { any; }; - listen-on-v6 { any; }; - listen-on tls ephemeral { any; }; - listen-on-v6 tls ephemeral { any; }; - listen-on tls ephemeral http local { any; }; - listen-on-v6 tls ephemeral http local { any; }; - - recursion yes; - forwarders { - 9.9.9.9; - 149.112.112.112; - }; - forward only; - - allow-query { any; }; - allow-recursion { any; }; - allow-transfer { none; }; - blackhole { bogusnets; }; -}; diff --git a/modules/apps/calibre/default.nix b/modules/apps/calibre/default.nix index bddf5c8..6fddb81 100644 --- a/modules/apps/calibre/default.nix +++ b/modules/apps/calibre/default.nix @@ -1,189 +1,17 @@ -{ config, lib, pkgs, ... }: +{ config, lib, ... }: let cfg = config.homelab.apps.calibre; - - PUID = toString config.users.users.calibre.uid; - PGID = toString config.users.groups.media.gid; - - books = "/srv/books"; - calibre-config = "/srv/calibre-config"; - calibre-web-config = "/srv/calibre-web-config"; - - networkName = "calibre"; - proxyNet = config.homelab.apps.traefik.sharedNetworkName; in { - options.homelab.apps.calibre = { - enable = lib.mkEnableOption "Calibre (Desktop + Web)"; - desktop.enable = lib.mkEnableOption "Calibre Desktop (KasmVNC)"; - web.enable = lib.mkEnableOption "Calibre Web"; + options.homelab.apps.calibre.enable = lib.mkEnableOption "Calibre"; + + config = lib.mkIf cfg.enable { + users.users.calibre = { + uid = lib.mkForce 3010; + isSystemUser = true; + group = config.users.groups.media.name; + home = "/var/empty"; + shell = null; + }; }; - - config = lib.mkMerge [ - { - homelab.apps.calibre = lib.mkIf cfg.enable { - desktop.enable = true; - web.enable = true; - }; - } - - # Common - (lib.mkIf (cfg.desktop.enable || cfg.web.enable) { - homelab = { - users.media.enable = true; - virtualisation.containers.enable = true; - }; - - users.users.calibre = { - uid = lib.mkForce 3010; - isSystemUser = true; - group = config.users.groups.media.name; - home = "/var/empty"; - shell = null; - }; - - fileSystems."${books}" = { - device = "192.168.0.11:/mnt/SMALL/MEDIA/BOOKS"; - fsType = "nfs"; - options = [ - "rw" - "auto" - "nfsvers=4.2" - "rsize=1048576" "wsize=1048576" - "soft" - "timeo=600" "retrans=2" - "_netdev" "nosuid" "tcp" - ]; - }; - - # Make sure the Docker network exists. - systemd.services."docker-${networkName}-create-network" = { - requiredBy = [ - "docker-calibre.service" - ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - if ! ${pkgs.docker}/bin/docker network ls | grep -q ${networkName}; then - ${pkgs.docker}/bin/docker network create ${networkName} - fi - ''; - }; - }) - - # Calibre desktop - (lib.mkIf cfg.desktop.enable { - fileSystems."${calibre-config}" = { - device = "192.168.0.11:/mnt/SMALL/CONFIG/CALIBRE"; - fsType = "nfs"; - options = [ - "rw" - "auto" - "nfsvers=4.2" - "rsize=1048576" "wsize=1048576" - "soft" - "timeo=600" "retrans=2" - "_netdev" "nosuid" "tcp" - ]; - }; - - virtualisation.oci-containers.containers.calibre = let - innerPort = 8080; - in { - hostname = "calibre"; - image = "lscr.io/linuxserver/calibre:v8.10.0-ls354"; - autoStart = true; - ports = [ - # Open ports if you don't use Traefik - "9480:${toString innerPort}" # Calibre desktop GUI - #"9481:8181" # Calibre desktop GUI HTTPS - #"9581:8081" # Calibre webserver gui - ]; - extraOptions = [ - "--network=${networkName}" - "--network=${proxyNet}" - - # syscalls are unkown to Docker - #"--security-opt" "seccomp=unconfined" - ]; - environment = { - inherit PUID PGID; - #UMASK = "022"; - - TZ = config.time.timeZone; - - #PASSWORD = ""; - #CLI_ARGS = ""; - }; - volumes = [ - "${calibre-config}:/config" - - "${books}:/media/books" - ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.calibre.rule" = "Host(`calibre.depeuter.dev`)"; - "traefik.http.services.calibre.loadbalancer.server.port" = toString innerPort; - }; - }; - }) - - # Calibre Web - (lib.mkIf cfg.web.enable { - fileSystems."${calibre-web-config}" = { - device = "192.168.0.11:/mnt/SMALL/CONFIG/CALIBRE-WEB"; - fsType = "nfs"; - options = [ - "rw" - "auto" - "nfsvers=4.2" - "rsize=1048576" "wsize=1048576" - "soft" - "timeo=600" "retrans=2" - "_netdev" "nosuid" "tcp" - ]; - }; - - virtualisation.oci-containers.containers.calibre-web = let - innerPort = 8083; - in { - hostname = "calibre-web"; - image = "lscr.io/linuxserver/calibre-web:0.6.25-ls346"; - autoStart = true; - ports = [ - # Open ports if you don't use Traefik - "8083:${toString innerPort}" # Web UI - ]; - extraOptions = [ - "--network=${networkName}" - "--network=${proxyNet}" - ]; - environment = { - inherit PUID PGID; - #UMASK = "022"; - - TZ = config.time.timeZone; - - # (x86-64 only) Adds the ability to perform ebook conversion - DOCKER_MODS = "linuxserver/mods:universal-calibre"; - # Allow Google Oauth - #OAUTHLIB_RELAX_TOKEN_SCOPE = "1"; - }; - volumes = [ - "${calibre-web-config}:/config" - - "${books}:/media/books" - ]; - labels = { - "traefik.enable" = "true"; - "traefik.docker.network" = proxyNet; - "traefik.http.routers.calibre-web.rule" = "Host(`books.depeuter.dev`)"; - "traefik.http.services.calibre-web.loadbalancer.server.port" = toString innerPort; - }; - }; - }) - ]; } diff --git a/modules/apps/changedetection/default.nix b/modules/apps/changedetection/default.nix deleted file mode 100644 index ee88751..0000000 --- a/modules/apps/changedetection/default.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.homelab.apps.changedetection; -in { - options.homelab.apps.changedetection.enable = lib.mkEnableOption "Changedetection.io"; - - config = lib.mkIf cfg.enable { - homelab.virtualisation.containers.enable = true; - - virtualisation.oci-containers.containers.changedetection = { - hostname = "changedetection"; - image = "ghcr.io/dgtlmoon/changedetection.io"; - autoStart = true; - ports = [ - "5000:5000/tcp" - ]; - extraOptions = [ - ]; - volumes = [ - "changedetection:/datastore" - ]; - environment = { - LOGGER_LEVEL = "WARNING"; - }; - }; - }; -} diff --git a/modules/apps/default.nix b/modules/apps/default.nix index 7c8b8f8..268476e 100644 --- a/modules/apps/default.nix +++ b/modules/apps/default.nix @@ -1,16 +1,12 @@ { imports = [ ./arr - ./bind9 ./calibre - ./changedetection - ./freshrss ./gitea ./jellyfin ./plex ./speedtest ./technitium-dns - ./traefik ./vaultwarden ]; } diff --git a/modules/apps/freshrss/default.nix b/modules/apps/freshrss/default.nix deleted file mode 100644 index 4f4456f..0000000 --- a/modules/apps/freshrss/default.nix +++ /dev/null @@ -1,93 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.homelab.apps.freshrss; - - networkName = "freshrss"; -in { - options.homelab.apps.freshrss = { - enable = lib.mkEnableOption "FreshRSS"; - port = lib.mkOption { - type = lib.types.int; - default = 9080; - description = "FreshRSS WebUI port"; - }; - }; - - config = let - inherit (config.homelab.apps.freshrss) port; - in - lib.mkIf cfg.enable { - homelab.virtualisation.containers.enable = true; - - fileSystems."/srv/freshrss" = { - device = "192.168.0.11:/mnt/SMALL/CONFIG/FRESHRSS"; - fsType = "nfs"; - options = [ - "rw" - "auto" - "nfsvers=4.2" - "async" "soft" "timeo=600" - "retrans=2" - "_netdev" - "nosuid" - "tcp" - ]; - }; - - systemd.services."docker-${networkName}-create-network" = { - description = "Create Docker network for ${networkName}"; - requiredBy = [ - "docker-freshrss.service" - ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - if ! ${pkgs.docker}/bin/docker network ls | grep -q ${networkName}; then - ${pkgs.docker}/bin/docker network create ${networkName} - fi - ''; - }; - - virtualisation.oci-containers.containers.freshrss = { - hostname = "freshrss"; - image = "freshrss/freshrss:1.25.0"; - autoStart = true; - user = "0:33"; - ports = [ - "${toString port}:80/tcp" - ]; - extraOptions = [ - "--network=${networkName}" - ]; - environment = { - TZ = config.time.timeZone; - CRON_MIN = "3,18,33,48"; # Alternatively, configure cron inside container. - SERVER_DNS = "rss.depeuter.dev"; - TRUSTED_PROXY = "172.16.0.1/12 192.168.0.1/16"; - }; - volumes = [ - "/srv/freshrss/www/freshrss/data:/var/www/FreshRSS/data" - "/srv/freshrss/www/freshrss/extensions:/var/www/FreshRSS/extensions" - ]; - labels = { - "traefik.enable" = "true"; - - "traefik.http.middlewares.freshrssM1.compress" = "true"; - "traefik.http.middlewares.freshrssM2.headers.browserXssFilter" = "true"; - "traefik.http.middlewares.freshrssM2.headers.forceSTSHeader" = "true"; - "traefik.http.middlewares.freshrssM2.headers.frameDeny" = "true"; - "traefik.http.middlewares.freshrssM2.headers.referrerPolicy" = "no-referrer-when-downgrade"; - "traefik.http.middlewares.freshrssM2.headers.stsSeconds" = "31536000"; - "traefik.http.routers.freshrss.entryPoints" = "websecure"; - "traefik.http.routers.freshrss.tls" = "true"; - - "traefik.http.services.freshrss.loadbalancer.server.port" = "80"; - "traefik.http.routers.freshrss.middlewares" = "freshrssM1,freshrssM2"; - "traefik.http.routers.freshrss.rule" = "Host(`rss.depeuter.dev`)"; - }; - }; - }; -} diff --git a/modules/apps/gitea/default.nix b/modules/apps/gitea/default.nix index 0361bd5..7a99a55 100644 --- a/modules/apps/gitea/default.nix +++ b/modules/apps/gitea/default.nix @@ -124,7 +124,7 @@ in { gitea = { hostname = "gitea"; - image = "codeberg.org/forgejo/forgejo:11.0.1-rootless"; + image = "codeberg.org/forgejo/forgejo:8.0.3-rootless"; autoStart = true; user = "${toString UID}:${toString GID}"; ports = [ @@ -379,25 +379,6 @@ in { # A relative path is interpreted as _`AppWorkPath`_/%(ROOT)s FORGEJO__repository__ROOT = repoDir; # ... - # Force every new repository to be private. - FORGEJO__repository__FORCE_PRIVATE = "false"; - # Default private when creating a new repository with push-to-create. - FORGEJO__repository__DEFAULT_PUSH_TO_CREATE = "true"; - # ... - # Allow users to push local repositories to Forgejo and have them automatically created for a user. - FORGEJO__repository__ENABLE_PUSH_CREATE_USER = "true"; - # Allow users to push local repositories to Forgejo and have them automatically created for an org. - FORGEJO__repository__ENABLE_PUSH_CREATE_ORG = "false"; - # Comma separated list of globally disabled repo units. - FORGEJO__repository__DISABLED_REPO_UNITS = ""; - # Comma separated list of default new repo units. - FORGEJO__repository__DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls,repo.releases,repo.actions"; - # Comma separated list of default forked repo units. - FORGEJO__repository__DEFAULT_FORK_REPO_UNITS = "repo.code,repo.pulls"; - # Prefix archive files by placing them in a directory named after the repository. - FORGEJO__repository__PREFIX_ARCHIVE_FILES = "true"; - # Disable migrating feature. - FORGEJO__repository__DISABLE_MIGRATIONS = "false"; # Disable stars feature. FORGEJO__repository__DISABLE_STARS = "true"; # Disable repository forking. @@ -576,7 +557,7 @@ in { #FORGEJO__picture__AVATAR_RENDERED_SIZE_FACTOR = "2"; # Maximum allowed file size for uploaded avatars. # This is to limit the amount of RAM used when resizing the image. - FORGEJO__picture__AVATAR_MAX_FILE_SIZE = "1048576"; + #FORGEJO__picture__AVATAR_MAX_FILE_SIZE = "1048576"; # If the uploaded file is not larger than this byte size, the image will be used as is, without resizing/converting. #FORGEJO__picture__AVATAR_MAX_ORIGIN_SIZE = "262144"; # Chinese users can choose "duoshuo" diff --git a/modules/apps/jellyfin/default.nix b/modules/apps/jellyfin/default.nix index 011f56b..9a1bc14 100644 --- a/modules/apps/jellyfin/default.nix +++ b/modules/apps/jellyfin/default.nix @@ -4,7 +4,6 @@ let cfg = config.homelab.apps.jellyfin; networkName = "jellyfin"; - inherit (config.homelab.fileSystems) media; UID = 3008; GID = config.users.groups.media.gid; @@ -13,11 +12,6 @@ in { config = lib.mkIf cfg.enable { homelab = { - fileSystems.media.video = { - enable = true; - permissions = [ "read" ]; - }; - users = { apps.enable = true; media.enable = true; @@ -38,6 +32,18 @@ in { ]; }; + "/srv/video" = { + device = "192.168.0.11:/mnt/SMALL/MEDIA/VIDEO"; + fsType = "nfs"; + options = [ + "ro" + "nfsvers=4.2" + "async" "soft" + "timeo=100" "retry=50" "actimeo=1800" "lookupcache=all" + "nosuid" "tcp" + ]; + }; + "/srv/homevideo" = { device = "192.168.0.11:/mnt/BIG/MEDIA/HOMEVIDEO/ARCHIVE"; fsType = "nfs"; @@ -95,7 +101,7 @@ in { virtualisation.oci-containers.containers = { jellyfin = { hostname = "jellyfin"; - image = "jellyfin/jellyfin:10.10.7"; + image = "jellyfin/jellyfin:10.10.0"; user = "${toString UID}:${toString GID}"; autoStart = true; ports = [ @@ -111,7 +117,7 @@ in { "cache:/cache" "/srv/audio:/media/audio" - "${media.video.hostPath}:/media/video" + "/srv/video:/media/video" "/srv/homevideo:/media/homevideo" "/srv/photo:/media/photo" ]; @@ -120,28 +126,11 @@ in { }; }; - jellyfin-vue = { - hostname = "jellyfin-vue"; - image = "ghcr.io/jellyfin/jellyfin-vue:unstable"; - autoStart = true; - ports = [ - "8080:80/tcp" - ]; - extraOptions = [ - "--network=${networkName}" - ]; - labels = { - }; - }; - - feishin = let - feishinPort = "9180"; - in { + feishin = { hostname = "feishin"; - image = "ghcr.io/jeffvli/feishin:0.19.0"; - autoStart = true; + image = "ghcr.io/jeffvli/feishin:0.7.1"; ports = [ - "${feishinPort}:9180/tcp" # Web player (HTTP) + "9180:9180/tcp" # Web player (HTTP) ]; extraOptions = [ "--network=${networkName}" @@ -158,11 +147,8 @@ in { TZ = config.time.timeZone; }; labels = { - "traefik.enable" = "true"; - "traefik.http.routers.feishin.rule" = "Host(`play.jelly.depeuter.dev`)"; - "traefik.http.services.feishin.loadbalancer.server.port" = feishinPort; - "traefik.tls.options.default.minVersion" = "VersionTLS13"; }; + autoStart = true; }; }; }; diff --git a/modules/apps/plex/default.nix b/modules/apps/plex/default.nix index b307b86..251f9dd 100644 --- a/modules/apps/plex/default.nix +++ b/modules/apps/plex/default.nix @@ -6,63 +6,44 @@ in { options.homelab.apps.plex.enable = lib.mkEnableOption "Plex"; config = lib.mkIf cfg.enable { - homelab = { - users = { - apps.enable = true; - media.enable = true; - }; - fileSystems.media.video.enable = true; - virtualisation.containers.enable = true; - }; - users.users.plex = { uid = lib.mkForce 3009; isSystemUser = true; - group = config.users.groups.apps.name; - extraGroups = [ - config.users.groups.media.name - ]; + group = config.users.groups.media; home = "/var/empty"; shell = null; }; - virtualisation.oci-containers.containers.plex = let - videoHostPath = config.homelab.fileSystems.media.video.hostPath; - in { - hostname = "plex"; - image = "plexinc/pms-docker:1.41.6.9685-d301f511a"; - autoStart = true; - ports = [ - "32400:32400/tcp" # Plex Media Server - "1900:1900/udp" # Plex DLNA Server - "32469:32469/tcp" # Plex DLNA Server - "32410:32410/udp" # GDM network discovery - "32412:32412/udp" # GDM network discovery - "32413:32413/udp" # GDM network discovery - "32414:32414/udp" # GDM network discovery - # "8324:8324/tcp" # Controlling Plex for Roku via Plex Companion - ]; - environment = { - #ADVERTISE_AP = "..."; # TODO Configure ip - ALLOWED_NETWORKS = "192.168.0.0/24,172.16.0.0/16"; - CHANGE_CONFIG_DIR_OWNERSHIP = "false"; - HOSTNAME = "Hugo-Plex"; - PLEX_CLAIM = "claim-d5MqsjMeCZrUF6oUvssr"; - PLEX_UID = toString config.users.users.plex.uid; - PLEX_GID = toString config.users.groups.media.gid; - TZ = config.time.timeZone; - }; - volumes = [ - # TODO Backup over NFS - "plex-config:/config" - "plex-transcode:/transcode" - - "${videoHostPath}:/data/video:ro" - ]; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.plex.rule" = "Host(`plex.depeuter.dev`)"; - "traefik.http.services.plex.loadbalancer.server.port" = "32400"; + virtualisation.oci-containers.containers = { + plex = { + hostname = "plex"; + image = "plexinc/pms-docker:1.41.0.8992-8463ad060"; + autoStart = true; + ports = [ + "32400:32400/tcp" # Plex Media Server + "1900:1900/udp" # Plex DLNA Server + "32469:32469/tcp" # Plex DLNA Server + "32410:32410/udp" # GDM network discovery + "32412:32412/udp" # GDM network discovery + "32413:32413/udp" # GDM network discovery + "32414:32414/udp" # GDM network discovery + # "8324:8324/tcp" # Controlling Plex for Roku via Plex Companion + ]; + environment = { + ADVERTISE_AP = "..."; # TODO Configure ip + ALLOWED_NETWORKS = "192.168.0.0/24,172.16.0.0/16"; + CHANGE_CONFIG_DIR_OWNERSHIP = "false"; + HOSTNAME = "PlexServer"; + PLEX_CLAIM = "..."; # TODO Add token + PLEX_UID = config.users.users.plex.uid; + PLEX_GID = config.users.groups.media.gid; + TZ = config.time.timeZone; + }; + volumes = [ + # TODO "config:/var/lib/plexmediaserver" + # TODO "transcode-temp:/transcode" + # TODO "media:/data" + ]; }; }; }; diff --git a/modules/apps/traefik/default.nix b/modules/apps/traefik/default.nix deleted file mode 100644 index 7f6ce38..0000000 --- a/modules/apps/traefik/default.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.homelab.apps.traefik; - - port = 8080; -in { - options.homelab.apps.traefik = { - enable = lib.mkEnableOption "Traefik Reverse Proxy"; - sharedNetworkName = lib.mkOption { - type = lib.types.str; - default = "traefik"; - description = "The name of the shared network to connect the container to."; - }; - }; - - config = lib.mkIf cfg.enable { - homelab.virtualisation.containers.enable = true; - - # Make sure the Docker network exists. - systemd.services."docker-${cfg.sharedNetworkName}-create-network" = { - description = "Create Docker network for ${cfg.sharedNetworkName}"; - requiredBy = [ - "docker-traefik.service" - ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - script = '' - if ! ${pkgs.docker}/bin/docker network ls | grep -q ${cfg.sharedNetworkName}; then - ${pkgs.docker}/bin/docker network create ${cfg.sharedNetworkName} - fi - ''; - }; - - virtualisation.oci-containers.containers.traefik = { - hostname = "traefik"; - image = "traefik:v3.4.3"; - autoStart = true; - ports = [ - "80:80/tcp" - "443:443/tcp" - "${toString port}:${toString port}/tcp" # Web UI (enabled by --api.insecure=true) - ]; - extraOptions = [ - "--network=${cfg.sharedNetworkName}" - ]; - environmentFiles = [ - /home/admin/.cloudflare.secret - ]; - cmd = [ - "--api.insecure=true" - - # Add Docker provider - "--providers.docker=true" - "--providers.docker.exposedByDefault=false" - - # Add web entrypoint - "--entrypoints.web.address=:80/tcp" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" - - # Add websecure entrypoint - "--entrypoints.websecure.address=:443/tcp" - "--entrypoints.websecure.http.tls=true" - "--entrypoints.websecure.http.tls.certResolver=letsencrypt" - "--entrypoints.websecure.http.tls.domains[0].main=depeuter.dev" - "--entrypoints.websecure.http.tls.domains[0].sans=*.depeuter.dev" - "--entrypoints.websecure.http.tls.domains[1].sans=*.${config.networking.hostName}.depeuter.dev" - - # Certificates - "--certificatesresolvers.letsencrypt.acme.dnschallenge=true" - "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare" - "--certificatesresolvers.letsencrypt.acme.email=tibo.depeuter@telenet.be" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - ]; - volumes = [ - "letsencryp:/letsencrypt" - - "/var/run/docker.sock:/var/run/docker.sock:ro" - ]; - labels = { - "traefik.enable" = "true"; - "traefik.http.routers.traefik.rule" = "Host(`traefik.${config.networking.hostName}.depeuter.dev`)"; - "traefik.http.services.traefik.loadbalancer.server.port" = toString port; - }; - }; - }; -} diff --git a/modules/apps/vaultwarden/default.nix b/modules/apps/vaultwarden/default.nix index 4510299..196beb4 100644 --- a/modules/apps/vaultwarden/default.nix +++ b/modules/apps/vaultwarden/default.nix @@ -5,24 +5,7 @@ let networkName = "vaultwarden"; in { - options.homelab.apps.vaultwarden = { - enable = lib.mkEnableOption "Vaultwarden"; - port = lib.mkOption { - type = lib.types.int; - default = 10102; - description = "Vaultwarden WebUI port"; - }; - domain = lib.mkOption { - type = lib.types.string; - example = "https://vault.depeuter.dev"; - description = "Domain to configure Vaultwarden on"; - }; - name = lib.mkOption { - type = lib.types.string; - example = "Hugo's Vault"; - description = "Service name to use for invitations and mail"; - }; - }; + options.homelab.apps.vaultwarden.enable = lib.mkEnableOption "Vaultwarden"; config = lib.mkIf cfg.enable { homelab = { @@ -50,16 +33,13 @@ in { ''; }; - virtualisation.oci-containers.containers = let - dbHostname = "vaultwarden-db"; - dbPort = 5432; - in { - vaultwardenDb = { - hostname = dbHostname; + virtualisation.oci-containers.containers = { + vaultwarden-db = { + hostname = "vaultwarden-db"; image = "postgres:15.8-alpine"; autoStart = true; ports = [ - "${toString dbPort}:5432/tcp" + "5432:5432/tcp" ]; extraOptions = [ "--network=${networkName}" @@ -77,16 +57,16 @@ in { dataDir = "/data"; in { hostname = "vaultwarden"; - image = "vaultwarden/server:1.34.3-alpine"; + image = "vaultwarden/server:1.30.5-alpine"; autoStart = true; ports = [ - "${toString cfg.port}:80/tcp" + "10102:80/tcp" ]; extraOptions = [ "--network=${networkName}" ]; dependsOn = [ - "vaultwardenDb" + "vaultwarden-db" ]; volumes = [ "vaultwarden:${dataDir}" @@ -135,7 +115,7 @@ in { ## Details: ## - https://docs.diesel.rs/2.1.x/diesel/pg/struct.PgConnection.html ## - https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING - DATABASE_URL = "postgresql://vaultwarden:ChangeMe@${dbHostname}:${toString dbPort}/vaultwarden"; + DATABASE_URL = "postgresql://vaultwarden:ChangeMe@vaultwarden-db:5432/vaultwarden"; ## Enable WAL for the DB ## Set to false to avoid enabling WAL during startup. @@ -264,7 +244,7 @@ in { ## For development # DOMAIN=http://localhost ## For public server - DOMAIN = cfg.domain; + DOMAIN = "https://vault.depeuter.dev"; ## For public server (URL with port number) # DOMAIN=https://vw.domain.tld:8443 ## For public server (URL with path) @@ -318,7 +298,7 @@ in { ## Note that setting this option to true prevents logins until the email address has been verified! ## The welcome email will include a verification link, and login attempts will periodically ## trigger another verification email to be sent. - SIGNUPS_VERIFY = "false"; + SIGNUPS_VERIFY = "true"; ## If SIGNUPS_VERIFY is set to true, this limits how many seconds after the last time ## an email verification link has been sent another verification email will be sent @@ -348,7 +328,7 @@ in { ## Invitations org admins to invite users, even when signups are disabled # INVITATIONS_ALLOWED=true ## Name shown in the invitation emails that don't come from a specific organization - INVITATION_ORG_NAME = cfg.name; + INVITATION_ORG_NAME = "Hugo's Vault"; ## The number of hours after which an organization invite token, emergency access invite token, ## email verification token and deletion request token will expire (must be at least 1) @@ -591,7 +571,7 @@ in { ## Note: if SMTP_USERNAME is specified, SMTP_PASSWORD is mandatory SMTP_HOST = "smtp.gmail.com"; SMTP_FROM = "vault@depeuter.dev"; - SMTP_FROM_NAME = cfg.name; + SMTP_FROM_NAME = "Hugo's Vault"; # SMTP_USERNAME=username # SMTP_PASSWORD=password # SMTP_TIMEOUT=15 diff --git a/modules/default.nix b/modules/default.nix index 1a000c3..5d901bc 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,7 +1,6 @@ { imports = [ ./apps - ./fileSystems ./services ./virtualisation diff --git a/modules/fileSystems/default.nix b/modules/fileSystems/default.nix deleted file mode 100644 index 7c25689..0000000 --- a/modules/fileSystems/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imports = [ - ./media - ]; -} diff --git a/modules/fileSystems/media/default.nix b/modules/fileSystems/media/default.nix deleted file mode 100644 index 41cb81f..0000000 --- a/modules/fileSystems/media/default.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - imports = [ - ./video - ]; -} diff --git a/modules/fileSystems/media/video/default.nix b/modules/fileSystems/media/video/default.nix deleted file mode 100644 index e46193c..0000000 --- a/modules/fileSystems/media/video/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ config, lib, ... }: - -let - cfg = config.homelab.fileSystems.media.video; - - remotePath = "/mnt/SMALL/MEDIA/VIDEO"; - - maxPermissions = permissions: - if builtins.elem "write" permissions then "rw" - else "ro"; - permissionsOption = maxPermissions cfg.permissions; -in { - options.homelab.fileSystems.media.video = { - enable = lib.mkEnableOption "MEDIA/VIDEO dataset"; - hostPath = lib.mkOption { - type = lib.types.path; - default = "/srv/video"; - description = "Mountpath on host"; - }; - permissions = lib.mkOption { - type = lib.types.listOf (lib.types.enum [ "read" "write" ]); - default = [ "read" ]; - description = "Mount options permissions"; - }; - }; - - config = lib.mkIf cfg.enable { - fileSystems."${cfg.hostPath}" = { - device = "192.168.0.11:${remotePath}"; - fsType = "nfs"; - options = [ - permissionsOption - "auto" - "nfsvers=4.2" - "async" "soft" - "rsize=1048576" "wsize=1048576" - "timeo=600" "retry=50" "retrans=2" "actimeo=1800" "lookupcache=all" - "_netdev" "nosuid" "tcp" - ]; - }; - }; -} diff --git a/modules/services/actions/default.nix b/modules/services/actions/default.nix index ea6b025..338b963 100644 --- a/modules/services/actions/default.nix +++ b/modules/services/actions/default.nix @@ -44,6 +44,6 @@ in { ]; }; }; + }; } - diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml deleted file mode 100644 index e17dab1..0000000 --- a/secrets/secrets.yaml +++ /dev/null @@ -1,19 +0,0 @@ -users: - admin: - authorized_keys: - NixOS: ENC[AES256_GCM,data:sj2hkUkWp628KuXp+AnncLdawHpxb9fH1ZHnIisP0x9Tght9+/X2sWHpuMSeqi2i/R8B+Wgte66QkuwAOB0j+oB9N+66EhehmWZlK5hD/22p,iv:z18U+LvAQgPDfBBewE3lJmWZd0NGCPwJIe/h3tupuZc=,tag:ZJar3spO66JbDXygdTHh2w==,type:str] -sops: - age: - - recipient: age1qzutny0mqpcccqw6myyfntu6wcskruu9ghzvt6r4te7afkqwnguq05ex37 - enc: | - -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjUSt2REk2Mmd0bk9ubjJk - dXFiY2JNR1dyZW9qTUdzaWZhY3c3amVwQzA0CkZHNVpZVjhsWXhVQVNaR0xONzhh - Y0lQaWNaNmpYYVdrRnZIZUhvUFUzcWMKLS0tIDAvSmF0VmpxcnZEQStXUjNCUE5Z - RnA2Lzk2WHFxOEh6dHN0aGhVSVpLTW8KA7IOvGDMBtgo4pe0Sw3Lol243xCDAJ4i - PhcJFiUObVRFZN7ISlULnOlTO3pT9jWvvmC5rDZWId3PQ8qjPvnOUg== - -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-10-04T17:33:22Z" - mac: ENC[AES256_GCM,data:I7I7uDFEWfw9+4KROtjHMVhaxYrVK5QmLfFZShSajF0A2Zxu9lg+fDGiMHk40JC5zD31P70QS/ipye1mBGQbCbLEA7uBUhNzZ7G1g58cIXF6vSGmt0fovm0MVSxEJ44r05fx6uT4OJu5BYVxYSlG84gTj9rCFXxxcBJMrh+6yaI=,iv:c1vudsp9bg0Pc2ddRyvWn6Tf0LhqNuEjxG9D4PpHqxs=,tag:K/1PSHhrTdsNPcPmRv/2Ew==,type:str] - unencrypted_suffix: _unencrypted - version: 3.10.2 diff --git a/users/admin/default.nix b/users/admin/default.nix index 4038266..552909b 100644 --- a/users/admin/default.nix +++ b/users/admin/default.nix @@ -18,8 +18,8 @@ in { ]; initialPassword = "ChangeMe"; openssh.authorizedKeys.keys = [ - # HomeLab > NixOS > admin > ssh - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWIOOEqTy8cWKpENVbzD4p7bsQgQb/Dgpzk8i0dZ00T" + # TODO ChangeMe + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPrG+ldRBdCeHEXrsy/qHXIJYg8xQXVuiUR0DxhFjYNg" ]; packages = with pkgs; [ curl