Docker: reglas de enrutamiento de Traefik que fallan silenciosamente — corrige las etiquetas correctamente

¿Te fue útil?

Desplegaste. Los contenedores están sanos. Los puertos están abiertos. El DNS apunta correctamente. Y aun así Traefik devuelve un tranquilo e indiferente 404 page not found como si te estuviera haciendo un favor.

Este modo de fallo es la razón por la que la gente llama a los proxies inversos “simples”: porque simplifican tu sistema concentrando todos tus errores en un solo lugar. Traefik + etiquetas Docker es potente, pero también es una trampa peligrosa con bozal educado. No siempre gritará cuando tus reglas de ruta no coincidan. Simplemente… no enruta nada.

Qué significa realmente “falla silenciosa” en Traefik

“Falla silenciosa” no significa que Traefik esté roto. Significa que Traefik está haciendo exactamente lo que le dijiste—basado en etiquetas que le dijiste por error.

Síntomas típicos:

  • Traefik devuelve 404 page not found para un host que estás seguro existe.
  • Golpeas el entrypoint de Traefik, pero el router nunca coincide, así que cae al manejador por defecto (404).
  • El contenedor está arriba y escuchando, pero Traefik enruta al puerto interno equivocado (o a ninguno).
  • Las middlewares no se aplican, TLS no se activa, las redirecciones no ocurren y te sientes perseguido.

Traefik no es “silencioso” si sabes dónde mirar: el panel, la configuración del proveedor, la vista de configuración dinámica y los logs. El silencio está en tu terminal porque las etiquetas Docker son fáciles de escribir mal y difíciles de validar visualmente.

Hechos interesantes y un poco de contexto

  1. Traefik popularizó la “descubierta de configuración” en la era de contenedores: vigila eventos Docker, construye rutas dinámicamente y evita configuraciones de proxy editadas a mano.
  2. Las etiquetas Docker preceden al dominio de Traefik; eran una característica genérica de metadatos que los proxies inversos reutilizaron como plano de control completo.
  3. Traefik v2 fue un cambio mental rompedor: routers, services y middlewares reemplazaron el modelo más simple frontend/backend de v1. Muchas configuraciones de “funcionaba el año pasado” murieron aquí.
  4. El parseo de reglas se volvió más estricto con el tiempo: pequeños errores de sintaxis en Host(), comillas o backticks a menudo impiden que un router exista del todo.
  5. Los EntryPoints no son puertos; son oyentes nombrados. Un router ligado a websecure no coincidirá con tráfico que llegue por web, aunque ambos estén en el mismo contenedor.
  6. Los tipos YAML de Docker Compose muerden fuerte: una etiqueta que parece string puede ser parseada de forma extraña a menos que la pongas entre comillas.
  7. Los valores por defecto de Traefik pueden ocultar tu intención: si exposedByDefault es true, podrías enrutar accidentalmente a contenedores que nunca etiquetaste—hasta que lo cambias y todo desaparece.
  8. Los experimentos con HTTP/3 cambiaron expectativas: las pilas modernas empujan QUIC; los entrypoints y ajustes TLS desalineados son ahora más visibles porque los clientes reintentan de forma distinta.

Guía rápida de diagnóstico (haz esto en orden)

Si estás de guardia y perdiendo minutos, deja de adivinar. Revisa el sistema tal como Traefik lo ve.

1) ¿Está Traefik recibiendo la petición por el entrypoint que crees?

  • Confirma que el cliente golpea la IP/DNS correcta.
  • Confirma que la petición llega a Traefik (no a una página de salud del balanceador de carga en la nube o a una IP antigua).
  • Confirma HTTP vs HTTPS y el host SNI.

2) ¿Tiene Traefik un router que podría coincidir?

  • Revisa el panel o la API para ver routers.
  • Busca el nombre de tu router; verifica la regla, entrypoints, TLS y el enlace al servicio.

3) Si el router existe, ¿coincide?

  • Compara host/path de la petición con la regla exactamente.
  • Busca conflictos de prioridad y routers “catch-all”.

