Confusión con AllowedIPs de WireGuard: por qué el tráfico no va a donde esperas (y cómo arreglarlo)

¿Te fue útil?

Levantas un túnel WireGuard. El handshake parece sano. Los contadores de bytes aumentan un poco. Y aun así el tráfico que querías que pasara por la VPN
sigue saliendo por la interfaz equivocada o, peor aún: desaparece en un vacío silencioso donde los pings van a morir.

Nueve de cada diez veces, la causa raíz no es la criptografía, el MTU ni “el internet está caído”. Es un malentendido de
AllowedIPs: qué significa, quién lo usa y cómo se convierte en rutas reales en un sistema operativo real.

El modelo mental: AllowedIPs es política de enrutamiento, no un ACL

Si te llevas una cosa: AllowedIPs es un input para la decisión de enrutamiento.
No es una regla de firewall. No es “quién puede conectarse.”
Tampoco es “qué IPs existen al otro lado.”

En WireGuard, cada peer tiene una lista de AllowedIPs. Esa lista hace dos trabajos:

  1. Selección de peer para salida. Cuando el host local quiere enviar un paquete a una IP de destino,
    WireGuard elige el peer cuya AllowedIPs contenga ese destino. Eso es efectivamente
    “qué peer debe llevar este paquete”.
  2. Validación de origen entrante. Cuando un paquete llega desde un peer, WireGuard comprueba si la
    IP origen del paquete está dentro de la AllowedIPs de ese peer. Si no, WireGuard lo descarta.

Eso es todo. No programa mágicamente toda tu red a menos que otra cosa (usualmente wg-quick)
traduzca esos prefijos en rutas del kernel. Y aun así, siguen siendo solo rutas.

Aquí está el modo de fallo que mantiene a los SRE empleados: la gente asume que AllowedIPs son “subredes remotas.”
A veces lo son. A veces son “subredes remotas más la ruta por defecto porque quiero túnel completo.”
Y a veces es “la IP del propio peer.” Pero ninguna de esas es universalmente correcta. Son intenciones,
y las intenciones necesitan coincidencia con enrutamiento, reenvío, NAT y comportamientos DNS.

Otro detalle clave: WireGuard no habla “rutas” directamente. Habla “peers y prefijos permitidos.”
El kernel del sistema operativo habla rutas. wg-quick es el traductor y ocasional mono del caos.

Broma #1: AllowedIPs se llama “Allowed” porque “PleaseStopSendingMyPacketsIntoTheWrongTunnelIPs”
no cabía en un archivo de configuración.

Hechos interesantes y contexto histórico

Un poco de contexto hace que la rareza se sienta menos personal.

  • WireGuard entró en el kernel de Linux en 2020 (Linux 5.6). Antes vivía fuera del árbol, lo que moldeó sus interfaces minimalistas.
  • WireGuard evita intencionalmente “cambios de modo” como muchos VPN tradicionales (modo transporte vs túnel). En su lugar, siempre es L3: enrutas paquetes IP.
  • wg (la herramienta) no añade rutas. Fue una separación deliberada: el driver VPN conoce peers; el OS conoce el enrutamiento.
  • wg-quick es un envoltorio de conveniencia que usa herramientas estándar (ip, resolvconf/systemd-resolved, iptables/nft) para crear una “experiencia VPN”.
  • AllowedIPs se asemeja a una tabla de enrutamiento comprimida: es esencialmente el equivalente por-peer de “estos prefijos pertenecen por aquí”, más una comprobación anti-spoofing.
  • WireGuard usa un concepto de “enrutamiento por clave criptográfica”: en vez de seleccionar un túnel por interfaz, selecciona un peer por clave pública y coincidencia de prefijo de destino.
  • Linux soporta múltiples tablas de enrutamiento y reglas (enrutamiento por política). wg-quick las usa para configuraciones de túnel completo para evitar sobrescribir la tabla principal.
  • Los prefijos solapados son legales en la configuración de WireGuard, pero las reglas de selección (coincidencia de prefijo más largo) pueden sorprenderte en despliegues con varios peers.
  • IPv6 suele fallar primero porque la gente ajusta AllowedIPs para IPv4 y olvida valores por defecto de IPv6 o respuestas AAAA de DNS. El túnel funciona; el navegador no.

Cómo se mueven realmente los paquetes: rutas del kernel, WireGuard y wg-quick

Las tres capas de enrutamiento con las que tratas (te guste o no)

Cuando ejecutas WireGuard en Linux, hay tres puntos de decisión relevantes:

  1. Enrutamiento de Linux: elige una interfaz de salida y el siguiente salto para una IP de destino usando tablas de rutas y reglas de política.
  2. Selección de peer de WireGuard: dentro de la interfaz WireGuard, se elige qué peer debe llevar el paquete basándose en la coincidencia del destino con AllowedIPs.
  3. Enrutamiento/reenvío en el extremo remoto: el extremo debe saber qué hacer con el paquete siguiente (entregar localmente, reenviar, NAT, etc.).

