Si gestionas múltiples servicios web en un único servidor, tarde o temprano tendrás que resolver el problema del proxy inverso. Tras probar varias soluciones, migré a Traefik como proxy inverso integrado con Docker y ha sido una de las mejores decisiones de infraestructura que he tomado en años. En este artículo comparto mi experiencia práctica, partiendo de la configuración en producción que corre en este mismo servidor.
Qué es Traefik y por qué elegirlo como proxy inverso para Docker
Traefik es un proxy inverso y balanceador de carga moderno, construido de forma nativa para entornos en contenedores. A diferencia de Nginx o Apache configurados manualmente, Traefik se integra directamente con Docker y actualiza su configuración de forma automática cada vez que un contenedor se inicia o se detiene.
Las principales ventajas que me convencieron:
- Configuración sin intervención: basta con añadir etiquetas al contenedor Docker, sin archivos de configuración separados que editar
- SSL automático con Let’s Encrypt: los certificados se generan y renuevan sin intervención manual
- Panel web integrado para monitorizar routers, servicios y middleware
- Soporte nativo para Docker, Kubernetes, Consul y otros proveedores
- Middleware potente: redirecciones, autenticación básica/OAuth, limitación de velocidad, compresión y mucho más
Mi arquitectura con Traefik y Docker
Mi servidor ejecuta una infraestructura de varios servicios, todos orquestados mediante Docker Compose y conectados en la misma red bridge interna dedicada. Traefik es el único contenedor que expone puertos al exterior y actúa como punto de entrada único para todo el tráfico.
Los servicios activos son:
- Traefik — el proxy inverso, expuesto en los puertos 80 y 443
- WordPress (este blog) — accesible en
rogue1.itywww.rogue1.it - Varios servicios internos — cada uno en su propio subdominio, no expuestos directamente
- Bases de datos — no expuestas al exterior, accesibles únicamente a través de la red interna
Ningún contenedor excepto Traefik tiene puertos mapeados en el host: todo el tráfico debe pasar por el proxy inverso. Esto simplifica enormemente la gestión de la seguridad.
Configuración de Traefik con Docker Compose
Aquí está la estructura del docker-compose.yml para Traefik, con los puntos más importantes comentados. Los dominios en los bloques de código se han reemplazado por example.com a efectos ilustrativos.
Entrypoints: los puertos de escucha
Los Entrypoints definen en qué puertos escucha Traefik. Una configuración típica incluye al menos HTTP y HTTPS:
command:
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
Traefik también admite entrypoints TCP genéricos, útiles para gestionar otros protocolos (correo, federación, etc.) manteniendo un único punto de entrada para todo el tráfico del servidor.
Proveedor Docker: la magia del autodescubrimiento
El parámetro --providers.docker=true habilita el proveedor Docker: Traefik se conecta al socket de Docker en modo de solo lectura y monitoriza los contenedores en ejecución en tiempo real. Cuando se inicia un contenedor con la etiqueta traefik.enable=true, Traefik lo registra automáticamente como servicio.
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
Montar el socket en modo de solo lectura (:ro) es una buena práctica de seguridad: Traefik lee el estado de los contenedores pero no puede modificarlos.
SSL automático con Let’s Encrypt
Esta es probablemente la característica más apreciada de Traefik: la renovación automática de certificados SSL mediante Let’s Encrypt. La configuración es mínima:
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=you@email.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
Utilizo el HTTP challenge (http-01): Let’s Encrypt verifica la propiedad del dominio realizando una solicitud HTTP en el puerto 80. Los certificados se guardan en el archivo acme.json en un volumen persistente y se renuevan automáticamente antes de su vencimiento.
Enrutamiento con etiquetas Docker
El núcleo de la configuración de cada servicio reside en las etiquetas Docker. En lugar de un archivo de configuración centralizado, cada contenedor declara sus propias reglas de enrutamiento. Aquí un ejemplo completo:
labels:
- "traefik.enable=true"
# HTTP Router: redirect to HTTPS
- "traefik.http.routers.myapp-http.rule=Host(`example.com`) || Host(`www.example.com`)"
- "traefik.http.routers.myapp-http.entrypoints=web"
- "traefik.http.routers.myapp-http.middlewares=myapp-https-redirect"
- "traefik.http.middlewares.myapp-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.myapp-https-redirect.redirectscheme.permanent=true"
# HTTPS Router: actual traffic
- "traefik.http.routers.myapp.rule=Host(`example.com`) || Host(`www.example.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.tls=true"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
El patrón de redirección HTTP → HTTPS
Un patrón que repito para cada servicio es el doble router: uno para HTTP (puerto 80) que redirige permanentemente a HTTPS, y otro para HTTPS (puerto 443) que gestiona el tráfico real con TLS. El middleware redirectscheme gestiona la redirección 301, que también es correcta para el SEO.
El panel de control de Traefik
Traefik incluye un panel web muy útil para la monitorización. La mejor práctica es exponerlo en un subdominio dedicado accesible solo mediante HTTPS, con autenticación básica obligatoria:
- "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=YOURUSER:BCRYPT_HASH"
El servicio especial api@internal es el propio panel. El middleware basicauth protege el acceso con una contraseña cifrada con bcrypt — nunca en texto plano. Genera el hash bcrypt con htpasswd -nB username. Importante: en docker-compose, los símbolos $ deben escaparse como $$.
Desde el panel puedes ver en tiempo real todos los routers activos, servicios, middleware aplicado y el estado de los certificados TLS. Es una herramienta de depuración indispensable, pero mantenla siempre protegida: expone el mapa completo de la infraestructura.
Añadir un nuevo servicio: ejemplo práctico
Para mostrar lo sencillo que es añadir un nuevo servicio, aquí está la configuración genérica para una aplicación en su propio subdominio dedicado:
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice-http.rule=Host(`myservice.example.com`)"
- "traefik.http.routers.myservice-http.entrypoints=web"
- "traefik.http.routers.myservice-http.middlewares=myservice-https-redirect"
- "traefik.http.middlewares.myservice-https-redirect.redirectscheme.scheme=https"
- "traefik.http.middlewares.myservice-https-redirect.redirectscheme.permanent=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.example.com`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.routers.myservice.tls=true"
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
- "traefik.http.services.myservice.loadbalancer.server.port=8080"
Simplemente reemplaza myservice con el nombre de tu servicio, actualiza el subdominio e indica el puerto interno en el que escucha el contenedor. Sin puertos expuestos en el host, sin cambios en archivos de configuración centralizados: Traefik lee las etiquetas y configura el enrutamiento por sí solo en cuestión de segundos.
Consideraciones de seguridad
Prácticas de seguridad que aplico en mi configuración:
- Socket Docker en solo lectura:
/var/run/docker.sock:/var/run/docker.sock:ro— Traefik lee pero no escribe - Panel protegido por autenticación básica con contraseña cifrada con bcrypt, nunca en texto plano
- API del panel no insegura:
--api.insecure=false, expuesta únicamente mediante router autenticado en HTTPS - Sin puertos de servicio expuestos en el host: solo Traefik tiene puertos mapeados, los demás contenedores se comunican únicamente en la red interna
- HTTPS forzado en todos los servicios con redirección permanente 301
- Subdominio del panel no obvio: evitar nombres predecibles como
admin.otraefik.para reducir la superficie de ataque de bots
Pros y contras tras meses en producción
Pros
- Añadir un nuevo servicio solo requiere etiquetas en docker-compose, sin ninguna otra configuración
- Los certificados SSL nunca han caducado, la renovación es completamente automática
- El panel hace visible de inmediato el estado de toda la infraestructura
- Los registros de Traefik son muy detallados y simplifican la depuración
- Comunidad activa y documentación excelente
Contras
- La sintaxis de las etiquetas puede volverse verbosa para configuraciones complejas
- La depuración de middleware requiere algo de práctica inicial
- Escapar
$en las etiquetas de docker-compose (que se convierten en$$) es una fuente habitual de errores - Las configuraciones muy personalizadas requieren archivos de configuración estática adicionales
Conclusiones
Usar Traefik como proxy inverso integrado con Docker ha simplificado enormemente la gestión de mi infraestructura. El enfoque de configuración como código mediante etiquetas Docker, la gestión automática de SSL y el panel de monitorización lo convierten en la opción ideal para cualquiera que gestione múltiples servicios en contenedores en un único servidor.
Si todavía usas Nginx o Apache con configuraciones manuales en un entorno Docker, te recomiendo evaluar una migración a Traefik: el tiempo invertido en la curva de aprendizaje inicial se recupera rápidamente gracias a la simplicidad de la gestión diaria.
¿Tienes preguntas sobre la configuración o quieres compartir tu experiencia con Traefik? ¡Deja un comentario abajo!








