Si corres más de tres servicios autoalojados, ya chocaste con el infierno de los puertos. Jellyfin en el 8096, Immich en el 2283, Forgejo en el 3000: recordar qué puerto corresponde a qué servicio deja de tener gracia muy rápido. Traefik v3 lo resuelve de forma limpia: un solo contenedor LXC maneja todo el tráfico de entrada, termina el TLS y enruta por hostname automáticamente. Sin bloques de nginx que editar a mano cada vez que agregas un servicio.
Este es un recorrido completo: crear el LXC, configurar Traefik v3 con los proveedores de Docker y de archivos, conectar Let's Encrypt con el desafío DNS-01 de Cloudflare y armar un stack de middlewares que vale la pena conservar. Al final, cada servicio tiene un subdominio HTTPS real con certificados que se renuevan solos, sin nada autofirmado.
¿Por qué Traefik y no Nginx Proxy Manager?
NPM está bien para empezar. Traefik es mejor para ingenieros. La diferencia clave: Traefik detecta contenedores Docker nuevos y reconfigura el enrutamiento automáticamente con etiquetas, sin clics en una interfaz ni ediciones manuales de configuración. Defines la ruta en tu docker-compose.yml y queda activa. El proveedor de archivos se encarga de los servicios que no son Docker (LXC simples, VMs, cualquier cosa con una IP). Traefik v3, lanzado en 2024, dejó atrás mucho lastre heredado y ajustó la API de middlewares.
La contrapartida es real: la sintaxis de configuración de Traefik tiene su curva de aprendizaje. Reserva entre 30 y 60 minutos la primera vez.
Hardware para este setup
Un mini PC Beelink EQ12 como host de Proxmox es suficiente: 16 GB de RAM, N100 y unos 6 W en reposo según el fabricante. Margen de sobra para un stack de homelab completo. Para almacenamiento, un SSD SATA Samsung 870 EVO de 1 TB para el sistema y un disco NAS WD Red Plus de 4 TB para el almacenamiento masivo. La red puede pasar por un switch administrable TP-Link TL-SG108E de 8 puertos con reservas DHCP fijas para cada nodo.
Si vas a crecer a algo más grande, el Minisforum MS-01 con doble 10GbE vale la inversión, y vas a querer un UPS CyberPower CP1500PFCLCD para mantener todo encendido durante cortes breves.
Paso 1: crea el LXC de Traefik
Usa el script de la comunidad: está mantenido y te ahorra 20 minutos:
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/traefik.sh)"
Acepta los valores por defecto: Debian 12, 512 MB de RAM, 1 vCPU y 4 GB de disco. Asígnale una IP fija (en esta guía uso 192.168.0.10) y resérvala en el router. Después de crearlo, anota el ID del contenedor. Define el hostname:
pct exec <CTID> -- hostnamectl set-hostname traefik
Paso 2: configuración estática (traefik.yaml)
La configuración estática vive en /etc/traefik/traefik.yaml dentro del LXC. Es la configuración de arranque de Traefik y no se recarga en caliente. Entra al LXC por SSH:
pct enter <CTID>
nano /etc/traefik/traefik.yaml
Esta es una configuración estática lista para producción:
global:
checkNewVersion: false
sendAnonymousUsage: false
api:
dashboard: true
insecure: false
log:
level: INFO
filePath: /var/log/traefik/traefik.log
accessLog:
filePath: /var/log/traefik/access.log
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: your@email.com
storage: /etc/traefik/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
providers:
file:
directory: /etc/traefik/conf.d
watch: true
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik_net
Decisiones clave: HTTP redirige automáticamente a HTTPS en el entrypoint, exposedByDefault: false significa que tú eliges qué contenedores exponer en lugar de exponer todo por accidente, y el desafío DNS-01 hace que no necesites el puerto 80 abierto hacia afuera, algo crítico en homelabs detrás de CGNAT.
Paso 3: token de API de Cloudflare para DNS-01
En Cloudflare: Profile → API Tokens → Create Token → plantilla "Edit zone DNS". Limítalo a tu zona específica. Copia el token.
Defínelo como variable de entorno en la unidad de systemd de Traefik:
systemctl edit traefik
Agrega:
[Service]
Environment="CF_DNS_API_TOKEN=your_cloudflare_token_here"
Crea el archivo de almacenamiento ACME y restringe sus permisos:
touch /etc/traefik/acme.json
chmod 600 /etc/traefik/acme.json
Reinicia Traefik:
systemctl restart traefik
journalctl -u traefik -f
La primera vez, prueba contra la CA de staging de Let's Encrypt agregando caServer: "https://acme-staging-v02.api.letsencrypt.org/directory" al bloque acme:. Hazlo antes de pasar a producción o vas a chocar con los límites de emisión.
Paso 4: proveedor de archivos, para servicios que no son Docker
El proveedor de archivos vigila /etc/traefik/conf.d/ y recarga en caliente cuando hay cambios. Crea un YAML por servicio o agrúpalos. Este es el del propio Proxmox en 192.168.0.100:8006:
# /etc/traefik/conf.d/proxmox.yaml
http:
routers:
proxmox:
rule: "Host(`proxmox.yourdomain.com`)"
service: proxmox
tls:
certResolver: letsencrypt
middlewares:
- secure-headers
services:
proxmox:
loadBalancer:
servers:
- url: "https://192.168.0.100:8006"
passHostHeader: true
serversTransport: ignorecert
serversTransports:
ignorecert:
insecureSkipVerify: true
middlewares:
secure-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
contentTypeNosniff: true
frameDeny: true
browserXssFilter: true
insecureSkipVerify es necesario por el certificado autofirmado de Proxmox; como Traefik termina el TLS hacia afuera, es seguro.
Paso 5: proveedor de Docker, enrutamiento automático de contenedores
Para servicios en Docker, usa etiquetas en tu docker-compose.yml. Este es el de Immich:
services:
immich-server:
image: ghcr.io/immich-app/immich-server:release
networks:
- traefik_net
labels:
- "traefik.enable=true"
- "traefik.http.routers.immich.rule=Host(`photos.yourdomain.com`)"
- "traefik.http.routers.immich.entrypoints=websecure"
- "traefik.http.routers.immich.tls.certresolver=letsencrypt"
- "traefik.http.services.immich.loadbalancer.server.port=2283"
networks:
traefik_net:
external: true
Primero crea la red compartida:
docker network create traefik_net
Traefik ve la etiqueta, crea el router y el servicio y solicita un certificado, todo sin reiniciar. Por esto los ingenieros prefieren Traefik frente a las alternativas con interfaz gráfica.
Paso 6: protege el panel
No corras el panel con insecure: true. Agrega autenticación HTTP Basic:
htpasswd -nb admin yourpassword
Pega la salida en una configuración del proveedor de archivos:
# /etc/traefik/conf.d/dashboard.yaml
http:
routers:
dashboard:
rule: "Host(`traefik.yourdomain.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))"
service: api@internal
tls:
certResolver: letsencrypt
middlewares:
- dashboard-auth
middlewares:
dashboard-auth:
basicAuth:
users:
- "admin:$apr1$..." # output from htpasswd
Firewall y redirección de puertos
Abre los puertos 80 y 443 en tu router apuntando a la IP fija del LXC de Traefik. Esa es la única exposición externa. Todo lo demás se queda interno. Si configuraste OPNsense como firewall de Proxmox, crea la regla NAT ahí en lugar de depender del router de tu proveedor: te da registro por regla y una segmentación por VLANs más fácil.
Si estás detrás de CGNAT o prefieres no redirigir ningún puerto, Traefik se combina perfectamente con Cloudflare Tunnel: Traefik maneja el enrutamiento interno y el TLS, y el túnel se encarga del acceso externo sin abrir el 443.
Problemas comunes
El certificado no se emite. El 99% de las veces son los permisos de acme.json o un token de Cloudflare con el alcance equivocado. Revisa journalctl -u traefik -f justo después de reiniciar: el mensaje de error es explícito.
502 Bad Gateway. Traefik llegó al router, pero el backend está caído o el puerto es incorrecto. Verifícalo con curl http://192.168.0.x:PORT desde dentro del LXC de Traefik.
El router no coincide. Las reglas distinguen mayúsculas y minúsculas. Host() requiere el hostname en minúsculas: Host('Photos.domain.com') no va a coincidir con una petición a photos.domain.com.
Seguridad del socket de Docker. Montar /var/run/docker.sock directamente le da a Traefik acceso equivalente a root sobre el demonio de Docker. En un entorno compartido o de confianza parcial, ponle delante docker-socket-proxy y limítalo a llamadas de API de solo lectura.
Cómo encaja en un stack más grande
Traefik es la capa de entrada: no reemplaza a un gestor de contenedores. Si usas Coolify v4 en Proxmox LXC, configura Coolify para usar Traefik como proxy en lugar del Caddy integrado. Los dos se llevan bien: Coolify maneja el ciclo de vida de los despliegues y Traefik se encarga del enrutamiento y los certificados.
Si quieres un nodo de Traefik dedicado y siempre encendido, separado de tu host principal de Proxmox, una Raspberry Pi 5 de 8 GB consume menos de 5 W en reposo. Combínala con una carcasa USB para SSD y un SSD de 120 GB para tener mejor resistencia a la escritura que con una tarjeta SD.
Veredicto
Traefik v3 es el proxy inverso correcto para un homelab que ya dejó de ser un juguete. La curva de aprendizaje es real, pero acotada: una vez que funcionan la configuración estática y la primera ruta del proveedor de archivos, cada servicio nuevo se agrega en cinco minutos. El enrutamiento automático por etiquetas de Docker es realmente mejor que cualquier alternativa con interfaz gráfica, y el flujo de Let's Encrypt + DNS-01 de Cloudflare te da certificados reales incluso detrás de CGNAT.
El script de la comunidad te lleva de cero a funcionando en menos de 10 minutos. Esta guía cubre el 90% de la configuración que el script deja en tus manos.
Aviso: este artículo contiene enlaces de afiliado. Si compras a través de ellos, puedo ganar una pequeña comisión sin costo extra para ti.
¿Quieres algo así para tu negocio?
Instalo infraestructura privada y autoalojada en Proxmox: IA, automatización y herramientas internas en hardware que es tuyo, documentado y entregado. Ver el stack de IA privada →
¿No sabes qué necesitas? Agenda una llamada gratis.