From c294e159e2a2fed0b1265aff92e18ea3e7007f5b Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Mon, 26 May 2025 22:38:29 +0200 Subject: [PATCH 1/5] feat: Basic recursive dns --- modules/apps/bind9/db.depeuter.dev | 16 ++++++++ modules/apps/bind9/default.nix | 54 +++++++++++++++++++++++++++ modules/apps/bind9/named.conf | 2 + modules/apps/bind9/named.conf.local | 4 ++ modules/apps/bind9/named.conf.options | 35 +++++++++++++++++ modules/apps/default.nix | 1 + 6 files changed, 112 insertions(+) create mode 100644 modules/apps/bind9/db.depeuter.dev create mode 100644 modules/apps/bind9/default.nix create mode 100644 modules/apps/bind9/named.conf create mode 100644 modules/apps/bind9/named.conf.local create mode 100644 modules/apps/bind9/named.conf.options diff --git a/modules/apps/bind9/db.depeuter.dev b/modules/apps/bind9/db.depeuter.dev new file mode 100644 index 0000000..fbd06c3 --- /dev/null +++ b/modules/apps/bind9/db.depeuter.dev @@ -0,0 +1,16 @@ +$TTL 604800 +@ IN SOA ns1.depeuter.dev. admin.depeuter.dev. ( + 5 ; Serial + 604800 ; Refresh + 86400 ; Retry + 2419200 ; Expire + 604800 ) ; Negative Cache TTL + +; name servers - NS records + IN NS ns1.depeuter.dev. +; IN NS ns2.depeuter.dev. + +ns1.depeuter.dev. IN A 192.168.0.91 +;ns1.depeuter.dev. IN A 192.158.0.X + +hugo.depeuter.dev. IN A 192.168.0.11 diff --git a/modules/apps/bind9/default.nix b/modules/apps/bind9/default.nix new file mode 100644 index 0000000..a2346c1 --- /dev/null +++ b/modules/apps/bind9/default.nix @@ -0,0 +1,54 @@ +{ 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 new file mode 100644 index 0000000..d301bd7 --- /dev/null +++ b/modules/apps/bind9/named.conf @@ -0,0 +1,2 @@ +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 new file mode 100644 index 0000000..442eca9 --- /dev/null +++ b/modules/apps/bind9/named.conf.local @@ -0,0 +1,4 @@ +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 new file mode 100644 index 0000000..b05f4bf --- /dev/null +++ b/modules/apps/bind9/named.conf.options @@ -0,0 +1,35 @@ +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/default.nix b/modules/apps/default.nix index 2d487e8..81c6a06 100644 --- a/modules/apps/default.nix +++ b/modules/apps/default.nix @@ -1,6 +1,7 @@ { imports = [ ./arr + ./bind9 ./calibre ./changedetection ./freshrss From d693c4a93b0aa75204465269d79d050cb0c0d1c5 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Thu, 26 Jun 2025 11:50:52 +0200 Subject: [PATCH 2/5] feat(calibre): Pin image versions --- modules/apps/calibre/default.nix | 64 ++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 23 deletions(-) diff --git a/modules/apps/calibre/default.nix b/modules/apps/calibre/default.nix index fc7cd57..aa00c89 100644 --- a/modules/apps/calibre/default.nix +++ b/modules/apps/calibre/default.nix @@ -6,24 +6,28 @@ let 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"; in { options.homelab.apps.calibre = { - enable = lib.mkEnableOption "Calibre (Desktop + Web)"; - desktop = lib.mkEnableOption "Calibre Desktop (KasmVNC)"; - web = lib.mkEnableOption "Calibre Web"; + enable = lib.mkEnableOption "Calibre (Desktop + Web)"; + desktop.enable = lib.mkEnableOption "Calibre Desktop (KasmVNC)"; + web.enable = lib.mkEnableOption "Calibre Web"; }; config = lib.mkMerge [ { homelab.apps.calibre = lib.mkIf cfg.enable { - desktop = true; - web = true; + desktop.enable = true; + web.enable = true; }; } # Common - (lib.mkIf (cfg.desktop || cfg.web) { + (lib.mkIf (cfg.desktop.enable || cfg.web.enable) { homelab = { users.media.enable = true; virtualisation.containers.enable = true; @@ -37,7 +41,7 @@ in { shell = null; }; - fileSystems."/srv/books" = { + fileSystems."${books}" = { device = "192.168.0.11:/mnt/SMALL/MEDIA/BOOKS"; fsType = "nfs"; options = [ @@ -69,8 +73,8 @@ in { }) # Calibre desktop - { - fileSystems."/srv/calibre-config" = { + (lib.mkIf cfg.desktop.enable { + fileSystems."${calibre-config}" = { device = "192.168.0.11:/mnt/SMALL/CONFIG/CALIBRE"; fsType = "nfs"; options = [ @@ -84,13 +88,15 @@ in { ]; }; - virtualisation.oci-containers.containers.calibre = { + virtualisation.oci-containers.containers.calibre = let + innerPort = 8080; + in { hostname = "calibre"; - image = "lscr.io/linuxserver/calibre:latest"; + image = "lscr.io/linuxserver/calibre:8.5.0"; autoStart = true; ports = [ # Open ports if you don't use Traefik - "9480:8080" # Calibre desktop GUI + "9480:${toString innerPort}" # Calibre desktop GUI #"9481:8181" # Calibre desktop GUI HTTPS #"9581:8081" # Calibre webserver gui ]; @@ -110,16 +116,21 @@ in { #CLI_ARGS = ""; }; volumes = [ - "/srv/calibre-config:/config" + "${calibre-config}:/config" - "/srv/books:/media/books" + "${books}:/media/books" ]; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.calibre.rule" = "Host(`calibre.depeuter.dev`)"; + "traefik.http.services.calibre.loadbalancer.server.port" = toString innerPort; + }; }; - } + }) # Calibre Web - { - fileSystems."/srv/calibre-web-config" = { + (lib.mkIf cfg.web.enable { + fileSystems."${calibre-web-config}" = { device = "192.168.0.11:/mnt/SMALL/CONFIG/CALIBRE-WEB"; fsType = "nfs"; options = [ @@ -133,13 +144,15 @@ in { ]; }; - virtualisation.oci-containers.containers.calibre-web = { + virtualisation.oci-containers.containers.calibre-web = let + innerPort = 8083; + in { hostname = "calibre-web"; - image = "lscr.io/linuxserver/calibre-web:latest"; + image = "lscr.io/linuxserver/calibre-web:0.6.24"; autoStart = true; ports = [ # Open ports if you don't use Traefik - "8083:8083" # Web UI + "8083:${toString innerPort}" # Web UI ]; extraOptions = [ "--network=${networkName}" @@ -156,11 +169,16 @@ in { #OAUTHLIB_RELAX_TOKEN_SCOPE = "1"; }; volumes = [ - "/srv/calibre-web-config:/config" + "${calibre-web-config}:/config" - "/srv/books:/media/books" + "${books}:/media/books" ]; + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.calibre-web.rule" = "Host(`books.depeuter.dev`)"; + "traefik.http.services.calibre-web.loadbalancer.server.port" = toString innerPort; + }; }; - } + }) ]; } From d0d6fac7ef9410ca0471d5c9f9bd0cc7554ad177 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Mon, 1 Sep 2025 18:06:25 +0200 Subject: [PATCH 3/5] chore(vaultwarden): Update image --- modules/apps/vaultwarden/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/apps/vaultwarden/default.nix b/modules/apps/vaultwarden/default.nix index a2f8d0a..4510299 100644 --- a/modules/apps/vaultwarden/default.nix +++ b/modules/apps/vaultwarden/default.nix @@ -54,7 +54,7 @@ in { dbHostname = "vaultwarden-db"; dbPort = 5432; in { - vaultwarden-db = { + vaultwardenDb = { hostname = dbHostname; image = "postgres:15.8-alpine"; autoStart = true; @@ -77,7 +77,7 @@ in { dataDir = "/data"; in { hostname = "vaultwarden"; - image = "vaultwarden/server:1.33.2-alpine"; + image = "vaultwarden/server:1.34.3-alpine"; autoStart = true; ports = [ "${toString cfg.port}:80/tcp" @@ -86,7 +86,7 @@ in { "--network=${networkName}" ]; dependsOn = [ - dbHostname + "vaultwardenDb" ]; volumes = [ "vaultwarden:${dataDir}" From ac47ec4689a227d71c928250589409be0db60ca9 Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Thu, 4 Sep 2025 10:39:02 +0200 Subject: [PATCH 4/5] fix(traefik): Add proxy network --- modules/apps/arr/default.nix | 8 +++ modules/apps/traefik/default.nix | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 modules/apps/traefik/default.nix diff --git a/modules/apps/arr/default.nix b/modules/apps/arr/default.nix index 2687e2a..de696f5 100644 --- a/modules/apps/arr/default.nix +++ b/modules/apps/arr/default.nix @@ -4,6 +4,8 @@ let cfg = config.homelab.apps.arr; networkName = "arrStack"; + proxyNet = config.homelab.apps.traefik.sharedNetworkName; + appNames = [ "bazarr" "lidarr" "prowlarr" "qbittorrent" "radarr" "sonarr" ]; inUse = builtins.any (app: cfg.${app}.enable) appNames; @@ -233,6 +235,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.bazarr.uid; @@ -267,6 +270,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.lidarr.uid; @@ -293,6 +297,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.prowlarr.uid; @@ -324,6 +329,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.qbittorrent.uid; @@ -355,6 +361,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.radarr.uid; @@ -388,6 +395,7 @@ in { ]; extraOptions = [ "--network=${networkName}" + "--network=${proxyNet}" ]; environment = { PUID = toString config.users.users.sonarr.uid; diff --git a/modules/apps/traefik/default.nix b/modules/apps/traefik/default.nix new file mode 100644 index 0000000..7f6ce38 --- /dev/null +++ b/modules/apps/traefik/default.nix @@ -0,0 +1,90 @@ +{ 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; + }; + }; + }; +} From a7f56a7cf73b7a3c8f385e983b6d6af25ae702db Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Thu, 4 Sep 2025 10:46:41 +0200 Subject: [PATCH 5/5] fix(traefik): Specify network --- modules/apps/arr/default.nix | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/apps/arr/default.nix b/modules/apps/arr/default.nix index de696f5..cedd01e 100644 --- a/modules/apps/arr/default.nix +++ b/modules/apps/arr/default.nix @@ -253,6 +253,7 @@ in { ]; 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; }; @@ -283,6 +284,12 @@ in { # TODO Fix path "/srv/lidarr-backup:/media/Backups" ]; + labels = { + "traefik.enable" = "true"; + "traefik.docker.network" = proxyNet; + "traefik.http.routers.lidarr.rule" = "Host(`lidarr.depeuter.dev`)"; + "traefik.http.services.lidarr.loadbalancer.server.port" = toString port; + }; }; prowlarr = let @@ -311,6 +318,7 @@ in { ]; 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; }; @@ -344,6 +352,7 @@ in { ]; 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; }; @@ -378,6 +387,7 @@ in { ]; 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; }; @@ -412,6 +422,7 @@ in { ]; 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; };