Hasta ahora hemos trabajado exclusivamente con Docker como proveedor. Las labels de los contenedores son una forma cómoda de configurar Traefik, pero tienen una limitación importante: la configuración está atada a cada contenedor. ¿Y si quieres tener middlewares o routers que se compartan entre varios servicios? ¿O si quieres configurar servicios que no están en Docker? ¿O simplemente prefieres tener toda la configuración en un archivo en lugar de esparcida en labels por ocho archivos docker-compose distintos?
Para todo eso está el File provider, el proveedor de archivos de Traefik. Te permite definir toda la configuración dinámica (routers, servicios, middlewares) en archivos YAML o TOML. Y lo mejor es que puedes recargar la configuración en caliente, sin reiniciar Traefik. Esto te puede ahorrar más de un disgusto cuando necesites cambiar algo en producción.
En el capítulo anterior viste cómo balancear tráfico entre múltiples instancias de un servicio, cómo configurar health checks y sticky sessions. Pues bien, todo eso que configuraste con labels de Docker, también puedes hacerlo con archivos. Y más.
¿File provider vs Docker provider?
Cada uno tiene su sitio.
- Docker provider: ideal para la configuración específica de cada servicio (dominio, entrypoint, TLS). Va con el contenedor, viaja con él, se despliega con él. Si mueves el contenedor a otra máquina, la configuración se mueve con él.
- File provider: ideal para configuración compartida (middlewares comunes, routers globales, servicios externos). Es el lugar donde pones lo que no pertenece a un contenedor concreto.
Lo bueno es que puedes usar ambos a la vez. No es excluyente. De hecho, te recomiendo que uses los dos combinados. Es el enfoque híbrido que uso en producción y funciona de maravilla: los middlewares compartidos en archivos, la configuración específica de cada servicio en las labels de Docker.
Piénsalo así: las labels son para lo que es propio del contenedor (su dominio, su entrypoint, si usa TLS o no). Los archivos son para lo que es global (los rate limits que aplican a todos los servicios, las cabeceras de seguridad que toda la infraestructura debe tener, los servicios externos que no están en Docker).
Configurar el File provider
Para usar el File provider, tienes que indicarlo en tu traefik.yml,
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
directory: /etc/traefik/dynamic/
watch: true
directory: el directorio donde Traefik buscará archivos de configuración. Puede ser también un archivo único confilenamesi prefieres tener todo en un solo sitio.watch: si estrue, Traefik monitoriza el directorio y recarga la configuración automáticamente cuando los archivos cambian. Sin necesidad de reiniciar.
Y en el docker-compose.yml montas el directorio,
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic:/etc/traefik/dynamic:ro
Fíjate que los montamos como :ro (read-only). En producción no tiene sentido que Traefik pueda escribir en sus propios archivos de configuración. Eso es cosa tuya, del administrador.
Usar un archivo único en lugar de un directorio
Si prefieres tener todo en un único archivo, puedes usar filename en lugar de directory,
providers:
file:
filename: /etc/traefik/dynamic.yml
watch: true
¿Cuál elegir? Te recomiendo el directorio desde el principio, aunque empieces con un solo archivo. ¿Por qué? Porque conforme tu infraestructura crece, separar por temas te evita tener que buscar entre mil líneas de YAML. Empieza con directorio, aunque solo tengas un archivo dentro. Cuando necesites separar, solo tienes que crear un archivo nuevo.
Puedes incluso combinar filename y directory si quieres cargar un archivo base y luego extensiones. Pero no te líes demasiado. Con el directorio tienes suficiente.
Estructura de un archivo de configuración dinámica
Los archivos de configuración dinámica siguen la misma estructura que las labels, pero en formato YAML.
http:
routers:
mi-router:
rule: Host(`app.dominio.com`)
service: mi-servicio
entryPoints:
- websecure
tls:
certResolver: letsencrypt
services:
mi-servicio:
loadBalancer:
servers:
- url: "http://192.168.1.10:3000"
healthCheck:
path: /health
interval: 10s
timeout: 3s
middlewares:
rate-limit:
rateLimit:
average: 100
burst: 200
period: 1m
Fíjate en la estructura: http como sección principal, y dentro routers, services, middlewares. Es exactamente lo mismo que ves en las labels de Docker, pero en YAML estructurado.
Para TCP y UDP la estructura es similar pero con tcp y udp como secciones principales. Da igual que mezcles todo en un mismo archivo o lo separes en varios. Traefik lo fusiona todo.
Secciones completas del File provider
Las secciones que puedes definir en el File provider son,
http.routers: reglas de enrutamiento para tráfico HTTP/HTTPS.http.services: definiciones de servicios HTTP con balanceo, health checks, sticky sessions.http.middlewares: middlewares que se aplican a las peticiones HTTP.http.serversTransports: configuración de transporte HTTP, como timeout, proxy inverso, o ignorar certificados.tcp.routers: reglas de enrutamiento para tráfico TCP.tcp.services: servicios TCP con balanceo de carga.tcp.middlewares: middlewares TCP (más limitados que los HTTP).udp.routers: routers para tráfico UDP.udp.services: servicios UDP.
Ya te habrás dado cuenta de que el modelo es el mismo para HTTP, TCP y UDP. Una vez que entiendes cómo funciona uno, los demás son exactamente igual pero cambiando la sección.
Middlewares compartidos
Este es el caso de uso más habitual del File provider. Definir middlewares una vez y usarlos desde cualquier contenedor Docker. Si has leído los capítulos anteriores sobre middlewares básicos y de autenticación, ya sabes lo potentes que son. Ahora vas a ver cómo centralizarlos.
Crea un archivo dynamic/middlewares.yml,
http:
middlewares:
rate-limit-100:
rateLimit:
average: 100
burst: 200
period: 1m
sec-headers:
headers:
customResponseHeaders:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "DENY"
X-XSS-Protection: "1; mode=block"
Referrer-Policy: "strict-origin-when-cross-origin"
Permissions-Policy: "camera=(), microphone=(), geolocation=()"
auth-basico-admin:
basicAuth:
usersFile: /etc/traefik/users.txt
solo-red-local:
ipAllowList:
sourceRange:
- "192.168.1.0/24"
- "10.0.0.0/8"
compresion:
compress:
excludedContentTypes:
- text/event-stream
redirect-https:
redirectRegex:
permanent: false
regex: "^http://"
replacement: "https://"
rate-limit-estricto:
rateLimit:
average: 20
burst: 40
period: 1m
Y luego en los labels de Docker los referencias con @file,
labels:
- "traefik.http.routers.mi-app.middlewares=rate-limit-100@file,sec-headers@file"
Fíjate en el @file al final. Eso le dice a Traefik que busque ese middleware en el File provider, no en las labels de Docker. Es el mismo mecanismo que usas para referenciar cualquier recurso de cualquier proveedor: nombre@nombre-del-proveedor.
Cadenas de middlewares de distintos proveedores
Puedes mezclar middlewares de Docker y del File provider en el mismo router. Esto es muy útil cuando tienes middlewares específicos del contenedor (definidos en sus labels) y quieres combinarles con los globales del File provider,
labels:
- "traefik.http.routers.mi-app.middlewares=rate-limit-100@file,sec-headers@file,mi-middleware-local@docker"
Traefik los ejecuta en el orden en que los listas. Primero el rate limit, luego las cabeceras de seguridad, y por último el middleware local del contenedor. Dale caña a este patrón, porque te permite construir pipelines de procesamiento muy modulares.
Middleware de redirect: caso real
Uno de los middlewares que más uso desde el File provider es el de redirección. Por ejemplo, para redirigir tráfico de un dominio antiguo a uno nuevo sin tocar cada contenedor,
http:
middlewares:
redirect-old-domain:
redirectRegex:
permanent: true
regex: "^https://antiguo.dominio.com/(.*)"
replacement: "https://nuevo.dominio.com/${1}"
Lo aplicas a un router y listo. Todos los que lleguen al dominio antiguo se redirigen automáticamente al nuevo, manteniendo la ruta. Esto te puede ahorrar más de un disgusto durante una migración.
Middleware de retry y circuit breaker
Para servicios críticos, puedes combinar reintentos con circuit breaker desde el File provider,
http:
middlewares:
retry-peticiones:
retry:
attempts: 3
initialInterval: 100ms
circuit-breaker-api:
circuitBreaker:
expression: "NetworkErrorRatio() > 0.5 || LatencyAtQuantileMS(50.0) > 100"
checkPeriod: 10s
fallbackDuration: 30s
recoveryDuration: 30s
El circuit breaker evita que un servicio que está fallando reciba más tráfico del que puede manejar, dándole tiempo para recuperarse. Y el retry reintenta peticiones fallidas automáticamente.
Middlewares que solo tienen sentido desde el File provider
Hay middlewares que raramente tienen sentido definirlos en las labels de Docker porque son globales por naturaleza. Por ejemplo,
IP AllowList para el dashboard
El dashboard de Traefik debería estar siempre protegido por IP. No tiene sentido ponerlo en las labels de un contenedor, porque el dashboard no es un contenedor como tal, es parte de Traefik.
http:
middlewares:
dashboard-auth:
basicAuth:
usersFile: /etc/traefik/users.txt
ipAllowList:
sourceRange:
- "192.168.1.0/24"
routers:
dashboard:
rule: Host(`traefik.dominio.com`)
service: api@internal
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
- dashboard-auth
Fíjate en el service: api@internal. Ese es el servicio interno del dashboard de Traefik. Solo puedes referenciarlo desde el File provider, no desde las labels de Docker.
Cabeceras de seguridad globales
Las cabeceras de seguridad como HSTS, Content-Security-Policy, o X-Frame-Options son típicamente globales. Quieres que todas tus aplicaciones las tengan. Definirlas en el File provider y referenciarlas desde cada contenedor es mucho más limpio que copiar las mismas veinte líneas de YAML en las labels de cada servicio.
Routers desde archivo
También puedes definir routers completos en archivos. Esto es útil para servicios que no están en Docker, o para configurar rutas que no pertenecen a ningún contenedor,
http:
routers:
api-externa:
rule: Host(`api.dominio.com`) && PathPrefix(`/v2`)
entryPoints:
- websecure
service: api-v2
tls:
certResolver: letsencrypt
middlewares:
- rate-limit-100@file
- sec-headers@file
landing-page:
rule: Host(`dominio.com`) || Host(`www.dominio.com`)
entryPoints:
- websecure
service: landing-estatico
tls:
certResolver: letsencrypt
priority: 10
api-publica:
rule: Host(`api.dominio.com`) && PathPrefix(`/public`)
entryPoints:
- websecure
service: api-publica
middlewares:
- rate-limit-estricto@file
Prioridades entre routers
Cuando tienes varios routers que pueden coincidir con la misma petición, Traefik usa la prioridad. Por defecto, la prioridad se calcula automáticamente: cuantos más matchers tenga la regla, mayor prioridad.
Pero a veces necesitas forzarla. Por ejemplo, si tienes un router genérico para Host(dominio.com) y otro específico para Host(dominio.com) && PathPrefix(/api), el específico tendrá prioridad automáticamente. Pero si quieres que un router con una regla simple tenga prioridad sobre otro con reglas más complejas, usa priority explícitamente.
http:
routers:
catchall:
rule: HostRegexp(`{subdomain:[a-z]+}.dominio.com`)
service: default-service
priority: 1
especifico:
rule: Host(`admin.dominio.com`)
service: admin-service
priority: 100
El router especifico tiene prioridad 100 frente al 1 del catchall. Así te aseguras de que admin.dominio.com va al servicio correcto y no se lo come el catchall.
Servicios externos (no Docker)
El File provider brilla cuando necesitas enrutar a servicios que no están en Docker. Por ejemplo, un servidor físico corriendo una base de datos, o un servicio en otra máquina,
http:
services:
postgres-externo:
loadBalancer:
servers:
- url: "http://192.168.1.50:5432"
api-terceros:
loadBalancer:
servers:
- url: "https://api.proveedor.com"
passHostHeader: false
landing-estatico:
loadBalancer:
servers:
- url: "http://10.0.0.10:8080"
healthCheck:
path: /healthz
interval: 30s
timeout: 5s
unhealthyStatuses:
- 500
- 503
Servicios con múltiples servidores y balanceo
Igual que configuraste en el capítulo anterior el balanceo de carga con las labels de Docker, puedes hacerlo desde el File provider,
http:
services:
api-cluster:
loadBalancer:
servers:
- url: "http://192.168.1.10:8080"
- url: "http://192.168.1.11:8080"
- url: "http://192.168.1.12:8080"
healthCheck:
path: /health
interval: 10s
timeout: 3s
sticky:
cookie:
name: _session
httpOnly: true
serversTransport: backend-transport
serversTransports:
backend-transport:
insecureSkipVerify: true
maxIdleConnsPerHost: 100
forwardingTimeouts:
dialTimeout: 10s
responseHeaderTimeout: 10s
Esto configura un cluster de tres servidores con health check cada 10 segundos, sticky sessions mediante cookie, y un transporte personalizado que ignora certificados SSL (útil cuando los backends usan certificados autofirmados).
Sticky sessions con configuración avanzada
Las sticky sessions que viste en el capítulo anterior también se configuran desde archivo,
http:
services:
app-sesion:
loadBalancer:
servers:
- url: "http://10.0.0.1:3000"
- url: "http://10.0.0.2:3000"
- url: "http://10.0.0.3:3000"
sticky:
cookie:
name: "traefik-session"
secure: true
httpOnly: true
sameSite: "lax"
maxAge: 3600
Esto te puede ahorrar más de un disgusto si tienes aplicaciones que guardan estado en memoria. Configuras la cookie, la marcas como segura y httpOnly, y los usuarios siempre caen en la misma instancia mientras la cookie sea válida.
Configuración dinámica para TCP y UDP
El File provider también funciona para TCP y UDP. En el capítulo 12 veremos esto en profundidad, pero te adelanto cómo se estructura por si necesitas enrutar tráfico TCP desde ya,
tcp:
routers:
mumble-server:
rule: HostSNI(`*`)
entryPoints:
- mumble
service: mumble-servicio
tls:
passthrough: true
postgres-remoto:
rule: HostSNI(`db.dominio.com`)
entryPoints:
- postgres
service: postgres-cluster
tls:
passthrough: true
services:
mumble-servicio:
loadBalancer:
servers:
- address: "192.168.1.100:64738"
postgres-cluster:
loadBalancer:
servers:
- address: "192.168.1.20:5432"
- address: "192.168.1.21:5432"
healthCheck:
path: "/health"
interval: 5s
timeout: 3s
udp:
routers:
dns-server:
entryPoints:
- dns
service: dns-cluster
services:
dns-cluster:
loadBalancer:
servers:
- address: "10.0.0.53:53"
- address: "10.0.0.54:53"
Con TCP y UDP la estructura es calcada a HTTP: routers que definen reglas, servicios que apuntan a servidores, y middlewares donde aplican.
Varios archivos de configuración
Puedes tener varios archivos en el directorio dynamic/ y Traefik los cargará todos. Esto te permite organizar la configuración por temas,
dynamic/
├── middlewares.yml # Middlewares compartidos
├── routers.yml # Routers globales
├── servicios-externos.yml # Servicios fuera de Docker
├── tcp.yml # Configuración TCP/UDP
├── security.yml # Cabeceras de seguridad y whitelists
└── dashboard.yml # Router y middlewares del dashboard
Traefik los carga todos y los fusiona automáticamente. Si hay conflictos (dos archivos definen el mismo router), Traefik te lanzará un error. Así que asegúrate de que los nombres de routers, servicios y middlewares sean únicos en todo el conjunto de archivos.
Orden de carga y fusión
Traefik no garantiza un orden de carga específico. Lo que sí garantiza es que la fusión es completa: si un archivo define routers y otro define middlewares, el resultado final contiene todo. El problema llega cuando dos archivos definen el mismo recurso con distinta configuración. Ahí Traefik lanza un error y no aplica ninguno de los dos.
Para evitar esto, te recomiendo una convención de nombres: prefija cada recurso según el archivo donde está definido. Por ejemplo,
# middlewares.yml
http:
middlewares:
mw-rate-limit-global:
mw-sec-headers-global:
# routers.yml
http:
routers:
rt-api-externa:
rt-dashboard:
# servicios-externos.yml
http:
services:
svc-api-cluster:
svc-landing:
No es obligatorio, pero cuando tienes veinte middlewares y quince routers, agradeces tener nombres que te digan de un vistazo qué es cada cosa.
Configuración por directorios anidados
Una técnica avanzada es organizar los archivos en subdirectorios. Traefik no los soporta de forma nativa, pero puedes usar un truco con montajes de Docker: monta varios directorios en el mismo punto de montaje,
services:
traefik:
volumes:
- ./dynamic/middlewares:/etc/traefik/dynamic/middlewares:ro
- ./dynamic/routers:/etc/traefik/dynamic/routers:ro
- ./dynamic/services:/etc/traefik/dynamic/services:ro
Pero esto es más complicado de mantener. Te recomiendo que te quedes con un solo directorio plano. Es más sencillo y cumple su función.
Recarga en caliente
Una de las grandes ventajas del File provider con watch: true es que puedes modificar los archivos y Traefik los recarga sin necesidad de reiniciar.
Esto es muy útil cuando,
- Añades un nuevo middleware compartido.
- Cambias la IP de un servidor externo porque lo has migrado a otra máquina.
- Añades un router nuevo para un servicio que acabas de poner en marcha.
- Modificas las cabeceras de seguridad para cumplir con un nuevo requisito.
- Desactivas temporalmente un servicio cambiando su router.
Solo tienes que editar el archivo y guardar. Traefik lo detecta y aplica los cambios en segundos. Sin reinicios, sin cortes de servicio, sin tener que esperar a que el contenedor se levante otra vez.
Cómo verificar que la recarga ha funcionado
Cuando modificas un archivo, puedes verificar que Traefik lo ha cargado correctamente de varias formas,
- En los logs de Traefik: busca líneas como
Configuration loaded from file provider. - En el dashboard: los recursos aparecen automáticamente si la recarga ha ido bien.
- Con la API de Traefik: haz una petición al endpoint
/api/http/routerspara ver los routers activos.
curl -s https://traefik.dominio.com/api/http/routers | jq '.'
Si algo falla, Traefik no se cae. Simplemente ignora el archivo con errores y se queda con la última configuración válida. Esto te puede ahorrar más de un disgusto si cometes un error de sintaxis en medio de la noche.
Errores típicos en la recarga
El error más común es tener un YAML mal formado. Un espacio de más o un tabulador en lugar de espacios y el archivo no se carga. Traefik es muy sensible a la indentación. Usa siempre espacios, nunca tabuladores.
Otro error típico es referenciar un middleware o servicio que no existe. Si desde un router haces referencia a middlewares: - rate-limit-100@file pero ese middleware no está definido en ningún archivo, Traefik rechazará la configuración y se quedará con la anterior.
Para evitar estos problemas, te recomiendo validar tus archivos YAML antes de copiarlos al servidor. Puedes usar herramientas como yamllint o incluso el propio Traefik en modo dry-run,
docker run --rm -v $(pwd)/dynamic:/dynamic traefik:v3.7 traefik healthcheck
No es un validador exhaustivo, pero te da una primera línea de defensa.
Ejemplo práctico completo
Voy a dejarte un ejemplo completo con File provider, con varios servicios reales,
traefik.yml:
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
postgres:
address: ":5432"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
file:
directory: /etc/traefik/dynamic
watch: true
api:
dashboard: true
certificatesResolvers:
letsencrypt:
acme:
email: tu@email.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
dynamic/middlewares.yml:
http:
middlewares:
rate-limit-50:
rateLimit:
average: 50
burst: 100
period: 1m
sec-headers:
headers:
customResponseHeaders:
X-Content-Type-Options: "nosniff"
X-Frame-Options: "DENY"
X-XSS-Protection: "1; mode=block"
Referrer-Policy: "strict-origin-when-cross-origin"
customRequestHeaders:
X-Forwarded-Proto: "https"
auth-admin:
basicAuth:
usersFile: /etc/traefik/users.txt
geobloqueo-api:
plugin:
geoblock:
allowedCountries:
- "ES"
- "MX"
- "AR"
api: "https://geo.api.proveedor.com"
retry-3:
retry:
attempts: 3
initialInterval: 500ms
dynamic/routers.yml:
http:
routers:
dashboard:
rule: Host(`traefik.dominio.com`)
service: api@internal
entryPoints:
- websecure
tls:
certResolver: letsencrypt
middlewares:
- auth-admin
api-publica:
rule: Host(`api.dominio.com`) && PathPrefix(`/v1`)
entryPoints:
- websecure
service: api-v1-externa
tls:
certResolver: letsencrypt
middlewares:
- rate-limit-50
- sec-headers
dynamic/servicios-externos.yml:
http:
services:
api-v1-externa:
loadBalancer:
servers:
- url: "http://10.0.0.10:4000"
- url: "http://10.0.0.11:4000"
healthCheck:
path: /api/health
interval: 10s
timeout: 3s
sticky:
cookie:
name: "api-session"
httpOnly: true
docker-compose.yml:
services:
traefik:
image: traefik:v3.7
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic:/etc/traefik/dynamic:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./users.txt:/etc/traefik/users.txt:ro
networks:
- traefik-net
nextcloud:
image: nextcloud:stable
volumes:
- ./nextcloud:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.routers.nextcloud.rule=Host(`cloud.dominio.com`)"
- "traefik.http.routers.nextcloud.entrypoints=websecure"
- "traefik.http.routers.nextcloud.tls=true"
- "traefik.http.routers.nextcloud.tls.certresolver=letsencrypt"
- "traefik.http.routers.nextcloud.middlewares=rate-limit-50@file,sec-headers@file"
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
networks:
- traefik-net
wordpress:
image: wordpress:latest
volumes:
- ./wordpress:/var/www/html
labels:
- "traefik.enable=true"
- "traefik.http.routers.wordpress.rule=Host(`blog.dominio.com`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls=true"
- "traefik.http.routers.wordpress.tls.certresolver=letsencrypt"
- "traefik.http.routers.wordpress.middlewares=sec-headers@file"
networks:
- traefik-net
networks:
traefik-net:
name: traefik-net
Fíjate en cómo NextCloud usa el rate limit y las cabeceras de seguridad desde el File provider, mientras que WordPress solo usa las cabeceras. Cada servicio aplica los middlewares que necesita, sin tener que definirlos. Así mantienes la configuración limpia y evitas duplicar YAML.
Casos prácticos reales
Voy a contarte tres situaciones reales donde el File provider me ha sacado de un apuro.
Caso 1: Migración de servidores sin cortes
Tenía un servicio crítico que apuntaba a un servidor físico en 192.168.1.100:8080. Había que migrarlo a un cluster nuevo en 10.0.0.10:8080 y 10.0.0.11:8080. Con el File provider, el cambio fue editar el archivo servicios-externos.yml, cambiar el servidor único por los dos nuevos, y guardar. Traefik recargó en caliente. Ni un solo corte de servicio.
# Antes
http:
services:
app-legacy:
loadBalancer:
servers:
- url: "http://192.168.1.100:8080"
# Después
http:
services:
app-legacy:
loadBalancer:
servers:
- url: "http://10.0.0.10:8080"
- url: "http://10.0.0.11:8080"
healthCheck:
path: /health
Caso 2: Bloquear un ataque por IP
Me llegó un aviso de que una IP estaba haciendo scraping agresivo a una API pública. En lugar de tocar el firewall o modificar el docker-compose, añadí un middleware en caliente,
http:
middlewares:
bloquear-scraper:
ipAllowList:
sourceRange:
- "203.0.113.0/32"
rejectStatusCode: 429
Y lo referencié desde el router de la API. El cambio fue inmediato. El scraper empezó a recibir 429 Too Many Requests. Sin reiniciar nada.
Caso 3: Añadir autenticación a un servicio legacy
Un servicio antiguo no tenía autenticación. Había que protegerlo hasta que el equipo de desarrollo lo actualizara. En cinco minutos,
- Generé un fichero
users.txtconhtpasswd. - Añadí el middleware
auth-basico-adminal archivomiddlewares.yml. - Lo referencié en el router del servicio legacy desde el File provider.
El servicio legacy ni se enteró. Para él, todas las peticiones llegaban igual. Traefik se encargaba de autenticar antes de pasar la petición.
Buenas prácticas
- Separa la configuración en varios archivos: middlewares, routers, servicios externos. Así es más fácil de mantener y de encontrar lo que buscas.
- Usa
watch: truepara recarga automática. Editas el archivo y Traefik lo aplica sin reiniciar. Esto es clave en producción. - Para middlewares compartidos, el File provider es la opción correcta. No los dupliques en labels de cada contenedor. Centraliza y reutiliza.
- Para servicios en Docker, usa las labels. Es más natural, la configuración viaja con el contenedor, y al hacer deploy de una nueva versión, la configuración se actualiza sola.
- Usa
@filepara referenciar recursos del File provider desde las labels de Docker. Y recuerda que también puedes referenciar recursos de Docker con@docker. - Valida el YAML antes de subirlo. Un error de sintaxis y Traefik ignora el archivo. Usa
yamllinto tu editor favorito. - Pon nombres descriptivos a tus middlewares y routers.
rate-limit-50es mejor querl1. Cuando tengas veinte middlewares, lo agradecerás. - Los archivos en
:ro: monta los archivos de configuración como read-only. Traefik no necesita escribir en ellos. - Monitorea los logs de Traefik cuando modifiques archivos en producción. Un vistazo rápido a los logs te confirma que la recarga ha ido bien.
- Usa prioridades con cabeza: no pongas priority a todo. Solo cuando necesites forzar el orden entre routers que compiten por la misma ruta.
Conclusión
El File provider te da flexibilidad para centralizar la configuración que se comparte entre servicios, y para enrutar tráfico a servidores que no están en Docker. Combinado con el Docker provider, tienes lo mejor de ambos mundos: la configuración específica viaja con cada contenedor, y la configuración global está centralizada en archivos que puedes modificar en caliente.
La recarga en caliente es una de esas características que cuando la pruebas, no entiendes cómo has podido vivir sin ella. Editas un archivo, guardas, y el cambio se aplica en segundos. Sin reinicios, sin cortes de servicio, sin tener que levantar contenedores.
En el próximo capítulo veremos los Plugins, cómo extender Traefik más allá de los middlewares que vienen por defecto. Verás cómo instalar plugins, cómo configurarlos desde el File provider, y cómo combinarlos con todo lo que has aprendido hasta ahora. Dale caña.
Más información
- File provider — Documentación oficial de Traefik v3
- Dynamic Configuration Methods — Traefik v3
- File Routing Configuration Reference — Traefik v3
- HTTP Middlewares Reference — Traefik v3
- IPAllowList Middleware — Traefik v3
- Retry Middleware — Traefik v3
- Circuit Breaker Middleware — Traefik v3
- Providers Overview — Traefik v3
- Migración de v2 a v3 — IPWhiteList a IPAllowList
- Tutorial Traefik — atareao.es