Problema

Muchos homelabs empiezan con hardware barato (Raspberry Pi, mini‑NAS) y van añadiendo servicios a medida que aparecen necesidades. Con el tiempo la cantidad de contenedores, redes Docker y túneles VPN crece hasta que la gestión se vuelve engorrosa: cada nodo tiene su propio firewall, DNS local y reverse proxy, y la topología de red está fragmentada. Cuando se adquiere un servidor más potente, la tentación es migrar todo a una única plataforma de virtualización, pero surge la duda de cómo reorganizar VMs/LXC, si mantener la malla WireGuard y cómo simplificar la cadena de DNS/Proxy sin perder la flexibilidad que ofrecían los nodos independientes.

El reto genérico es: consolidar varios hosts con funciones distintas en una sola máquina virtualizada, manteniendo aislamiento lógico, alta disponibilidad de servicios críticos y una arquitectura de red que siga permitiendo acceso interno y externo de forma segura.

Causa

  1. Distribución de servicios por nodo
    Cada Pi ejecuta un stack completo (por ejemplo, Grafana + Prometheus en una, CryptoPad en otra). La separación original se basó en limitaciones de CPU/RAM, no en requisitos de seguridad o aislamiento. Cuando el hardware ya no es un limitante, esa distribución se vuelve innecesaria.

  2. Redes Docker aisladas y puentes macvlan
    Traefik y AdGuard se exponen mediante macvlan para que el router los vea como dispositivos físicos. Los puentes entre contenedores de diferentes hosts se implementan con redes overlay manuales, lo que genera complejidad de configuración y depuración.

  3. Malla WireGuard entre todos los hosts
    La VPN sirve para conectar los dispositivos locales con un vServer externo y para exponer servicios a través de frp. Cada nodo mantiene su propia clave y endpoint, lo que implica gestión de pares duplicada y rutas estáticas en cada host.

  4. Dependencia de un NAS para tráfico de datos y reverse proxy
    El Synology aloja Traefik, AdGuard, bases de datos y multimedia. Cuando el NAS también actúa como router de capa 3, cualquier cambio en la topología afecta a la resolución DNS y a la disponibilidad del proxy.

  5. Falta de segmentación de red
    Todo el tráfico interno comparte la misma VLAN del router. Sin VLAN, los ataques laterales entre contenedores o entre servicios de diferentes niveles de confianza son más probables.

Solución

1. Definir roles lógicos y mapearlos a VMs o contenedores LXC

Rol lógico Recomendación de aislamiento Ejemplo de implementación
Reverse proxy / DNS (Traefik, AdGuard, Unbound) VM dedicada o LXC con macvlan para exposición directa VM “gateway” con 2 NIC: una macvlan en la red física y otra interna para los contenedores
Servicios de monitorización (Prometheus, Loki, Grafana, Alloy) LXC por su bajo overhead y fácil acceso a host‑level recursos LXC “monitoring” conectado a red interna de Proxmox
Home Assistant + Zigbee VM (para pasar USB dongle directamente) VM “home‑assistant” con passthrough del dongle
Aplicaciones web ligeras (CryptPad, SearXNG, IT‑Tools) LXC o Docker dentro de una VM “apps” LXC “apps‑light” con Docker instalado
Almacenamiento compartido (NAS) Mantener Synology como NFS/SMB only Montar NFS en todas las VMs/LXC
Túneles externos (frp, WireGuard) VM “tunnel” que centraliza los peers VM con 2 NIC: una macvlan para internet y otra interna para la malla

Con esta división se conserva la separación de confianza sin crear una VM por cada contenedor. Los LXC son ideales para procesos que no requieren acceso directo a hardware; las VMs se usan cuando se necesita passthrough (USB, GPU) o aislamiento completo.

2. Rediseñar la red en Proxmox

  1. Crear una bridge “vmbr0” vinculada al puerto físico del FritzBox.
  2. Definir una bridge interna “vmbr1” para la comunicación entre VMs/LXC.
  3. Asignar macvlan a la VM “gateway” para que Traefik y AdGuard aparezcan como dispositivos físicos en la LAN.
  4. Opcional: habilitar VLAN 10 (infra) y VLAN 20 (iot) en el switch del FritzBox y mapearlas a “vmbr0.10” y “vmbr0.20”. Cada VM recibe la VLAN correspondiente según su rol.

Esta arquitectura permite que los servicios de capa 7 (Traefik) sigan respondiendo a dominios locales sin depender de puentes Docker, y que el tráfico de IoT quede aislado en su propia VLAN.

