Use labels for reverse proxy podman services

This commit is contained in:
Yan Lin 2025-09-07 22:56:42 +02:00
parent 69537d20b3
commit 17cccac820
3 changed files with 135 additions and 223 deletions

View file

@ -39,6 +39,16 @@ in
"/home/yanlin/.config/nix/config/homeassistant/scenes.yaml:/config/scenes.yaml:ro" "/home/yanlin/.config/nix/config/homeassistant/scenes.yaml:/config/scenes.yaml:ro"
"/home/yanlin/.config/nix/config/homeassistant/scripts.yaml:/config/scripts.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 = { environment = {
TZ = "Europe/Copenhagen"; TZ = "Europe/Copenhagen";
@ -69,6 +79,16 @@ in
# Mount the declarative config file # Mount the declarative config file
"${immichConfigFile}:/config/immich.json:ro" "${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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -146,6 +166,16 @@ in
"/mnt/storage/appbulk/plex-transcode:/transcode" "/mnt/storage/appbulk/plex-transcode:/transcode"
"/mnt/storage/Media:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -154,10 +184,6 @@ in
VERSION = "docker"; VERSION = "docker";
}; };
ports = [
"32400:32400"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
"--device=/dev/dri:/dev/dri" # Hardware acceleration "--device=/dev/dri:/dev/dri" # Hardware acceleration
@ -174,6 +200,16 @@ in
"/var/lib/containers/sonarr/config:/config" "/var/lib/containers/sonarr/config:/config"
"/mnt/storage/Media:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -181,10 +217,6 @@ in
TZ = "Europe/Copenhagen"; TZ = "Europe/Copenhagen";
}; };
ports = [
"8989:8989"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
]; ];
@ -200,6 +232,16 @@ in
"/var/lib/containers/radarr/config:/config" "/var/lib/containers/radarr/config:/config"
"/mnt/storage/Media:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -207,10 +249,6 @@ in
TZ = "Europe/Copenhagen"; TZ = "Europe/Copenhagen";
}; };
ports = [
"7878:7878"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
]; ];
@ -226,6 +264,16 @@ in
"/var/lib/containers/bazarr/config:/config" "/var/lib/containers/bazarr/config:/config"
"/mnt/storage/Media:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -233,10 +281,6 @@ in
TZ = "Europe/Copenhagen"; TZ = "Europe/Copenhagen";
}; };
ports = [
"6767:6767"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
]; ];
@ -252,6 +296,16 @@ in
"/var/lib/containers/qbit/config:/config" "/var/lib/containers/qbit/config:/config"
"/mnt/storage/Media:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";
@ -278,6 +332,16 @@ in
"/mnt/storage/appbulk/Paperless/consume:/usr/src/paperless/consume" "/mnt/storage/appbulk/Paperless/consume:/usr/src/paperless/consume"
"/mnt/storage/appbulk/Paperless/export:/usr/src/paperless/export" "/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 = { environment = {
PAPERLESS_REDIS = "redis://paperless-redis:6379"; PAPERLESS_REDIS = "redis://paperless-redis:6379";
@ -285,20 +349,16 @@ in
PAPERLESS_OCR_LANGUAGES = "chi-sim"; PAPERLESS_OCR_LANGUAGES = "chi-sim";
PAPERLESS_FILENAME_FORMAT = "{{ created }}-{{ correspondent }}-{{ title }}"; PAPERLESS_FILENAME_FORMAT = "{{ created }}-{{ correspondent }}-{{ title }}";
PAPERLESS_TIME_ZONE = "Europe/Copenhagen"; PAPERLESS_TIME_ZONE = "Europe/Copenhagen";
PAPERLESS_URL = "https://paperless.hs.yanlincs.com"; PAPERLESS_URL = "https://paperless.${config.networking.hostName}.yanlincs.com";
PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://paperless.hs.yanlincs.com"; PAPERLESS_CSRF_TRUSTED_ORIGINS = "https://paperless.${config.networking.hostName}.yanlincs.com";
PAPERLESS_ALLOWED_HOSTS = "paperless.hs.yanlincs.com"; PAPERLESS_ALLOWED_HOSTS = "paperless.${config.networking.hostName}.yanlincs.com";
PAPERLESS_CORS_ALLOWED_HOSTS = "https://paperless.hs.yanlincs.com"; PAPERLESS_CORS_ALLOWED_HOSTS = "https://paperless.${config.networking.hostName}.yanlincs.com";
PAPERLESS_SECRET_KEY = "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee"; PAPERLESS_SECRET_KEY = "e11fl1oa-*ytql8p)(06fbj4ukrlo+n7k&q5+$1md7i+mge=ee";
USERMAP_UID = "1000"; USERMAP_UID = "1000";
USERMAP_GID = "100"; USERMAP_GID = "100";
CA_TS_FALLBACK_DIR = "/usr/src/paperless/data"; CA_TS_FALLBACK_DIR = "/usr/src/paperless/data";
}; };
ports = [
"8001:8000"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
]; ];
@ -321,12 +381,22 @@ in
# RSS reader (Miniflux) # RSS reader (Miniflux)
containers.rss = { containers.rss = {
image = "docker.io/miniflux/miniflux:latest"; 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 = { environment = {
DATABASE_URL = "postgres://miniflux:miniflux@rss-db/miniflux?sslmode=disable"; DATABASE_URL = "postgres://miniflux:miniflux@rss-db/miniflux?sslmode=disable";
ADMIN_USERNAME = "yanlin"; ADMIN_USERNAME = "yanlin";
ADMIN_PASSWORD = "1Hayashi-2Hiko"; ADMIN_PASSWORD = "1Hayashi-2Hiko";
BASE_URL = "https://rss.hs.yanlincs.com"; BASE_URL = "https://rss.${config.networking.hostName}.yanlincs.com";
CREATE_ADMIN = "1"; CREATE_ADMIN = "1";
RUN_MIGRATIONS = "1"; RUN_MIGRATIONS = "1";
HTTP_CLIENT_TIMEOUT = "50000"; HTTP_CLIENT_TIMEOUT = "50000";
@ -336,10 +406,6 @@ in
CLEANUP_REMOVE_SESSIONS_DAYS = "30"; CLEANUP_REMOVE_SESSIONS_DAYS = "30";
}; };
ports = [
"8002:8080"
];
extraOptions = [ extraOptions = [
"--network=podman" "--network=podman"
]; ];
@ -376,10 +442,16 @@ in
volumes = [ volumes = [
"/var/lib/containers/link:/etc/linkding/data" "/var/lib/containers/link:/etc/linkding/data"
]; ];
ports = [ labels = {
"9090:9090" "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 = [ extraOptions = [
"--network=podman" "--network=podman"
@ -396,6 +468,16 @@ in
"/var/lib/containers/cloud/config:/config" "/var/lib/containers/cloud/config:/config"
"/mnt/storage/appbulk/cloud:/data" "/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 = { environment = {
PUID = "1000"; PUID = "1000";

View file

@ -96,4 +96,8 @@
launchd.agents.syncthing = lib.mkIf (pkgs.stdenv.isDarwin && config.services.syncthing.enable) { launchd.agents.syncthing = lib.mkIf (pkgs.stdenv.isDarwin && config.services.syncthing.enable) {
config.RunAtLoad = true; 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
} }

View file

@ -7,6 +7,12 @@
# Static configuration # Static configuration
staticConfigOptions = { 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 # Entry points for HTTP and HTTPS
entrypoints = { entrypoints = {
web = { web = {
@ -57,146 +63,22 @@
}; };
}; };
# Dynamic configuration for services # Dynamic configuration for services not running in containers
dynamicConfigOptions = { dynamicConfigOptions = {
http = { http = {
routers = { 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 = { syncthing = {
rule = "Host(`syncthing.hs.yanlincs.com`)"; rule = "Host(`syncthing.${config.networking.hostName}.yanlincs.com`)";
service = "syncthing"; service = "syncthing";
tls = { tls = {
certResolver = "cloudflare"; certResolver = "cloudflare";
domains = [{ domains = [{
main = "*.hs.yanlincs.com"; main = "*.${config.networking.hostName}.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";
}]; }];
}; };
}; };
}; };
services = { services = {
homeassistant = {
loadBalancer = {
servers = [{
url = "http://localhost:8123";
}];
};
};
immich = {
loadBalancer = {
servers = [{
url = "http://localhost:5000";
}];
};
};
syncthing = { syncthing = {
loadBalancer = { loadBalancer = {
servers = [{ 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" ]; 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 # Create environment file for Traefik Cloudflare credentials
systemd.services.traefik-env-setup = { systemd.services.traefik-env-setup = {
description = "Setup Traefik environment file"; description = "Setup Traefik environment file";