diff --git a/traefik/dynamic_conf_node01.yml b/traefik/dynamic_conf_node01.yml new file mode 100644 index 0000000..030b26a --- /dev/null +++ b/traefik/dynamic_conf_node01.yml @@ -0,0 +1,711 @@ +http: + + serversTransports: + default-transport: + forwardingTimeouts: + dialTimeout: 30s + responseHeaderTimeout: 30s + idleConnTimeout: 90s + insecure-transport: + insecureSkipVerify: true + + middlewares: + + secure-headers: + headers: + accessControlAllowMethods: + - GET + - OPTIONS + - PUT + - POST + accessControlMaxAge: 100 + addVaryHeader: true + frameDeny: true + customRequestHeaders: + X-Forwarded-Proto: "https" + X-Forwarded-Port: "443" + X-Forwarded-Ssl: "on" + sslProxyHeaders: + X-Forwarded-Proto: "https" + browserXssFilter: true + contentTypeNosniff: true + referrerPolicy: "same-origin" + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + + ha-headers: + headers: + customRequestHeaders: + X-Forwarded-Proto: "https" + X-Forwarded-Port: "443" + X-Forwarded-Ssl: "on" + sslProxyHeaders: + X-Forwarded-Proto: "https" + browserXssFilter: true + contentTypeNosniff: true + referrerPolicy: "same-origin" + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + customResponseHeaders: + X-Frame-Options: "SAMEORIGIN" + + authelia-auth: + forwardAuth: + address: "http://authelia:9091/api/authz/forward-auth?rd=https://auth.goattw.net/" + trustForwardHeader: true + authResponseHeaders: + - Remote-User + - Remote-Groups + - Remote-Name + - Remote-Email + + strip-trailing-dot-speedtest: + redirectRegex: + regex: '^https://speedtest\.goattw\.net\.(/.*)?$' + replacement: "https://speedtest.goattw.net${1}" + permanent: false + + # ============================================================ + # CROWDSEC-BOUNCER - Block malicious IPs via CrowdSec decisions + # ============================================================ + # Purpose: Queries CrowdSec local API before passing requests through. + # Blocks IPs flagged by local detection or community blocklists. + # Notes: API key generated via: docker exec crowdsec cscli bouncers add traefik-bouncer + # CrowdSec runs on docker-node01 at port 8081. + # ============================================================ + crowdsec-bouncer: + plugin: + crowdsec-bouncer: + enabled: true + crowdsecLapiKey: VMCnws/j+9pmsT4YT+t3HzrvX8OhBCwoquwo4NqWJPs + crowdsecLapiHost: crowdsec:8080 + crowdsecMode: live + + routers: + + nextcloud: + rule: "Host(`cloud.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: nextcloud-service + middlewares: ["secure-headers@file"] + + homeassistant: + rule: "Host(`ha.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: homeassistant-service + middlewares: ["ha-headers@file"] + + plex: + rule: "Host(`plex.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: plex-service + middlewares: ["secure-headers@file", "crowdsec-bouncer@file"] + + homepage: + rule: "Host(`home.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: homepage-service + middlewares: ["secure-headers@file", "crowdsec-bouncer@file"] + + sonarr: + rule: "Host(`sonarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: sonarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + radarr: + rule: "Host(`radarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: radarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + prowlarr: + rule: "Host(`prowlarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: prowlarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + overseerr: + rule: "Host(`request.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: overseerr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + tautulli: + rule: "Host(`stats.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tautulli-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + transmission: + rule: "Host(`transmission.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: transmission-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + sabnzbd: + rule: "Host(`sabnzbd.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: sabnzbd-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + uptime-kuma: + rule: "Host(`uptime.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: uptime-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + beszel: + rule: "Host(`beszel.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: beszel-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + dozzle: + rule: "Host(`dozzle.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dozzle-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + paperless: + rule: "Host(`paperless.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: paperless-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + grafana: + rule: "Host(`grafana.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: grafana-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + prometheus: + rule: "Host(`prometheus.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: prometheus-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + loki: + rule: "Host(`loki.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: loki-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + tdarr: + rule: "Host(`tdarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tdarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + gitea: + rule: "Host(`gitea.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: gitea-service + middlewares: ["secure-headers@file"] + + portainer: + rule: "Host(`portainer.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: portainer-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + immich: + rule: "Host(`immich.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: immich-service + middlewares: ["secure-headers@file"] + + dockge: + rule: "Host(`dockge.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dockge-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + open-webui: + rule: "Host(`ai.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: open-webui-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + bazarr: + rule: "Host(`bazarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: bazarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + lidarr: + rule: "Host(`lidarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: lidarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + smokeping: + rule: "Host(`smokeping.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: smokeping-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + it-tools: + rule: "Host(`it-tools.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: it-tools-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + plex-utills: + rule: "Host(`plex-utills.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: plex-utills-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + navidrome: + rule: "Host(`music.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: navidrome-service + middlewares: ["secure-headers@file"] + + semaphore: + rule: "Host(`semaphore.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: semaphore-service + middlewares: ["authelia-auth@file"] + + netbox: + rule: "Host(`netbox.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: netbox-service + middlewares: ["authelia-auth@file"] + + wazuh: + rule: "Host(`wazuh.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: wazuh-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + dagu: + rule: "Host(`dagu.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dagu-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + + n8n: + rule: "Host(`n8n.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: n8n-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + node-red: + rule: "Host(`nodered.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: node-red-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + woodpecker: + rule: "Host(`ci.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: woodpecker-service + middlewares: ["secure-headers@file"] + + filebrowser: + rule: "Host(`files.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: filebrowser-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + healthchecks: + rule: "Host(`healthchecks.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: healthchecks-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + + tandoor: + rule: "Host(`tandoor.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tandoor-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + ntfy: + rule: "Host(`ntfy.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: ntfy-service + tls: + certResolver: letsencrypt + + speedtest-trailing-dot: + rule: "Host(`speedtest.goattw.net.`)" + entryPoints: + - websecure + priority: 200 + middlewares: + - strip-trailing-dot-speedtest@file + service: speedtest-service + tls: + certResolver: letsencrypt + + speedtest: + rule: "Host(`speedtest.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: speedtest-service + tls: + certResolver: letsencrypt + + linkding: + rule: "Host(`linkding.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: linkding-service + tls: + certResolver: letsencrypt + + vikunja: + rule: "Host(`vikunja.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: vikunja-service + tls: + certResolver: letsencrypt + + watchyourlan: + rule: "Host(`watchyourlan.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: watchyourlan-service + tls: + certResolver: letsencrypt + + glances: + rule: "Host(`glances.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: glances-service + tls: + certResolver: letsencrypt + + netdata: + rule: "Host(`netdata.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: netdata-service + tls: + certResolver: letsencrypt + + mealie: + rule: "Host(`mealie.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: mealie-service + tls: + certResolver: letsencrypt + + services: + + nextcloud-service: + loadBalancer: + servers: [{ url: "http://192.168.99.31:11000" }] + serversTransport: default-transport + + homeassistant-service: + loadBalancer: + servers: [{ url: "http://192.168.99.100:8123" }] + passHostHeader: true + serversTransport: default-transport + + plex-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:32400" }] + serversTransport: default-transport + + homepage-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3000" }] + serversTransport: default-transport + + sonarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8989" }] + serversTransport: default-transport + + radarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:7878" }] + serversTransport: default-transport + + prowlarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9696" }] + serversTransport: default-transport + + overseerr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5055" }] + serversTransport: default-transport + + tautulli-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8181" }] + serversTransport: default-transport + + transmission-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9091" }] + serversTransport: default-transport + + sabnzbd-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8081" }] + serversTransport: default-transport + + uptime-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3001" }] + serversTransport: default-transport + + beszel-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8090" }] + serversTransport: default-transport + + dozzle-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8082" }] + serversTransport: default-transport + + paperless-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8010" }] + serversTransport: default-transport + + grafana-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3005" }] + serversTransport: default-transport + + prometheus-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9090" }] + serversTransport: default-transport + + loki-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3100" }] + serversTransport: default-transport + + tdarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8265" }] + serversTransport: default-transport + + gitea-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:3002" }] + serversTransport: default-transport + + portainer-service: + loadBalancer: + servers: + - url: "https://192.168.99.186:9443" + serversTransport: insecure-transport + + immich-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:2283" }] + serversTransport: default-transport + + dockge-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5001" }] + serversTransport: default-transport + + open-webui-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8080" }] + serversTransport: default-transport + + bazarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:6767" }] + serversTransport: default-transport + + lidarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8686" }] + serversTransport: default-transport + + smokeping-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8086" }] + serversTransport: default-transport + + it-tools-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8085" }] + serversTransport: default-transport + + plex-utills-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5000" }] + serversTransport: default-transport + + navidrome-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:4533" }] + serversTransport: default-transport + + semaphore-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:3001" }] + serversTransport: default-transport + + netbox-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8084" }] + serversTransport: default-transport + + wazuh-service: + loadBalancer: + servers: [{ url: "https://192.168.99.199" }] + serversTransport: insecure-transport + + + healthchecks-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8091" }] + serversTransport: default-transport + + + dagu-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8092" }] + serversTransport: default-transport + filebrowser-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8093" }] + serversTransport: default-transport + + woodpecker-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8086" }] + serversTransport: default-transport + + node-red-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:1880" }] + serversTransport: default-transport + tandoor-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8094" }] + serversTransport: default-transport + + n8n-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5678" }] + serversTransport: default-transport + + ntfy-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8095" + serversTransport: default-transport + + speedtest-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8096" + serversTransport: default-transport + + linkding-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8097" + serversTransport: default-transport + + vikunja-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8098" + serversTransport: default-transport + + watchyourlan-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8840" + serversTransport: default-transport + + glances-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:61208" + serversTransport: default-transport + + netdata-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:19999" + serversTransport: default-transport + + mealie-service: + loadBalancer: + servers: + - url: "http://192.168.99.183:9925" + serversTransport: default-transport diff --git a/traefik/dynamic_conf_node02.yml b/traefik/dynamic_conf_node02.yml new file mode 100644 index 0000000..c3fe8ac --- /dev/null +++ b/traefik/dynamic_conf_node02.yml @@ -0,0 +1,711 @@ +http: + + serversTransports: + default-transport: + forwardingTimeouts: + dialTimeout: 30s + responseHeaderTimeout: 30s + idleConnTimeout: 90s + insecure-transport: + insecureSkipVerify: true + + middlewares: + + secure-headers: + headers: + accessControlAllowMethods: + - GET + - OPTIONS + - PUT + - POST + accessControlMaxAge: 100 + addVaryHeader: true + frameDeny: true + customRequestHeaders: + X-Forwarded-Proto: "https" + X-Forwarded-Port: "443" + X-Forwarded-Ssl: "on" + sslProxyHeaders: + X-Forwarded-Proto: "https" + browserXssFilter: true + contentTypeNosniff: true + referrerPolicy: "same-origin" + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + + ha-headers: + headers: + customRequestHeaders: + X-Forwarded-Proto: "https" + X-Forwarded-Port: "443" + X-Forwarded-Ssl: "on" + sslProxyHeaders: + X-Forwarded-Proto: "https" + browserXssFilter: true + contentTypeNosniff: true + referrerPolicy: "same-origin" + stsSeconds: 31536000 + stsIncludeSubdomains: true + stsPreload: true + customResponseHeaders: + X-Frame-Options: "SAMEORIGIN" + + authelia-auth: + forwardAuth: + address: "http://authelia:9091/api/authz/forward-auth?rd=https://auth.goattw.net/" + trustForwardHeader: true + authResponseHeaders: + - Remote-User + - Remote-Groups + - Remote-Name + - Remote-Email + + strip-trailing-dot-speedtest: + redirectRegex: + regex: '^https://speedtest\.goattw\.net\.(/.*)?$' + replacement: "https://speedtest.goattw.net${1}" + permanent: false + + # ============================================================ + # CROWDSEC-BOUNCER - Block malicious IPs via CrowdSec decisions + # ============================================================ + # Purpose: Queries CrowdSec local API before passing requests through. + # Blocks IPs flagged by local detection or community blocklists. + # Notes: API key generated via: docker exec crowdsec cscli bouncers add traefik-bouncer + # CrowdSec runs on docker-node01 at port 8081. + # ============================================================ + crowdsec-bouncer: + plugin: + crowdsec-bouncer: + enabled: true + crowdsecLapiKey: VMCnws/j+9pmsT4YT+t3HzrvX8OhBCwoquwo4NqWJPs + crowdsecLapiHost: 192.168.99.186:8081 + crowdsecMode: live + + routers: + + nextcloud: + rule: "Host(`cloud.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: nextcloud-service + middlewares: ["secure-headers@file"] + + homeassistant: + rule: "Host(`ha.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: homeassistant-service + middlewares: ["ha-headers@file"] + + plex: + rule: "Host(`plex.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: plex-service + middlewares: ["secure-headers@file", "crowdsec-bouncer@file"] + + homepage: + rule: "Host(`home.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: homepage-service + middlewares: ["secure-headers@file", "crowdsec-bouncer@file"] + + sonarr: + rule: "Host(`sonarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: sonarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + radarr: + rule: "Host(`radarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: radarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + prowlarr: + rule: "Host(`prowlarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: prowlarr-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + overseerr: + rule: "Host(`request.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: overseerr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + tautulli: + rule: "Host(`stats.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tautulli-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + transmission: + rule: "Host(`transmission.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: transmission-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + sabnzbd: + rule: "Host(`sabnzbd.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: sabnzbd-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + uptime-kuma: + rule: "Host(`uptime.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: uptime-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + beszel: + rule: "Host(`beszel.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: beszel-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + dozzle: + rule: "Host(`dozzle.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dozzle-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + paperless: + rule: "Host(`paperless.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: paperless-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + grafana: + rule: "Host(`grafana.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: grafana-service + middlewares: ["secure-headers@file", "authelia-auth@file", "crowdsec-bouncer@file"] + + prometheus: + rule: "Host(`prometheus.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: prometheus-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + loki: + rule: "Host(`loki.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: loki-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + tdarr: + rule: "Host(`tdarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tdarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + gitea: + rule: "Host(`gitea.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: gitea-service + middlewares: ["secure-headers@file"] + + portainer: + rule: "Host(`portainer.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: portainer-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + immich: + rule: "Host(`immich.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: immich-service + middlewares: ["secure-headers@file"] + + dockge: + rule: "Host(`dockge.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dockge-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + open-webui: + rule: "Host(`ai.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: open-webui-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + bazarr: + rule: "Host(`bazarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: bazarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + lidarr: + rule: "Host(`lidarr.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: lidarr-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + smokeping: + rule: "Host(`smokeping.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: smokeping-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + it-tools: + rule: "Host(`it-tools.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: it-tools-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + plex-utills: + rule: "Host(`plex-utills.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: plex-utills-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + navidrome: + rule: "Host(`music.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: navidrome-service + middlewares: ["secure-headers@file"] + + semaphore: + rule: "Host(`semaphore.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: semaphore-service + middlewares: ["authelia-auth@file"] + + netbox: + rule: "Host(`netbox.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: netbox-service + middlewares: ["authelia-auth@file"] + + wazuh: + rule: "Host(`wazuh.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: wazuh-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + dagu: + rule: "Host(`dagu.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: dagu-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + + n8n: + rule: "Host(`n8n.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: n8n-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + node-red: + rule: "Host(`nodered.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: node-red-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + woodpecker: + rule: "Host(`ci.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: woodpecker-service + middlewares: ["secure-headers@file"] + + filebrowser: + rule: "Host(`files.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: filebrowser-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + healthchecks: + rule: "Host(`healthchecks.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: healthchecks-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + + tandoor: + rule: "Host(`tandoor.goattw.net`)" + entryPoints: ["websecure"] + tls: { certResolver: letsencrypt } + service: tandoor-service + middlewares: ["secure-headers@file", "authelia-auth@file"] + + ntfy: + rule: "Host(`ntfy.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: ntfy-service + tls: + certResolver: letsencrypt + + speedtest-trailing-dot: + rule: "Host(`speedtest.goattw.net.`)" + entryPoints: + - websecure + priority: 200 + middlewares: + - strip-trailing-dot-speedtest@file + service: speedtest-service + tls: + certResolver: letsencrypt + + speedtest: + rule: "Host(`speedtest.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: speedtest-service + tls: + certResolver: letsencrypt + + linkding: + rule: "Host(`linkding.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: linkding-service + tls: + certResolver: letsencrypt + + vikunja: + rule: "Host(`vikunja.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: vikunja-service + tls: + certResolver: letsencrypt + + watchyourlan: + rule: "Host(`watchyourlan.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: watchyourlan-service + tls: + certResolver: letsencrypt + + glances: + rule: "Host(`glances.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: glances-service + tls: + certResolver: letsencrypt + + netdata: + rule: "Host(`netdata.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: netdata-service + tls: + certResolver: letsencrypt + + mealie: + rule: "Host(`mealie.goattw.net`)" + entryPoints: + - websecure + middlewares: + - authelia-auth@file + service: mealie-service + tls: + certResolver: letsencrypt + + services: + + nextcloud-service: + loadBalancer: + servers: [{ url: "http://192.168.99.31:11000" }] + serversTransport: default-transport + + homeassistant-service: + loadBalancer: + servers: [{ url: "http://192.168.99.100:8123" }] + passHostHeader: true + serversTransport: default-transport + + plex-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:32400" }] + serversTransport: default-transport + + homepage-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3000" }] + serversTransport: default-transport + + sonarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8989" }] + serversTransport: default-transport + + radarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:7878" }] + serversTransport: default-transport + + prowlarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9696" }] + serversTransport: default-transport + + overseerr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5055" }] + serversTransport: default-transport + + tautulli-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8181" }] + serversTransport: default-transport + + transmission-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9091" }] + serversTransport: default-transport + + sabnzbd-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8081" }] + serversTransport: default-transport + + uptime-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3001" }] + serversTransport: default-transport + + beszel-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8090" }] + serversTransport: default-transport + + dozzle-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8082" }] + serversTransport: default-transport + + paperless-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8010" }] + serversTransport: default-transport + + grafana-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3005" }] + serversTransport: default-transport + + prometheus-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:9090" }] + serversTransport: default-transport + + loki-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:3100" }] + serversTransport: default-transport + + tdarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8265" }] + serversTransport: default-transport + + gitea-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:3002" }] + serversTransport: default-transport + + portainer-service: + loadBalancer: + servers: + - url: "https://192.168.99.186:9443" + serversTransport: insecure-transport + + immich-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:2283" }] + serversTransport: default-transport + + dockge-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5001" }] + serversTransport: default-transport + + open-webui-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8080" }] + serversTransport: default-transport + + bazarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:6767" }] + serversTransport: default-transport + + lidarr-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8686" }] + serversTransport: default-transport + + smokeping-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8086" }] + serversTransport: default-transport + + it-tools-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8085" }] + serversTransport: default-transport + + plex-utills-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5000" }] + serversTransport: default-transport + + navidrome-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:4533" }] + serversTransport: default-transport + + semaphore-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:3001" }] + serversTransport: default-transport + + netbox-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8084" }] + serversTransport: default-transport + + wazuh-service: + loadBalancer: + servers: [{ url: "https://192.168.99.199" }] + serversTransport: insecure-transport + + + healthchecks-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8091" }] + serversTransport: default-transport + + + dagu-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8092" }] + serversTransport: default-transport + filebrowser-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8093" }] + serversTransport: default-transport + + woodpecker-service: + loadBalancer: + servers: [{ url: "http://192.168.99.186:8086" }] + serversTransport: default-transport + + node-red-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:1880" }] + serversTransport: default-transport + tandoor-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:8094" }] + serversTransport: default-transport + + n8n-service: + loadBalancer: + servers: [{ url: "http://192.168.99.183:5678" }] + serversTransport: default-transport + + ntfy-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8095" + serversTransport: default-transport + + speedtest-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8096" + serversTransport: default-transport + + linkding-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8097" + serversTransport: default-transport + + vikunja-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8098" + serversTransport: default-transport + + watchyourlan-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:8840" + serversTransport: default-transport + + glances-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:61208" + serversTransport: default-transport + + netdata-service: + loadBalancer: + servers: + - url: "http://192.168.99.198:19999" + serversTransport: default-transport + + mealie-service: + loadBalancer: + servers: + - url: "http://192.168.99.183:9925" + serversTransport: default-transport diff --git a/traefik/traefik-drift-check.sh b/traefik/traefik-drift-check.sh new file mode 100755 index 0000000..9d4db77 --- /dev/null +++ b/traefik/traefik-drift-check.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# Nightly Traefik dynamic_conf.yml drift check +# Runs on ansible-control; alerts to ntfy if node01 and node02 differ +# beyond the known intentional crowdsecLapiHost difference. + +NODE01="tommy@192.168.99.186" +NODE02="tommy@192.168.99.187" +CONF_PATH="/home/tommy/traefik/dynamic_conf.yml" +NTFY_URL="https://ntfy.goattw.net/homelab-alerts" +KNOWN_DIFF_PATTERN="crowdsecLapiHost" + +logger -t traefik-drift-check "starting drift check" + +node01_content=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$NODE01" "cat $CONF_PATH" 2>/dev/null) +node02_content=$(ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "$NODE02" "cat $CONF_PATH" 2>/dev/null) + +if [[ -z "$node01_content" || -z "$node02_content" ]]; then + logger -t traefik-drift-check "ERROR: could not fetch config from one or both nodes" + curl -sf \ + -H "Priority: high" \ + -H "Tags: warning" \ + -H "Title: Traefik drift-check: fetch failed" \ + -d "Could not SSH to node01 or node02 to fetch dynamic_conf.yml" \ + "$NTFY_URL" || true + exit 1 +fi + +# Diff, filter out the known intentional line +unexpected_diff=$(diff \ + <(echo "$node01_content" | grep -v "$KNOWN_DIFF_PATTERN") \ + <(echo "$node02_content" | grep -v "$KNOWN_DIFF_PATTERN") 2>/dev/null) + +if [[ -n "$unexpected_diff" ]]; then + logger -t traefik-drift-check "DRIFT DETECTED — unexpected differences found" + diff_summary=$(echo "$unexpected_diff" | head -20) + curl -sf \ + -H "Priority: high" \ + -H "Tags: warning" \ + -H "Title: Traefik config drift detected" \ + -d "dynamic_conf.yml differs between node01 and node02 (beyond crowdsecLapiHost). + +$diff_summary + +Fix: sync node02 from node01 canonical." \ + "$NTFY_URL" || true + logger -t traefik-drift-check "alert sent to ntfy" + exit 1 +else + logger -t traefik-drift-check "no unexpected drift — configs match (crowdsecLapiHost difference expected)" + exit 0 +fi