services: traefik: image: traefik:v3.6.1 ports: - 80:80 - 443:443 - 8082:8080 environment: - CF_DNS_API_TOKEN_FILE=/run/secrets/cloudflare_api_token volumes: - /var/run/docker.sock:/var/run/docker.sock - ./static.yml:/etc/traefik/traefik.yml:ro - ./dynamic.yml:/etc/traefik/dynamic/dynamic.yml:ro - /home/doc/projects/swarm-data/traefik/certificates:/certificates - /home/doc/projects/swarm-data/traefik/logs:/var/log/traefik secrets: - cloudflare_api_token networks: - frostlabs healthcheck: test: [ "CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/ping" ] interval: 30s timeout: 5s retries: 3 start_period: 30s deploy: mode: replicated replicas: 1 placement: constraints: - node.labels.task == control # crowdsec: # image: crowdsecurity/crowdsec:latest # environment: # # Disable online API enrollment (use for local setup) # - DISABLE_ONLINE_API=false # # Set collections to install # - COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve # # Enable Prometheus metrics # - METRICS_PORT=6060 # volumes: # # Persistent CrowdSec configuration and data # - /home/doc/projects/swarm-data/crowdsec/config:/etc/crowdsec # - /home/doc/projects/swarm-data/crowdsec/data:/var/lib/crowdsec/data # # Traefik access logs (read-only) # - /home/doc/projects/swarm-data/traefik/logs:/var/log/traefik:ro # # Acquis configuration # - ./acquis.yaml:/etc/crowdsec/acquis.yaml:ro # networks: # - frostlabs # deploy: # mode: replicated # replicas: 1 # placement: # constraints: # - node.labels.task == control # restart_policy: # condition: on-failure # delay: 5s # max_attempts: 3 # healthcheck: # test: [ "CMD", "cscli", "version" ] # interval: 30s # timeout: 10s # retries: 3 # start_period: 60s portainer: image: portainer/portainer-ce:latest command: -H tcp://tasks.agent:9001 --tlsskipverify volumes: - /home/doc/projects/swarm-data/portainer:/data networks: - frostlabs ports: - 9000:9000 deploy: mode: replicated replicas: 1 placement: constraints: - node.labels.task == control labels: - "traefik.enable=true" - "traefik.swarm.network=frostlabs" - "traefik.http.routers.portainer.rule=Host(`portainer.frostlabs.me`)" - "traefik.http.routers.portainer.entrypoints=websecure" - "traefik.http.routers.portainer.tls=true" - "traefik.http.routers.portainer.tls.certresolver=cloudflare" - "traefik.http.services.portainer.loadbalancer.server.port=9000" agent: image: portainer/agent:latest volumes: - /var/run/docker.sock:/var/run/docker.sock - /var/lib/docker/volumes:/var/lib/docker/volumes networks: - frostlabs deploy: mode: global redis: image: redis:alpine command: --save 60 1 --loglevel warning volumes: - /home/doc/projects/swarm-data/authentik/redis:/data networks: - frostlabs healthcheck: test: [ "CMD", "redis-cli", "ping" ] interval: 30s timeout: 5s retries: 3 start_period: 10s deploy: replicas: 1 placement: constraints: - node.labels.task == compute resources: limits: memory: 512M reservations: memory: 128M authentik_server: image: ghcr.io/goauthentik/server:2025.10.0 command: server environment: AUTHENTIK_SECRET_KEY: "file:///run/secrets/auth-key" AUTHENTIK_REDIS__HOST: "redis" AUTHENTIK_POSTGRESQL__HOST: "10.0.4.10" AUTHENTIK_POSTGRESQL__PORT: "5432" AUTHENTIK_POSTGRESQL__USER: "admin" AUTHENTIK_POSTGRESQL__NAME: "authentik" AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/postgres-master" # Optional: Set error reporting (set to false for privacy) AUTHENTIK_ERROR_REPORTING__ENABLED: "false" secrets: - auth-key - postgres-master volumes: - /home/doc/projects/swarm-data/authentik/media:/media - /home/doc/projects/swarm-data/authentik/templates:/templates - /var/run/docker.sock:/var/run/docker.sock networks: - frostlabs healthcheck: test: [ "CMD-SHELL", "ak healthcheck" ] interval: 30s timeout: 10s retries: 3 start_period: 90s deploy: replicas: 1 placement: constraints: - node.labels.task == control resources: limits: memory: 1G cpus: '1.0' reservations: memory: 512M labels: - "traefik.enable=true" - "traefik.swarm.network=frostlabs" - "traefik.http.routers.authentik.rule=Host(`auth.frostlabs.me`)" - "traefik.http.routers.authentik.entrypoints=websecure" - "traefik.http.routers.authentik.tls=true" - "traefik.http.routers.authentik.tls.certresolver=cloudflare" - "traefik.http.services.authentik.loadbalancer.server.port=9000" depends_on: - redis authentik_worker: image: ghcr.io/goauthentik/server:2025.10.0 command: worker environment: AUTHENTIK_SECRET_KEY: "file:///run/secrets/auth-key" AUTHENTIK_REDIS__HOST: "redis" AUTHENTIK_POSTGRESQL__HOST: "10.0.4.10" AUTHENTIK_POSTGRESQL__PORT: "5432" AUTHENTIK_POSTGRESQL__USER: "admin" AUTHENTIK_POSTGRESQL__NAME: "authentik" AUTHENTIK_POSTGRESQL__PASSWORD: "file:///run/secrets/postgres-master" # Optional: Set error reporting (set to false for privacy) AUTHENTIK_ERROR_REPORTING__ENABLED: "false" secrets: - auth-key - postgres-master volumes: - /home/doc/projects/swarm-data/authentik/media:/media - /home/doc/projects/swarm-data/authentik/templates:/templates - /var/run/docker.sock:/var/run/docker.sock networks: - frostlabs deploy: replicas: 1 placement: constraints: - node.labels.task == compute resources: limits: memory: 1G cpus: '1.0' reservations: memory: 512M depends_on: - redis networks: frostlabs: external: true secrets: cloudflare_api_token: external: true auth-key: external: true postgres-master: external: true