|
| 1 | +# ============================================================================= |
| 2 | +# REFERENCE ONLY — NOT PART OF THE TEMPLATE |
| 3 | +# ============================================================================= |
| 4 | +# |
| 5 | +# This file documents a self-hosted Traefik 3.6 gateway configuration for teams |
| 6 | +# that manage their own reverse proxy instead of using a managed gateway. |
| 7 | +# |
| 8 | +# Teams deploying to managed platforms (Railway, Cloud Run, Fly.io) should use |
| 9 | +# the platform's built-in routing and load balancing instead of running a |
| 10 | +# self-hosted Traefik instance. |
| 11 | +# |
| 12 | +# This is for teams wanting a self-hosted Traefik gateway on a VPS or |
| 13 | +# bare-metal server with automatic TLS via Let's Encrypt. |
| 14 | +# |
| 15 | +# HOW TO USE: |
| 16 | +# 1. Create the external network: docker network create traefik-public |
| 17 | +# 2. Set ACME_EMAIL and DOMAIN in your .env (or export them) |
| 18 | +# 3. Start the gateway: docker compose -f compose.gateway.yml up -d |
| 19 | +# 4. Add the example service labels (see bottom of this file) to your own |
| 20 | +# compose.yml services, then bring them up on the same traefik-public network |
| 21 | +# |
| 22 | +# THIS FILE IS NEVER USED BY THE TEMPLATE DIRECTLY. |
| 23 | +# It is documentation — a reference for self-hosted gateway deployments. |
| 24 | +# ============================================================================= |
| 25 | + |
| 26 | +services: |
| 27 | + |
| 28 | + traefik: |
| 29 | + image: traefik:3.6 |
| 30 | + restart: always |
| 31 | + ports: |
| 32 | + # HTTP — receives Let's Encrypt TLS challenges and redirects to HTTPS |
| 33 | + - "80:80" |
| 34 | + # HTTPS — TLS-terminated traffic |
| 35 | + - "443:443" |
| 36 | + volumes: |
| 37 | + # Docker socket (read-only) — Traefik reads labels from running containers |
| 38 | + - /var/run/docker.sock:/var/run/docker.sock:ro |
| 39 | + # Persistent volume for Let's Encrypt certificates |
| 40 | + - traefik-certificates:/certificates |
| 41 | + command: |
| 42 | + # --- Docker provider --- |
| 43 | + # Enable Docker label-based service discovery |
| 44 | + - --providers.docker |
| 45 | + # Only route containers that explicitly set traefik.enable=true |
| 46 | + - --providers.docker.exposedbydefault=false |
| 47 | + # Scope discovery to services tagged with traefik.constraint-label=traefik-public |
| 48 | + - --providers.docker.constraints=Label(`traefik.constraint-label`, `traefik-public`) |
| 49 | + |
| 50 | + # --- Entrypoints --- |
| 51 | + - --entrypoints.http.address=:80 |
| 52 | + - --entrypoints.https.address=:443 |
| 53 | + |
| 54 | + # --- HTTP → HTTPS redirect (global, via entrypoint configuration) --- |
| 55 | + - --entrypoints.http.http.redirections.entryPoint.to=https |
| 56 | + - --entrypoints.http.http.redirections.entryPoint.scheme=https |
| 57 | + - --entrypoints.http.http.redirections.entryPoint.permanent=true |
| 58 | + |
| 59 | + # --- TLS / Let's Encrypt (ACME) --- |
| 60 | + # TLS-ALPN-01 challenge — requires port 443 to be publicly reachable. |
| 61 | + # If port 443 is firewalled or shared, switch to the HTTP-01 challenge: |
| 62 | + # - --certificatesresolvers.le.acme.httpchallenge=true |
| 63 | + # - --certificatesresolvers.le.acme.httpchallenge.entrypoint=http |
| 64 | + - --certificatesresolvers.le.acme.tlschallenge=true |
| 65 | + # Your email for Let's Encrypt renewal notifications |
| 66 | + - --certificatesresolvers.le.acme.email=${ACME_EMAIL?Variable ACME_EMAIL not set} |
| 67 | + # Store certificates in the mounted volume |
| 68 | + - --certificatesresolvers.le.acme.storage=/certificates/acme.json |
| 69 | + |
| 70 | + # --- Observability --- |
| 71 | + - --accesslog |
| 72 | + - --log |
| 73 | + labels: |
| 74 | + - traefik.enable=true |
| 75 | + - traefik.docker.network=traefik-public |
| 76 | + |
| 77 | + # https-redirect middleware — named alias so service routers can reference it |
| 78 | + # The global redirect is enforced by the entrypoint command args above; |
| 79 | + # this label makes the middleware available by name for per-router use. |
| 80 | + - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https |
| 81 | + - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true |
| 82 | + |
| 83 | + # --- Rate limiting middleware (reference — not active by default) --- |
| 84 | + # To enable rate limiting on a service, add these labels to that service |
| 85 | + # and reference the middleware name in its router labels: |
| 86 | + # traefik.http.middlewares.rate-limit.ratelimit.average=100 |
| 87 | + # traefik.http.middlewares.rate-limit.ratelimit.burst=50 |
| 88 | + # traefik.http.middlewares.rate-limit.ratelimit.period=1m |
| 89 | + # Then apply it to a router: |
| 90 | + # traefik.http.routers.<name>-https.middlewares=rate-limit |
| 91 | + networks: |
| 92 | + - traefik-public |
| 93 | + |
| 94 | +# ============================================================================= |
| 95 | +# EXAMPLE BACKEND SERVICE (commented out — for reference only) |
| 96 | +# ============================================================================= |
| 97 | +# Copy these labels into your compose.yml backend service. |
| 98 | +# Replace STACK_NAME, DOMAIN, the image reference, and the container port |
| 99 | +# to match your workload. The network and constraint-label entries are |
| 100 | +# required for Traefik to discover and route to your service. |
| 101 | +# |
| 102 | +# backend: |
| 103 | +# image: your-org/your-backend:latest |
| 104 | +# restart: always |
| 105 | +# networks: |
| 106 | +# - traefik-public |
| 107 | +# - default |
| 108 | +# labels: |
| 109 | +# - traefik.enable=true |
| 110 | +# - traefik.docker.network=traefik-public |
| 111 | +# - traefik.constraint-label=traefik-public |
| 112 | +# |
| 113 | +# # Container port the backend listens on |
| 114 | +# - traefik.http.services.${STACK_NAME:-app}-backend.loadbalancer.server.port=8000 |
| 115 | +# |
| 116 | +# # HTTP router — redirects to HTTPS via the https-redirect middleware |
| 117 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-http.rule=Host(`api.${DOMAIN:-localhost}`) |
| 118 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-http.entrypoints=http |
| 119 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-http.middlewares=https-redirect |
| 120 | +# |
| 121 | +# # HTTPS router — serves TLS-terminated traffic with Let's Encrypt cert |
| 122 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-https.rule=Host(`api.${DOMAIN:-localhost}`) |
| 123 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-https.entrypoints=https |
| 124 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-https.tls=true |
| 125 | +# - traefik.http.routers.${STACK_NAME:-app}-backend-https.tls.certresolver=le |
| 126 | +# |
| 127 | +# # Optionally apply rate limiting (requires rate-limit middleware above): |
| 128 | +# # - traefik.http.routers.${STACK_NAME:-app}-backend-https.middlewares=rate-limit |
| 129 | +# ============================================================================= |
| 130 | + |
| 131 | +networks: |
| 132 | + # Shared external network — must be created before running this file: |
| 133 | + # docker network create traefik-public |
| 134 | + traefik-public: |
| 135 | + external: true |
| 136 | + |
| 137 | +volumes: |
| 138 | + # Stores Let's Encrypt certificates across container restarts |
| 139 | + traefik-certificates: |
0 commit comments