3. Consolidar la malla WireGuard

  • Crear una única instancia de WireGuard en la VM “gateway”.
  • Cada cliente (ordenador, móvil, vServer) se conecta a esa única puerta de enlace.
  • En la VM “gateway” se habilita AllowedIPs = 0.0.0.0/0 para el vServer y rutas específicas (10.0.0.0/24) para los contenedores internos.
  • El resto de VMs/LXC usan la ruta predeterminada del host (/etc/network/interfaces o Netplan) para salir a través de la VM “gateway”.

Resultado: sólo una clave pública/privada que gestionar, y la topología de rutas se mantiene en un único punto.

4. Simplificar la cadena Traefik → AdGuard → Unbound

  1. Traefik actúa como entrypoint único (puerto 80/443) y se configura con providers.docker y providers.file para los contenedores internos.
  2. AdGuard Home se coloca detrás de Traefik como servicio Docker o LXC, pero con network_mode: bridge y sin macvlan.
  3. Unbound se ejecuta en la misma VM “gateway” o como contenedor independiente; su puerto 53 se expone solo a la red interna (vmbr1).
  4. Configuración DNS: los clientes internos usan la IP de la VM “gateway” como DNS. La VM reenvía consultas a Unbound, que a su vez delega a AdGuard para filtros de publicidad y a los resolvers externos para el resto.

Con este flujo, la exposición de DNS a la LAN se mantiene, pero se elimina la necesidad de puentes Docker entre hosts.

5. Preparar la futura integración de OPNsense y VLAN

  • Dejar “vmbr0” libre para que OPNsense, cuando se despliegue, tome el rol de router/firewall.
  • Mientras tanto, la VM “gateway” funciona como router temporal, pero todas las reglas de firewall se implementan con iptables o nftables dentro de esa VM.
  • Cuando OPNsense esté listo, simplemente migrar la IP pública y la regla de NAT a la nueva VM y desconectar la VM “gateway”.

Cuándo aplicar esta solución

  • Escalabilidad requerida: cuando el número de contenedores supera la capacidad de gestión manual de redes Docker.
  • Hardware consolidado disponible: un servidor con suficiente RAM/CPU para alojar varias VMs/LXC sin sobrecargar.
  • Necesidad de aislamiento lógico: si diferentes grupos de servicios (IoT, monitorización, multimedia) deben estar en VLAN separadas o con políticas de firewall distintas.
  • Gestión de VPN compleja: cuando la malla WireGuard tiene más de tres peers y la administración de claves se vuelve engorrosa.

No es recomendable si el entorno sigue siendo de bajo consumo (menos de 4 contenedores) o si el hardware disponible es limitado; en esos casos la sobrecarga de Proxmox puede ser innecesaria.

Código

# Crear bridge interno en Proxmox
cat > /etc/network/interfaces.d/vmbr1.cfg <<EOF
auto vmbr1
iface vmbr1 inet static
    address 10.10.10.1/24
    bridge_ports none
    bridge_stp off
    bridge_fd 0
EOF

# Configuración básica de WireGuard en la VM gateway
wg genkey | tee privatekey | wg pubkey > publickey
cat > /etc/wireguard/wg0.conf <<EOF
[Interface]
Address = 10.200.200.1/24
ListenPort = 51820
PrivateKey = $(cat privatekey)

# Peer ejemplo (vServer)
[Peer]
PublicKey = <vserver_public_key>
AllowedIPs = 10.200.200.2/32
Endpoint = your.vps.ip:51820
PersistentKeepalive = 25
EOF
systemctl enable --now wg-quick@wg0

Verificación

  1. Conectividad interna: ping desde una LXC “monitoring” a la IP de la VM “gateway” (10.10.10.1) y a la IP del NAS (NFS).
  2. Resolución DNS: dig @10.10.10.1 example.com debe devolver una respuesta y, si se prueba un dominio bloqueado, AdGuard debe devolver NXDOMAIN.
  3. Acceso externo: abrir https://midominio.tld desde fuera de la red; Traefik debe redirigir al contenedor correspondiente y el certificado debe ser válido.
  4. WireGuard: en un cliente remoto, wg show debe listar la interfaz con endpoint = <public_ip>:51820 y transfer > 0.
  5. VLAN: conectar un dispositivo a la VLAN IoT y comprobar que solo puede alcanzar la IP de Home Assistant y no la red de monitorización.

Notas adicionales

  • Passthrough de USB: la VM que aloje Home Assistant necesita habilitar usb0: host=xxxx:xxxx en la configuración de la VM y reiniciar el host para que el dongle sea reconocido.
  • Backup de VMs/LXC: usa vzdump con --mode snapshot para crear backups consistentes sin detener los contenedores.
  • Persistencia de macvlan: en la VM “gateway”, asigna la macvlan a una interfaz física que no