4) Si coincide, ¿puede Traefik alcanzar el servicio?

  • Valida la conectividad de red Docker: Traefik debe compartir una red con el contenedor destino.
  • Verifica que el puerto que usa Traefik sea correcto: un puerto de balanceador explícito vence a la autodetección.

5) Si llega al servicio, ¿las middlewares y TLS hacen lo que crees?

  • Confirma nombres de la cadena de middlewares y el scope del proveedor (@docker vs @file).
  • Verifica ajustes TLS: tls=true, certresolver, dominios y entrypoint.

Ese es el orden. No lo inviertas. La mayor parte del tiempo se pierde depurando “certs” cuando el router nunca coincidió en primer lugar.

Cómo decide Traefik a dónde va el tráfico (y por qué importan las etiquetas)

En Traefik v2, el flujo de la petición es:

  1. EntryPoint acepta la conexión (ejemplo: web en :80, websecure en :443).
  2. Router coincide con la petición (regla: host/path/headers, además de entrypoints y requisito TLS).
  3. Middlewares mutan la petición/respuesta (redirección, auth, headers, limitación, etc.).
  4. Service define el upstream (IP:puerto del contenedor, opciones de balanceo).

Las etiquetas Docker son la fuente de configuración dinámica. El proveedor Docker vigila contenedores y traduce etiquetas en routers/services/middlewares.

Aquí está lo crucial: Traefik felizmente funciona con una configuración parcial. Si la etiqueta de tu router está malformada, Traefik podría no crear ese router en absoluto. Si tu router existe pero apunta a una middleware inexistente, puede fallar al adjuntarla. Si falta la etiqueta del puerto del servicio y Docker expone múltiples puertos, Traefik podría elegir el incorrecto.

Y si ningún router coincide, Traefik devuelve un 404 que se ve exactamente como “Traefik está arriba”. Por eso la gente pierde horas.

Una cita que vale la pena recordar, porque resume todo el trabajo:

“La esperanza no es una estrategia.” — Gene Kranz

Depurar etiquetas en Traefik es donde la esperanza va a morir. Bien. Cámbiala por observabilidad y convenciones.

Corrige las etiquetas correctamente: patrones que no se degradan

Principio 1: Nombra siempre routers, servicios y middlewares explícitamente

Confiar en nombres implícitos es cómo terminas preguntándote “¿por qué Traefik está adjuntando el servicio equivocado?” a las 2 a.m. Usa nombres estables. Úsalos en todas partes.

Principio 2: Especifica siempre el puerto del servicio

Sí, Traefik puede autodetectar puertos. No, no deberías dejarlo, a menos que disfrutes del enrutamiento probabilístico.

Regla práctica: si un contenedor expone múltiples puertos, o si usas puertos de salud/administración, siempre establece:

  • traefik.http.services.<service>.loadbalancer.server.port

Principio 3: Usa un router por hostname + entrypoint, luego compón el comportamiento con middlewares

No metas demasiado en una sola regla de router. Mantén el matching simple; mantén el comportamiento modular.

Principio 4: Pon comillas a los valores de las etiquetas en Compose (y sé consistente con backticks)

Compose es YAML. YAML tiene opiniones. La sintaxis de reglas de Traefik también tiene opiniones. Estás atrapado entre dos parsers con definiciones distintas de “string”. Pon tus etiquetas entre comillas. Usa backticks dentro de reglas de Traefik de forma consistente.

Bueno (entre comillas): "Host(`app.example.com`) && PathPrefix(`/api`)"
Malo (sin comillas): Host(`app.example.com`) (funciona a veces, hasta que deja de hacerlo)

Principio 5: Decide si quieres exponer contenedores por defecto. Luego hazlo cumplir.

En producción, configura el proveedor Docker con exposedByDefault=false y habilita explícitamente por servicio con traefik.enable=true. Esto reduce exposiciones accidentales y también hace que los fallos sean más claros: si no está habilitado, no aparecerá.

Broma #1: Si mantienes exposedByDefault=true, no estás ejecutando un proxy inverso—estás ejecutando un generador de sorpresas.

