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