Si cualquiera de esas tres capas discrepa, obtienes la clásica experiencia “handshake pero sin tráfico”.
El éxito del handshake solo prueba que UDP puede alcanzar el peer y que las claves son válidas. No dice nada sobre
la ruta de retorno, el NAT o el reenvío.

Qué hace realmente wg-quick (y por qué deberías leer su salida)

wg-quick up wg0 es conveniente. También es dogmático:

  • Usa la interfaz (ip link add wg0 type wireguard).
  • Asigna direcciones a la interfaz desde Address =.
  • Configura peers de WireGuard y sus AllowedIPs.
  • Añade rutas para cada prefijo AllowedIPs (a menos que se use enrutamiento por política).
  • Para túnel completo (0.0.0.0/0 o ::/0), suele añadir reglas de enrutamiento por política y una tabla separada.
  • Puede configurar DNS (dependiendo de DNS = y tu pila de resolvers).
  • Puede añadir reglas de firewall si usas PostUp/PostDown o integraciones distro.

La parte crítica: esas rutas no son “rutas de WireGuard.” Son rutas del kernel.
Si luego ajustas AllowedIPs y no vuelves a ejecutar wg-quick (o no ajustas manualmente las rutas),
la tabla de enrutamiento del kernel puede no coincidir con tu intención. Esa descoincidencia es sutil y común.

El patrón “ruta por defecto a través de WireGuard”

Establecer AllowedIPs = 0.0.0.0/0, ::/0 para un peer dice:
para cualquier IP de destino, elige este peer. Pero no necesariamente significa que el kernel enviará
todos los paquetes a la interfaz wg0. Eso depende de las reglas de enrutamiento.

En Linux, wg-quick suele implementar el túnel completo así:

  • Añade una ruta por defecto en una tabla de enrutamiento separada (a menudo la tabla 51820).
  • Añade entradas ip rule para que el tráfico originado desde la IP de la interfaz WireGuard
    (o paquetes marcados) use esa tabla.
  • Añade excepciones para que la IP del endpoint del peer siga saliendo por el uplink real, no por el túnel
    (para evitar tunelizar el túnel).

Esa excepción es por qué a veces “mi VPN subió y se mató a sí misma” sucede: si la excepción del endpoint
está equivocada (por cambios DNS, confusión dual-stack o si estás detrás de CGNAT y el endpoint es variable),
tus paquetes UDP al endpoint se enrutan dentro del túnel. El túnel entonces no puede alcanzar el endpoint.
Es auto-sabotaje, con lógica perfecta.

Guion rápido de diagnóstico

Quieres velocidad. También quieres evitar la trampa clásica de cambiar cinco cosas a la vez y luego
no saber cuál la solucionó.

Primero: establece si los paquetes entran y salen de la interfaz WireGuard

  1. Comprueba handshake + contadores de transferencia.
  2. Comprueba la decisión de enrutamiento del kernel para el destino con ip route get (IPv4 e IPv6).
  3. Captura en wg0 y en la interfaz física para ver a dónde van realmente los paquetes.

Segundo: confirma que la lógica de selección de peer coincide con tu intención de AllowedIPs

  1. Lista peers y sus AllowedIPs.
  2. Busca solapamientos (por ejemplo, dos peers que reclaman 10.0.0.0/8).
  3. Valida que las direcciones origen de paquetes entrantes estén dentro de AllowedIPs del emisor (descarga por anti-spoofing).

Tercero: valida el reenvío/NAT y la ruta de retorno en el extremo remoto

  1. ¿Está habilitado el reenvío IP en el “servidor” o peer gateway?
  2. ¿La red remota conoce una ruta de vuelta al subnet del cliente VPN?
  3. Si dependes de NAT, ¿se aplica realmente a la interfaz y rango de origen correctos?

Cuarto: maneja los asesinos aburridos: MTU y DNS

  1. Prueba PMTU con ping -M do (IPv4) y tamaños de paquete realistas.
  2. Confirma que los servidores DNS y dominios de búsqueda son los que crees después de que el túnel suba.
  3. Confirma que IPv6 no se fuga ni se vuelve un agujero negro (especialmente con túnel completo solo IPv4).

Tareas prácticas: comandos, salidas y decisiones

Esta es la parte que ejecutas durante un incidente. Cada tarea incluye: comando, qué significa la salida,
y qué decisión tomas a continuación.

Task 1: Confirmar que WireGuard ve al peer y está intercambiando paquetes

cr0x@server:~$ sudo wg show
interface: wg0
  public key: 9zHhYw...redacted...
  private key: (hidden)
  listening port: 51820

peer: 2YpG3h...redacted...
  endpoint: 203.0.113.50:54022
  allowed ips: 10.40.0.2/32, 10.99.0.0/16
  latest handshake: 28 seconds ago
  transfer: 14.20 MiB received, 18.77 MiB sent
  persistent keepalive: every 25 seconds

Significado: el handshake es reciente y los contadores no son cero. WireGuard puede alcanzar el endpoint y descifrar/cifrar tráfico.
Aún no es prueba de que el OS enrute el tráfico hacia wg0, o que el extremo lejano lo reenvíe.