Ejemplo canónico de Compose que evita fallos silenciosos

Este patrón tiene menos piezas móviles y falla más ruidosamente:

cr0x@server:~$ cat docker-compose.yml
version: "3.9"

networks:
  edge:
    external: true

services:
  traefik:
    image: traefik:v2.11
    command:
      - --api.dashboard=true
      - --api.insecure=false
      - --entrypoints.web.address=:80
      - --entrypoints.websecure.address=:443
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      - --providers.docker.network=edge
      - --log.level=INFO
      - --accesslog=true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - edge
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(`traefik.example.com`)"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls=true"
      - "traefik.http.routers.traefik.service=api@internal"

  app:
    image: ghcr.io/example/app:latest
    environment:
      - PORT=8080
    networks:
      - edge
    labels:
      - "traefik.enable=true"

      - "traefik.http.routers.app.rule=Host(`app.example.com`)"
      - "traefik.http.routers.app.entrypoints=websecure"
      - "traefik.http.routers.app.tls=true"
      - "traefik.http.routers.app.service=app-svc"

      - "traefik.http.services.app-svc.loadbalancer.server.port=8080"

      - "traefik.http.middlewares.app-headers.headers.framedeny=true"
      - "traefik.http.routers.app.middlewares=app-headers"

Fíjate en lo explícito:

  • Traefik usa una red Docker específica (--providers.docker.network=edge).
  • El puerto del servicio app está fijado a 8080.
  • Los nombres de router/servicio/middleware son estables y referenciados explícitamente.
  • Traefik en sí mismo está enrutado vía api@internal, lo que reduce la confusión de “¿por qué no funciona el panel?”.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estos son los chequeos que realmente ejecuto. Cada tarea incluye: comando, salida típica, qué significa y la decisión que tomas.

Task 1: Confirmar que el contenedor Traefik está en ejecución y qué imagen/versión

cr0x@server:~$ docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
NAMES      IMAGE          STATUS          PORTS
traefik    traefik:v2.11  Up 2 hours      0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
app        ghcr.io/example/app:latest  Up 2 hours

Significado: Traefik está en ejecución y enlazando :80/:443 en el host.

Decisión: Si Traefik no está arriba o los puertos no están mapeados, detente. Arregla el ciclo de vida del contenedor o el firewall del host antes de tocar etiquetas.

Task 2: Inspeccionar flags de arranque de Traefik (providers, exposedByDefault, network)

cr0x@server:~$ docker inspect traefik --format '{{json .Config.Cmd}}'
["--api.dashboard=true","--entrypoints.web.address=:80","--entrypoints.websecure.address=:443","--providers.docker=true","--providers.docker.exposedbydefault=false","--providers.docker.network=edge","--log.level=INFO","--accesslog=true"]

Significado: El proveedor Docker está activado, la exposición por defecto está desactivada, y Traefik buscará backends en la red edge.

Decisión: Si --providers.docker.network está establecido, tu app debe estar adjunta a esa red o el enrutamiento fallará.

Task 3: Verificar que el contenedor app esté en la misma red Docker que espera Traefik

