--- title: "Traefik como proxy inverso con Docker y Let's Encrypt" description: "Despliega Traefik v3 con Docker Compose en Ubuntu 24.04, publica contenedores con etiquetas, obtén certificados de Let's Encrypt y protege el panel con clave." category: "Docker Avanzado" language: es source: https://cubepath.com/es/docs/docker-avanzado/proxy-inverso-traefik-con-docker updated: 2026-09-25 --- # Traefik como proxy inverso con Docker y Let's Encrypt Traefik es un proxy inverso que lee la configuración de enrutado directamente de las etiquetas de tus contenedores Docker: al arrancar un contenedor con las etiquetas adecuadas, Traefik crea la ruta y solicita el certificado TLS sin que tengas que recargar nada. En este tutorial desplegarás Traefik v3 con Docker Compose en Ubuntu 24.04, publicarás un servicio de ejemplo con HTTPS de Let's Encrypt, balancearás carga entre varias réplicas y protegerás el panel de Traefik con autenticación básica. ## Requisitos previos Para seguir esta guía necesitas: - Un servidor con Ubuntu 24.04 LTS y una IP pública, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo` que pertenezca al grupo `docker`. - Docker Engine y el plugin Docker Compose instalados desde el repositorio oficial de Docker. - Un dominio con dos registros DNS de tipo A apuntando a la IP del servidor: `whoami.your_domain` y `traefik.your_domain`. Sustituye `your_domain` por tu dominio en todo el tutorial. - Los puertos 80 y 443 libres en el servidor (sin Nginx ni Apache escuchando en ellos). ## Conceptos básicos Traefik separa la configuración en dos partes: - **Configuración estática**: se lee al arrancar (fichero `traefik.yml`). Define los puntos de entrada (`entryPoints`, los puertos en los que escucha), los proveedores (en este caso Docker) y los resolvedores de certificados. - **Configuración dinámica**: cambia en caliente. Con el proveedor Docker procede de las etiquetas de cada contenedor y define **routers** (qué peticiones aceptar, por ejemplo por `Host`), **services** (a qué contenedor y puerto enviarlas) y **middlewares** (transformaciones intermedias como autenticación o limitación de peticiones). ## Paso 1: Abrir el cortafuegos Traefik necesita el puerto 80 para el reto HTTP de Let's Encrypt y para redirigir a HTTPS, y el 443 para servir el tráfico cifrado. Si usas UFW, permite ambos junto con SSH: ```bash sudo ufw allow OpenSSH sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable ``` Comprueba las reglas: ```bash sudo ufw status ``` ```output Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 80/tcp ALLOW Anywhere 443/tcp ALLOW Anywhere ``` > Importante: los puertos que publicas con `ports:` en Docker se abren mediante reglas de iptables propias de Docker y no pasan por UFW. Publica solo los puertos de Traefik y deja el resto de contenedores sin `ports:`, accesibles únicamente a través del proxy. ## Paso 2: Crear la red compartida Traefik y los contenedores que publica tienen que compartir una red Docker. Crea una red externa llamada `proxy`, que podrán usar todos tus proyectos de Compose: ```bash docker network create proxy ``` ```output 3f1c8a2d9b7e4f0a6c5d1e2b8a9f7c6d5e4b3a2c1d0e9f8a7b6c5d4e3f2a1b0c ``` ## Paso 3: Escribir la configuración estática Crea el directorio del proyecto: ```bash sudo mkdir -p /opt/traefik sudo chown "$USER": /opt/traefik cd /opt/traefik ``` Crea el fichero de configuración estática: ```bash nano traefik.yml ``` ```yaml entryPoints: web: address: ":80" http: redirections: entryPoint: to: websecure scheme: https websecure: address: ":443" http: tls: certResolver: letsencrypt providers: docker: exposedByDefault: false network: proxy certificatesResolvers: letsencrypt: acme: email: admin@your_domain storage: /letsencrypt/acme.json httpChallenge: entryPoint: web api: dashboard: true log: level: INFO accessLog: {} ``` Qué hace cada bloque: - `entryPoints`: Traefik escucha en el 80 (`web`) y en el 443 (`websecure`). Todo lo que llega al 80 se redirige a HTTPS, y todos los routers de `websecure` usan por defecto el resolvedor `letsencrypt`. - `providers.docker`: con `exposedByDefault: false`, Traefik ignora los contenedores que no tengan la etiqueta `traefik.enable=true`. `network: proxy` indica por qué red llegar a ellos. - `certificatesResolvers`: registra una cuenta ACME con tu correo y guarda los certificados en `acme.json`. Cambia `admin@your_domain` por un correo real, ya que Let's Encrypt lo usa para avisos. - `api.dashboard`: activa el panel web, que publicarás de forma protegida en el paso 6. ## Paso 4: Arrancar Traefik con Docker Compose Crea el fichero de Compose: ```bash nano compose.yaml ``` ```yaml services: traefik: image: traefik:v3 container_name: traefik restart: unless-stopped ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yml:/etc/traefik/traefik.yml:ro - ./letsencrypt:/letsencrypt networks: - proxy networks: proxy: external: true ``` Traefik lee por defecto `/etc/traefik/traefik.yml`, así que no hace falta pasarle ningún argumento. El socket de Docker se monta en solo lectura porque Traefik solo necesita consultar los contenedores. > Advertencia: el acceso al socket de Docker equivale a acceso root en el host. Usa siempre la imagen oficial `traefik` y no expongas el panel sin autenticación. Arranca el contenedor: ```bash docker compose up -d ``` Comprueba que está en marcha y que no hay errores en el registro: ```bash docker compose ps docker compose logs traefik ``` ```output NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS traefik traefik:v3 "/entrypoint.sh trae…" traefik 10 seconds ago Up 9 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp traefik | time="..." level=info msg="Traefik version 3.x.x built on ..." ``` ## Paso 5: Publicar un servicio con HTTPS Como servicio de ejemplo usarás `traefik/whoami`, un pequeño servidor web que responde con los datos de la petición y el nombre del contenedor. Crea un proyecto aparte, como harías con una aplicación real: ```bash mkdir -p /opt/traefik/whoami nano /opt/traefik/whoami/compose.yaml ``` ```yaml services: whoami: image: traefik/whoami restart: unless-stopped networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.your_domain`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.services.whoami.loadbalancer.server.port=80" networks: proxy: external: true ``` Las etiquetas crean un router llamado `whoami` que acepta peticiones HTTPS para `whoami.your_domain` y las envía al puerto 80 del contenedor. No hay sección `ports:`: el contenedor no es accesible desde fuera salvo a través de Traefik. Arranca el servicio: ```bash cd /opt/traefik/whoami docker compose up -d ``` La primera vez, Traefik solicita el certificado a Let's Encrypt, lo que tarda unos segundos. Comprueba primero que HTTP redirige a HTTPS: ```bash curl -sI http://whoami.your_domain | grep -i location ``` ```output Location: https://whoami.your_domain/ ``` Después comprueba la respuesta por HTTPS: ```bash curl https://whoami.your_domain ``` ```output Hostname: 8d2f4c1b7a9e IP: 127.0.0.1 IP: 172.18.0.3 RemoteAddr: 172.18.0.2:41234 GET / HTTP/1.1 Host: whoami.your_domain ... ``` Si `curl` devuelve un error de certificado, revisa el registro de Traefik con `docker logs traefik`; el mensaje de ACME indica si falló la resolución DNS o el acceso al puerto 80. ### Balancear carga entre réplicas Cuando un servicio de Compose tiene varios contenedores, Traefik los añade todos al mismo backend y reparte las peticiones en round-robin. Escala `whoami` a tres réplicas: ```bash docker compose up -d --scale whoami=3 ``` Lanza varias peticiones y fíjate en el campo `Hostname`, que cambia en cada respuesta: ```bash for i in 1 2 3; do curl -s https://whoami.your_domain | grep Hostname; done ``` ```output Hostname: 8d2f4c1b7a9e Hostname: 1a7c3e9f2b4d Hostname: 5e0b8d6a3c1f ``` ## Paso 6: Publicar el panel de Traefik con contraseña El panel muestra todos los routers, servicios y middlewares activos, así que debe ir protegido. Usarás el middleware `basicAuth` con un fichero de usuarios en formato htpasswd. Instala `htpasswd`, que está en el paquete `apache2-utils`: ```bash sudo apt install apache2-utils ``` Genera el usuario `admin` con hash bcrypt. El comando te pedirá la contraseña dos veces: ```bash htpasswd -cB /opt/traefik/usersfile admin chmod 600 /opt/traefik/usersfile ``` ```output New password: Re-type new password: Adding password for user admin ``` Edita `/opt/traefik/compose.yaml` y añade el fichero de usuarios y las etiquetas del panel al servicio `traefik`: ```bash nano /opt/traefik/compose.yaml ``` ```yaml services: traefik: image: traefik:v3 container_name: traefik restart: unless-stopped ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yml:/etc/traefik/traefik.yml:ro - ./letsencrypt:/letsencrypt - ./usersfile:/etc/traefik/usersfile:ro networks: - proxy labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.your_domain`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.middlewares=dashboard-auth" - "traefik.http.middlewares.dashboard-auth.basicauth.usersfile=/etc/traefik/usersfile" networks: proxy: external: true ``` `api@internal` es el servicio interno de Traefik que sirve el panel y su API. Al usar un fichero de usuarios en lugar de la etiqueta `basicauth.users` evitas tener que escapar los caracteres `$` del hash en el YAML de Compose. Recrea el contenedor para aplicar los cambios: ```bash cd /opt/traefik docker compose up -d ``` Comprueba que sin credenciales se deniega el acceso: ```bash curl -I https://traefik.your_domain/dashboard/ ``` ```output HTTP/2 401 www-authenticate: Basic realm="traefik" ``` Abre `https://traefik.your_domain/dashboard/` en el navegador (la barra final es necesaria), introduce el usuario `admin` y la contraseña, y verás los routers `whoami` y `dashboard` en la sección **HTTP**. ## Paso 7: Añadir middlewares a un servicio Los middlewares se declaran con etiquetas y se asignan a un router con `routers..middlewares`. Como ejemplo, limita `whoami` a una media de 10 peticiones por segundo por IP de origen, con ráfagas de hasta 20, y añade la cabecera HSTS. Edita `/opt/traefik/whoami/compose.yaml` y amplía las etiquetas: ```bash nano /opt/traefik/whoami/compose.yaml ``` ```yaml labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`whoami.your_domain`)" - "traefik.http.routers.whoami.entrypoints=websecure" - "traefik.http.routers.whoami.middlewares=whoami-ratelimit,whoami-headers" - "traefik.http.services.whoami.loadbalancer.server.port=80" - "traefik.http.middlewares.whoami-ratelimit.ratelimit.average=10" - "traefik.http.middlewares.whoami-ratelimit.ratelimit.burst=20" - "traefik.http.middlewares.whoami-headers.headers.stsSeconds=31536000" ``` Aplica el cambio y comprueba que la cabecera aparece en la respuesta: ```bash cd /opt/traefik/whoami docker compose up -d curl -sI https://whoami.your_domain | grep -i strict-transport ``` ```output strict-transport-security: max-age=31536000 ``` Si superas el límite, Traefik responde con `429 Too Many Requests`. ## Solución de problemas - **`404 page not found` al acceder al dominio**: Traefik no tiene un router para ese host. Comprueba que el contenedor tiene `traefik.enable=true`, que está en la red `proxy` y que la regla `Host` coincide exactamente con el dominio. - **`Gateway Timeout` o `Bad Gateway`**: el contenedor está en una red a la que Traefik no llega o el puerto de `loadbalancer.server.port` no es el puerto en el que escucha la aplicación dentro del contenedor. - **El navegador muestra el certificado `TRAEFIK DEFAULT CERT`**: Let's Encrypt no pudo validar el dominio. Revisa `docker logs traefik | grep -i acme`; lo habitual es que el registro DNS aún no apunte al servidor o que el puerto 80 esté bloqueado. - **Errores de límite de Let's Encrypt (`too many certificates`)**: no borres `letsencrypt/acme.json` para reintentar, ya que Traefik vuelve a pedir todos los certificados. Durante las pruebas puedes añadir `caServer: https://acme-staging-v02.api.letsencrypt.org/directory` dentro del bloque `acme`. ## Conclusión Tienes Traefik funcionando como punto de entrada único de tu servidor, con redirección a HTTPS, certificados de Let's Encrypt que se renuevan solos, balanceo entre réplicas y un panel protegido. Para publicar cualquier otra aplicación basta con conectarla a la red `proxy` y añadirle las etiquetas del paso 5. Como siguientes pasos, puedes usar el reto DNS para obtener certificados comodín, activar las métricas de Prometheus de Traefik o añadir el middleware `ipAllowList` para restringir el panel a tu IP.