Decisión: si el handshake está obsoleto (minutos+) o la transferencia permanece en cero, enfoca en la alcanzabilidad UDP, la dirección del endpoint
y firewall/NAT. Si está sano, continúa con el enrutamiento.

Task 2: Comprobar las direcciones de la interfaz (el paso “qué IP estoy usando”)

cr0x@server:~$ ip -brief address show dev wg0
wg0             UP             10.40.0.1/24 fd00:40::1/64

Significado: wg0 tiene direcciones IPv4 e IPv6. Si tu peer espera /32 pero configuraste /24, eso no es automáticamente incorrecto,
pero afecta tus suposiciones de enrutamiento y qué debes NATear.

Decisión: confirma que ambos lados concuerdan en el esquema de direccionamiento (rutas host vs subredes), y que
AllowedIPs incluye las direcciones origen del peer.

Task 3: Pregunta al kernel a dónde enviará un destino específico

cr0x@server:~$ ip route get 10.99.10.25
10.99.10.25 dev wg0 src 10.40.0.1 uid 0
    cache

Significado: el kernel enviaría paquetes a 10.99.10.25 vía wg0. Bien.
Si dice dev eth0 u otra interfaz, la tabla de enrutamiento del kernel no está alineada con tu intención.

Decisión: si el enrutamiento es incorrecto, inspecciona rutas y reglas de política (ip route, ip rule).
No toques aún la configuración de WireGuard.

Task 4: Haz lo mismo para IPv6 (porque dual-stack disfruta gaslighting)

cr0x@server:~$ ip -6 route get 2606:4700:4700::1111
2606:4700:4700::1111 via fe80::1 dev eth0 src 2001:db8:12::10 metric 1024 pref medium

Significado: el tráfico IPv6 sale por eth0, no por wg0. Si esperabas túnel completo, probablemente olvidaste
::/0 en AllowedIPs o las reglas de enrutamiento por política para IPv6 no fueron añadidas.

Decisión: decide si quieres tunelizar IPv6, bloquearlo o dejarlo intacto. “No lo sé” es cómo terminas
con medio túnel y una caída confusa.

Task 5: Inspeccionar rutas añadidas por AllowedIPs

cr0x@server:~$ ip route show table main | grep -E 'wg0|10\.99\.|10\.40\.'
10.40.0.0/24 dev wg0 proto kernel scope link src 10.40.0.1
10.99.0.0/16 dev wg0 scope link

Significado: tienes una ruta directa a 10.99.0.0/16 vía wg0. Eso coincide con AllowedIPs del peer.
Si la ruta falta, tu sistema ni siquiera intentará colocar tráfico en el túnel.

Decisión: si faltan rutas, comprueba si usaste wg (sin rutas) vs wg-quick (añade rutas),
o si NetworkManager/systemd-networkd está gestionando rutas en otro lugar.

Task 6: Comprobar reglas de enrutamiento por política (túnel completo y “por qué solo parte del tráfico va por wg0”)

cr0x@server:~$ ip rule show
0:      from all lookup local
32764:  from all fwmark 0xca6c lookup 51820
32765:  from all lookup main suppress_prefixlength 0
32766:  from all lookup main
32767:  from all lookup default

Significado: el tráfico marcado con fwmark 0xca6c usa la tabla 51820.
La regla suppress_prefixlength 0 es un truco común de wg-quick para evitar bucles de enrutamiento.

Decisión: si esperabas túnel completo pero no ves estas reglas, wg-quick probablemente no las aplicó
(o alguna otra herramienta las eliminó). Arregla el enrutamiento primero; no amplíes AllowedIPs aleatoriamente.

Task 7: Inspeccionar la tabla de enrutamiento específica de WireGuard (si se usa)

cr0x@server:~$ ip route show table 51820
default dev wg0 scope link
203.0.113.50 via 192.0.2.1 dev eth0

Significado: en la tabla 51820, la ruta por defecto va vía wg0, pero el endpoint 203.0.113.50 está explícitamente enrutado vía el gateway de eth0.
Esa es la excepción “no tunelizar el túnel”.

Decisión: si la excepción del endpoint falta o apunta al gateway equivocado, el túnel puede oscilar o no establecerse nunca.
Arregla el enrutamiento del endpoint, especialmente si el endpoint es un nombre de host que resuelve múltiples IPs.

Task 8: Verificar que el reenvío esté habilitado en un peer gateway

cr0x@server:~$ sysctl net.ipv4.ip_forward net.ipv6.conf.all.forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

Significado: este nodo no reenviará paquetes entre interfaces. Si debe actuar como gateway site-to-site,
eso es un obstáculo duro.

Decisión: habilita el reenvío (y persístelo) si este host debe enrutar tráfico; de lo contrario rediseña:
mantenlo como endpoint de túnel solo host.

Task 9: Confirmar que reglas de firewall/NAT coinciden con el diseño (ejemplo iptables)