cr0x@server:~$ docker inspect app --format '{{json .NetworkSettings.Networks}}'
{"edge":{"IPAMConfig":null,"Links":null,"Aliases":["app","3e9c1b7b4a2d"],"MacAddress":"02:42:ac:18:00:05","DriverOpts":null,"NetworkID":"b7b9d6c3b34a","EndpointID":"f2b59b5f8e67","Gateway":"172.24.0.1","IPAddress":"172.24.0.5","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"DNSNames":["app","3e9c1b7b4a2d"]}}

Significado: La app está en edge con una IP que Traefik puede enrutar.

Decisión: Si la app no está en esa red, añádela. No “simplemente abras un puerto” a menos que quieras eludir tu proxy por completo.

Task 4: Confirmar las etiquetas que Traefik leerá (y detectar errores tipográficos rápido)

cr0x@server:~$ docker inspect app --format '{{json .Config.Labels}}' | jq -r 'to_entries[] | "\(.key)=\(.value)"' | sort
traefik.enable=true
traefik.http.routers.app.entrypoints=websecure
traefik.http.routers.app.rule=Host(`app.example.com`)
traefik.http.routers.app.service=app-svc
traefik.http.routers.app.tls=true
traefik.http.routers.app.middlewares=app-headers
traefik.http.middlewares.app-headers.headers.framedeny=true
traefik.http.services.app-svc.loadbalancer.server.port=8080

Significado: Las etiquetas están presentes y escritas correctamente. Ahora puedes razonar sobre la configuración de Traefik de forma determinista.

Decisión: Si ves traefik.http.router (falta la “s”), o nombres desajustados, corrige las etiquetas antes de tocar cualquier otra cosa.

Task 5: Revisar logs de Traefik por errores del proveedor (parseo, middleware faltante)

cr0x@server:~$ docker logs traefik --since 15m | tail -n 20
time="2026-01-03T09:18:41Z" level=info msg="Configuration loaded from flags."
time="2026-01-03T09:21:10Z" level=info msg="Skipping same configuration for provider docker"
time="2026-01-03T09:22:07Z" level=error msg="middleware \"app-auth@docker\" does not exist" routerName=app@docker entryPointName=websecure
time="2026-01-03T09:22:07Z" level=error msg="error while adding middleware: middleware \"app-auth@docker\" does not exist" entryPointName=websecure routerName=app@docker

Significado: El router existe, pero referencia una middleware que no existe. Esto a menudo aún enruta, solo sin la middleware, lo cual es su propio tipo de “falla silenciosa”.

Decisión: Define la middleware con la etiqueta correspondiente o elimínala del router. No dejes referencias rotas; se convierten en fallos de seguridad con el tiempo.

Task 6: Validar que los routers existen consultando la API de Traefik (dentro del contenedor)

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | head -n 20'
[{"entryPoints":["websecure"],"service":"app-svc@docker","rule":"Host(`app.example.com`)","status":"enabled","using":["websecure"],"name":"app@docker"},{"entryPoints":["websecure"],"service":"api@internal","rule":"Host(`traefik.example.com`)","status":"enabled","using":["websecure"],"name":"traefik@docker"}]

Significado: Tu router es real en la configuración dinámica de Traefik, no solo en tu imaginación.

Decisión: Si tu router falta aquí, Traefik no lo cargó. Eso es un problema de etiquetas, una restricción del proveedor o la configuración de exposición.

Task 7: Confirmar el puerto del servicio que Traefik usará

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/services | jq -r ".[] | select(.name==\"app-svc@docker\") | .loadBalancer.servers"'
[
  {
    "url": "http://172.24.0.5:8080"
  }
]

Significado: Traefik apunta a la IP y puerto correctos.

Decisión: Si ves el puerto equivocado (a menudo 80), fija explícitamente loadbalancer.server.port y redepliega.

Task 8: Probar el backend directamente desde el contenedor Traefik (chequeo de ruta de red)

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qSO- http://172.24.0.5:8080/health -O /dev/null'
  HTTP/1.1 200 OK
  Content-Type: application/json
  Date: Sat, 03 Jan 2026 09:25:01 GMT
  Content-Length: 17

Significado: La conectividad está bien; los fallos están en el enrutamiento/matching/TLS/middleware, no en la alcanzabilidad de red.

Decisión: Si esto falla, arregla la red Docker, el puerto en que escucha el contenedor o el binding de la app (0.0.0.0 vs 127.0.0.1).

Task 9: Verificar que la cabecera Host de la petición coincide con la regla del router

cr0x@server:~$ curl -sS -D- -o /dev/null -H 'Host: app.example.com' http://127.0.0.1/
HTTP/1.1 301 Moved Permanently
Location: https://app.example.com/
Date: Sat, 03 Jan 2026 09:25:28 GMT
Content-Length: 17
Content-Type: text/plain; charset=utf-8

Significado: Algo hizo match en HTTP y probablemente redirigió a HTTPS (ya sea vía middleware o redirección en entrypoint).

Decisión: Si obtienes 404 aquí, la regla del router no coincidió. Revisa las comillas de Host, el dominio y los entrypoints.

Task 10: Confirmar el enrutamiento HTTPS y el comportamiento de certificados (SNI importa)

cr0x@server:~$ curl -sS -D- -o /dev/null https://app.example.com/
HTTP/2 200
content-type: text/html; charset=utf-8
date: Sat, 03 Jan 2026 09:26:02 GMT
server: traefik

Significado: TLS funciona y el router hace match en websecure.

Decisión: Si el handshake TLS falla o ves el certificado equivocado, revisa flags TLS del router, el certresolver y si estás golpeando la instancia Traefik correcta.

Task 11: Detectar conflictos de reglas y problemas de prioridad

cr0x@server:~$ docker exec -it traefik sh -lc 'wget -qO- http://127.0.0.1:8080/api/http/routers | jq -r ".[] | [.name,.rule,(.priority|tostring)] | @tsv" | sort -k2'
app@docker	Host(`app.example.com`)	
catchall@docker	HostRegexp(`{any:.+}`)	1

Significado: Tienes un router catch-all que puede robar tráfico si su prioridad es mayor o si tu router de app no coincide exactamente.

Decisión: Establece prioridades explícitas. No confíes en que “probablemente se ordene solo.” No lo hará.

Task 12: Revisar eventos Docker para ver si Traefik está notando cambios en contenedores

cr0x@server:~$ docker events --since 5m --filter type=container --filter event=start
2026-01-03T09:24:10.128722391Z container start 3e9c1b7b4a2d (image=ghcr.io/example/app:latest, name=app)

Significado: Docker está emitiendo eventos de ciclo de vida; Traefik debería captarlos si tiene acceso al socket.

Decisión: Si Traefik no se está actualizando, confirma que el montaje del socket Docker está presente y que los permisos de lectura son suficientes.

Task 13: Confirmar que Traefik puede leer el socket Docker (común en entornos hardening)

cr0x@server:~$ docker exec -it traefik sh -lc 'ls -l /var/run/docker.sock'
srw-rw----    1 root     docker           0 Jan  3 08:01 /var/run/docker.sock

Significado: El socket existe. Los permisos pueden seguir siendo un problema dependiendo del usuario con que corra Traefik.

Decisión: Si Traefik corre como un usuario no-root y no puede leer este socket, verás errores del proveedor y routers faltantes. Arregla usuario/grupo o ejecuta con permisos adecuados.

Task 14: Validar el archivo Compose que realmente desplegaste (no el que editaste)

cr0x@server:~$ docker compose config | sed -n '1,120p'
services:
  app:
    image: ghcr.io/example/app:latest
    labels:
      traefik.enable: "true"
      traefik.http.routers.app.entrypoints: websecure
      traefik.http.routers.app.rule: Host(`app.example.com`)
      traefik.http.routers.app.service: app-svc
      traefik.http.routers.app.tls: "true"
      traefik.http.services.app-svc.loadbalancer.server.port: "8080"
networks:
  edge:
    external: true

Significado: Esta es la configuración renderizada después de que Compose fusiona, interpola variables y parsea YAML. Es la verdad.

Decisión: Si las etiquetas renderizadas difieren (comillas faltantes, cadenas truncadas), corrige la fuente Compose. Depurar el archivo equivocado es un clásico auto-atentado.

Tres microhistorias del mundo corporativo

Microhistoria 1: El incidente causado por una suposición equivocada

Estaban migrando una app orientada al cliente desde una configuración Nginx escrita a mano a Traefik con etiquetas Docker. El plan parecía bueno: cada servicio tenía etiquetas y había una red “edge” ordenada. Incluso alguien escribió un README, que es la señal de que esto iba a doler.

La suposición equivocada: “Si el contenedor es accesible desde el host, Traefik también puede alcanzarlo.” Exposaron la app en 0.0.0.0:8080 para pruebas y confirmaron que funcionaba con curl http://host:8080. Luego removieron el mapeo de puertos porque “Traefik maneja el ingreso ahora”.

Despliegue en producción: Traefik devolvió 404 para el hostname. La gente persiguió DNS, luego certificados, luego “quizá el load balancer”. Mientras tanto, el servicio estaba sano y los logs tranquilos. El equipo de app empezó a sugerir rollback. El equipo de plataforma empezó a sugerir oración.

El problema fue aburrido: Traefik estaba configurado con --providers.docker.network=edge, pero el contenedor app sólo estaba adjunto a la red Compose por defecto. Traefik nunca vio un endpoint que pudiera usar. Sin red, no hay servicio, no hay ruta.

La solución tomó cinco minutos: adjuntar la app a edge y redeplegar. El postmortem tomó más tiempo, porque lo difícil no fue la corrección; fue admitir que habían “probado” un camino de red distinto al de producción.

Microhistoria 2: La optimización que salió mal

Otra compañía tenía una iniciativa de “las etiquetas deben ser mínimas”. La lógica no era loca: demasiadas etiquetas son difíciles de leer y los errores por copy-paste son reales. Así que eliminaron etiquetas explícitas de puerto de servicio, confiando en la autodetección de Traefik. Funcionó para la mayoría de servicios. Esa es la trampa: el éxito parcial es la forma más cara de fallo.

Más tarde, un servicio añadió un segundo puerto expuesto para métricas. Docker ahora mostraba dos candidatos. Traefik eligió uno. Era el incorrecto. Las peticiones fueron al endpoint de métricas, que respondía rápido pero no útilmente. Los clientes vieron 404s y respuestas “not found”. Nada estaba técnicamente caído; todo estaba prácticamente roto.

El on-call inicialmente culpó a un mal deploy. El rollback no ayudó porque la exposición del puerto de métricas se mantuvo. Culparon a Traefik. Subieron recursos. Cambiaron timeouts. Añadieron reintentos (que lo hizo más ruidoso).

La solución real fue deshacer la “optimización” y fijar la etiqueta de puerto del servicio. La lección no fue “la autodetección es mala”. La lección fue: en producción, la ambigüedad es un bug que aún no has conocido.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Un equipo fintech tenía un hábito que parecía molesto y ceremonial: cada cambio en el proxy inverso requería un “ensayo de ruta” en staging, incluyendo una consulta scriptada a las APIs de routers y services de Traefik. No confiaban en el panel. No confiaban en mirar etiquetas a simple vista. Ejecutaban un script y archivaban la salida con el ticket del cambio.

Durante un despliegue rutinario, un desarrollador renombró un router de billing a billing-app pero olvidó actualizar la referencia a la middleware. Traefik registró un error sobre la middleware faltante, pero la ruta siguió sirviendo tráfico—solo que sin una middleware de auth que imponía acceso interno solamente.

En muchas organizaciones, así es como terminas con un incidente de seguridad que empieza con “no pensábamos que era alcanzable”. Aquí, el ensayo en staging lo atrapó porque su script afirmaba que el router tenía la cadena de middlewares esperada adjunta.

Arreglaron la etiqueta antes de que llegara a producción. El ritual aburrido pareció burocracia hasta que evitó un incidente que habría sido caro y humillante. Esto es lo que parece la “cultura de fiabilidad” cuando realmente funciona.

Errores comunes: síntoma → causa raíz → solución

Estos son los reincidentes. Si Traefik “falla silenciosamente”, suele ser uno de estos con bigote falso.

1) Síntoma: 404 de Traefik para el hostname correcto

Causa raíz: La regla del router no coincide (dominio equivocado, comillas mal, cliente envía Host distinto), o el router está ligado al entrypoint equivocado.

Solución: Verifica que el router exista en la API, luego compara la regla con una petición real. Asegura que traefik.http.routers.<name>.entrypoints incluya el entrypoint que estás golpeando.

2) Síntoma: Router ausente totalmente en panel/API

