Traefik es un proxy inverso y balanceador de carga escrito en Go que obtiene certificados de Let's Encrypt automáticamente y recarga sus rutas en caliente, sin reiniciar el proceso. Aunque es muy popular con Docker y Kubernetes, también funciona perfectamente como binario independiente delante de aplicaciones que corren en el propio servidor. En este tutorial instalarás Traefik v3 en Ubuntu 24.04 como servicio de systemd con un usuario sin privilegios, publicarás una aplicación local con HTTPS y protegerás el dashboard con usuario y contraseña.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Un dominio con dos registros DNS de tipo A apuntando a la IP del servidor: your_domain (para la aplicación) y traefik.your_domain (para el dashboard).
  • Los puertos 80 y 443 libres: si tienes Nginx o Apache instalados, detenlos antes de empezar.

A lo largo de la guía sustituye your_domain por tu dominio y admin@your_domain por un correo real, que Let's Encrypt usa para avisos de caducidad.

Paso 1: Descargar el binario de Traefik

Traefik se distribuye como un único binario en las releases de GitHub. Obtén el número de la última versión publicada:

TRAEFIK_VERSION=$(curl -fsSL https://api.github.com/repos/traefik/traefik/releases/latest | grep -Po '"tag_name": "\K[^"]+')
echo "$TRAEFIK_VERSION"
v3.7.13

Comprueba que empieza por v3. Descarga el archivo para tu arquitectura (amd64 en la mayoría de servidores, arm64 en ARM) junto con su archivo de sumas de verificación:

cd /tmp
curl -fsSLO "https://github.com/traefik/traefik/releases/download/${TRAEFIK_VERSION}/traefik_${TRAEFIK_VERSION}_linux_amd64.tar.gz"
curl -fsSLO "https://github.com/traefik/traefik/releases/download/${TRAEFIK_VERSION}/traefik_${TRAEFIK_VERSION}_checksums.txt"
sha256sum --ignore-missing -c "traefik_${TRAEFIK_VERSION}_checksums.txt"
traefik_v3.7.13_linux_amd64.tar.gz: OK

Extrae el binario e instálalo en /usr/local/bin:

tar -xzf "traefik_${TRAEFIK_VERSION}_linux_amd64.tar.gz" traefik
sudo install -m 0755 traefik /usr/local/bin/traefik
traefik version
Version:      3.7.13
Codename:     langres
Go version:   go1.26.8
Built:        2026-09-04T12:32:22Z
OS/Arch:      linux/amd64

Paso 2: Crear el usuario y los directorios

Traefik no necesita ejecutarse como root. Crea un usuario de sistema sin shell ni directorio personal:

sudo useradd --system --no-create-home --shell /usr/sbin/nologin traefik

Crea el directorio de configuración, uno para la configuración dinámica y otro para guardar los certificados:

sudo mkdir -p /etc/traefik/dynamic /var/lib/traefik
sudo chown -R root:traefik /etc/traefik
sudo chmod 750 /etc/traefik /etc/traefik/dynamic
sudo chown traefik:traefik /var/lib/traefik
sudo chmod 700 /var/lib/traefik

Traefik guarda los certificados y sus claves privadas en un archivo JSON y se niega a usarlo si otros usuarios pueden leerlo. Créalo vacío con permisos 600:

sudo install -o traefik -g traefik -m 600 /dev/null /var/lib/traefik/acme.json

Paso 3: Escribir la configuración estática

Traefik separa dos tipos de configuración:

  • Estática (traefik.yml): puntos de entrada, proveedores y resolvedores de certificados. Se lee al arrancar.
  • Dinámica (archivos en /etc/traefik/dynamic/): routers, servicios y middlewares. Traefik la recarga automáticamente al detectar cambios.

Crea la configuración estática:

sudo nano /etc/traefik/traefik.yml
entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@your_domain
      storage: /var/lib/traefik/acme.json
      httpChallenge:
        entryPoint: web

providers:
  file:
    directory: /etc/traefik/dynamic
    watch: true

api:
  dashboard: true

log:
  level: INFO

accessLog: {}

Qué hace cada bloque:

  • entryPoints: Traefik escucha en los puertos 80 y 443 y redirige todo el tráfico HTTP a HTTPS.
  • certificatesResolvers: define letsencrypt, que obtiene certificados mediante el reto HTTP-01 en el puerto 80.
  • providers.file: lee rutas desde archivos YAML y las recarga al cambiar.
  • api.dashboard: activa el dashboard, que solo será accesible a través del router protegido que crearás en el paso 6.
  • log y accessLog: sin archivo de destino, ambos van a la salida estándar y los recoge el journal de systemd.

Paso 4: Crear el servicio de systemd

Crea la unidad de systemd. AmbientCapabilities=CAP_NET_BIND_SERVICE permite al usuario traefik escuchar en los puertos 80 y 443 sin ser root, y las opciones Protect* limitan lo que el proceso puede modificar en el sistema:

sudo nano /etc/systemd/system/traefik.service
[Unit]
Description=Traefik reverse proxy
Documentation=https://doc.traefik.io/traefik/
Wants=network-online.target
After=network-online.target

[Service]
User=traefik
Group=traefik
ExecStart=/usr/local/bin/traefik --configFile=/etc/traefik/traefik.yml
Restart=on-failure
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
ReadWritePaths=/var/lib/traefik
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target

Abre los puertos en el firewall. Si UFW está activo, recuerda permitir también SSH para no perder el acceso:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Arranca Traefik y habilítalo al inicio:

sudo systemctl daemon-reload
sudo systemctl enable --now traefik
sudo systemctl status traefik --no-pager
● traefik.service - Traefik reverse proxy
     Loaded: loaded (/etc/systemd/system/traefik.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-09-25 10:04:12 UTC; 3s ago

Comprueba que escucha en ambos puertos:

sudo ss -tlnp | grep traefik
LISTEN 0      4096               *:443              *:*    users:(("traefik",pid=2215,fd=8))
LISTEN 0      4096               *:80               *:*    users:(("traefik",pid=2215,fd=7))

Paso 5: Publicar una aplicación con HTTPS

Para la prueba necesitas una aplicación escuchando en local. Si todavía no tienes una, abre una segunda terminal y arranca un servidor HTTP de prueba con Python en el puerto 8080, solo en 127.0.0.1:

mkdir -p ~/demo && echo "Hola desde el backend" > ~/demo/index.html
python3 -m http.server 8080 --bind 127.0.0.1 --directory ~/demo

De vuelta en la primera terminal, crea la configuración dinámica. Un router decide qué peticiones atiende (por el nombre de host) y un servicio define a qué backend las envía:

sudo nano /etc/traefik/dynamic/app.yml
http:
  routers:
    app:
      rule: "Host(`your_domain`)"
      entryPoints:
        - websecure
      service: app
      tls:
        certResolver: letsencrypt

  services:
    app:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

Asigna el archivo al grupo traefik para que pueda leerlo:

sudo chown root:traefik /etc/traefik/dynamic/app.yml
sudo chmod 640 /etc/traefik/dynamic/app.yml

No hace falta reiniciar nada: Traefik detecta el archivo nuevo, crea el router y solicita el certificado. Sigue el proceso en el journal:

sudo journalctl -u traefik -f

Si ves errores de ACME, revisa la sección de solución de problemas. Cuando el certificado esté listo, pulsa Ctrl+C y prueba la aplicación:

curl -I http://your_domain
curl https://your_domain

La primera petición devuelve una redirección permanente (código 301 o 308) a https://your_domain/, y la segunda el contenido del backend:

Hola desde el backend

Para repartir carga entre varios backends basta con añadir más entradas a servers. Traefik las usa en round robin.

Paso 6: Proteger el dashboard

El dashboard muestra todos los routers, servicios y middlewares activos, por lo que nunca debe quedar abierto. Instala htpasswd para generar la contraseña cifrada con bcrypt:

sudo apt install apache2-utils
htpasswd -nB admin

Introduce una contraseña robusta cuando la pida. El comando imprime una línea como esta, que usarás en la configuración:

admin:$2y$05$3Q2m8kYx1vQ7bq0Jd1Hk9eQyA3Zb7x1bJ0Vn8S1pD8m2Qf0nWkZ5G

Crea el router del dashboard con un middleware de autenticación básica:

sudo nano /etc/traefik/dynamic/dashboard.yml
http:
  routers:
    dashboard:
      rule: "Host(`traefik.your_domain`)"
      entryPoints:
        - websecure
      service: api@internal
      middlewares:
        - dashboard-auth
      tls:
        certResolver: letsencrypt

  middlewares:
    dashboard-auth:
      basicAuth:
        users:
          - 'admin:$2y$05$3Q2m8kYx1vQ7bq0Jd1Hk9eQyA3Zb7x1bJ0Vn8S1pD8m2Qf0nWkZ5G'

Sustituye el hash por el que generaste. Usa comillas simples para que el $ no se interprete. api@internal es el servicio interno de Traefik que sirve el dashboard y la API.

sudo chown root:traefik /etc/traefik/dynamic/dashboard.yml
sudo chmod 640 /etc/traefik/dynamic/dashboard.yml

Comprueba que sin credenciales se rechaza el acceso y con ellas no:

curl -s -o /dev/null -w "%{http_code}\n" https://traefik.your_domain/dashboard/
curl -s -o /dev/null -w "%{http_code}\n" -u admin https://traefik.your_domain/dashboard/
401
200

Abre https://traefik.your_domain/dashboard/ en el navegador (la barra final es necesaria) para ver los routers app y dashboard en verde.

Paso 7: Añadir cabeceras de seguridad

Los middlewares se reutilizan entre routers. Añade uno que envíe HSTS y otras cabeceras de seguridad a la aplicación editando /etc/traefik/dynamic/app.yml:

sudo nano /etc/traefik/dynamic/app.yml
http:
  routers:
    app:
      rule: "Host(`your_domain`)"
      entryPoints:
        - websecure
      service: app
      middlewares:
        - security-headers
      tls:
        certResolver: letsencrypt

  middlewares:
    security-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        contentTypeNosniff: true
        frameDeny: true
        referrerPolicy: "strict-origin-when-cross-origin"

  services:
    app:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

Verifica las cabeceras:

curl -sI https://your_domain | grep -iE 'strict-transport|x-frame|x-content'
strict-transport-security: max-age=31536000; includeSubDomains
x-content-type-options: nosniff
x-frame-options: DENY

Solución de problemas

  • acme: error: 400 ... Timeout during connect o Connection refused en el journal: Let's Encrypt no llega al puerto 80. Comprueba el registro DNS con dig +short your_domain y que el puerto 80 esté abierto en UFW y en el firewall del proveedor.
  • permissions 644 for /var/lib/traefik/acme.json are too open: ejecuta sudo chmod 600 /var/lib/traefik/acme.json y reinicia con sudo systemctl restart traefik.
  • bind: permission denied al arrancar: falta AmbientCapabilities=CAP_NET_BIND_SERVICE en la unidad, o no ejecutaste daemon-reload después de editarla.
  • 404 page not found: ningún router coincide con la petición. Revisa la regla Host() y comprueba en el journal que Traefik no ha rechazado el archivo YAML por un error de sintaxis.
  • 502 Bad Gateway: Traefik no conecta con el backend. Verifica que la aplicación escucha en la dirección configurada con curl http://127.0.0.1:8080.

Conclusión

Tienes Traefik v3 funcionando como servicio de systemd sin privilegios de root, publicando una aplicación con certificados de Let's Encrypt que se renuevan solos, redirección de HTTP a HTTPS, cabeceras de seguridad y un dashboard protegido. Como siguientes pasos, puedes añadir más aplicaciones con un archivo por servicio en /etc/traefik/dynamic/, usar el reto DNS-01 para obtener certificados comodín, o activar el proveedor de Docker para que Traefik descubra contenedores a partir de sus etiquetas.