cr0x@server:~$ sudo iptables -t nat -S | grep -E 'POSTROUTING|wg0|eth0'
-A POSTROUTING -s 10.40.0.0/24 -o eth0 -j MASQUERADE

Significado: paquetes con origen en 10.40.0.0/24 que salen por eth0 serán NATeados. Si tus clientes viven en 10.40.0.0/24 y quieres que accedan
a Internet a través de este servidor, esto probablemente se requiere.

Decisión: si necesitas site-to-site sin NAT, no hagas masquerade. En su lugar, añade rutas en la red remota de vuelta a 10.40.0.0/24.
NAT “funciona” hasta que rompe auditoría, conectividad entrante y tus ganas de vivir.

Task 10: Capturar tráfico para ver el giro equivocado

cr0x@server:~$ sudo tcpdump -ni wg0 host 10.99.10.25
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
12:11:02.100112 IP 10.40.0.1 > 10.99.10.25: ICMP echo request, id 2101, seq 1, length 64
12:11:03.110144 IP 10.40.0.1 > 10.99.10.25: ICMP echo request, id 2101, seq 2, length 64

Significado: paquetes están entrando en wg0. Si no hay respuestas, el problema probablemente esté más allá de este host:
enrutamiento remoto, firewall remoto o validación AllowedIPs en el lado remoto.

Decisión: captura también en el extremo remoto. Si el remoto recibe pero no responde, inspecciona sus rutas y firewall.
Si nunca recibe, inspecciona el NAT del endpoint y si estás enviando al peer correcto.

Task 11: Inspeccionar solapamientos de AllowedIPs de peers (el fusil oculto)

cr0x@server:~$ sudo wg show wg0 allowed-ips
2YpG3h...redacted...	10.40.0.2/32
2YpG3h...redacted...	10.99.0.0/16
7QkLm1...redacted...	10.99.10.0/24

Significado: hay un solapamiento: un peer reclama 10.99.0.0/16, otro reclama 10.99.10.0/24.
La coincidencia de prefijo más largo significa que 10.99.10.x irá al peer /24, no al /16.

Decisión: decide si eso es intencional. Si no, elimina o estrecha uno de los prefijos.
Si sí, documéntalo en voz alta y prueba el comportamiento de failover, porque es fácil romperlo durante onboarding.

Task 12: Ver qué aplicó realmente wg-quick (audita el “traductor”)