Causa raíz: Falta traefik.enable mientras exposedByDefault=false; o las restricciones del proveedor lo excluyen; o las claves de etiqueta están malformadas.

Solución: Añade traefik.enable=true; revisa flags del proveedor; valida etiquetas vía docker inspect y docker compose config.

3) Síntoma: Router existe, pero las peticiones van al servicio equivocado

Causa raíz: Colisión de nombres de servicio, selección implícita de servicio, o múltiples routers apuntando accidentalmente a un servicio por defecto compartido.

Solución: Establece traefik.http.routers.<router>.service=<service> explícitamente y usa nombres de servicio únicos por app.

4) Síntoma: TLS funciona a veces; a veces obtienes el certificado por defecto

Causa raíz: El router no está ligado a websecure o falta tls=true; o mismatch SNI; o múltiples instancias Traefik detrás de un LB.

Solución: Asegura que el router tenga entrypoints=websecure y tls=true. Confirma que el cliente usa el hostname correcto y golpea la instancia prevista.

5) Síntoma: Middleware “no aplicada”, pero el enrutamiento funciona

Causa raíz: Desajuste de nombre de middleware, scope de proveedor distinto (@docker vs @file), o middleware definida en otro contenedor y no referenciada correctamente.

Solución: Revisa logs de Traefik por “middleware does not exist.” Usa una única fuente de verdad: define middlewares junto a routers o en un file provider y referencia con sufijo.

