Por qué Traefik v3 en lugar de nginx para tu stack Docker
nginx es un excelente servidor HTTP, pero su configuración es estática: cada nuevo servicio requiere un nuevo archivo vhost, una recarga del proceso y a menudo una modificación manual de la renovación ACME. Traefik fue diseñado para entornos en contenedores donde la topología cambia constantemente. En la versión 3, lleva esto aún más lejos con soporte nativo de HTTP/3 (QUIC), una sintaxis de middlewares simplificada y un runtime más estricto que rechaza configuraciones ambiguas.
- Descubrimiento automático de contenedores mediante labels Docker — sin recarga manual al añadir un servicio.
- HTTPS automático con Let's Encrypt (challenge TLS-ALPN-01 o HTTP-01): certificados obtenidos, almacenados y renovados sin intervención.
- Middlewares nativos declarables por label: BasicAuth, rate-limit, cabeceras de seguridad, redirecciones — sin escribir ningún módulo nginx.
- Dashboard integrado en tiempo real: visualiza todas las rutas, middlewares y estado de los certificados desde el navegador.
- Soporte HTTP/3 (QUIC) en una sola línea de configuración: mejora el rendimiento en conexiones de alta latencia.
- Enrutamiento por Host, PathPrefix, Headers o cualquier combinación — las reglas se escriben con sintaxis expresiva de Go template.
- API REST interna: consulta el estado del enrutador, inspecciona backends activos, automatiza integraciones CI/CD.
- Compatible con Docker Swarm, Kubernetes y Nomad — migra sin cambiar tus labels.
Requisitos técnicos antes de empezar
Esta instalación requiere un VPS con Debian 12 o Ubuntu 22.04/24.04 (los comandos son idénticos), Docker Engine 25+ y Docker Compose v2.24+ (el comando docker compose sin guion). Verifica que los puertos 80 y 443 están abiertos en entrada desde Internet en tu firewall. Necesitarás un nombre de dominio cuyos DNS controles: apunta un registro A a la IP de tu VPS antes de empezar, de lo contrario Let's Encrypt no podrá emitir el certificado. Se requiere una dirección de correo válida para las notificaciones de expiración ACME.
Instalación completa de Traefik v3 paso a paso
Crear la red Docker compartida. Traefik debe estar en la misma red que los servicios que proxifica. Créala una sola vez:
docker network create traefik-public. Esta red se referenciará en cadadocker-compose.ymlde tus servicios.Crear el archivo
acme.jsonpara los certificados. Let's Encrypt escribirá sus certificados en este archivo. Debe pertenecer a root con permisos estrictamente 600:touch /opt/traefik/acme.json && chmod 600 /opt/traefik/acme.json. Si los permisos son incorrectos, Traefik se negará a arrancar.Crear el
docker-compose.ymlde Traefik. Coloca el archivo en/opt/traefik/docker-compose.ymlcon la configuración completa: entrypoints TLS, el resolver ACME de Let's Encrypt y las labels del dashboard protegido.Generar el hash BasicAuth para el dashboard. Reemplaza la cadena hardcoded por un hash bcrypt real:
echo $(htpasswd -nB admin) | sed -e 's/\$/\$\$/g'. El comandohtpasswdestá en el paqueteapache2-utils. Los signos$deben duplicarse ($$) en los valores de labels de Docker Compose.Arrancar Traefik. Desde
/opt/traefik/:docker compose up -d. Verifica los logs:docker compose logs -f traefik. Debes ver"Starting provider" providerType=Dockery luego"Attaching router" routerName=dashboard.Añadir un servicio detrás de Traefik. En el
docker-compose.ymlde tu aplicación, únete a la redtraefik-public(como externa) y añade las cuatro labels clave:traefik.enable=true, la reglaHost(), el entrypointwebsecure, el certresolver y el puerto del backend.Verificar los certificados Let's Encrypt. Inspecciona
acme.json:cat /opt/traefik/acme.json | python3 -m json.tool | grep -A3 'domain'. Debes ver tus dominios con una fecha de expiración a 90 días. Alternativamente, el dashboard de Traefik lista todos los certificados activos en la pestaña *Routers*.Validar la redirección HTTP→HTTPS. Prueba con curl:
curl -v http://app.dominio.com. Debes recibir un301 Moved Permanentlyahttps://. Si obtienes conexión rechazada en el puerto 80, verifica que las reglas del firewall permiten ese puerto.Activar HTTP/3 en el navegador. Añade la cabecera
Alt-Svcmediante un middleware global en tus labels de Traefik. La cabeceraAlt-Svc: h3=":443"; ma=86400indica al navegador que tu servidor soporta QUIC. Verifica concurl --http3 https://app.dominio.com -v.
Middlewares esenciales: BasicAuth, rate-limit y cabeceras de seguridad
Los middlewares de Traefik se aplican mediante labels Docker directamente en el router del servicio afectado. Aquí están los tres middlewares más útiles en producción, declarados en el propio servicio sin tocar la configuración central de Traefik.
- BasicAuth en una ruta privada — para proteger una herramienta de administración (Adminer, Flower, etc.): añade las labels
traefik.http.middlewares.adminauth.basicauth.usersytraefik.http.routers.myadmin.middlewares=adminauthen el servicio. - Rate-limit anti-abuso — protege una API o un formulario de contacto: configura
ratelimit.average=100(100 req/s de media) yratelimit.burst=50(ráfaga de 50 tolerada), luego aplica el middleware al router. - Cabeceras de seguridad HTTP —
X-Frame-Options,X-Content-Type-Options,Strict-Transport-Security: el middlewareheadersde Traefik acepta todos estos valores directamente como labels, sin archivo de configuración nginx separado. - Redirect Regex — para redirigir
www.dominio.comadominio.com: usa el middlewareredirectregexconpermanent=truey una regex^https://www\.(.+)→https://${1}. - Compress — activa la compresión gzip/brotli en todas las respuestas textuales con una sola label:
traefik.http.middlewares.compress.compress=true. Aplícala globalmente añadiéndola como middleware por defecto en la configuración estática.
HTTP/3 (QUIC) en dos líneas. En la sección command del docker-compose.yml de Traefik, añade --entrypoints.websecure.http3=true y expón el puerto UDP 443 (443:443/udp). QUIC establece conexiones hasta un 30% más rápido en redes con pérdidas y elimina el head-of-line blocking de TLS sobre TCP. Los navegadores modernos (Chrome 87+, Firefox 88+, Safari 16.4+) lo activan automáticamente tras el primer intercambio mediante la cabecera Alt-Svc. No se necesitan cambios en la aplicación.
Migración desde Traefik v2: cambios que rompen la compatibilidad
Traefik v3 introduce rupturas intencionales con v2 para limpiar ambigüedades acumuladas. La buena noticia: la migración es progresiva — las configuraciones v2 y v3 pueden coexistir durante la transición. Aquí están los puntos que rompen con más frecuencia.
docker.swarmModerenombrado adocker.swarmmode(todo en minúsculas). Si tu config v2 usa la casing antigua, Traefik v3 la ignora silenciosamente y el descubrimiento Swarm no funciona.- Regla
PathPrefixsin trailing slash: en v3,PathPrefix('/api')es equivalente aPathPrefix('/api/')— el trailing slash se normaliza. Si tenías reglas que dependían de este comportamiento, revísalas. tls.certificatesen configuración dinámica: en v3, esta sección debe estar en la configuración estática (traefik.yml) o mediante un proveedor dedicado.- Middleware
errors: el parámetroqueryse renombra aurl. Cualquier configuración que useerrors.querydebe actualizarse aerrors.url. - Eliminación del soporte del protocolo
spiffe: si usabas autenticación SPIFFE en una infraestructura Consul, migra a una solución mTLS estándar antes de actualizar a v3. - Configuración
constraintsde Docker: la sintaxis de las restricciones ha cambiado para alinearse con el formato estándar de tags Docker. Verifica tu lista de restricciones si filtrabas servicios por tag.
Traefik v3 vs nginx vs Caddy: ¿qué reverse proxy para Docker?
Desplace la tabla
| Criterio | Traefik v3 | nginx | Caddy v2 |
|---|---|---|---|
| Configuración | Labels Docker, TOML o YAML — recarga automática en caliente | Archivos vhost estáticos — recarga manual (`nginx -s reload`) | Caddyfile declarativo — recarga automática en caliente |
| HTTPS automático | Integrado de forma nativa (ACME v2, challenge TLS-ALPN o HTTP-01) | Requiere certbot + cron + script de recarga | Integrado de forma nativa, el más sencillo de configurar (una línea) |
| Enrutamiento dinámico Docker | Nativo: descubrimiento en tiempo real de contenedores via Docker socket | No nativo: requiere nginx-proxy o modificación manual | Nativo mediante el plugin caddy-docker-proxy (no oficial) |
| HTTP/3 (QUIC) | Soportado nativamente desde v3 (2024), activación en una línea | Soportado desde nginx 1.25 (2023), configuración adicional necesaria | Soportado nativamente desde Caddy 2.6 (2022) |
| Rendimiento bruto | Ligeramente inferior a nginx en caudales muy altos (>50k req/s) | Referencia industrial para alto caudal y concurrencia | Comparable a nginx para la mayoría de cargas web estándar |
| Curva de aprendizaje | Moderada — conceptos de router/servicio/middleware a asimilar | Alta para HTTPS + Docker — documentación fragmentada | Baja — la configuración más concisa para casos simples |
Solución de problemas: los cinco errores más frecuentes
La mayoría de los problemas de Traefik en producción vienen de tres fuentes: los permisos del archivo acme.json, la red Docker ausente, y las labels mal escapadas en Compose. Aquí están los errores con sus mensajes reales.
level=error msg="Unable to obtain ACME certificate" error="acme: error 403"— Let's Encrypt no puede verificar tu dominio. Comprueba que el puerto 80 está abierto desde Internet y que el DNS de tu dominio apunta a la IP del VPS.level=error msg="The acme.json file has bad file permissions"y Traefik se niega a arrancar — los permisos del archivo no son 600. Corrige:chmod 600 /opt/traefik/acme.json. Este check es intencionalmente bloqueante.- Servicio visible en el dashboard de Traefik pero error 502 Bad Gateway — el contenedor del servicio no está en la red
traefik-public. Verifica condocker inspect <container> | grep -A20 Networks. Añade la red en eldocker-compose.ymldel servicio y recrea el contenedor. - Labels ignoradas silenciosamente, ruta ausente del dashboard — olvidaste
traefik.enable=trueen el servicio, o--providers.docker.exposedbydefault=falseestá activo y la label está ausente. invalid character '$' in label value— los signos$en los hashes BasicAuth no están duplicados en el archivo Compose. La sintaxis correcta es$$2y$$10$$...endocker-compose.yml. Si pasas el valor mediante una variable de entorno, un solo$es suficiente.
Siguiente paso: reforzar tu stack Docker para producción
Traefik v3 gestiona el enrutamiento y TLS, pero un stack Docker listo para producción requiere más: healthchecks en los contenedores, política de reinicio, logs centralizados, rotación de secretos, copias de seguridad de volúmenes. Consulta nuestra guía docker-compose-production-checklist para una lista de verificación completa a aplicar antes de poner en producción cualquier servicio en contenedor en tu VPS.