cr0x@server:~$ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.40.0.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] ip -4 route add 10.99.0.0/16 dev wg0
[#] resolvconf -a tun.wg0 -m 0 -x
[#] iptables -A FORWARD -i wg0 -j ACCEPT
[#] iptables -A FORWARD -o wg0 -j ACCEPT
[#] iptables -t nat -A POSTROUTING -s 10.40.0.0/24 -o eth0 -j MASQUERADE

Significado: este es el conjunto real de cambios. Puedes ver el MTU, las rutas, cambios DNS y reglas iptables.
Si tu modelo mental difiere de esta salida, tu modelo mental está equivocado.

Decisión: si la salida de wg-quick muestra cambios que no pretendías (manipulación de DNS, NAT, reenvío),
deja de usar comportamientos implícitos y fíjalo con configuración explícita o tu propia orquestación.

Task 13: Comprobar reverse path filtering (un silencioso que descarta)

cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.wg0.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.wg0.rp_filter = 1

Significado: el filtrado estricto de ruta inversa puede descartar paquetes si el kernel piensa que la ruta de retorno para la IP origen
no volvería por la misma interfaz. Con enrutamiento por política y caminos asimétricos, esto puede romper el tráfico WireGuard de maneras creativas.

Decisión: en gateways con enrutamiento pesado, considera poner rp_filter en modo suelto (2) cuando corresponda,
pero hazlo intencionalmente y con revisión de seguridad.

Task 14: Validar MTU/PMTU rápidamente (no adivines, mide)

cr0x@server:~$ ping -c 3 -M do -s 1372 10.99.10.25
PING 10.99.10.25 (10.99.10.25) 1372(1400) bytes of data.
1380 bytes from 10.99.10.25: icmp_seq=1 ttl=62 time=31.2 ms
1380 bytes from 10.99.10.25: icmp_seq=2 ttl=62 time=30.9 ms
1380 bytes from 10.99.10.25: icmp_seq=3 ttl=62 time=31.0 ms

--- 10.99.10.25 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms

Significado: si esto tiene éxito con un tamaño realista, los problemas de fragmentación son menos probables.
Si falla con “Message too long”, tu MTU es demasiado alto en algún punto del camino.

Decisión: ajusta el MTU en wg0 (o deja que wg-quick lo configure), especialmente a través de PPPoE, LTE o túneles anidados.

Task 15: Confirmar rutas en el lado remoto (porque las rutas de retorno existen)

cr0x@server:~$ ssh ops@remote-gw 'ip route show | grep 10.40.0.0/24'
10.40.0.0/24 dev wg0 scope link

Significado: el lado remoto sabe que 10.40.0.0/24 es accesible vía wg0, así que las respuestas pueden volver.
Si el remoto no es el endpoint sino un router LAN detrás de él, necesitas rutas allí también.

Decisión: si falta la ruta de retorno, añádela (preferible) o usa NAT (último recurso) dependiendo de tus necesidades de seguridad y observabilidad.

Selección de peers y la trampa “gana el prefijo más específico”

La selección de peer de WireGuard es determinista y simple: encuentra el peer con una entrada AllowedIPs
que mejor coincida con la IP de destino usando la coincidencia de prefijo más largo. Eso es básicamente cómo funcionan también las tablas de enrutamiento.
La simplicidad es buena—hasta que accidentalmente creas una política que no querías.

Qué pasa con los solapamientos

Imagínate que tienes:

  • Peer A: AllowedIPs = 10.0.0.0/8 (un peer “red corporativa catch-all”)
  • Peer B: AllowedIPs = 10.42.0.0/16 (un site-to-site específico)

El tráfico a 10.42.x.y va al Peer B. El tráfico a 10.99.x.y va al Peer A.
Eso está bien cuando es intencional. También es una fuente de incidentes “por qué el tráfico de prod fue a la VPN de laboratorio”
cuando alguien copia un bloque de configuración.

Los solapamientos también afectan la validación entrante: si Peer B envía un paquete con origen 10.99.1.10
pero Peer B no tiene 10.99.0.0/16 en su AllowedIPs, el receptor descarta el paquete.
Así que los solapamientos pueden causar direccionamiento de salida y descartes de entrada dependiendo de quién crea qué.

No trates AllowedIPs como “rutas anunciadas” a menos que construyas el sistema alrededor de ello

En algunos sistemas VPN, el plano de control distribuye rutas dinámicamente. WireGuard no lo hace.
Si quieres algo parecido a la distribución de rutas, tienes que construirlo (con gestión de configuración, plantillas
o tu propio controlador) y entonces debes gestionar los solapamientos como una preocupación de primera clase.

Una regla pragmática: evita solapamientos a menos que lo hagas a propósito y puedas explicar la razón en una frase.
Si no puedes, estás acumulando futuras caídas.

Túnel dividido vs túnel completo: qué cambia y qué se rompe

Túnel dividido: solo enviar subredes específicas por wg0

Este es el valor por defecto sensato para la mayoría de los casos corporativos y site-to-site. Intención de ejemplo:
“Solo 10.99.0.0/16 debería ir por WireGuard.”

Patrón de configuración:

  • AllowedIPs del peer cliente incluye solo rangos privados remotos y quizá la IP wg del servidor.
  • Las rutas del kernel para esos rangos apuntan a wg0.
  • La ruta por defecto permanece en la red normal.

Modos de fallo:

  • El remoto usa DNS que resuelve a IPs públicas; el tráfico sale por la ruta por defecto, no por el túnel.
  • Registros AAAA de IPv6 evitan tu túnel solo IPv4.
  • La aplicación fija IPs; tu suposición de “solo la subred X” está equivocada respecto a cómo se despliega el servicio.

Túnel completo: enrutar Internet a través de la VPN

Útil para redes no confiables, control de egress o IP de origen consistente. También es donde
la mayoría de la confusión de AllowedIPs se vuelve costosa.

Patrón de configuración:

  • AllowedIPs del peer cliente incluye 0.0.0.0/0 y usualmente ::/0.
  • Se usa enrutamiento por política para que la IP del endpoint sea exenta y el sistema no tunelice su tráfico de control.
  • Servidor/gateway debe NATear o enrutar el tráfico del cliente aguas abajo.

Modos de fallo:

  • DNS se rompe: tu resolver solo es accesible por el túnel, pero el túnel depende de DNS para encontrar el endpoint.
  • El endpoint cambia IP; tu ruta de excepción apunta a la dirección de ayer; el túnel muere al reconectar.
  • Sólo IPv4 está tunelizado, IPv6 se fuga o se queda en agujero negro, los navegadores obtienen “timeouts” aleatorios.

Broma #2: Los VPNs de túnel completo son como mudarse de casa: aprendes cuánto posees cuando tienes que enrutar todo.

Tres mini-historias corporativas desde el frente

Incidente: la suposición equivocada de que “AllowedIPs es un ACL”

Una empresa mediana desplegó WireGuard para acceso de contratistas. El diseño era simple: los contratistas deberían alcanzar un puñado de servicios internos
(un servidor Git, un sistema de tickets, una caché de compilación). El equipo de seguridad insistió: “Solo permitir esas IPs.”
El equipo de red cumplió poniendo en los clientes una lista estrecha de AllowedIPs: unas pocas /32 para los servicios.

El túnel subió. Los handshakes se veían bien. Los contratistas seguían sin poder alcanzar los servicios de forma fiable. Peor aún, las fallas eran intermitentes,
que es el tipo de fallo más caro porque todos pierden tiempo demostrando que no son ellos.
El SRE de guardia miró estadísticas de WireGuard: el tráfico salía del cliente, llegaba al servidor y luego… nada.

La causa raíz fue sutil pero predecible: los servicios internos estaban detrás de balanceadores y a veces respondían desde IPs diferentes.
Los contratistas se conectaban al VIP (una de las /32), pero conexiones posteriores eran redirigidas a IPs backend no presentes en AllowedIPs.
El kernel del cliente enroutaba esas conexiones backend por la interfaz normal, no por wg0. Desde la perspectiva del servidor, ni siquiera vio
esos paquetes. Desde la perspectiva del usuario, “la VPN es inestable.”

La solución no fue “ensanchar todo a 0.0.0.0/0.” La solución fue alinear la intención de enrutamiento con la topología del servicio:
cambiaron de /32 por host a subredes internas específicas que realmente contenían el balanceador y los backends, además fijaron DNS
para esos servicios a direcciones internas alcanzables por el túnel. También documentaron la regla: AllowedIPs gobierna el enrutamiento,
no la autorización
. Las reglas de firewall manejan la autorización.

La lección: si intentas usar AllowedIPs como un límite de seguridad, construirás un límite poco fiable.
Pon el control de acceso donde corresponde: firewalls, proxies con identidad y auth de servicio. Deja que el enrutamiento haga enrutamiento.

Optimización que salió mal: “simplificar” colapsando AllowedIPs

Otra organización tenía docenas de peers site-to-site WireGuard hacia un hub central. Cada peer tenía AllowedIPs cuidadosamente acotadas:
sitio A 10.10.0.0/16, sitio B 10.20.0.0/16, etc. Funcionaba, mayormente.
Luego alguien propuso una “limpieza”: “Ponemos 10.0.0.0/8 para todos los sitios, así no actualizamos configs cuando aparece una nueva subred.”

El cambio pasó la revisión porque sonaba operativo conveniente. También creó AllowedIPs solapadas por todas partes.
WireGuard entonces tomó decisiones deterministas: el peer con la ruta más específica para un destino dado ganaría, pero ahora muchos peers tenían la
misma especificidad. La selección del hub se volvió sensible al orden de configuración y al tiempo de actualización.

El incidente que siguió no fue un apagón total. Fue peor: ciertas subredes se enroutaban intermitentemente al sitio equivocado, y el firewall del sitio equivocado
las descartaba. Las aplicaciones que reintentaban “a veces funcionaban”. El monitoreo se llenó, pero con patrones que parecían problemas de latencia.
El equipo de red pasó días persiguiendo congestión fantasma.

Revertir no fue inmediato porque algunos sitios nuevos se desplegaron asumiendo la configuración “simplificada”, y su enrutamiento dependía de ello.
La solución final fue restaurar propiedad no solapada: cada sitio obtuvo prefijos explícitos, mantenidos por infrastructure-as-code.
La “optimización” costó más que el trabajo manual original.

Práctica aburrida pero correcta que salvó el día: tests explícitos de rutas en CI

El equipo más resiliente con el que trabajé trató las configuraciones de WireGuard como código, no como objetos artesanales.
Cada cambio al AllowedIPs de un peer o al endpoint pasaba por una pipeline que ejecutaba una pequeña batería de aserciones de ruta.
No era fancy. Simplemente implacable.

Tenían un arnés de pruebas que arrancaba un entorno ligero de network namespace, aplicaba la configuración propuesta y ejecutaba
ip route get para un conjunto de destinos críticos. También inspeccionaba wg show allowed-ips en busca de solapamientos.
Si un nuevo prefijo solapaba con uno existente sin una excepción aprobada, la pipeline fallaba.

Un viernes, un ingeniero bien intencionado intentó añadir una nueva subred remota y tipeó por error 10.0.0.0/8 en lugar de 10.80.0.0/16.
En un equipo típico, eso se convierte en incidente de fin de semana. Aquí, el job de CI lo rechazó inmediatamente con un diff legible: “Solapa con el peer X; redirigiría
tráfico para estos destinos”.

No pasó nada heroico. No sonó la alarma. Ese es el punto.
La práctica no era glamorosa, pero hacía los cambios de enrutamiento aburridos—y lo aburrido es la característica más subestimada en sistemas en producción.

Una cita que aún vale: La esperanza no es una estrategia — General Gordon R. Sullivan.

Errores comunes: síntomas → causa raíz → solución

1) “El handshake funciona, pero no puedo hacer ping a nada detrás del peer”

Síntoma: wg show muestra handshake reciente; ping a hosts LAN remotos falla.

Causa raíz: falta de reenvío en el gateway remoto, o falta de ruta de retorno desde la LAN remota hacia tu subnet VPN.

Solución: habilita forwarding IP en el gateway y añade una ruta en el router LAN remoto apuntando tu subnet VPN vía el gateway WireGuard. Usa NAT solo si es necesario.

2) “El tráfico sigue saliendo por mi conexión normal a Internet” (sorpresa de túnel dividido)

Síntoma: se esperaba tráfico interno por wg0, pero ip route get muestra dev eth0 (o Wi‑Fi).

Causa raíz: falta de ruta del kernel para el destino, o la IP de destino no está en AllowedIPs de ningún peer.

Solución: asegura que los prefijos de destino estén en AllowedIPs del peer y que existan rutas (vía wg-quick o ip route add manual).

3) “Túnel completo habilitado, ahora el túnel no sube”

Síntoma: después de poner AllowedIPs = 0.0.0.0/0, el handshake falla o oscila.

Causa raíz: el tráfico al endpoint se enruta hacia wg0 (tunelizando el túnel), a menudo porque falta o está mal la ruta de excepción del endpoint.

Solución: usa el enfoque de enrutamiento por política de wg-quick o añade una ruta explícita para la IP del endpoint vía el gateway físico. Evita hostnames de endpoint que cambian sin manejar actualizaciones.

4) “Algunas subredes funcionan, una subred se va misteriosamente al peer equivocado”

Síntoma: tráfico a 10.99.10.0/24 va a un lugar inesperado; otras redes 10.99.x se comportan distinto.

Causa raíz: AllowedIPs solapadas con prefijo más largo seleccionando otro peer.

Solución: elimina solapamientos o hazlos intencionales y documentados; verifica con wg show allowed-ips.

5) “Funciona IPv4, pero IPv6 está roto (o se fuga)”

Síntoma: IPv4 alcanza recursos internos, pero los navegadores hacen timeout en algunos sitios; ip -6 route get muestra egreso fuera de VPN.

Causa raíz: tunelizaste 0.0.0.0/0 pero no ::/0, o DNS devuelve registros AAAA que toman otro camino.

Solución: o soportas IPv6 completamente por el túnel (AllowedIPs + rutas + firewall) o deshabilitas/blackholeas IPv6 en ese host cuando está en VPN.

6) “Los paquetes entran en wg0 pero nunca obtienen respuestas”

Síntoma: tcpdump en wg0 muestra paquetes salientes; no hay respuestas entrantes.

Causa raíz: el lado remoto descarta entrada porque la IP fuente no está en sus AllowedIPs (chequeo anti-spoofing), o el firewall remoto lo bloquea.

Solución: asegúrate de que AllowedIPs del peer remoto incluya tu(s) rango(s) de origen. Luego verifica que el firewall remoto permita tráfico desde la subnet VPN.

7) “Todo va lento, especialmente descargas grandes”

Síntoma: pings pequeños funcionan; transferencias grandes se atascan o van lentas.

Causa raíz: desajuste MTU/PMTU que causa pérdida por fragmentación o ICMP “fragmentation needed” en agujero negro.

Solución: reduce MTU de wg0; prueba con ping -M do y asegúrate de que ICMP no esté bloqueado en el camino.

8) “Después de reiniciar la red, el enrutamiento está mal hasta que reinicio wg0”

Síntoma: WireGuard está arriba, pero las rutas/reglas del kernel faltan o están alteradas tras cambios de enlace.

Causa raíz: gestores de red competidores (NetworkManager, systemd-networkd, scripts personalizados) reescribiendo rutas y reglas.

Solución: elige una autoridad. Si usas wg-quick, asegúrate de que sea el que aplica reglas; de lo contrario gestiona rutas explícitamente en tu stack de red.

Listas de verificación / plan paso a paso

Checklist A: Construir un túnel dividido correcto (site-to-site o acceso interno)

  1. Define los prefijos de destino reales (subredes, no /32s ilusorios). Incluye balanceadores, backends y resolvers DNS según sea necesario.
  2. Configura AllowedIPs del peer exactamente a esos prefijos en el lado cliente. Manténlos no solapados siempre que sea posible.
  3. Levanta el túnel con wg-quick y confirma rutas en ip route.
  4. Usa ip route get para confirmar decisiones del kernel para cada destino crítico.
  5. Verifica rutas de retorno en el lado remoto para la subnet cliente VPN (o configura NAT deliberadamente).
  6. Documenta la propiedad: qué peer “posee” qué prefijos. Trátalo como IPAM, porque efectivamente lo es.

Checklist B: Construir un túnel completo correcto (egreso a Internet por WireGuard)

  1. Decide IPv4-only vs dual-stack. Si no vas a tunelizar IPv6, deshabilítalo explícitamente o bloquéalo para evitar fugas y colgamientos raros.
  2. Configura AllowedIPs a rutas por defecto: 0.0.0.0/0 y usualmente ::/0.
  3. Confirma que existe enrutamiento por política: ip rule y una tabla dedicada que incluya una ruta de excepción para el endpoint.
  4. Confirma reenvío y NAT en el servidor si el servidor provee egress.
  5. Valida comportamiento DNS: asegura que los resolvers sean alcanzables después de subir el túnel y antes de que se caiga al reconectar.
  6. Ejecuta tests PMTU y fija MTU explícitamente si tu entorno es variable (LTE, PPPoE, túneles anidados).