6) Síntoma: 502 Bad Gateway de Traefik

Causa raíz: Traefik coincide con el router pero no puede alcanzar el upstream (red equivocada, puerto equivocado, app escuchando solo en localhost, contenedor reiniciándose).

Solución: Prueba desde el contenedor Traefik hacia IP:puerto upstream. Fija el puerto del servicio. Asegura que la app hace bind en 0.0.0.0.

7) Síntoma: Todo funciona en HTTP, falla en HTTPS

Causa raíz: El router está definido solo para web, o falta el router HTTPS con configuración TLS / certresolver.

Solución: Crea un router dedicado websecure, pon tls=true y asegúrate de configurar el certresolver si hace falta.

8) Síntoma: Cambiaste etiquetas pero el comportamiento de Traefik no cambió

Causa raíz: Editaste el archivo Compose pero no redeplegaste; o Traefik no tomó eventos por permisos del socket; o estás mirando la instancia Traefik equivocada.

Solución: Redepliega el servicio; revisa eventos Docker; revisa logs de Traefik por refresh del proveedor; confirma la instancia objetivo con logs de acceso.

Broma #2: Traefik no “ignora” tus etiquetas. Simplemente las interpreta de una forma que hará que tu yo futuro presente una queja.

Listas de verificación / plan paso a paso

Paso a paso: Crear una ruta basada en etiquetas que no falle silenciosamente

  1. Elige una única red Docker para tráfico edge (p. ej., edge). Pon Traefik y cada servicio enrutado allí.
  2. Configura explícitamente el comportamiento del proveedor Traefik:
    • --providers.docker=true
    • --providers.docker.exposedbydefault=false
    • --providers.docker.network=edge
  3. Para cada servicio:
    • Añade traefik.enable=true.
    • Crea un router con un nombre estable: traefik.http.routers.<router>.*.
    • Líalo al/los entrypoint(s) correctos.
    • Pon tls=true para routers HTTPS.
    • Establece service=<service-name> explícitamente.
    • Fija loadbalancer.server.port explícitamente.
  4. Ejecuta docker compose config y verifica que las etiquetas renderizadas sean correctas.
  5. Verifica routers y services vía la API de Traefik después del despliegue.
  6. Prueba desde dentro del contenedor Traefik hacia la IP:puerto upstream.
  7. Sólo entonces depura TLS/certs/middlewares.

Checklist: Antes de culpar a Traefik

  • El contenedor y Traefik comparten una red que Traefik está configurado para usar.
  • El router existe en la API de Traefik.
  • La regla del router coincide con el Host y Path de la petición.
  • El router está ligado al entrypoint que recibe la petición.
  • El puerto del servicio está fijado y es correcto.
  • El upstream es accesible desde el contenedor Traefik.
  • No hay un router catch-all robando tráfico por prioridad.
  • Las referencias a middlewares existen y están correctamente en scope.

Preguntas frecuentes

1) ¿Por qué recibo un 404 de Traefik en vez de un error cuando las etiquetas están mal?

Porque 404 es la respuesta correcta cuando ningún router coincide con la petición. La ausencia de un router no es una excepción de tiempo de ejecución; es una configuración ausente.

2) Mi router existe, pero aun así no coincide. ¿Cuál es la forma más rápida de probarlo?

Envía una petición con una cabecera Host explícita al mismo entrypoint que estás probando, luego compárala con la regla del router desde la API de Traefik.

3) ¿Realmente necesito poner comillas a los valores de etiquetas en Docker Compose?

Sí. El parseo YAML y los caracteres especiales (backticks, comas, dos puntos) son donde nace el “funcionaba en mi laptop”. Ponlas entre comillas y sigue con tu vida.

4) ¿Cuándo debo usar PathPrefix vs Path?

Path hace match exacto. PathPrefix hace match de un subárbol. Para APIs, PathPrefix(`/api`) es común. Sé explícito y evita solapamientos accidentales con otros routers.

5) ¿Por qué Traefik enruta al puerto equivocado?

Autodetección. Si Docker expone múltiples puertos (o la imagen declara varios), Traefik elige uno. Fija el puerto con loadbalancer.server.port.

6) ¿Cuál es la diferencia entre web/websecure y los puertos 80/443?

web y websecure son nombres de entrypoints. Normalmente corresponden a puertos, pero es el nombre lo que los routers ligan. Puedes mapear entrypoints a cualquier puerto.

7) ¿Por qué a veces la middleware “falla a medias” sin romper el enrutamiento?

Traefik puede adjuntar lo que existe y registrar errores por lo que no existe. Eso es bueno para disponibilidad, pero peligroso para controles de seguridad. Trata errores de middleware como fallos de despliegue.

8) ¿Debería poner todas las middlewares en el contenedor Traefik para centralizar la configuración?

Solo si eres disciplinado. Centralizar puede reducir la duplicación, pero también aumenta el radio de explosión y fomenta dependencias enmarañadas. Para stacks pequeños, mantiene middlewares cerca de los servicios que afectan.

9) ¿Es seguro exponer el panel de Traefik?

No por defecto. Enrútalo por websecure, añade middleware de autenticación y evita api.insecure=true en producción. Trátalo como una interfaz administrativa—porque lo es.

10) ¿Cómo evito la exposición accidental de contenedores al azar?

Configura exposedByDefault=false y requiere traefik.enable=true. Luego usa una verificación en CI que falle si un servicio carece de etiquetas explícitas de router/servicio/puerto.

Siguientes pasos que puedes hacer hoy

Si las reglas de ruta de Traefik “fallecen silenciosamente”, la solución rara vez es mágica. Es higiene:

  1. Haz el enrutamiento explícito: nombres de router, nombres de servicio, entrypoints, flags TLS y puerto upstream.
  2. Estandariza tu patrón de etiquetas para que cada servicio luzca igual. La consistencia es una herramienta de depuración.
  3. Adopta el orden rápido de diagnóstico: entrypoint → existencia del router → coincidencia → alcanzabilidad del upstream → middleware/TLS.
  4. Añade una guardia aburrida: una comprobación scriptada que consulte routers/services de Traefik tras el despliegue y afirme reglas y puertos esperados.

Cuando Traefik está configurado limpiamente, no es misterioso. Es un enrutador de peticiones con opiniones fuertes y poca paciencia. Encuéntrate a medio camino: sé explícito, verifica vía API y deja de confiar en lo que “debería” funcionar.

← Anterior
Copias de seguridad de volúmenes Docker que realmente restauran
Siguiente →
Seguridad del socket de Docker: el montaje que equivale a root (y alternativas más seguras)

Deja un comentario