diff --git a/modules/podman.nix b/modules/podman.nix index a838415..b8d2498 100644 --- a/modules/podman.nix +++ b/modules/podman.nix @@ -39,6 +39,16 @@ in "/home/yanlin/.config/nix/config/homeassistant/scenes.yaml:/config/scenes.yaml:ro" "/home/yanlin/.config/nix/config/homeassistant/scripts.yaml:/config/scripts.yaml:ro" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.homeassistant.rule" = "Host(`home.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.homeassistant.entrypoints" = "websecure"; + "traefik.http.routers.homeassistant.tls" = "true"; + "traefik.http.routers.homeassistant.tls.certresolver" = "cloudflare"; + "traefik.http.routers.homeassistant.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.homeassistant.loadbalancer.server.port" = "8123"; + }; environment = { TZ = "Europe/Copenhagen"; @@ -69,6 +79,16 @@ in # Mount the declarative config file "${immichConfigFile}:/config/immich.json:ro" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.immich.rule" = "Host(`photo.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.immich.entrypoints" = "websecure"; + "traefik.http.routers.immich.tls" = "true"; + "traefik.http.routers.immich.tls.certresolver" = "cloudflare"; + "traefik.http.routers.immich.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.immich.loadbalancer.server.port" = "8080"; + }; environment = { PUID = "1000"; @@ -146,6 +166,16 @@ in "/mnt/storage/appbulk/plex-transcode:/transcode" "/mnt/storage/Media:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.plex.rule" = "Host(`plex.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.plex.entrypoints" = "websecure"; + "traefik.http.routers.plex.tls" = "true"; + "traefik.http.routers.plex.tls.certresolver" = "cloudflare"; + "traefik.http.routers.plex.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.plex.loadbalancer.server.port" = "32400"; + }; environment = { PUID = "1000"; @@ -154,10 +184,6 @@ in VERSION = "docker"; }; - ports = [ - "32400:32400" - ]; - extraOptions = [ "--network=podman" "--device=/dev/dri:/dev/dri" # Hardware acceleration @@ -174,6 +200,16 @@ in "/var/lib/containers/sonarr/config:/config" "/mnt/storage/Media:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.sonarr.rule" = "Host(`sonarr.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.sonarr.entrypoints" = "websecure"; + "traefik.http.routers.sonarr.tls" = "true"; + "traefik.http.routers.sonarr.tls.certresolver" = "cloudflare"; + "traefik.http.routers.sonarr.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.sonarr.loadbalancer.server.port" = "8989"; + }; environment = { PUID = "1000"; @@ -181,10 +217,6 @@ in TZ = "Europe/Copenhagen"; }; - ports = [ - "8989:8989" - ]; - extraOptions = [ "--network=podman" ]; @@ -200,6 +232,16 @@ in "/var/lib/containers/radarr/config:/config" "/mnt/storage/Media:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.radarr.rule" = "Host(`radarr.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.radarr.entrypoints" = "websecure"; + "traefik.http.routers.radarr.tls" = "true"; + "traefik.http.routers.radarr.tls.certresolver" = "cloudflare"; + "traefik.http.routers.radarr.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.radarr.loadbalancer.server.port" = "7878"; + }; environment = { PUID = "1000"; @@ -207,10 +249,6 @@ in TZ = "Europe/Copenhagen"; }; - ports = [ - "7878:7878" - ]; - extraOptions = [ "--network=podman" ]; @@ -226,6 +264,16 @@ in "/var/lib/containers/bazarr/config:/config" "/mnt/storage/Media:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.bazarr.rule" = "Host(`bazarr.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.bazarr.entrypoints" = "websecure"; + "traefik.http.routers.bazarr.tls" = "true"; + "traefik.http.routers.bazarr.tls.certresolver" = "cloudflare"; + "traefik.http.routers.bazarr.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.bazarr.loadbalancer.server.port" = "6767"; + }; environment = { PUID = "1000"; @@ -233,10 +281,6 @@ in TZ = "Europe/Copenhagen"; }; - ports = [ - "6767:6767" - ]; - extraOptions = [ "--network=podman" ]; @@ -252,6 +296,16 @@ in "/var/lib/containers/qbit/config:/config" "/mnt/storage/Media:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.qbittorrent.rule" = "Host(`qbit.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.qbittorrent.entrypoints" = "websecure"; + "traefik.http.routers.qbittorrent.tls" = "true"; + "traefik.http.routers.qbittorrent.tls.certresolver" = "cloudflare"; + "traefik.http.routers.qbittorrent.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.qbittorrent.loadbalancer.server.port" = "8080"; + }; environment = { PUID = "1000"; @@ -278,6 +332,16 @@ in "/mnt/storage/appbulk/Paperless/consume:/usr/src/paperless/consume" "/mnt/storage/appbulk/Paperless/export:/usr/src/paperless/export" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.paperless.rule" = "Host(`paperless.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.paperless.entrypoints" = "websecure"; + "traefik.http.routers.paperless.tls" = "true"; + "traefik.http.routers.paperless.tls.certresolver" = "cloudflare"; + "traefik.http.routers.paperless.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.paperless.loadbalancer.server.port" = "8000"; + }; environment = { PAPERLESS_REDIS = "redis://paperless-redis:6379"; @@ -285,20 +349,16 @@ in PAPERLESS_OCR_LANGUAGES = "chi-sim"; PAPERLESS_FILENAME_FORMAT = "{{ created }}-{{ correspondent }}-{{ title }}"; PAPERLESS_TIME_ZONE = "Europe/Copenhagen"; - PAPERLESS_URL = "https://paperless.hs.yanlincs.com"; - PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://paperless.hs.yanlincs.com"; - PAPERLESS_ALLOWED_HOSTS = "paperless.hs.yanlincs.com"; - PAPERLESS_CORS_ALLOWED_HOSTS = "https://paperless.hs.yanlincs.com"; + PAPERLESS_URL = "https://paperless.${config.networking.hostName}.yanlincs.com"; + PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://paperless.${config.networking.hostName}.yanlincs.com"; + PAPERLESS_ALLOWED_HOSTS = "paperless.${config.networking.hostName}.yanlincs.com"; + PAPERLESS_CORS_ALLOWED_HOSTS = "https://paperless.${config.networking.hostName}.yanlincs.com"; PAPERLESS_SECRET_KEY = "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee"; USERMAP_UID = "1000"; USERMAP_GID = "100"; CA_TS_FALLBACK_DIR = "/usr/src/paperless/data"; }; - ports = [ - "8001:8000" - ]; - extraOptions = [ "--network=podman" ]; @@ -321,12 +381,22 @@ in # RSS reader (Miniflux) containers.rss = { image = "docker.io/miniflux/miniflux:latest"; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.rss.rule" = "Host(`rss.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.rss.entrypoints" = "websecure"; + "traefik.http.routers.rss.tls" = "true"; + "traefik.http.routers.rss.tls.certresolver" = "cloudflare"; + "traefik.http.routers.rss.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.rss.loadbalancer.server.port" = "8080"; + }; environment = { DATABASE_URL = "postgres://miniflux:miniflux@rss-db/miniflux?sslmode=disable"; ADMIN_USERNAME = "yanlin"; ADMIN_PASSWORD = "1Hayashi-2Hiko"; - BASE_URL = "https://rss.hs.yanlincs.com"; + BASE_URL = "https://rss.${config.networking.hostName}.yanlincs.com"; CREATE_ADMIN = "1"; RUN_MIGRATIONS = "1"; HTTP_CLIENT_TIMEOUT = "50000"; @@ -336,10 +406,6 @@ in CLEANUP_REMOVE_SESSIONS_DAYS = "30"; }; - ports = [ - "8002:8080" - ]; - extraOptions = [ "--network=podman" ]; @@ -376,10 +442,16 @@ in volumes = [ "/var/lib/containers/link:/etc/linkding/data" ]; - - ports = [ - "9090:9090" - ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.linkding.rule" = "Host(`link.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.linkding.entrypoints" = "websecure"; + "traefik.http.routers.linkding.tls" = "true"; + "traefik.http.routers.linkding.tls.certresolver" = "cloudflare"; + "traefik.http.routers.linkding.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.linkding.loadbalancer.server.port" = "9090"; + }; extraOptions = [ "--network=podman" @@ -396,6 +468,16 @@ in "/var/lib/containers/cloud/config:/config" "/mnt/storage/appbulk/cloud:/data" ]; + + labels = { + "traefik.enable" = "true"; + "traefik.http.routers.cloud.rule" = "Host(`cloud.${config.networking.hostName}.yanlincs.com`)"; + "traefik.http.routers.cloud.entrypoints" = "websecure"; + "traefik.http.routers.cloud.tls" = "true"; + "traefik.http.routers.cloud.tls.certresolver" = "cloudflare"; + "traefik.http.routers.cloud.tls.domains[0].main" = "*.${config.networking.hostName}.yanlincs.com"; + "traefik.http.services.cloud.loadbalancer.server.port" = "80"; + }; environment = { PUID = "1000"; diff --git a/modules/syncthing.nix b/modules/syncthing.nix index e0b4f13..ea28796 100644 --- a/modules/syncthing.nix +++ b/modules/syncthing.nix @@ -96,4 +96,8 @@ launchd.agents.syncthing = lib.mkIf (pkgs.stdenv.isDarwin && config.services.syncthing.enable) { config.RunAtLoad = true; }; + + # For NixOS systems, we need to add Syncthing as a manual service in Traefik + # Since Syncthing runs as a systemd service (not container), we'll handle routing via static config + # or create a container wrapper for it to use with service discovery } diff --git a/modules/traefik.nix b/modules/traefik.nix index 0410956..4aa0295 100644 --- a/modules/traefik.nix +++ b/modules/traefik.nix @@ -7,6 +7,12 @@ # Static configuration staticConfigOptions = { + # Enable Docker provider for automatic service discovery + providers.docker = { + endpoint = "unix:///var/run/docker.sock"; + exposedByDefault = false; # Only expose containers with traefik.enable=true + network = "podman"; # Use podman network + }; # Entry points for HTTP and HTTPS entrypoints = { web = { @@ -57,146 +63,22 @@ }; }; - # Dynamic configuration for services + # Dynamic configuration for services not running in containers dynamicConfigOptions = { http = { routers = { - homeassistant = { - rule = "Host(`home.hs.yanlincs.com`)"; - service = "homeassistant"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - immich = { - rule = "Host(`photo.hs.yanlincs.com`)"; - service = "immich"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; syncthing = { - rule = "Host(`syncthing.hs.yanlincs.com`)"; + rule = "Host(`syncthing.${config.networking.hostName}.yanlincs.com`)"; service = "syncthing"; tls = { certResolver = "cloudflare"; domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - plex = { - rule = "Host(`plex.hs.yanlincs.com`)"; - service = "plex"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - sonarr = { - rule = "Host(`sonarr.hs.yanlincs.com`)"; - service = "sonarr"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - radarr = { - rule = "Host(`radarr.hs.yanlincs.com`)"; - service = "radarr"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - bazarr = { - rule = "Host(`bazarr.hs.yanlincs.com`)"; - service = "bazarr"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - qbittorrent = { - rule = "Host(`qbit.hs.yanlincs.com`)"; - service = "qbittorrent"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - paperless = { - rule = "Host(`paperless.hs.yanlincs.com`)"; - service = "paperless"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - rss = { - rule = "Host(`rss.hs.yanlincs.com`)"; - service = "rss"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - linkding = { - rule = "Host(`link.hs.yanlincs.com`)"; - service = "linkding"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; - }]; - }; - }; - cloud = { - rule = "Host(`cloud.hs.yanlincs.com`)"; - service = "cloud"; - tls = { - certResolver = "cloudflare"; - domains = [{ - main = "*.hs.yanlincs.com"; + main = "*.${config.networking.hostName}.yanlincs.com"; }]; }; }; }; services = { - homeassistant = { - loadBalancer = { - servers = [{ - url = "http://localhost:8123"; - }]; - }; - }; - immich = { - loadBalancer = { - servers = [{ - url = "http://localhost:5000"; - }]; - }; - }; syncthing = { loadBalancer = { servers = [{ @@ -204,69 +86,6 @@ }]; }; }; - plex = { - loadBalancer = { - servers = [{ - url = "http://localhost:32400"; - }]; - }; - }; - sonarr = { - loadBalancer = { - servers = [{ - url = "http://localhost:8989"; - }]; - }; - }; - radarr = { - loadBalancer = { - servers = [{ - url = "http://localhost:7878"; - }]; - }; - }; - bazarr = { - loadBalancer = { - servers = [{ - url = "http://localhost:6767"; - }]; - }; - }; - qbittorrent = { - loadBalancer = { - servers = [{ - url = "http://localhost:8080"; - }]; - }; - }; - paperless = { - loadBalancer = { - servers = [{ - url = "http://localhost:8001"; - }]; - }; - }; - rss = { - loadBalancer = { - servers = [{ - url = "http://localhost:8002"; - }]; - }; - }; - linkding = { - loadBalancer = { - servers = [{ - url = "http://localhost:9090"; - }]; - }; - }; - cloud = { - loadBalancer = { - servers = [{ - url = "http://localhost:5001"; - }]; - }; - }; }; }; }; @@ -275,6 +94,13 @@ environmentFiles = [ "/run/secrets/traefik-env" ]; }; + # Ensure Traefik can access Docker socket + systemd.services.traefik.serviceConfig = { + SupplementaryGroups = [ "podman" ]; + # Mount Docker/Podman socket for service discovery + BindPaths = [ "/run/podman/podman.sock:/var/run/docker.sock" ]; + }; + # Create environment file for Traefik Cloudflare credentials systemd.services.traefik-env-setup = { description = "Setup Traefik environment file";