# Managed by Ansible — do not edit manually services: traefik: image: traefik:{{ traefik_version }} container_name: traefik restart: unless-stopped ports: - "80:80" - "443:443" - "993:993" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - {{ traefik_data_dir }}/traefik.yml:/traefik.yml:ro - {{ traefik_data_dir }}/acme.json:/acme.json - /var/log/traefik:/var/log/traefik networks: - traefik_public labels: - "traefik.enable=true" # Dashboard — accessible at cloud.ladkau.de/dashboard/ protected by basic auth - "traefik.http.routers.dashboard.rule=Host(`{{ domain_cloud }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=dashboard-auth" {% set ns = namespace(entries=[]) %} {% for user in traefik_dashboard_users | default([]) %} {% set ns.entries = ns.entries + [user.username + ':' + (user.password | password_hash('bcrypt', (user.username | hash('md5'))[:22]) | replace('$', '$$'))] %} {% endfor %} - "traefik.http.middlewares.dashboard-auth.basicauth.users={{ ns.entries | join(',') }}" # Rate-limit middlewares — referenced by services as rate-limit@docker / rate-limit-lax@docker # Standard: 60 req/min per IP, burst 20 — protects all services from bot floods - "traefik.http.middlewares.rate-limit.rateLimit.average=60" - "traefik.http.middlewares.rate-limit.rateLimit.period=1m" - "traefik.http.middlewares.rate-limit.rateLimit.burst=20" # Lax: 300 req/min per IP, burst 100 — for Nextcloud sync clients making many small requests - "traefik.http.middlewares.rate-limit-lax.rateLimit.average=300" - "traefik.http.middlewares.rate-limit-lax.rateLimit.period=1m" - "traefik.http.middlewares.rate-limit-lax.rateLimit.burst=100" networks: traefik_public: external: true