Cómo instalar Traefik en Docker Swarm con certificados

Cables de red coloridos conectados a switch representando enrutamiento

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: false es prudente — solo servicios con traefik.enable=true se proxyfican.
  • swarmMode: true lee servicios Swarm, no contenedores individuales.
  • dnsChallenge es más robusto que httpChallenge para 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 web con 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.

Entradas relacionadas