Problema
Al ejecutar wg‑easy dentro de un contenedor Docker en un router OpenWrt, los clientes WireGuard establecen la conexión pero pierden la capacidad de alcanzar tanto la LAN como la WAN. Las peticiones DNS (por ejemplo a 1.1.1.1) nunca llegan, y cualquier intento de ping a la puerta de enlace local devuelve Destination Port Unreachable. El síntoma típico es una interfaz tun0 activa en el cliente, tráfico visible en el contenedor, pero sin rutas de salida hacia la red del router ni hacia Internet.
Este escenario no es exclusivo de wg‑easy; cualquier contenedor que exponga una interfaz TUN y dependa del puente Docker para el enrutamiento puede quedar aislado por la configuración predeterminada del firewall y del NAT de OpenWrt.
Causa
-
Aislamiento del puente Docker
Docker crea una redbridge(por ejemplowg) que, por defecto, no tiene reglas de NAT ni de reenvío hacia la zona LAN de OpenWrt. El tráfico que sale portun0llega al contenedor, pero nunca cruza el puente haciabr‑lan. -
Reglas de firewall de OpenWrt
OpenWrt clasifica sus interfaces en zonas (lan,wan,guest, etc.). Si la interfaz virtualwg0(creada por wg‑easy) no está asignada a una zona con permiso de reenvío, los paquetes son descartados antes de que el router pueda masqueradearlos. -
Falta de
MASQUERADEpara la subred de WireGuard
La subred interna de wg‑easy (por ejemplo10.42.42.0/24) necesita una regla de NAT que convierta sus direcciones en la IP del router antes de enviarlas a la WAN. Sin ella, la respuesta nunca vuelve al cliente. -
Configuración de DNS en el cliente
wg‑easy suele advertir al cliente que use la IP del propio contenedor (10.42.42.1) como servidor DNS. Si el contenedor no puede reenviar consultas DNS a un resolvedor externo, la resolución falla y parece que “no hay DNS”. -
Parámetros de sysctl incompletos
Algunas variables (net.ipv4.ip_forward,net.ipv4.conf.all.src_valid_mark) son necesarias para que el kernel acepte paquetes con marcas de origen válidas y los reenvíe entre interfaces. Si no se establecen, el tráfico se bloquea silenciosamente.
Solución
1. Verificar y asignar la zona de firewall
En la UI de LuCI o mediante uci, crea una zona “wg” y permite el reenvío hacia “lan” y “wan”.
uci add firewall zone
uci set firewall.@zone[-1].name='wg'
uci set firewall.@zone[-1].network='wg0'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'
# Permitir forwarding wg → lan y wg → wan
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='lan'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='wan'
uci commit firewall
/etc/init.d/firewall restart
2. Añadir regla NAT para la subred de WireGuard
iptables -t nat -A POSTROUTING -s 10.42.42.0/24 -o br-lan -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.42.42.0/24 -o eth0 -j MASQUERADE # si eth0 es la WAN
Persistir la regla en /etc/firewall.user o usando uci:
uci add firewall redirect
uci set firewall.@redirect[-1].src='*'
uci set firewall.@redirect[-1].src_dport='51820'
uci set firewall.@redirect[-1].target='DNAT'
uci set firewall.@redirect[-1].dest='wg'
uci commit firewall
3. Habilitar el reenvío IP y los marcadores de origen
Asegúrate de que los sysctls están activos en el host y dentro del contenedor. En OpenWrt:
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.src_valid_mark=1
En el docker‑compose.yml ya aparecen bajo sysctls, pero verifica que el archivo real se cargó:
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
4. Configurar DNS para los clientes WireGuard
En la sección [Interface] del archivo de configuración generado por wg‑easy, añade:
DNS = 10.42.42.1
Si prefieres usar un resolvedor externo, habilita el reenvío de consultas DNS desde el contenedor:
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p udp --sport 53 -j ACCEPT
O instala dnsmasq dentro del contenedor y apunta a 1.1.1.1 como upstream.
5. Revisar la definición de la red Docker
El puente wg debe estar conectado a la red LAN del host para que el router vea la IP del contenedor como parte de la LAN. En docker‑compose.yml:
networks:
wg:
driver: bridge
enable_ipv6: true
ipam:
config:
- subnet: 10.42.42.0/24
Asegúrate de que ipv4_address asignado al contenedor (10.42.42.42) no colisiona con ninguna IP estática de la LAN.
6. Reiniciar servicios
docker compose down && docker compose up -d
/etc/init.d/firewall restart
Cuándo aplicar esta solución
- Síntomas: cliente WireGuard conectado, pero sin acceso a LAN, WAN o DNS;
pinga la puerta de enlace devuelve Destination Port Unreachable;nslookupnunca alcanza servidores externos. - Entorno: router OpenWrt con Docker instalado, contenedor que expone WireGuard (wg‑easy, wireguard-go, etc.) y usa una red bridge personalizada.
- Exclusiones: si el contenedor se ejecuta en modo
host(no hay puente) o si la LAN ya está configurada como zona de reenvío para la interfazwg0, la regla NAT y la zona adicional pueden ser redundantes.
Código
# 1. Crear zona wg y permitir forwarding
uci add firewall zone
uci set firewall.@zone[-1].name='wg'
uci set firewall.@zone[-1].network='wg0'
uci set firewall.@zone[-1].input='ACCEPT'
uci set firewall.@zone[-1].output='ACCEPT'
uci set firewall.@zone[-1].forward='REJECT'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='lan'
uci add firewall forwarding
uci set firewall.@forwarding[-1].src='wg'
uci set firewall.@forwarding[-1].dest='wan'
uci commit firewall
/etc/init.d/firewall restart
# 2. Regla NAT para la subred WireGuard
iptables -t nat -A POSTROUTING -s 10.42.42.0/24 -o br-lan -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.42.42.0/24 -o eth0 -j MASQUERADE
# 3. Habilitar sysctls
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv4.conf.all.src_valid_mark=1
# 4. Reiniciar Docker y firewall
docker compose down && docker compose up -d
/etc/init.d/firewall restart
Verificación
-
Estado de la interfaz
ip a show wg0 ip a show tun0 # en el clientewg0debe tener una IP dentro de10.42.42.0/24. -
Prueba de ping a la LAN
ping -c 3 192.168.1.1Debería responder sin Destination Port Unreachable.
-
Resolución DNS
nslookup google.com 10.42.42.1La respuesta debe provenir del contenedor o del upstream configurado.
-
Comprobación de NAT
En el router:iptables -t nat -L POSTROUTING -n -v | grep 10.42.42.0La regla
MASQUERADEdebe mostrarse con contadores incrementándose tras el ping. -
Firewall logs
logread -e wg0No deberían aparecer rechazos de paquetes entre
wgylan/wan.
Notas adicionales
- Persistencia de iptables: OpenWrt vuelve a cargar
/etc/firewall.useren cada reinicio. Añade la regla NAT allí para evitar perderla. - Múltiples subredes: si utilizas IPv6 en wg‑easy, replica la regla
MASQUERADEcon-t nat -A POSTROUTING -s fdcc:ad94:bacf:61a3::/64 -j MASQUERADE. - Docker‑compose vs. Docker‑run: los parámetros
--cap-add=NET_ADMINy--sysctlson obligatorios; omitirlos vuelve a producir el aislamiento. - Depuración rápida:
tcpdump -i wg0 -nnen el router muestra si los paquetes