Problema
En entornos homelab donde TrueNAS actúa como nodo de almacenamiento y también ejecuta contenedores Docker (a través de Dockhand o plugins), es frecuente querer exponer varios servicios mediante un único punto de entrada. El objetivo suele ser:
- Un reverse proxy que escuche en 80/443 en una IP dedicada.
- Certificados TLS válidos tanto para acceso externo (Let’s Encrypt) como para tráfico interno LAN, evitando que los dispositivos locales consuman ancho de banda de la nube.
- Resolución DNS interna que apunte los sub‑dominios al alias IP del proxy, sin interferir con la red de la ISP.
- Integración con herramientas de hardening (crowdsec, geoblocking, Suricata).
El bloqueo típico ocurre cuando el contenedor del proxy no puede unirse a la red que TrueNAS ha configurado (bridge, macvlan o alias). El error se manifiesta como “network not found” o “port already allocated”, y la UI de Dockhand muestra que el contenedor está detenido. Sin una red adecuada, los certificados ACME no pueden validar dominios y la resolución DNS interna no funciona.
Causa
Los fallos más comunes provienen de tres áreas:
-
Modelo de red de Docker
bridgepredeterminado no permite que el contenedor escuche en una IP distinta a la del host.hostelimina el aislamiento de puertos pero impide asignar una IP alias.macvlannecesita una sub‑red libre en el switch y la VLAN correcta; si el switch (UniFi) no permite tráfico entre la VLAN del host y la del contenedor, los paquetes se pierden.
-
Asignación de IP alias en TrueNAS
- La IP adicional debe estar configurada en la interfaz física y marcada como “secondary”.
- Si la máscara o la puerta de enlace no coinciden con la sub‑red del contenedor, el tráfico nunca llega al proxy.
-
Certificados y ACME challenge
- Cuando el contenedor está aislado, el puerto 80/443 que Let’s Encrypt necesita para el HTTP‑01 challenge no está expuesto al exterior.
- En LAN, los clientes pueden rechazar certificados auto‑firmados si el nombre del CN no coincide con la resolución DNS interna.
Solución
1. Preparar la interfaz de red en TrueNAS
- Accede a Network → Interfaces.
- Selecciona la NIC que usa TrueNAS y crea una Alias con la IP que reservarás para el proxy (ej.
192.168.10.10/24). - Aplica y verifica con
ping 192.168.10.10desde otro equipo de la LAN.
2. Crear una red Docker macvlan
El macvlan permite que el contenedor tenga su propia MAC e IP dentro de la sub‑red LAN, evitando colisiones con el host.
docker network create -d macvlan \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.1 \
-o parent=eth0 \
lan_proxy
eth0es la interfaz física de TrueNAS; ajústala si usas otro nombre.- La sub‑red debe coincidir con la de la IP alias.
3. Deploy de Traefik (ejemplo) dentro de Dockhand
En Dockhand, crea una nueva aplicación y pega el siguiente docker-compose.yml. Usa la red lan_proxy y asigna la IP alias al contenedor.
version: "3.8"
services:
traefik:
image: traefik:latest
container_name: traefik
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "[email protected]"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
ports: [] # No se exponen puertos en modo host
networks:
lan_proxy:
ipv4_address: 192.168.10.10
volumes:
- /mnt/pool/docker/traefik/letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
networks:
lan_proxy:
external: true
Puntos clave
ports: []evita conflicto con la IP alias; el tráfico llega directamente a la MAC del contenedor.ipv4_addressfija la IP del proxy a la alias configurada.- El volumen
letsencryptpersiste los certificados entre reinicios. --api.insecuresolo para pruebas; en producción habilita autenticación o usa el dashboard protegido.
4. Alternativa con Caddy (más simple para TLS automático)
version: "3.8"
services:
caddy:
image: caddy:latest
container_name: caddy
networks:
lan_proxy:
ipv4_address: 192.168.10.10
volumes:
- /mnt/pool/docker/caddy/Caddyfile:/etc/caddy/Caddyfile
- /mnt/pool/docker/caddy/data:/data
restart: unless-stopped
networks:
lan_proxy:
external: true
Caddyfile básico:
{
email [email protected]
acme_ca https://acme-v02.api.letsencrypt.org/directory
}
*.example.com {
reverse_proxy * http://192.168.10.20:3000
}
Caddy gestiona automáticamente los desafíos HTTP‑01 usando la IP del contenedor, sin necesidad de puertos expuestos.
5. Configurar DNS interno en UniFi
- En el controlador UniFi, abre Settings → Networks → DNS.
- Añade una entrada estática:
*.example.com → 192.168.10.10. - Asegúrate de que la VLAN donde está el alias IP tenga “Enable DNS Override” activo.
Con esto, cualquier sub‑dominio resuelve a la IP del proxy sin pasar por el DNS público.
6. Hardening básico
- CrowdSec: ejecuta como contenedor independiente y enlázalo a la red
lan_proxy. Configura elbouncerspara que Traefik/Caddy lean la lista de IP bloqueadas y añadan reglasIPBlock. - Suricata en UniFi: crea una regla que bloquee tráfico a
192.168.10.10fuera de la VLAN de gestión, evitando que dispositivos comprometidos usen el proxy como pivot. - TLS: habilita HSTS y
TLS 1.3en los entrypoints de Traefik (--entrypoints.websecure.http.tls.minVersion=VersionTLS13). - Firewall en TrueNAS: permite tráfico solo desde la sub‑red LAN a la IP alias, bloquea todo lo demás.
Cuándo aplicar esta solución
- Entorno homelab con TrueNAS como host Docker y necesidad de exponer varios servicios bajo sub‑dominios.
- Ancho de banda limitado en la nube; se busca que la LAN sirva contenido estático y backups.
- Requerimientos de TLS tanto externos (Let’s Encrypt) como internos (certificados auto‑firmados).
- Política de aislamiento: se prefiere que el proxy no comparta la pila de red del host para evitar conflictos de puertos.
No es recomendable cuando:
- La infraestructura de red no permite macvlan (por ejemplo, switches que filtran MAC desconocidas).
- Se necesita que el proxy acceda a recursos de la red del host mediante
localhost. En ese caso, usarhostnetwork con reglas de iptables específicas es más sencillo.
Código
# 1. Crear red macvlan
docker network create -d macvlan \
--subnet=192.168.10.0/24 \
--gateway=192.168.10.1 \
-o parent=eth0 \
lan_proxy
# 2. Deploy de Traefik con Docker Compose (guarda como docker-compose.yml)
cat > /mnt/pool/docker/traefik/docker-compose.yml <<'EOF'
version: "3.8"
services:
traefik:
image: traefik:latest
container_name: traefik
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "[email protected]"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
ports: []
networks:
lan_proxy:
ipv4_address: 192.168.10.10
volumes:
- /mnt/pool/docker/traefik/letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: unless-stopped
networks:
lan_proxy:
external: true
EOF
# 3. Levantar el stack
docker compose -f /mnt/pool/docker/traefik/docker-compose.yml up -d
Verificación
- Ping la IP del proxy desde otro equipo:
ping 192.168.10.10. - Accede a
http://example.comy verifica que el dashboard de Traefik (o Caddy) responde. - Usa
curl -I https://example.comy confirma que el certificado es válido (Let’s Encrypt) o que el certificado auto‑firmado se muestra sin errores de nombre. - En UniFi, revisa la tabla de DNS estático y confirma que
sub.example.comresuelve a192.168.10.10. - Revisa los logs de Traefik (
docker logs traefik) para asegurarte de que los desafíos ACME se completaron sin errores. - Simula un bloqueo con CrowdSec y verifica que la IP bloqueada recibe un
403del proxy.
Notas adicionales
- Persistencia de datos: siempre monta volúmenes externos para
/letsencrypt(Traefik) o/data(Caddy); de lo contrario perderás los certificados al reiniciar el contenedor. - MTU: en algunos switches macvlan necesita una MTU menor (1500 → 1492) para evitar fragmentación; ajusta con `–opt com