version: '3.9' services: traefik: image: traefik:v3.0 command: - --providers.docker.swarmMode=true - --providers.docker.exposedbydefault=false - --providers.file.directory=/dynamic - --providers.file.watch=true - --entrypoints.web.address=:80 - --entrypoints.websecure.address=:443 - --api.dashboard=false - --api.debug=false - --serversTransport.insecureSkipVerify=false - --entrypoints.web.http.redirections.entryPoint.to=websecure - --entrypoints.web.http.redirections.entryPoint.scheme=https - --entrypoints.websecure.http.tls.options=default@file - --log.level=INFO - --accesslog=true - --metrics.prometheus=true - --metrics.prometheus.addRoutersLabels=true # Internal-only ports (no host exposure) volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - traefik_letsencrypt:/letsencrypt - /root/stacks/core/dynamic:/dynamic:ro - traefik_logs:/logs networks: - traefik-public healthcheck: test: ["CMD", "traefik", "healthcheck"] interval: 30s timeout: 10s retries: 3 start_period: 60s deploy: resources: limits: memory: 512M cpus: '0.5' reservations: memory: 256M cpus: '0.1' placement: constraints: - node.role == manager labels: - traefik.enable=true - traefik.http.routers.traefik-rtr.rule=Host(`traefik.localhost`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) - traefik.http.routers.traefik-rtr.entrypoints=websecure - traefik.http.routers.traefik-rtr.tls=true - traefik.http.routers.traefik-rtr.middlewares=traefik-auth,security-headers - traefik.http.services.traefik-svc.loadbalancer.server.port=8080 - traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$2y$$10$$xvzBkbKKvRX.jGG6F7L.ReEMyEx.7BkqNGQO2rFt/1aBgx8jPElXW # admin:securepassword - traefik.http.middlewares.security-headers.headers.frameDeny=true - traefik.http.middlewares.security-headers.headers.sslRedirect=true - traefik.http.middlewares.security-headers.headers.browserXSSFilter=true - traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true - traefik.http.middlewares.security-headers.headers.forceSTSHeader=true - traefik.http.middlewares.security-headers.headers.stsSeconds=31536000 - traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true - traefik.http.middlewares.security-headers.headers.stsPreload=true - traefik.http.middlewares.security-headers.headers.customRequestHeaders.X-Forwarded-Proto=https # External load balancer (nginx) - This will be the only service with exposed ports external-lb: image: nginx:1.25-alpine ports: - "80:80" - "443:443" volumes: - nginx_config:/etc/nginx/conf.d:ro - traefik_letsencrypt:/ssl:ro - nginx_logs:/var/log/nginx networks: - traefik-public healthcheck: test: ["CMD", "nginx", "-t"] interval: 30s timeout: 10s retries: 3 start_period: 30s deploy: resources: limits: memory: 256M cpus: '0.25' reservations: memory: 128M cpus: '0.05' placement: constraints: - node.role == manager depends_on: - traefik volumes: traefik_letsencrypt: driver: local traefik_logs: driver: local nginx_config: driver: local driver_opts: type: none o: bind device: /home/jonathan/Coding/HomeAudit/stacks/core/nginx-config nginx_logs: driver: local networks: traefik-public: external: true