-
-
Save possebon/49640671d4169afeb8dd396612ac423a to your computer and use it in GitHub Desktop.
Traefik on Docker Swarm accessed via Cloudflare Tunnel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Please see https://mattdyson.org/blog/2024/02/using-traefik-with-cloudflare-tunnels for a detailed write-up of this configuration |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ROOT_DOMAIN=yourdomain.com | |
HTTP_TIMEOUT=60 | |
POLLING_INTERVAL=10 | |
PROPAGATION_TIMEOUT=3600 | |
TTL=300 | |
PROVIDERS_GOOGLE_CLIENT_ID=<GOOGLE CLIENT ID> | |
PROVIDERS_GOOGLE_CLIENT_SECRET=<GOOGLE CLIENT SECRET> | |
SECRET=RandomTextGoesHere | |
WHITELIST=<YOUR GOOGLE ACCOUNT EMAIL> | |
LOG_LEVEL=INFO | |
ZONE_ID=<YOUR CLOUDFLARE ZONE ID> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: '3.7' | |
services: | |
whoami: | |
image: traefik/whoami | |
command: | |
- --name=externalapp | |
deploy: | |
labels: | |
- "traefik.enable=true" | |
- "traefik.docker.network=traefik" | |
- "traefik.http.routers.external.rule=Host(`external.yourdomain.com`)" | |
- "traefik.http.routers.external.entrypoints=websecure" | |
- "traefik.http.routers.external.tls=true" | |
- "traefik.http.routers.external.middlewares=forward-auth" | |
- "traefik.http.services.external.loadbalancer.server.port=80" | |
- "traefik.constraint=proxy-public" | |
networks: | |
traefik: | |
external: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: '3.7' | |
services: | |
whoami: | |
image: traefik/whoami | |
command: | |
- --name=internalapp | |
deploy: | |
labels: | |
- "traefik.enable=true" | |
- "traefik.docker.network=traefik" | |
- "traefik.http.routers.internal.rule=Host(`internal.yourdomain.com`)" | |
- "traefik.http.routers.internal.entrypoints=websecure" | |
- "traefik.http.routers.internal.tls=true" | |
- "traefik.http.services.internal.loadbalancer.server.port=80" | |
networks: | |
traefik: | |
external: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: '3.7' | |
services: | |
reverse-proxy: | |
image: traefik:v2.10 | |
command: | |
- "--log" | |
- "--log.level=${LOG_LEVEL:-INFO}" | |
- "--log.format=json" | |
- "--api.insecure=true" | |
- "--providers.docker" | |
- "--providers.docker.swarmMode=true" | |
- "--providers.docker.exposedbydefault=false" | |
- "--providers.file.directory=/config" | |
- "--providers.file.watch=true" | |
- "--serversTransport.insecureSkipVerify=true" # Allow self-signed certificates for target hosts - https://doc.traefik.io/traefik/routing/overview/#insecureskipverify | |
- "--metrics" | |
- "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0" | |
- "--entrypoints.web.address=:80" | |
- "--entrypoints.web.http.redirections.entrypoint.to=websecure" | |
- "--entrypoints.web.http.redirections.entrypoint.scheme=https" | |
- "--entrypoints.websecure.address=:443" | |
- "--entrypoints.websecure.http.tls=true" | |
- "--entrypoints.websecure.http.tls.certresolver=letsencrypt" | |
- "--entrypoints.webinternal.address=:82" | |
- "--certificatesresolvers.letsencrypt.acme.email=<YOUR EMAIL>" | |
- "--certificatesresolvers.letsencrypt.acme.storage=/etc/traefik/acme/letsencrypt.json" | |
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare" | |
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.delaybeforecheck=300" | |
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.resolvers=8.8.8.8:53" | |
secrets: | |
- cf_token | |
environment: | |
- CLOUDFLARE_DNS_API_TOKEN_FILE=/run/secrets/cf_token | |
- CLOUDFLARE_HTTP_TIMEOUT=${HTTP_TIMEOUT} | |
- CLOUDFLARE_POLLING_INTERVAL=${POLLING_INTERVAL} | |
- CLOUDFLARE_PROPAGATION_TIMEOUT=${PROPAGATION_TIMEOUT} | |
- CLOUDFLARE_TTL=${TTL} | |
deploy: | |
restart_policy: | |
condition: any | |
delay: 5s | |
max_attempts: 3 | |
window: 120s | |
update_config: # Start new instance before stopping existing one | |
delay: 10s | |
order: start-first | |
parallelism: 1 | |
rollback_config: | |
parallelism: 0 | |
order: stop-first | |
placement: | |
constraints: | |
- node.role == manager | |
labels: | |
- traefik.enable=true | |
- traefik.http.routers.api.rule=Host(`traefik.${ROOT_DOMAIN}`) | |
- traefik.http.routers.api.service=api@internal | |
- traefik.http.routers.api.entrypoints=websecure | |
- traefik.http.routers.api.tls=true | |
- traefik.http.services.api.loadbalancer.server.port=8080 | |
ports: | |
# HTTP | |
- target: 80 | |
published: 80 | |
# HTTPS | |
- target: 443 | |
published: 443 | |
# Web UI (enabled by --api.insecure=true) | |
- target: 8080 | |
published: 8080 | |
networks: | |
- traefik | |
- internal | |
volumes: | |
# So that Traefik can listen to the Docker events | |
- /var/run/docker.sock:/var/run/docker.sock | |
- acme:/etc/traefik/acme | |
- traefik:/config | |
- cloudflare:/cloudflare | |
traefik-forward-auth: | |
image: thomseddon/traefik-forward-auth:2.1.0 | |
networks: | |
- traefik | |
environment: | |
- PROVIDERS_GOOGLE_CLIENT_ID=${PROVIDERS_GOOGLE_CLIENT_ID} | |
- PROVIDERS_GOOGLE_CLIENT_SECRET=${PROVIDERS_GOOGLE_CLIENT_SECRET} | |
- SECRET=${SECRET} | |
- AUTH_HOST=auth.${ROOT_DOMAIN} | |
- COOKIE_DOMAIN=${ROOT_DOMAIN} | |
- WHITELIST=${WHITELIST} | |
deploy: | |
labels: | |
- traefik.enable=true | |
- traefik.docker.network=traefik | |
- traefik.http.routers.auth.rule=Host(`auth.${ROOT_DOMAIN}`) | |
- traefik.http.routers.auth.entrypoints=websecure | |
- traefik.http.routers.auth.tls=true | |
- traefik.http.routers.auth.tls.domains[0].main=${ROOT_DOMAIN} | |
- traefik.http.routers.auth.tls.domains[0].sans=*.${ROOT_DOMAIN} | |
- traefik.http.routers.auth.tls.certresolver=letsencrypt | |
- traefik.http.routers.auth.service=auth@docker | |
- traefik.http.services.auth.loadbalancer.server.port=4181 | |
- traefik.http.middlewares.forward-auth.forwardauth.address=http://traefik-forward-auth:4181 | |
- traefik.http.middlewares.forward-auth.forwardauth.trustForwardHeader=true | |
- traefik.http.middlewares.forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User | |
- traefik.http.routers.auth.middlewares=forward-auth | |
- traefik.constraint=proxy-public | |
tunnel: | |
container_name: cloudflared-tunnel | |
image: cloudflare/cloudflared | |
restart: unless-stopped | |
command: tunnel run | |
deploy: | |
mode: replicated | |
replicas: 3 | |
update_config: | |
delay: 30s | |
order: start-first | |
monitor: 20s | |
networks: | |
- traefik | |
environment: | |
- TUNNEL_TOKEN=${TUNNEL_TOKEN} | |
error-pages: | |
image: tarampampam/error-pages:2.26.0 | |
environment: | |
TEMPLATE_NAME: l7-dark | |
networks: | |
- traefik | |
deploy: | |
mode: replicated | |
replicas: 2 | |
update_config: | |
delay: 20s | |
order: start-first | |
monitor: 10s | |
labels: | |
- traefik.enable=true | |
- traefik.docker.network=traefik | |
# use as "fallback" for any non-registered services (with priority below normal) | |
- traefik.http.routers.error-pages.rule=HostRegexp(`{host:.+}`) | |
- traefik.http.routers.error-pages.priority=10 | |
# should say that all of your services work on https | |
- traefik.http.routers.error-pages.tls='true' | |
- traefik.http.routers.error-pages.entrypoints=websecure | |
- traefik.http.routers.error-pages.middlewares=error-pages | |
- traefik.http.services.error-pages.loadbalancer.server.port=8080 | |
# "errors" middleware settings | |
- traefik.http.middlewares.error-pages.errors.status=400-599 | |
- traefik.http.middlewares.error-pages.errors.service=error-pages | |
- traefik.http.middlewares.error-pages.errors.query=/{status}.html | |
cloudflare-companion: | |
image: ghcr.io/tiredofit/docker-traefik-cloudflare-companion:latest | |
volumes: | |
- /var/run/docker.sock:/var/run/docker.sock | |
deploy: | |
placement: | |
constraints: | |
- node.role == manager | |
environment: | |
- TIMEZONE=Europe/London | |
- LOG_TYPE=CONSOLE | |
- LOG_LEVEL=INFO | |
- TRAEFIK_VERSION=2 | |
- RC_TYPE=CNAME | |
- TARGET_DOMAIN=${ROOT_DOMAIN} | |
- REFRESH_ENTRIES=TRUE | |
- DOCKER_SWARM_MODE=TRUE | |
- ENABLE_TRAEFIK_POLL=TRUE | |
- TRAEFIK_POLL_URL=https://traefik.${ROOT_DOMAIN}/api | |
- TRAEFIK_FILTER_LABEL=traefik.constraint | |
- TRAEFIK_FILTER=proxy-public | |
- DOMAIN1=${ROOT_DOMAIN} | |
- DOMAIN1_ZONE_ID=${ZONE_ID} | |
- DOMAIN1_PROXIED=TRUE | |
restart: always | |
networks: | |
- internal | |
secrets: | |
- cf_token | |
networks: | |
traefik: | |
external: true | |
internal: | |
volumes: | |
acme: | |
traefik: | |
cloudflare: | |
secrets: | |
cf_token: | |
external: true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment