Traefik es un proxy inverso y balanceador de carga gratuito que se configura solo: detecta las aplicaciones que usted arranca en Docker o en Kubernetes y les abre paso sin reiniciar nada. Además, les pone HTTPS con certificados gratuitos de Let’s Encrypt y los renueva. Por eso es una de las puertas de entrada más populares cuando los servicios viven en contenedores. En esta guía verá qué es Traefik, cómo instalarlo con Docker Compose, cómo funcionan sus middlewares y su dashboard, y cómo resolver su error más buscado, el «404 page not found».
Esta guía sirve a dos lectores. Si usted decide en una empresa, le bastan los apartados sobre qué es, para qué sirve, qué beneficios trae y qué límites tiene. Si administra los sistemas, además encontrará el sistema base, las arquitecturas soportadas, la instalación, la configuración básica, los comandos más comunes, siete escenarios de ejemplo y los errores frecuentes.
Por otra parte, no nos quedamos en la documentación. Primero descargamos la versión vigente, la 3.7.14, publicada el 6 de octubre de 2026. Después la pusimos a funcionar en un entorno aislado y medimos cada función con peticiones reales. Así encontramos cuatro cosas que conviene saber antes de usarlo. Primero, el panel sin contraseña entrega hasta las contraseñas cifradas de sus usuarios. Segundo, montar el socket de Docker como «solo lectura» no impide escribir en Docker. Tercero, si un contenedor está en dos redes, Traefik puede elegir la equivocada. Y cuarto, un archivo de configuración roto congela a los demás sin avisar en el panel.
Qué es Traefik y para qué sirve
Traefik es un programa de código abierto que recibe las visitas que llegan a un servidor y las entrega a la aplicación correcta. Su nombre se pronuncia como «traffic», tráfico en inglés, según explica su propio repositorio. Además, hace tres trabajos a la vez: es proxy inverso, es balanceador de carga y es quien gestiona los certificados HTTPS.
El proyecto nació en septiembre de 2015 y tiene licencia MIT. Hoy su repositorio oficial supera las 65.000 estrellas en GitHub, y su imagen de Docker acumula más de 3.500 millones de descargas. Lo mantiene la empresa Traefik Labs, que lo describe como un proxy de aplicaciones nativo de la nube. Si el concepto de proxy inverso es nuevo para usted, lo explicamos paso a paso en nuestra guía de Nginx Proxy Manager.
Explicado sin tecnicismos
Piense en un edificio de oficinas con un recepcionista. En un edificio tradicional, alguien debe avisarle cada vez que una empresa llega, se cambia de piso o se va. Si nadie le avisa, el recepcionista envía las visitas a una oficina vacía.
Traefik es un recepcionista distinto. Cada oficina cuelga en su puerta un letrero con su nombre, y él recorre los pasillos leyendo los letreros. Así, cuando mañana abre una oficina nueva, la encuentra solo. Y cuando una oficina cierra, deja de enviarle visitas. En este ejemplo, las oficinas son sus aplicaciones y los letreros son las etiquetas que usted escribe junto a cada una.
Qué lo hace distinto de otros proxies
La diferencia está en quién escribe la configuración. En un proxy clásico, usted edita un archivo o llena un formulario por cada servicio y luego recarga el programa. En cambio, con Traefik la aplicación se describe a sí misma, y el proxy lee esa descripción desde Docker o Kubernetes.
| Pregunta | Proxy inverso clásico | Traefik |
|---|---|---|
| ¿Dónde se declara un servicio nuevo? | En el archivo o el panel del proxy | Junto a la aplicación, con etiquetas |
| ¿Hay que recargar el proxy? | Sí, casi siempre | No: lo detecta solo |
| ¿Qué pasa si la aplicación cambia de dirección IP? | Hay que corregir el destino | Nada: Traefik la sigue |
| ¿Tiene panel para crear rutas? | Depende del producto | No: su panel solo muestra |
Además, lo medimos: la ruta de un contenedor nuevo estuvo lista a los 0,6 segundos de arrancarlo. Por tanto, publicar un servicio se reduce a escribir bien sus etiquetas.
Traefik Proxy y los productos de pago
Conviene separar los nombres, porque la documentación los mezcla. Traefik Proxy es el programa gratuito del que trata esta guía. Sobre él, Traefik Labs vende otros productos con funciones que el gratuito no trae:
| Función | Traefik Proxy, gratuito | Traefik Hub, de pago |
|---|---|---|
| Proxy inverso, balanceo y descubrimiento de servicios | Sí | Sí |
| HTTP/2, HTTP/3, TCP, UDP, gRPC y websockets | Sí | Sí |
| Certificados de Let’s Encrypt | Sí | Sí, también repartidos entre varias instancias |
| Registros, métricas y trazas | Sí | Sí |
| Complementos de terceros | Sí | Sí |
| Inicio de sesión con OIDC, JWT o LDAP | No | Sí |
| Cortafuegos de aplicaciones web | No | Sí |
| Límite de peticiones compartido entre instancias | No | Sí |
| Caché HTTP | No | Sí |
| Soporte comercial | Como servicio aparte | Sí |
Por eso, cuando un tutorial use una función que usted no encuentra, revise primero si pertenece al producto de pago. La tabla oficial de funciones lo aclara línea por línea.
Usos comunes de Traefik
Casi todos los usos de Traefik nacen de la misma necesidad: una sola puerta de entrada para servicios que aparecen, cambian y desaparecen.
| Uso | Ejemplo | Lo que se usa |
|---|---|---|
| Publicar varias aplicaciones con una sola IP | El inventario y la wiki en el mismo servidor | Routers con regla por nombre |
| Poner HTTPS sin administrar certificados | Una aplicación que solo habla HTTP | Certificados automáticos |
| Repartir visitas entre varias copias | Tres réplicas de la misma aplicación | Balanceo y comprobación de salud |
| Publicar algo que no está en Docker | Un NAS o una máquina virtual | Proveedor de archivos |
| Proteger un panel interno | Usuario, contraseña y solo la red de la oficina | Middlewares |
| Entrar a un clúster de Kubernetes | K3s lo trae instalado de fábrica | Ingress, IngressRoute y Gateway API |
| Publicar un servicio que no es web | Una base de datos o un servidor de correo | Routers TCP y UDP |
| Montar un laboratorio | Un servidor casero con decenas de contenedores | Todo lo anterior |
Por eso encaja con las herramientas que ya explicamos en este blog. Por ejemplo, con los contenedores de Docker, con los proyectos de Docker Compose y con los clústeres de Docker Swarm.
Beneficios de Traefik y sus límites
| Beneficio | En la práctica |
|---|---|
| Se configura solo | Una ruta nueva apareció a los 0,6 segundos, sin reiniciar |
| HTTPS automático | Con una autoridad de pruebas, sirvió el certificado 2,1 segundos después de arrancar |
| Sin cortes al añadir servicios | Mientras emitía un certificado nuevo, el otro sitio no falló ni una vez |
| Balanceo incluido | Repartió 300 peticiones entre tres réplicas: 99, 100 y 101 |
| Ligero | Usó 18 MiB de memoria en reposo y arrancó en 0,8 segundos |
| Un solo archivo ejecutable | No depende de otros programas ni de una base de datos |
| Gratuito | Licencia MIT, sin límite de rutas ni de servicios |
Lo que Traefik no hace
Sin embargo, conviene conocer los límites antes de adoptarlo, porque casi todos se descubren tarde:
- No tiene un panel para crear rutas. Su panel web solo muestra lo que ya está configurado.
- No sirve archivos. Es decir, no reemplaza a un servidor web: siempre necesita una aplicación detrás.
- Es un único punto de entrada. Si Traefik se detiene, todos los servicios publicados quedan fuera a la vez.
- No guarda respuestas en caché ni trae cortafuegos de aplicaciones en la versión gratuita.
- No reparte los certificados entre varias instancias. Por tanto, dos copias de Traefik con Let’s Encrypt exigen otra herramienta o el producto de pago.
- Cambia rápido. Publicó 40 versiones de la serie 3 en los últimos doce meses, y eso obliga a actualizar con calendario.
Cómo funciona Traefik: puntos de entrada, routers y servicios
Toda visita recorre el mismo camino dentro de Traefik. Primero entra por un puerto. Después, una regla decide a qué aplicación pertenece. Luego pasa por los ajustes que usted haya pedido y, por último, llega a uno de los servidores de esa aplicación. Cada tramo tiene nombre propio:
| Pieza | Qué decide | Ejemplo |
|---|---|---|
Punto de entrada (entryPoint) | Por qué puerto entra la visita | web en el puerto 80 y websecure en el 443 |
| Router | A qué aplicación va, según una regla | El nombre wiki.example.com |
| Middleware | Qué se le hace antes de entregarla | Pedir contraseña o redirigir a HTTPS |
| Servicio | A qué servidores se entrega y cómo se reparte | Tres réplicas, por turnos |
| Proveedor | De dónde saca Traefik todo lo anterior | Docker, Kubernetes o un archivo |
Además, cada pieza lleva el nombre de su proveedor detrás de una arroba. Por ejemplo, wiki@docker es un router que salió de las etiquetas de un contenedor y nas@file salió de un archivo. Ese apellido importa cuando una pieza usa a otra de un proveedor distinto.
Los proveedores: de dónde sale la configuración
Un proveedor es la fuente que Traefik consulta para saber qué aplicaciones existen. La versión 3.7 admite quince, y se pueden usar varios a la vez:
| Tipo | Proveedores | Cómo se describe cada servicio |
|---|---|---|
| Contenedores | Docker y Docker Swarm | Con etiquetas en el contenedor |
| Kubernetes | IngressRoute, Ingress, Gateway API e Ingress NGINX | Con recursos del clúster |
| Otros orquestadores | Consul Catalog, Nomad y Amazon ECS | Con etiquetas |
| Manual | Archivo y HTTP | Con un archivo YAML o TOML |
| Almacenes de claves | Consul, etcd, Redis y ZooKeeper | Con claves y valores |
En la práctica, casi todas las instalaciones pequeñas combinan dos: Docker para los contenedores y el archivo para lo que vive fuera de Docker.
Dos configuraciones que no se mezclan
Traefik separa lo que cambia poco de lo que cambia a diario. Desde la serie 3, su documentación les da nombres nuevos, aunque los antiguos siguen en casi todos los tutoriales:
| Configuración | Nombre antiguo | Qué contiene | Cuándo se aplica |
|---|---|---|---|
| De instalación | Estática | Puertos, proveedores, panel, registros y certificados automáticos | Al arrancar: cambiarla exige reiniciar |
| De enrutado | Dinámica | Routers, middlewares, servicios y certificados propios | En caliente, sin cortar nada |
La configuración de instalación admite tres formas: un archivo traefik.yml, argumentos en la línea de órdenes o variables de entorno que empiezan por TRAEFIK_. Sin embargo, son excluyentes. Es decir, si Traefik encuentra un archivo, no combina sus valores con los argumentos. Por eso conviene elegir una sola forma y mantenerla. Si usa el archivo, Traefik lo busca en /etc/traefik/, en $HOME/.config/ y en la carpeta de trabajo.
En cambio, la configuración de enrutado se recarga sola. En nuestra prueba, un contenedor nuevo tuvo su ruta a los 0,6 segundos, y un archivo nuevo tardó unos 2 segundos. Ese margen no es casual: Traefik espera dos segundos entre una recarga y la siguiente para no reconfigurarse sin parar.
Sistema operativo base y arquitecturas soportadas
Traefik no es un sistema operativo ni necesita uno concreto. Está escrito en Go y se distribuye como un único archivo ejecutable, sin dependencias. Por eso corre casi en cualquier parte, y usted puede elegir entre tres formas de usarlo.
El binario: cinco sistemas y dieciocho combinaciones
Cada versión publica en GitHub un ejecutable por sistema y procesador. Estos son los de la 3.7.14:
| Sistema operativo | Arquitecturas publicadas |
|---|---|
| Linux | amd64, arm64, armv7, armv6, 386, ppc64le, riscv64 y s390x |
| Windows | amd64, arm64 y 386 |
| macOS | amd64 para Intel y arm64 para Apple Silicon |
| FreeBSD | amd64 y 386 |
| OpenBSD | amd64, 386 y riscv64 |
Son dieciocho descargas de entre 42 y 50 MB. Así que funciona desde un servidor con procesador Intel o AMD hasta una Raspberry Pi antigua de 32 bits. Si quiere repasar la diferencia entre arquitecturas, la explicamos en la comparativa AMD64 vs ARM64.
La imagen oficial de Docker
Es la forma que usa esta guía. La imagen traefik de Docker Hub trae su propio sistema base, y al abrir la versión 3.7.14 encontramos esto:
| Dato | Lo que trae la imagen 3.7.14 |
|---|---|
| Sistema base | Alpine Linux 3.24, con solo 18 paquetes |
| Añadidos | Certificados raíz y zonas horarias |
| Programa | Un ejecutable de 185 MB, compilado con Go 1.26 |
| Arquitecturas en Linux | amd64, arm64, arm de 32 bits, ppc64le y s390x |
| Variantes para Windows | Nano Server y Server Core, LTSC 2022 y 2025 |
| Usuario | root; la imagen no declara otro |
| Comprobación de salud | No trae: hay que declararla |
| Puerto anunciado | Solo el 80 |
Por tanto, el servidor anfitrión puede ser cualquier Linux con Docker, o un Windows Server para las variantes de Windows. Además, la imagen exige un Docker razonablemente actual: desde la versión 3.6.16, Traefik necesita Docker 19.03 o posterior.
Kubernetes
La tercera forma es dentro de un clúster. Allí Traefik se instala con su gráfico oficial de Helm, que pide Kubernetes 1.25 o posterior. Además, algunas distribuciones lo traen de fábrica: K3s, por ejemplo, lo despliega solo al arrancar. Lo probamos en el escenario 6.
Requisitos: lo que midió nuestra prueba
La documentación no publica requisitos mínimos, así que los medimos. Usamos la imagen oficial 3.7.14 en Docker Desktop para Windows:
| Dato | Resultado |
|---|---|
| Tamaño de la descarga | 52,8 MB comprimidos |
| Espacio en disco, ya desempaquetada | 190 MB |
| Arranque hasta responder | 0,8 segundos |
| Memoria en reposo, con cinco routers | 18 MiB |
| Opciones de arranque disponibles | 547 |
| Líneas de registro en un arranque sin fallos | Ninguna |
Así que el consumo no es un obstáculo: cabe en el servidor más modesto. En cambio, sí conviene fijarse en la última fila. De fábrica, Traefik solo escribe errores, y un arranque correcto no deja ni una línea. Por eso, si quiere confirmar que arrancó, suba el nivel del registro a INFO.
Versiones de Traefik y soporte
Antes de instalar conviene saber qué versión usar, porque Traefik publica muchas. Esta es la tabla de soporte que mantiene el proyecto, a 7 de octubre de 2026:
| Serie | Publicada | Correcciones generales | Correcciones de seguridad |
|---|---|---|---|
| 3.7 | 5 de mayo de 2026 | Sí | Sí |
| 3.6 | 7 de noviembre de 2025 | Terminaron el 7 de mayo de 2026 | Terminaron el 16 de agosto de 2026 |
| 3.5 y anteriores | 2024 y 2025 | No | No |
| 2.11 | 12 de febrero de 2024 | Terminaron el 29 de abril de 2025 | Fin anunciado para el 7 de septiembre de 2026 |
La regla actual es sencilla: cada serie tiene soporte durante seis meses desde su publicación. Sin embargo, el ritmo dentro de cada serie es muy alto. Contamos las publicaciones en GitHub: 40 versiones de la serie 3 en doce meses, con una mediana de siete días entre una y la siguiente. Además, 28 de esas 40 citan al menos un aviso de seguridad en sus notas. La 3.7.14, por ejemplo, cierra ocho.
Por otra parte, la serie 2 sigue recibiendo versiones: la 2.11.58 salió el mismo 6 de octubre, aunque su fin de soporte ya pasó. Aun así, no conviene empezar hoy con ella. La sintaxis de las reglas cambió en la serie 3, y casi todos los ejemplos actuales la dan por hecha.
Qué etiqueta de la imagen usar
| Etiqueta | Qué recibe usted | Cuándo conviene |
|---|---|---|
traefik:v3.7.14 | Exactamente esa versión, siempre | En producción: usted decide cuándo actualizar |
traefik:v3.7 | La última corrección de la serie, al descargar de nuevo | En pruebas, o si actualiza cada semana |
traefik:v3 | La última serie 3, incluido un salto de 3.7 a 3.8 | Casi nunca |
traefik:latest | Lo último publicado | Nunca en producción |
En esta guía usamos la versión exacta. Así, lo que usted copie se comportará igual que en nuestras pruebas.
Instalar Traefik con Docker Compose
La forma más práctica de instalar Traefik es con Docker Compose, porque deja toda la instalación escrita en un archivo. Para seguir estos pasos necesita un servidor Linux con Docker y Compose, y los puertos 80 y 443 libres. Si aún no los tiene, antes le conviene nuestra guía de Docker.
Paso 1: cree una red compartida
Traefik con Docker funciona mejor cuando el proxy y las aplicaciones comparten una red propia. Así, las aplicaciones no publican ningún puerto en el servidor: solo Traefik lo hace.
docker network create red-proxy
Paso 2: escriba el compose.yaml de Traefik
Después, cree una carpeta llamada traefik y, dentro, este archivo compose.yaml. Es una instalación mínima, solo con HTTP, para comprobar que todo responde antes de pedir certificados:
services:
traefik:
image: traefik:v3.7.14
restart: unless-stopped
security_opt:
- no-new-privileges:true
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=red-proxy"
- "--entrypoints.web.address=:80"
- "--ping=true"
- "--log.level=INFO"
- "--accesslog=true"
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- red-proxy
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
timeout: 5s
retries: 3
networks:
red-proxy:
external: true
Cada línea tiene un motivo, y casi todas evitan un problema que reprodujimos:
| Línea | Qué hace | Qué pasa si falta |
|---|---|---|
image: traefik:v3.7.14 | Fija la versión exacta | Una actualización llega sin que usted la decida |
providers.docker=true | Activa la lectura de etiquetas | Traefik no ve ningún contenedor |
exposedbydefault=false | Solo publica lo que lleve traefik.enable=true | Publica todos los contenedores, incluido él mismo |
providers.docker.network | Dice por qué red llegar a cada contenedor | Con dos redes, puede elegir la que no alcanza |
entrypoints.web.address | Abre el puerto 80 con el nombre web | No hay por dónde entrar |
ping=true y healthcheck | Permiten a Docker saber si Traefik responde | El contenedor nunca aparece como sano |
log.level=INFO | Deja constancia del arranque y de los avisos | Solo se escriben los errores |
accesslog=true | Anota cada visita | No hay rastro de quién entró |
| El socket de Docker | Es por donde Traefik descubre los contenedores | No detecta nada |
La tercera fila merece una explicación. De fábrica, Traefik publica todo contenedor que encuentra, con el nombre del servicio como dirección. En nuestra primera prueba expuso así un contenedor sin ninguna etiqueta y también se expuso a sí mismo. Por eso exposedbydefault=false va siempre.
Paso 3: arranque y compruebe
docker compose up -d
docker compose ps
docker compose logs traefik
curl -i http://127.0.0.1/
La última orden debe responder 404 page not found. No es un fallo: significa que Traefik está en marcha y todavía no tiene ninguna ruta para esa visita. Además, pasado medio minuto, docker compose ps lo mostrará como healthy: es lo que tarda la primera comprobación.
Paso 4: publique la primera aplicación
Ahora cree otra carpeta, por ejemplo whoami, con su propio compose.yaml. Usamos traefik/whoami, una aplicación diminuta que devuelve lo que recibe y por eso sirve para diagnosticar:
services:
whoami:
image: traefik/whoami:v1.12.0
restart: unless-stopped
networks:
- red-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"
networks:
red-proxy:
external: true
Fíjese en lo que no aparece: la aplicación no tiene ports. Solo se une a la red compartida y se describe con tres etiquetas. Después arránquela y pruebe:
docker compose up -d
curl -H "Host: whoami.localhost" http://127.0.0.1/
La respuesta trae el nombre del contenedor y las cabeceras que Traefik añade, como X-Forwarded-For y X-Real-Ip, con la dirección del visitante. Además, usted no reinició el proxy en ningún momento.
Otras formas de instalar Traefik
Si no usa Docker, puede instalar Traefik como un programa más. En Linux basta con descargar el binario, comprobar su huella y copiarlo:
curl -LO https://github.com/traefik/traefik/releases/download/v3.7.14/traefik_v3.7.14_linux_amd64.tar.gz
curl -LO https://github.com/traefik/traefik/releases/download/v3.7.14/traefik_v3.7.14_checksums.txt
sha256sum --check --ignore-missing traefik_v3.7.14_checksums.txt
tar -xzf traefik_v3.7.14_linux_amd64.tar.gz traefik
sudo install -m 755 traefik /usr/local/bin/traefik
traefik version
Después escriba su configuración en /etc/traefik/traefik.yml, que es donde el programa la busca primero. Para dejarlo como servicio, el repositorio incluye una unidad de systemd de ejemplo en contrib/systemd/traefik.service. Sin embargo, es una plantilla: trae comentadas la línea de arranque, la del usuario propio y la de la capacidad CAP_NET_BIND_SERVICE. Por tanto, complételas para que Traefik abra los puertos 80 y 443 sin ser root.
En Kubernetes, en cambio, se instala con Helm. Estas son las órdenes de la documentación oficial:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik --wait
En Windows hay dos caminos: el ejecutable .zip de cada versión o las imágenes para contenedores de Windows. Sin embargo, casi toda la documentación y los ejemplos parten de Linux.
Configuración básica de Traefik
Con Traefik en marcha, configurar es sobre todo escribir etiquetas. Parecen crípticas, pero todas siguen el mismo patrón.
Las etiquetas, una por una
Cada etiqueta dice a qué pieza pertenece, cómo se llama esa pieza y qué opción cambia:
traefik.http.routers.wiki.rule=Host(`wiki.example.com`)
| | | | |
| | | | +-- la opción: aquí, la regla
| | | +------- el nombre que usted elige
| | +------------- el tipo de pieza: routers, services o middlewares
| +------------------- el protocolo: http, tcp o udp
+-------------------------- siempre empieza así
Estas son las que resuelven casi todos los casos:
| Etiqueta | Para qué sirve |
|---|---|
traefik.enable=true | Publica este contenedor |
traefik.http.routers.NOMBRE.rule | La regla que decide qué visitas son suyas |
traefik.http.routers.NOMBRE.entrypoints | Por qué punto de entrada se atiende |
traefik.http.routers.NOMBRE.tls.certresolver | Pide el certificado a ese resolvedor |
traefik.http.routers.NOMBRE.middlewares | La lista de middlewares, en orden |
traefik.http.routers.NOMBRE.priority | La prioridad, si dos reglas chocan |
traefik.http.services.NOMBRE.loadbalancer.server.port | El puerto interno de la aplicación |
traefik.http.services.NOMBRE.loadbalancer.server.scheme | https si la aplicación solo habla HTTPS |
traefik.http.services.NOMBRE.loadbalancer.healthcheck.path | La dirección que dice si la réplica está sana |
traefik.http.services.NOMBRE.loadbalancer.sticky.cookie | Mantiene a cada visitante en la misma réplica |
traefik.docker.network | La red por la que Traefik llega a este contenedor |
Hay tres reglas de uso que conviene recordar. Primero, el nombre de cada router debe ser único en todo el servidor. Si dos contenedores declaran el mismo router con reglas distintas, Traefik descarta los dos, y ambos responden 404. Segundo, el puerto se detecta solo cuando la imagen anuncia uno. Si anuncia varios, toma el más bajo; si no anuncia ninguno, hay que escribirlo. Tercero, una etiqueta mal escrita anula todas las de ese contenedor, aunque las demás aplicaciones siguen funcionando.
Las reglas: cómo decide Traefik a quién va cada visita
Una regla es una condición sobre la visita. Además, las condiciones se combinan con && para «y», con || para «o» y con ! para «no»:
| Condición | Coincide cuando | Ejemplo |
|---|---|---|
Host | El nombre pedido es ese | Host(`wiki.example.com`) |
HostRegexp | El nombre cumple una expresión regular | HostRegexp(`^.+\.example\.com$`) |
PathPrefix | La ruta empieza así | PathPrefix(`/api`) |
Path | La ruta es exactamente esa | Path(`/estado`) |
Method | El método es ese | Method(`POST`) |
Header | Trae una cabecera con ese valor | Header(`X-Entorno`, `pruebas`) |
Query | Trae ese parámetro en la dirección | Query(`vista`, `movil`) |
ClientIP | El visitante viene de esa red | ClientIP(`192.168.10.0/24`) |
Sin embargo, hay tres tropiezos habituales, y reprodujimos los tres. El primero son las comillas: los valores van entre acentos graves, y con comillas simples Traefik responde illegal rune literal y desactiva el router. El segundo viene de la serie 2, donde Host admitía varios nombres separados por comas. Ahora cada Host lleva uno solo, y varios nombres se escriben así: Host(`uno.example.com`) || Host(`dos.example.com`). El tercero es PathPrefix: la regla del prefijo /api también atrapó la ruta /apix.
Cuando dos reglas coinciden con la misma visita, gana la más larga. Por ejemplo, la regla del nombre más el prefijo /api mide 43 caracteres y la del nombre solo mide 21. Por tanto, la primera se evalúa antes. Si ese criterio no le sirve, fije la prioridad con la etiqueta priority.
El archivo dinámico: lo que no está en Docker
No todo vive en contenedores. Para publicar un NAS, una impresora o una máquina virtual, Traefik lee archivos YAML de una carpeta. Se activa con dos líneas. Primero, en command, el argumento --providers.file.directory=/etc/traefik/dinamica. Después, en volumes, el montaje ./dinamica:/etc/traefik/dinamica:ro. Las dos están en el archivo completo del apartado sobre el dashboard.
Cada archivo de esa carpeta describe routers y servicios con la misma lógica que las etiquetas, y verá uno entero en el escenario 3. Además, los cambios entran solos: en nuestra prueba, un archivo nuevo tuvo su ruta activa a los 2 segundos.
Ahora bien, esta carpeta tiene un comportamiento que la documentación no explica y que conviene conocer. Rompimos a propósito uno de tres archivos, con una comilla sin cerrar, y pasó esto:
| Momento | Lo que observamos |
|---|---|
| Al guardar el archivo roto | Las rutas que ya funcionaban siguieron respondiendo 200 |
| Mientras siguió roto | Ningún cambio de los otros archivos entró: uno nuevo respondió 404 |
| En el panel y en la API | Cero errores y cero avisos |
| En el registro | Error occurred during watcher callback, en cada cambio de la carpeta |
| Al reiniciar Traefik | Todas las rutas de la carpeta respondieron 404 |
| Al corregir el archivo | Todo volvió en una décima de segundo |
Es decir, un solo archivo roto congela la carpeta entera, y el daño aparece en el siguiente reinicio. Por eso, después de cada cambio, revise el registro. Además, monte siempre la carpeta y no un archivo suelto, como pide la documentación.
Middlewares de Traefik
Un middleware es un ajuste que se aplica a la visita antes de entregarla a la aplicación. La versión gratuita trae 24 para HTTP. Estos son los más usados, con lo que midió nuestra prueba:
| Middleware | Qué hace | Lo que medimos |
|---|---|---|
BasicAuth | Pide usuario y contraseña | 401 sin credenciales y 200 con ellas |
IPAllowList | Solo deja pasar ciertas redes | 403 desde fuera; una cabecera falsa no lo engañó |
RateLimit | Limita las peticiones por visitante | Con un tope de 5 por segundo, de 40 seguidas pasaron 7 y 33 recibieron 429 |
Headers | Añade cabeceras de seguridad | HSTS, nosniff y X-Frame-Options en la respuesta |
Compress | Comprime las respuestas | Un texto repetitivo de 20 KB quedó en 173 bytes con gzip |
RedirectScheme | Envía de HTTP a HTTPS | 301 en las lecturas y 308 en los envíos |
StripPrefix | Quita un prefijo de la ruta | /api/usuarios llegó como /usuarios |
Retry | Reintenta si el servidor no contesta | Al caer una réplica fallaron 3 peticiones sin él y 1 con él |
Buffering | Limita el tamaño de lo que se sube | 413 al superar el tope de 1 MB |
ForwardAuth | Delega el acceso en otro servicio | No lo probamos: es la vía para un inicio de sesión único |
Los middlewares de Traefik se declaran igual que los routers, con etiquetas, y luego se enlazan al router por su nombre. Además, se aplican en el orden en que usted los escribe:
labels:
- "traefik.http.routers.wiki.middlewares=solo-oficina,cabeceras-seguras"
- "traefik.http.middlewares.solo-oficina.ipallowlist.sourcerange=192.168.10.0/24"
- "traefik.http.middlewares.cabeceras-seguras.headers.stsseconds=31536000"
- "traefik.http.middlewares.cabeceras-seguras.headers.contenttypenosniff=true"
- "traefik.http.middlewares.cabeceras-seguras.headers.framedeny=true"
Tres detalles de los middlewares que ahorran horas
El primero es el signo $. Las contraseñas de BasicAuth se guardan cifradas, y ese texto cifrado lleva varios signos $. Sin embargo, Docker Compose los interpreta como variables. Cuando pegamos una contraseña cifrada sin duplicar cada signo, Compose avisó de que una variable «no estaba definida» y recortó el valor. Por tanto, en compose.yaml cada $ se escribe $$.
El segundo es que un middleware mal definido no deja la ruta abierta: la cierra. Desde la versión 3.7.3, un BasicAuth sin usuarios desactiva el router, y la visita recibe 404 en lugar de 401. Lo mismo ocurre si el router nombra un middleware que no existe.
El tercero es que un middleware se puede compartir. Si lo define en el archivo dinámico, cualquier contenedor lo usa añadiendo @file al nombre, por ejemplo cabeceras-seguras@file. Así evita repetir las mismas cinco etiquetas en cada aplicación.
HTTPS en Traefik: certificados con Let’s Encrypt
Traefik atiende HTTPS desde el primer momento, pero con un certificado que ningún navegador acepta. Cuando un router pide TLS y no hay certificado para ese nombre, sirve uno propio llamado TRAEFIK DEFAULT CERT. En nuestra prueba era autofirmado, con clave RSA de 2.048 bits y un año de validez, y Traefik lo generaba en cada arranque. Por eso, si su navegador muestra ese nombre en el aviso de seguridad, ya sabe qué ocurre: el certificado de verdad aún no existe.
Además, comprobamos qué acepta de fábrica. Rechazó las conexiones con TLS 1.0 y 1.1, y aceptó TLS 1.2 y 1.3. También negoció HTTP/2 sin configurar nada. En cambio, HTTP/3 exige activar una opción en el punto de entrada y publicar el puerto 443 también por UDP.
Lo que hay que añadir para tener certificados válidos
Traefik pide los certificados con un «resolvedor», que es su cliente de Let’s Encrypt. Para activarlo, añada estas seis líneas al command del proxy. Después publique el puerto 443 y cree un volumen para guardar los certificados:
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.email=admin@example.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
Las dos primeras envían a HTTPS todo lo que llegue por HTTP. La tercera abre el puerto seguro. Las tres últimas crean un resolvedor llamado le, con su correo, el archivo donde guarda todo y la forma de demostrar que el dominio es suyo. Luego, cada aplicación pide su certificado con tres etiquetas:
- "traefik.http.routers.whoami.rule=Host(`app.example.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=le"
Para que funcione, el nombre debe apuntar a la IP pública de su servidor y el puerto 80 debe llegar hasta Traefik. Si necesita repasar cómo se crea ese registro, lo explicamos en la guía del servidor DNS.
Los tres desafíos de Let’s Encrypt
Let’s Encrypt solo entrega un certificado a quien demuestra que controla el dominio. Esa prueba se llama desafío, y Traefik admite los tres tipos:
| Desafío | Qué exige | ¿Certificado comodín? | Opción en Traefik |
|---|---|---|---|
| HTTP-01 | Que el puerto 80 llegue al proxy desde internet | No | httpchallenge.entrypoint=web |
| TLS-ALPN-01 | Que el puerto 443 llegue al proxy desde internet | No | tlschallenge=true |
| DNS-01 | Una credencial de su proveedor de DNS; no abre puertos | Sí | dnschallenge.provider |
Por tanto, el desafío DNS es el único que sirve para nombres internos que no se publican en internet. A cambio, Traefik necesita una credencial que puede modificar su zona DNS, así que conviene crearla con el permiso mínimo.
Lo que midió nuestra prueba de certificados
Para no pedir certificados reales, usamos Pebble, la autoridad de pruebas que publica el propio Let’s Encrypt, dentro de la red de Docker. Por eso los tiempos son los de esa autoridad local y no los de internet:
| Lo que probamos | Resultado |
|---|---|
| Primer certificado, con el desafío HTTP | Servido 2,1 segundos después de arrancar |
| Qué sirve mientras llega | El certificado por defecto, con aviso del navegador |
| Clave del certificado, de fábrica | RSA de 4.096 bits |
Con la opción keytype=EC256 | ECDSA P-256, más ligera |
| Redirección a HTTPS activada | No estorbó al desafío HTTP |
| Añadir un segundo nombre en caliente | 2,1 segundos, y cero peticiones fallidas en el primero |
| Nombre que no apunta al proxy | Error en el registro y certificado por defecto |
| Reintentos tras ese error | Ninguno en el minuto siguiente |
| Reinicio con el volumen | El mismo certificado, sin pedir otro |
| Recreación sin el volumen | Pidió un certificado nuevo |
Dos filas merecen atención. La primera es la clave: Traefik pide RSA de 4.096 bits si usted no dice otra cosa. Funciona, pero cada conexión nueva cuesta más cálculo que con una clave de curva elíptica. La segunda es el error: cuando un nombre falla, Traefik no insiste por su cuenta. Lo vuelve a intentar cuando cambia la configuración o cuando se reinicia.
acme.json: el archivo que no se puede perder
Todo lo que el resolvedor obtiene queda en acme.json: la clave de su cuenta, los certificados y sus claves privadas. En nuestra prueba pesaba 10 KB con un solo certificado. Hay tres cosas que debe saber de este archivo.
Primero, debe guardarse en un volumen. Si no, cada vez que usted recrea el contenedor, Traefik pide todos los certificados de nuevo. Y Let’s Encrypt limita esas peticiones: cinco certificados por semana para el mismo conjunto de nombres y cincuenta por dominio registrado. Además, solo admite cinco validaciones fallidas por hora para cada nombre.
Segundo, sus permisos deben ser 600. Traefik lo crea así. Sin embargo, si alguien los abre, descarta el resolvedor entero. Lo reprodujimos con permisos 644 y el registro dijo: permissions 644 for /letsencrypt/acme.json are too open, please use 600. Mientras tanto, el sitio siguió respondiendo, pero con el certificado por defecto.
Tercero, hay que copiarlo. Quien tenga ese archivo tiene las claves privadas de todos sus sitios, así que la copia merece el mismo cuidado que una contraseña.
Mientras hace pruebas, use el entorno de ensayo de Let’s Encrypt, que tiene límites mucho más amplios. Basta con añadir una opción al resolvedor: --certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory. Sus certificados no son válidos para el navegador, pero confirman que todo el circuito funciona. Después, quite esa línea y borre el contenido del volumen.
Certificados propios
Si su empresa ya tiene un certificado, por ejemplo uno interno, no necesita el resolvedor. Copie el certificado y su clave a una carpeta que Traefik pueda leer y declárelos en un archivo dinámico:
tls:
certificates:
- certFile: /etc/traefik/dinamica/certs/intranet.crt
keyFile: /etc/traefik/dinamica/certs/intranet.key
Traefik elige solo el certificado que corresponde a cada nombre. En nuestras pruebas lo sirvió como mucho 2 segundos después de guardar el archivo, sin reiniciar. Sin embargo, hay un detalle documentado: si más adelante cambia el contenido del certificado pero no el archivo YAML, Traefik no se entera. Por eso, tras renovar un certificado propio, guarde de nuevo el archivo YAML.
El dashboard de Traefik
El dashboard de Traefik es un panel web que muestra, en vivo, qué puntos de entrada, routers, servicios y middlewares están activos. Además, marca en rojo los que tienen errores y explica el motivo. Sin embargo, es de solo lectura: no sirve para crear ni cambiar rutas.
Por qué no debe usar api.insecure
Casi todos los tutoriales activan el panel con --api.insecure=true, porque es una sola línea. Esa opción lo publica en el puerto 8080, sin usuario ni contraseña. Y el panel se alimenta de una API que entrega toda la configuración a quien la pida.
Lo comprobamos. Con esa opción activa, pedimos a la API el middleware que protegía otra aplicación con contraseña. La respuesta trajo el nombre del usuario y su contraseña cifrada, tal como estaban escritos. Así que cualquiera que llegue a ese puerto se lleva el mapa completo de sus servicios y el material para atacar sus contraseñas.
La forma correcta de publicar el dashboard de Traefik
La alternativa es tratar el panel como una aplicación más. Es decir, se activa la API sin el modo inseguro y se le pone delante un router con contraseña. Primero, genere la contraseña cifrada con esta orden, que además duplica los signos $ para Compose:
docker run --rm httpd:2.4-alpine htpasswd -nbB admin 'SuClaveDelPanel' | sed -e 's/\$/\$\$/g'
Después añada --api=true al command y estas etiquetas al propio servicio de Traefik:
labels:
- "traefik.enable=true"
- "traefik.http.routers.panel.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.panel.entrypoints=websecure"
- "traefik.http.routers.panel.tls.certresolver=le"
- "traefik.http.routers.panel.service=api@internal"
- "traefik.http.routers.panel.middlewares=panel-acceso"
- "traefik.http.middlewares.panel-acceso.basicauth.users=PEGUE_AQUI_EL_RESULTADO"
El servicio api@internal es el nombre interno del panel y de su API. Con esa configuración medimos lo siguiente:
| Petición | Sin credenciales | Con credenciales |
|---|---|---|
https://traefik.example.com/dashboard/ | 401 | 200 |
https://traefik.example.com/dashboard, sin la barra final | 401 | 404 |
https://traefik.example.com/ | 401 | Redirige a /dashboard/ |
https://traefik.example.com/api/rawdata | 401 | 200 |
| El mismo panel por HTTP, en el puerto 80 | Redirige a HTTPS | Redirige a HTTPS |
| La API por el puerto interno 8080 | 404 | 404 |
Por tanto, el panel solo responde por HTTPS, con contraseña y en su nombre. Además, la barra final de /dashboard/ es obligatoria, y eso explica muchos 404. Para un panel de administración conviene sumar un IPAllowList con la red de la oficina, como en el escenario 4.
El compose.yaml completo
Este es el archivo del proxy con todo lo anterior: HTTPS, la carpeta de archivos dinámicos y el panel protegido. Antes de arrancarlo, cree la carpeta dinamica junto al archivo:
services:
traefik:
image: traefik:v3.7.14
restart: unless-stopped
security_opt:
- no-new-privileges:true
command:
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=red-proxy"
- "--providers.file.directory=/etc/traefik/dinamica"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.le.acme.email=admin@example.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
- "--api=true"
- "--ping=true"
- "--log.level=INFO"
- "--accesslog=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./dinamica:/etc/traefik/dinamica:ro
- letsencrypt:/letsencrypt
networks:
- red-proxy
healthcheck:
test: ["CMD", "traefik", "healthcheck", "--ping"]
interval: 30s
timeout: 5s
retries: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.panel.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.panel.entrypoints=websecure"
- "traefik.http.routers.panel.tls.certresolver=le"
- "traefik.http.routers.panel.service=api@internal"
- "traefik.http.routers.panel.middlewares=panel-acceso"
- "traefik.http.middlewares.panel-acceso.basicauth.users=PEGUE_AQUI_EL_RESULTADO"
volumes:
letsencrypt:
networks:
red-proxy:
external: true
Cambie tres valores antes de usarlo: el correo, el nombre del panel y la contraseña cifrada. Mientras no sustituya PEGUE_AQUI_EL_RESULTADO, el router del panel queda desactivado y responde 404, que es el comportamiento seguro.
Comandos más comunes de Traefik
Traefik casi no tiene órdenes propias: el programa solo ofrece version y healthcheck, además de sus 547 opciones de arranque. Por eso, en el día a día se administra con las órdenes de Docker Compose, desde la carpeta del proxy:
| Orden | Para qué sirve |
|---|---|
docker compose config -q | Valida el archivo antes de aplicarlo |
docker compose up -d | Arranca el proxy o aplica los cambios del archivo |
docker compose ps | Muestra el estado y si está sano |
docker compose logs -f traefik | Sigue el registro en vivo |
docker compose logs --since 10m traefik | Muestra los últimos diez minutos |
docker compose exec traefik traefik version | Dice qué versión corre |
docker compose exec traefik traefik healthcheck --ping | Comprueba que responde |
docker compose restart traefik | Reinicia el proxy |
docker compose pull | Descarga la versión que indica el archivo |
docker run --rm traefik:v3.7.14 --help | Lista todas las opciones de arranque |
docker network inspect red-proxy | Enseña qué contenedores comparten la red |
docker compose config -q
docker compose up -d
docker compose ps
docker compose logs --since 10m traefik
docker compose exec traefik traefik version
docker compose exec traefik traefik healthcheck --ping
docker network inspect red-proxy
docker compose restart traefik
La orden healthcheck responde OK: http://:8080/ping cuando todo va bien. En cambio, si usted no activó --ping=true, contesta please enable `ping` to use health check. Además, si configuró Traefik con argumentos, debe repetir --ping en la propia orden, como en la tabla.
Actualizar sin sorpresas
Actualizar son dos órdenes después de cambiar la versión en el archivo:
docker compose pull
docker compose up -d
Ahora bien, Traefik es el único punto de entrada, así que cada reinicio corta todos los sitios a la vez. Lo medimos con peticiones seguidas, separadas por 20 milisegundos:
| Operación | Tiempo sin servicio |
|---|---|
docker compose restart traefik | 3,7 segundos |
| Recrear el contenedor, como hace una actualización | 2,0 segundos |
| Añadir, cambiar o quitar una aplicación | Ninguno |
Por eso conviene actualizar en una ventana acordada. En cambio, las peticiones en curso no se pierden: al detener Traefik con una petición de 6 segundos a medias, esperó a que terminara antes de salir.
Leer el registro de acceso
Con --accesslog=true, cada visita deja una línea como esta:
172.23.0.1 - - [07/Oct/2026:19:20:28 +0000] "GET / HTTP/1.1" 200 358 "-" "-" 272 "nas@file" "http://app:80" 1ms
De izquierda a derecha: la IP del visitante, la fecha, la petición, el código de respuesta y los bytes enviados. Después vienen la página de origen y el navegador. Los últimos cuatro campos son los más útiles: el número de la petición, el router que la atendió, el servidor que recibió la visita y cuánto tardó. Así, ante un fallo, la línea dice qué regla se aplicó y a dónde fue.
Además, hay dos opciones que ayudan cuando los registros van a otra herramienta. Con --accesslog.format=json, cada visita se escribe como un objeto con 31 campos. Y con --log.nocolor=true desaparecen los códigos de color que Traefik añade a cada línea del registro general, aunque no escriba en una terminal.
Escenarios de ejemplo con Traefik
Estos siete escenarios cubren lo que más se pide a Traefik en una empresa pequeña o en un laboratorio. Todos parten de la instalación anterior, con la red red-proxy y el resolvedor le, y todos los probamos.
Escenario 1: varias aplicaciones de proyectos distintos
Es el caso más común: cada aplicación vive en su carpeta, con su propio compose.yaml y sus contenedores auxiliares. La regla es sencilla. Solo el contenedor que atiende visitas se une a red-proxy, y el resto se queda en una red interna del proyecto:
services:
web:
image: nginx:1.30-alpine
restart: unless-stopped
networks:
- interna
- red-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.inventario.rule=Host(`inventario.example.com`)"
- "traefik.http.routers.inventario.entrypoints=websecure"
- "traefik.http.routers.inventario.tls.certresolver=le"
cache:
image: redis:8-alpine
restart: unless-stopped
networks:
- interna
networks:
interna:
red-proxy:
external: true
Así, la caché no es visible desde el proxy ni desde las demás aplicaciones. Sin embargo, el contenedor web queda en dos redes, y ahí aparece la trampa más frecuente de Traefik con Docker. Sin ninguna indicación, Traefik eligió la red equivocada en 5 de nuestros 6 intentos, y la visita terminó en 504 Gateway Timeout a los 30 segundos. Por eso la instalación de esta guía lleva --providers.docker.network=red-proxy. Con esa línea, respondió 200 en tres arranques seguidos.
Escenario 2: tres réplicas con balanceo y comprobación de salud
Para repartir las visitas entre varias copias no hay que declarar nada especial. Basta con arrancar más réplicas del mismo servicio, y Traefik las añade solo. Además, tres etiquetas le enseñan a retirar la réplica que deja de responder bien:
services:
app:
image: traefik/whoami:v1.12.0
restart: unless-stopped
networks:
- red-proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=le"
- "traefik.http.services.app.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.app.loadbalancer.healthcheck.interval=5s"
- "traefik.http.services.app.loadbalancer.healthcheck.timeout=2s"
networks:
red-proxy:
external: true
docker compose up -d --scale app=3
Esto fue lo que medimos con tres réplicas:
| Situación | Resultado |
|---|---|
| 300 peticiones seguidas | 99, 100 y 101 por réplica: reparto por turnos |
Sesión fija con sticky.cookie=true | 30 de 30 peticiones a la misma réplica |
| Una réplica empieza a responder con error 500 | Salió del reparto en el siguiente ciclo de comprobación |
| Todas las réplicas fallan la comprobación | 503, con el texto no available server |
| Una réplica se recupera | Volvió al reparto en el siguiente ciclo de comprobación |
| Una réplica muere de golpe | Fallaron 3 de 84 peticiones, todas en el primer cuarto de segundo; después Traefik ya la había retirado |
Es decir, Traefik distingue dos averías. Si el contenedor desaparece, lo retira al recibir el aviso de Docker, con comprobación o sin ella. En cambio, si el contenedor sigue vivo pero responde mal, solo la comprobación de salud lo saca. Sin ella, esa réplica seguiría recibiendo una de cada tres visitas. Ahora bien, repartir visitas no es lo mismo que tolerar la caída de un servidor entero: esa diferencia la explicamos en la guía de alta disponibilidad.
Escenario 3: un NAS o un servidor que no está en Docker
Muchos equipos traen su propia consola web con HTTPS y un certificado autofirmado: un NAS, un hipervisor o una impresora. Para publicarlos se usa el archivo dinámico. Guarde este contenido como dinamica/nas.yml:
http:
routers:
nas:
rule: "Host(`nas.example.com`)"
entryPoints:
- websecure
tls:
certResolver: le
service: nas
services:
nas:
loadBalancer:
serversTransport: equipo-interno
servers:
- url: "https://192.168.10.20:5001"
serversTransports:
equipo-interno:
insecureSkipVerify: true
El bloque serversTransports es la clave. Sin él, Traefik comprueba el certificado del equipo, no lo reconoce y responde 500 Internal Server Error. En el registro queda la causa: tls: failed to verify certificate. Además, hay un segundo fallo posible. Si escribe http en la dirección de un equipo que solo habla HTTPS, la respuesta es un 400 con el texto Client sent an HTTP request to an HTTPS server.
Sin embargo, insecureSkipVerify desactiva la comprobación en ese tramo. Por tanto, úselo solo dentro de su red de confianza. Si el equipo tiene un certificado de una autoridad interna, es mejor indicarla con la opción rootCAs.
Escenario 4: un panel interno con contraseña y solo desde la oficina
Los paneles de administración no deberían estar a la vista de todo internet. Con dos middlewares encadenados, primero se filtra por red y después se pide la contraseña:
labels:
- "traefik.enable=true"
- "traefik.http.routers.wiki.rule=Host(`wiki.example.com`)"
- "traefik.http.routers.wiki.entrypoints=websecure"
- "traefik.http.routers.wiki.tls.certresolver=le"
- "traefik.http.routers.wiki.middlewares=solo-oficina,wiki-acceso"
- "traefik.http.middlewares.solo-oficina.ipallowlist.sourcerange=192.168.10.0/24,10.8.0.0/24"
- "traefik.http.middlewares.wiki-acceso.basicauth.users=PEGUE_AQUI_EL_RESULTADO"
En nuestra prueba, una visita desde fuera de esas redes recibió 403 Forbidden sin llegar a ver la ventana de la contraseña. Además, intentamos engañar al filtro con una cabecera X-Forwarded-For falsa, y no funcionó: de fábrica, Traefik solo mira la dirección real de la conexión. Eso cambia si delante hay otro proxy o una red de distribución de contenidos. En ese caso todas las visitas llegan con la IP de ese intermediario, y usted debe indicar a Traefik en cuáles confía con forwardedHeaders.trustedIPs.
Por otra parte, BasicAuth deja pasar la cabecera con la contraseña hasta la aplicación. Si no la necesita, añada la opción removeheader=true al middleware.
Escenario 5: un servicio que no es web
Traefik también enruta conexiones TCP y UDP, por ejemplo hacia una base de datos. Hace falta un punto de entrada propio y un router de tipo TCP. Primero, añada el argumento --entrypoints.postgres.address=:5432 al command del proxy y publique ese puerto. Después, etiquete el contenedor de la base de datos:
labels:
- "traefik.enable=true"
- "traefik.tcp.routers.bd.rule=HostSNI(`*`)"
- "traefik.tcp.routers.bd.entrypoints=postgres"
- "traefik.tcp.services.bd.loadbalancer.server.port=5432"
La regla HostSNI(`*`) significa «cualquier conexión que entre por este puerto». En TCP sin cifrar no hay nombre que leer, así que cada puerto solo puede llevar a un destino. Además, en TCP Traefik no toca el contenido: la base de datos ve la IP del proxy, no la del cliente. Por último, un aviso de sentido común: publique una base de datos solo hacia la red interna, nunca hacia internet.
Escenario 6: Traefik en Kubernetes con K3s
En Kubernetes, Traefik cumple el papel de controlador de entrada: recibe las visitas del clúster y las reparte entre los pods. Lo probamos con K3s, la distribución ligera que lo trae de fábrica. Arrancamos la versión 1.37.1 y esto fue lo que instaló sin pedírselo:
| Dato | Lo que encontramos en K3s 1.37.1 |
|---|---|
| Versión de Traefik | 3.7.13, lista 48 segundos después de arrancar el nodo |
| Puertos | 80 y 443, con un servicio de tipo LoadBalancer |
| Usuario | Sin privilegios, con el sistema de archivos de solo lectura |
| Proveedores activos | IngressRoute e Ingress estándar |
| Gateway API | Recursos instalados; el proveedor se activa aparte |
| Memoria del pod | 23 MB |
Fíjese en la tercera fila: dentro de K3s, Traefik no corre como root, a diferencia de la imagen de Docker. Después publicamos una aplicación con el recurso propio de Traefik, el IngressRoute:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: cabeceras-seguras
spec:
headers:
contentTypeNosniff: true
frameDeny: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: whoami
spec:
entryPoints:
- web
routes:
- match: Host(`whoami.example.com`)
kind: Rule
middlewares:
- name: cabeceras-seguras
services:
- name: whoami
port: 80
La lógica es la misma que con las etiquetas: una regla, unos middlewares y un servicio. La ruta respondió a los 4 segundos, con las cabeceras del middleware. Además, un Ingress estándar con ingressClassName: traefik funcionó a la primera. Y al pasar de dos a cuatro réplicas, las cuatro recibían visitas 3,3 segundos después, sin tocar Traefik.
Hay un motivo de actualidad para mirar este escenario. El controlador Ingress NGINX, durante años uno de los más usados en Kubernetes, quedó sin mantenimiento en marzo de 2026, según anunció el propio proyecto Kubernetes. Desde entonces, su repositorio está archivado. Por eso Traefik incluye un proveedor que entiende las anotaciones de aquel controlador, pensado para migrar sin reescribir cada recurso.
Escenario 7: Traefik sin acceso directo al socket de Docker
El socket de Docker es la pieza más delicada de toda la instalación. Quien controla ese socket controla el servidor, porque puede crear contenedores con cualquier permiso. Y Traefik, que está expuesto a internet, lo tiene montado.
Casi todas las guías proponen montarlo con :ro, de solo lectura. Lo pusimos a prueba: desde un contenedor con el socket montado así, pedimos a Docker que creara un volumen, y lo creó. El motivo es que :ro protege el archivo del socket, no las órdenes que viajan por él. Por tanto, esa marca no limita nada de lo que importa.
La defensa real es poner un intermediario que solo deje pasar las consultas que Traefik necesita:
services:
socket-proxy:
image: tecnativa/docker-socket-proxy:v0.5.0
restart: unless-stopped
environment:
CONTAINERS: 1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- socket
traefik:
image: traefik:v3.7.14
restart: unless-stopped
depends_on:
- socket-proxy
command:
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://socket-proxy:2375"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=red-proxy"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
networks:
- red-proxy
- socket
networks:
socket:
internal: true
red-proxy:
external: true
Con este montaje, Traefik ya no tiene ningún volumen. Aun así, descubrió la aplicación de prueba y un contenedor nuevo, igual que antes. En cambio, estas fueron las respuestas del intermediario a otras órdenes:
| Petición a través del intermediario | Respuesta |
|---|---|
| Listar contenedores | 200 |
| Consultar la versión de Docker | 200 |
| Listar imágenes o volúmenes | 403 |
| Crear un volumen | 403 |
| Detener un contenedor | 403 |
Así, aunque alguien tomara el control de Traefik, solo podría leer la lista de contenedores. Además, la red socket es interna: ningún otro contenedor llega a ese intermediario.
Errores frecuentes en Traefik: 404 page not found, 502 y 504
Traefik no responde siempre con el mismo error, y eso es una ventaja. Cada código indica en qué tramo del camino se rompió la visita. Por eso, antes de tocar nada, fíjese en el número:
| Respuesta | Qué significa en Traefik | Dónde mirar primero |
|---|---|---|
404 page not found | Ningún router coincide con la visita | Etiquetas, nombre y punto de entrada |
502 Bad Gateway | Hay router, pero la aplicación no contestó | Puerto y dirección del servicio |
503, con no available server | Hay router, pero ninguna réplica sana | Comprobación de salud |
504 Gateway Timeout | No logró conectar con la aplicación | La red que comparten |
500 Internal Server Error | La aplicación habla HTTPS con un certificado desconocido | El transporte hacia el servidor |
Traefik 404: las causas que reprodujimos
El 404 es el error de Traefik con más búsquedas, y casi nunca significa que la aplicación falle. Significa que el proxy no encontró una ruta para esa visita. Además, la documentación explica por qué no responde 503: como su configuración cambia sola, no puede saber si esa ruta va a existir. Provocamos el 404 de once maneras distintas:
| Causa | Lo que dice el registro | Solución |
|---|---|---|
Falta traefik.enable=true | Nada | Añada la etiqueta |
| El nombre de la regla no es el que pide el navegador | Nada | Compare la regla con la dirección exacta |
| El router está en otro punto de entrada | Nada | Revise entrypoints, o pida por HTTPS |
| Una etiqueta mal escrita | field not found, node: rul | Corríjala: anula todas las del contenedor |
| El router nombra un middleware que no existe | middleware "noexiste@docker" does not exist | Revise el nombre o añada @file |
Un BasicAuth sin usuarios | no users found | Añada al menos un usuario |
| Comillas simples en la regla | illegal rune literal | Use acentos graves |
| Regla con la sintaxis de la serie 2 | unexpected number of parameters; got 2, expected one of [1] | Un nombre por cada Host |
| Dos contenedores con el mismo router | HTTP router defined multiple times with different configurations | Nombres únicos |
| La imagen no anuncia ningún puerto | port is missing | Añada la etiqueta del puerto |
| El panel sin la barra final | Nada | Pida /dashboard/ |
Las tres primeras causas y la última no dejan rastro, porque para Traefik no hay nada que anotar: simplemente no existe una ruta. Así que, ante un Traefik 404 sin mensajes, compare tres cosas con calma: la etiqueta enable, el nombre exacto y el punto de entrada. En las otras siete, el registro da la respuesta en una línea. Además, cuando el router llega a crearse, el panel lo muestra en rojo con el mismo texto.
Los errores 502, 503 y 504: la aplicación no contesta
Cuando hay router pero falla el destino, el código depende de cómo falle. Medimos también cuánto tarda cada uno en aparecer, porque esa espera suele confundirse con lentitud:
| Causa que reprodujimos | Respuesta | Tardó |
|---|---|---|
| Puerto equivocado en la etiqueta | 502 Bad Gateway | Al instante |
| Nombre de servidor que no existe | 502 Bad Gateway | Al instante |
| Dirección IP que no responde | 502 Bad Gateway | 21 segundos |
| Contenedor en una red que Traefik no alcanza | 504 Gateway Timeout | 30,0 segundos |
| Todas las réplicas fallan la comprobación de salud | 503 | Al instante |
| Aplicación HTTPS con certificado autofirmado | 500 Internal Server Error | Al instante |
Esquema http hacia un servidor que solo habla HTTPS | 400 | Al instante |
| La aplicación tarda 100 segundos en responder | 200, a los 100 segundos | Sin tope de fábrica |
El caso del 504 es el más repetido con Docker. Si la visita se queda exactamente 30 segundos esperando y termina en Gateway Timeout, casi seguro Traefik está intentando llegar al contenedor por una red que no comparte. La solución está en el escenario 1.
La última fila también importa. De fábrica, Traefik espera hasta 30 segundos para conectar, pero no pone ningún límite a la respuesta. Por tanto, una aplicación colgada puede retener visitas sin que nadie reciba un error.
Otros errores de Traefik y su causa
| Síntoma | Causa | Qué hacer |
|---|---|---|
El navegador avisa de TRAEFIK DEFAULT CERT | No hay certificado para ese nombre | Busque Unable to obtain ACME certificate en el registro |
permissions 644 for acme.json are too open | Alguien abrió los permisos del archivo | Devuélvalos a 600 |
Failed to retrieve information of the docker client and server host | Traefik no logra hablar con Docker | Revise el socket y la versión |
| Los cambios de un archivo dinámico no entran | Otro archivo de la carpeta está roto | Busque watcher callback en el registro |
| La contraseña correcta no funciona | El signo $ sin duplicar en compose.yaml | Escriba $$ |
| La aplicación solo ve la IP del proxy | Hay otro proxy delante de Traefik | Configure forwardedHeaders.trustedIPs |
413 al subir un archivo | Un middleware Buffering con tope | Suba el tope: de fábrica no existe |
please enable `ping` to use health check | Falta --ping=true | Añádalo y repítalo en la orden |
El tercer mensaje tiene una causa que hoy se repite mucho. Arrancamos varias versiones contra un Docker reciente, el motor 29. Las versiones 3.5.0 y 3.6.0 de Traefik fallaron con ese error cada segundo. En cambio, la 3.6.1 y la 3.7.14 funcionaron. Es decir, si actualizó Docker y Traefik dejó de ver sus contenedores, actualice también Traefik.
Traefik vs Nginx Proxy Manager, Caddy, Nginx y HAProxy
Traefik no es el único proxy inverso, ni el mejor para todo. La diferencia principal entre las alternativas es cómo se configuran: con etiquetas, con un panel o con un archivo.
| Herramienta | Licencia | Cómo se configura | Cuándo conviene |
|---|---|---|---|
| Traefik 3.7 | MIT | Etiquetas en los contenedores y archivos | Muchos contenedores que cambian a menudo: descubre los servicios solo |
| Nginx Proxy Manager 2.16 | MIT | Panel web | Pocos servicios, cambios a mano y un equipo que prefiere ver un formulario |
| Caddy 2.11 | Apache 2.0 | Un archivo de texto corto | Quien prefiere texto y control de versiones; el HTTPS es automático |
| Nginx | BSD | Archivos de texto, sin recarga automática | Cuando además hay que servir archivos o afinar cada detalle |
| HAProxy 3.4 | GPL 2.0 | Un archivo de texto | Repartir mucha carga entre varios servidores |
La duda más habitual es Traefik vs Nginx. Nginx es un servidor web que también hace de proxy inverso: sirve archivos, guarda caché y se configura a mano. En cambio, Traefik solo hace de proxy, pero se reconfigura solo. Por tanto, no compiten del todo. De hecho, muchas instalaciones ponen Traefik delante y un Nginx detrás, sirviendo cada aplicación.
Traefik frente a Nginx Proxy Manager, con nuestras mediciones
Probamos las dos herramientas en el mismo equipo, con el mismo método. Por eso podemos comparar cifras y no opiniones:
| Lo que medimos | Nginx Proxy Manager 2.16.0 | Traefik 3.7.14 |
|---|---|---|
| Tamaño de la descarga | 453 MB | 52,8 MB |
| Memoria en reposo | 99 MiB | 18 MiB |
| Primer arranque | 5,0 segundos | 0,8 segundos |
| Crear una ruta | Un formulario en el panel | Etiquetas junto a la aplicación |
| Pedir un certificado nuevo | El sitio dejó de responder 3,3 segundos | Sin interrupción |
| Clave del certificado, de fábrica | ECDSA P-384 | RSA de 4.096 bits |
Cabecera X-Forwarded-For falsa del visitante | La conserva y añade la real | La descarta |
| Tiempo máximo de respuesta, de fábrica | 90 segundos | Sin tope |
| Tamaño máximo de subida, de fábrica | 2.000 MB | Sin tope |
Así que la elección depende del equipo más que de la tecnología. Si quien lo va a administrar no quiere escribir configuración, el panel gana. En cambio, si ya describe su infraestructura en archivos, Traefik encaja mejor y consume menos.
Recomendaciones para usar Traefik en una empresa
Traefik viene configurado para que el primer ejemplo funcione, no para producción. Estas son las doce cosas que ajustaríamos desde el primer día, y todas salen de las pruebas de esta guía:
- Fije la versión exacta de la imagen y actualice con calendario. Además, lea las notas de cada versión, porque siete de cada diez corrigen fallos de seguridad.
- Ponga siempre
exposedbydefault=false. Así, solo se publica lo que usted etiqueta. - No use
api.insecurefuera de su propio computador. Publique el panel con contraseña y filtro de red, o no lo publique. - Ponga un intermediario delante del socket de Docker, como en el escenario 7. Recuerde que
:rono limita las órdenes. - Indique la red compartida con
providers.docker.network. Es la causa más común del error 504. - Guarde
acme.jsonen un volumen, con copia, y ensaye primero contra el entorno de pruebas de Let’s Encrypt. - Elija
keytype=EC256en el resolvedor si no necesita RSA. La clave de fábrica es más pesada. - Suba el registro a
INFOy léalo después de cada cambio, sobre todo si usa archivos dinámicos. - Active
aliasHeadersStrategy=deleteen los puntos de entrada si sus aplicaciones leen cabeceras. Traefik lo avisa en el registro de cada arranque, y en nuestra prueba una cabeceraX.Real.Ipfalsa llegó hasta la aplicación. - Ponga topes donde hagan falta. De fábrica subimos un archivo de 200 MB sin límite, y una respuesta de 100 segundos llegó completa.
- Use nombres únicos para routers y middlewares, con el proyecto como prefijo. Dos routers iguales se anulan entre sí.
- Recuerde que es un único punto de entrada: cada reinicio corta todos los sitios entre 2 y 4 segundos. Vigile el servicio desde fuera, como explicamos en la guía de monitoreo de servidores.
Métricas de Traefik para sus tableros
Por último, Traefik publica métricas para Prometheus con una sola opción, --metrics.prometheus=true. Si ya tiene tableros, puede llevarlas a Grafana y ver las visitas, los errores y los tiempos por servicio.
Preguntas frecuentes sobre Traefik
¿Traefik es gratis?
Sí. Traefik Proxy es software libre con licencia MIT, sin límite de rutas ni de servicios. Además, los certificados de Let’s Encrypt tampoco cuestan. Lo que se paga aparte son los productos Traefik Hub, que añaden funciones como el inicio de sesión único o el cortafuegos de aplicaciones.
¿Qué puerto usa Traefik?
Los que usted declare como puntos de entrada. Lo habitual es el 80 para HTTP y el 443 para HTTPS. Además, el puerto 8080 queda reservado al punto de entrada interno traefik: ahí responden el panel en modo inseguro y la comprobación ping. Por eso no conviene publicarlo.
¿Cuál es el usuario y la contraseña del dashboard de Traefik?
No hay. El panel no trae usuarios propios. Con api.insecure se abre sin pedir nada, y con la forma segura la contraseña la pone usted mediante un middleware. Si un panel de Traefik le deja entrar sin credenciales desde internet, está mal publicado.
¿Traefik reemplaza a Nginx?
Como proxy inverso, sí. Sin embargo, Traefik no sirve archivos ni ejecuta aplicaciones. Por tanto, si hoy usa Nginx como servidor web, lo seguirá necesitando detrás del proxy. Lo que cambia es quién recibe las visitas y quién gestiona los certificados.
¿Se puede usar Traefik sin Docker?
Sí. Es un único ejecutable que funciona como un servicio más del sistema, y se configura con un archivo. Además, el proveedor de archivos permite publicar cualquier servidor de la red. Lo que se pierde sin Docker es el descubrimiento automático.
¿Traefik es un balanceador de carga?
También. Reparte las visitas entre las réplicas de un servicio con cuatro estrategias. La de fábrica es el reparto por turnos con pesos. Las otras eligen la réplica con menos conexiones, la que responde más rápido o siempre la misma para cada visitante.
¿Traefik envía datos a sus creadores?
De fábrica, comprueba si hay versiones nuevas, y su propio registro avisa de que esa consulta recoge datos de uso. Se desactiva con --global.checknewversion=false. En cambio, el envío de estadísticas anónimas viene apagado, como también indica el registro al arrancar.
¿Puedo poner dos instancias de Traefik?
Sí, pero con un límite. Según la documentación, la versión gratuita no reparte los desafíos de Let’s Encrypt entre varias instancias. Por tanto, o bien los certificados los gestiona otra herramienta, o bien una sola instancia los pide.
Cómo lo aborda KHARONTE
Traefik resuelve el último tramo del camino: recibir la visita y entregarla. Sin embargo, antes de ese tramo hay una red que debe estar bien pensada. El firewall decide qué puertos llegan al proxy, las VLAN separan los servidores de los puestos de trabajo y las VPN dan paso a quienes trabajan fuera. Ese es el trabajo de nuestra línea de redes y conectividad: diseñamos, instalamos y administramos la red de la empresa, incluido el firewall perimetral con sus reglas y la publicación de servicios.
Por otra parte, los contenedores necesitan dónde correr. Los servidores y las máquinas virtuales que los alojan hacen parte de nuestra línea de infraestructura de TI, aunque no comercializamos los equipos. Además, cada cambio queda como un caso en la mesa de ayuda TI, con su criticidad y su historial.
Si necesita una persona dedicada a su plataforma, puede contar con ella como outsourcing de infraestructura de TI. Y si prefiere servicios administrados de TI que reúnan la red, los servidores y el soporte, revise nuestros servicios de TI para empresas.




