Traefik es el reverse proxy más popular en entornos Docker Swarm: configuración declarativa vía labels, certificados Let’s Encrypt automáticos, dashboard útil, y rendimiento probado. Esta guía cubre el despliegue paso a paso en Swarm, con certificados DNS challenge (recomendado para producción), configuración segura del dashboard, y labels productivos.
El objetivo: dejarlo listo para recibir tráfico de producción, no solo “funciona en mi VPS”.
Prerequisitos
- Docker Swarm inicializado (
docker swarm init). - Dominio apuntando a la IP pública de tu manager node.
- API token de tu proveedor DNS (Cloudflare, OVH, etc) — para DNS challenge.
- Email para Let’s Encrypt.
- Puertos 80 y 443 abiertos en el firewall hacia el manager.
Paso 1: red overlay compartida
Traefik necesita una red compartida con los servicios que va a proxyficar:
docker network create --driver=overlay --attachable traefik_public
El flag --attachable permite que contenedores no-swarm también se conecten si hace falta.
Paso 2: volumen para certificados
Let’s Encrypt almacena certificados en disco. Para un solo manager:
docker volume create traefik_letsencrypt
Para múltiples managers, necesitas shared storage (NFS, GlusterFS, o similar) para que el certificado pueda moverse entre nodos. Para esta guía asumimos un solo manager.
Paso 3: stack.yml de Traefik
version: "3.8"
services:
traefik:
image: traefik:v3.0
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik_letsencrypt:/letsencrypt
- /etc/traefik:/etc/traefik:ro
networks:
- traefik_public
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
resources:
limits:
memory: 512M
cpus: "1.0"
labels:
- traefik.enable=true
- traefik.docker.network=traefik_public
- traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)
- traefik.http.routers.dashboard.service=api@internal
- traefik.http.routers.dashboard.entrypoints=websecure
- traefik.http.routers.dashboard.tls.certresolver=cloudflare
- traefik.http.routers.dashboard.middlewares=auth
- traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$...
- traefik.http.services.dummy.loadbalancer.server.port=8080
volumes:
traefik_letsencrypt:
external: true
networks:
traefik_public:
external: true
Paso 4: traefik.yml estático
Crear /etc/traefik/traefik.yml en el manager:
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
swarmMode: true
network: traefik_public
certificatesResolvers:
cloudflare:
acme:
email: tu@example.com
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
log:
level: INFO
format: json
accessLog:
format: json
Puntos importantes:
exposedByDefault: falsees prudente — solo servicios contraefik.enable=truese proxyfican.swarmMode: truelee servicios Swarm, no contenedores individuales.dnsChallengees más robusto quehttpChallengepara producción (funciona detrás de NAT, no requiere puerto 80).
Paso 5: credentials para DNS challenge
El DNS challenge necesita API credentials. Para Cloudflare, crear un API token con permisos Zone:DNS:Edit en tus zonas.
Pasarlas via secrets o env vars:
services:
traefik:
environment:
- CF_API_EMAIL=tu@example.com
- CF_DNS_API_TOKEN=tu-token-aqui
Mejor aún con Docker secrets:
echo "tu-token-aqui" | docker secret create cf_api_token -
services:
traefik:
secrets:
- cf_api_token
environment:
- CF_DNS_API_TOKEN_FILE=/run/secrets/cf_api_token
secrets:
cf_api_token:
external: true
Paso 6: basic auth para el dashboard
Generar hash con htpasswd:
sudo apt install apache2-utils
htpasswd -nb admin tu-password-fuerte
# admin:$apr1$...
Escapar los $ con $$ en el stack.yml. O usar secret:
labels:
- traefik.http.middlewares.auth.basicauth.usersfile=/run/secrets/traefik_auth
Paso 7: desplegar
docker stack deploy -c stack.yml traefik
Verificar:
docker service ls | grep traefik
docker service logs traefik_traefik --tail 50
Los logs deben mostrar: – starting provider. – found authorization url. – certificates obtained for traefik.example.com.
Si falla: suele ser por credentials DNS, email inválido, o dominio mal configurado.
Paso 8: proxyficar un servicio de ejemplo
version: "3.8"
services:
whoami:
image: traefik/whoami
networks:
- traefik_public
deploy:
replicas: 2
labels:
- traefik.enable=true
- traefik.docker.network=traefik_public
- traefik.http.routers.whoami.rule=Host(`whoami.example.com`)
- traefik.http.routers.whoami.entrypoints=websecure
- traefik.http.routers.whoami.tls.certresolver=cloudflare
- traefik.http.services.whoami.loadbalancer.server.port=80
networks:
traefik_public:
external: true
docker stack deploy -c whoami.yml whoami
Traefik detecta el servicio, obtiene certificado, lo balance entre las 2 réplicas. Pruebas:
curl https://whoami.example.com
Debería responder con info del contenedor que sirve.
Configuración avanzada
Middleware chain para seguridad
Definir headers de seguridad estándar:
- traefik.http.middlewares.security-headers.headers.sslredirect=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.forceSTSHeader=true
- traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.security-headers.headers.browserXssFilter=true
- traefik.http.middlewares.security-headers.headers.referrerPolicy=no-referrer
Aplicar a tus routers: traefik.http.routers.mysite.middlewares=security-headers@docker.
Rate limiting
- traefik.http.middlewares.ratelimit.ratelimit.average=100
- traefik.http.middlewares.ratelimit.ratelimit.burst=200
IP whitelist para paths administrativos
- traefik.http.middlewares.admin-ips.ipwhitelist.sourcerange=10.0.0.0/8,203.0.113.42/32
Monitorización
Traefik expone métricas Prometheus:
metrics:
prometheus:
entryPoint: metrics
addEntryPointsLabels: true
addRoutersLabels: true
addServicesLabels: true
entryPoints:
metrics:
address: ":8082"
Scrape desde Prometheus con ServiceMonitor o config estática.
Actualizar Traefik
Cambiar versión en stack.yml y redesplegar:
sed -i 's/traefik:v3.0/traefik:v3.1/g' stack.yml
docker stack deploy -c stack.yml traefik
Swarm actualiza el servicio con rolling update (aunque con replicas:1, es un breve downtime).
Troubleshooting común
- Certificados no se generan: revisar logs. Común: DNS token sin permisos correctos, o rate limit de Let’s Encrypt (5 certs/dominio/semana).
- 404 en todos los paths: verificar labels en el servicio proxyficado (typo en
.rule). - “Gateway timeout”: el servicio no responde en el puerto declarado en loadbalancer.
- HTTPS no redirecciona desde HTTP: verificar config del entrypoint
webcon redirect. - Dashboard inaccesible: basicauth mal configurada, middleware no aplicada.
Seguridad: checklist
Conclusión
Traefik en Swarm es una pieza madura y productiva para servir aplicaciones web con HTTPS automático. La configuración inicial tiene detalles pero el resultado es declarativo: añadir un servicio nuevo es cinco labels en su stack.yml y Traefik lo proxyfica automáticamente. Para producción seria, completar con monitorización, middlewares de seguridad y backups del storage de certificados. Bien configurado, es invisible — como debe ser un reverse proxy.
Síguenos en jacar.es para más guías prácticas sobre Traefik, Docker Swarm y despliegue de servicios.