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) ytraefik.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: defineletsencrypt, 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.logyaccessLog: 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 connectoConnection refuseden el journal: Let's Encrypt no llega al puerto 80. Comprueba el registro DNS condig +short your_domainy 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: ejecutasudo chmod 600 /var/lib/traefik/acme.jsony reinicia consudo systemctl restart traefik.bind: permission deniedal arrancar: faltaAmbientCapabilities=CAP_NET_BIND_SERVICEen la unidad, o no ejecutastedaemon-reloaddespué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.