Checklist C: Configuración hub multi-peer sin sorpresas

  1. Haz AllowedIPs no solapados por defecto. Los solapamientos requieren nota de diseño explícita y tests.
  2. Usa gestión de configuración para generar configs consistentemente. Los humanos copian/pegan errores más rápido que los corrigen.
  3. Ejecuta detección automática de solapamientos usando la salida de wg show allowed-ips para validación.
  4. Prueba selección de rutas con ip route get y captura de paquetes para al menos una IP por prefijo.
  5. Planifica alcanzabilidad del endpoint (IPs estáticas, DNS estable o excepciones de ruta de endpoint explícitas).

Preguntas frecuentes

1) ¿Es AllowedIPs un firewall?

No. Influye en la selección de peer para salida y valida direcciones de origen entrantes. Usa reglas de firewall para autorización.
Si “aseguras” acceso solo estrechando AllowedIPs, mayormente solo romperás el enrutamiento.

2) ¿Por qué mi interfaz WireGuard tiene una IP que no está en AllowedIPs?

Las direcciones de interfaz (Address =) y AllowedIPs son conceptos distintos. La dirección de interfaz es lo que el host local usa como origen.
AllowedIPs es lo que cada peer reclama para enrutamiento y validación de origen. Deben ser compatibles, pero no son el mismo control.

3) ¿Necesito añadir rutas manualmente cuando cambio AllowedIPs?

Si usas wg directamente: sí, porque no tocará rutas. Si usas wg-quick: añadirá rutas en up,
pero cambiar AllowedIPs en caliente puede no actualizar las rutas del kernel como piensas. Trata los cambios como re-aplicaciones controladas.

4) ¿Por qué tengo “handshake pero sin tráfico”?

Porque el handshake solo prueba que UDP y las claves funcionan. El tráfico aún puede fallar por falta de rutas del kernel, falta de reenvío, falta de NAT,
descartes por firewall remoto o validación AllowedIPs en el receptor.

5) ¿Qué pasa si dos peers tienen el mismo prefijo AllowedIPs?

La coincidencia de prefijo más largo elige el prefijo más específico. Si la especificidad empata, el comportamiento depende del orden interno y puede ser inestable durante actualizaciones.
No confíes en empates; haz la propiedad explícita.

6) ¿Debo poner 0.0.0.0/0 en AllowedIPs en el servidor?

Usualmente no. En un “servidor” que acepta muchos clientes, generalmente das a cada cliente un /32 (y quizás subredes propiedad del cliente).
Poner 0.0.0.0/0 en la entrada del peer del servidor para un cliente le dice al servidor que envíe todo el tráfico a ese cliente. Rara vez quieres eso.

7) ¿Por qué añadir ::/0 rompe cosas incluso cuando IPv6 “no se usa”?

Porque las aplicaciones usan IPv6 cuando existe. Si enrutas IPv6 al túnel pero no provees reenvío/DNS/egreso IPv6 en el extremo, creas un agujero negro.
Decide deliberadamente: sopórtalo completamente o deshabilítalo.

8) ¿Puedo usar AllowedIPs para implementar “solo estos servicios van por VPN”?

Solo si esos servicios se mapean limpiamente a prefijos de destino que controlas. Si el servicio usa CDNs, backends dinámicos o redirecciones,
las IPs de destino cambiarán y tu intención de enrutamiento se violará. En esos casos, usa controles a nivel de aplicación y trata la VPN como transporte.

9) ¿Por qué ping funciona pero TCP no?

MTU y problemas PMTU son la respuesta clásica. ICMP es pequeño; TCP con problemas MSS/PMTU puede atascarse. También revisa firewalls con estado y enrutamiento asimétrico.
Confirma con pings PMTU y capturas de paquetes.

10) ¿Es wg-quick “malo”?

No. Es una herramienta sólida. Pero también es un wrapper que modifica rutas, reglas, DNS y a veces estado de firewall.
En producción, o te estandarizas en él y pruebas su comportamiento, o lo reemplazas por orquestación explícita.
La peor opción es “creemos que usamos wg-quick pero otras herramientas lo deshacen.”

Conclusión: pasos prácticos siguientes

Si el tráfico de WireGuard no va a donde esperas, deja de mirar el handshake.
Trata AllowedIPs como entrada de política de enrutamiento, luego verifica las capas del sistema en orden:
decisión de ruta del kernel, selección de peer de WireGuard y ruta de retorno remota.

Pasos siguientes que puedes hacer hoy:

  1. Elige un destino que falle y ejecuta ip route get (y ip -6 route get) para él. Cree la salida.
  2. Ejecuta wg show allowed-ips y busca solapamientos. Si encuentras uno que no puedes justificar, elimínalo.
  3. En peers gateway, verifica el reenvío y la ruta de retorno. Arregla eso antes de tocar MTU o DNS.
  4. Decide explícitamente túnel dividido vs túnel completo, incluyendo comportamiento IPv6. Decisiones a medias causan caídas completas.
  5. Escribe la propiedad de prefijos. En serio. Tu yo futuro te lo agradecerá en el próximo “por qué prod va a staging”.
← Anterior
Debian 13: host con iowait al 100% se congela — encuentra el proceso/VM ruidoso en 10 minutos
Siguiente →
Proxmox «pve-cluster.service failed»: Cómo recuperar la pila de clúster

Deja un comentario