VPN en Ubuntu/Debian: errores de UFW/nftables que te bloquean (y soluciones)

¿Te fue útil?

Enciendes una VPN, tu sesión SSH se congela y tu máquina de producción se convierte en un pisapapeles muy caro.
En algún punto entre las abstracciones “amigables” de UFW y el filtrado brutalmente honesto de nftables, acabaste
cortando tu propia línea de vida.

Esta es una guía de campo para los modos reales de fallo: sorpresas de enrutamiento, errores de seguimiento de estado, lagunas en el tráfico reenviado
y el clásico “permití el puerto de la VPN, ¿por qué no funciona nada?”. Diagnosticaremos rápido,
arreglaremos con precisión y te evitaremos aprender estas lecciones a las 3 a.m.

El modelo mental: qué cambia cuando se levanta una VPN

Una VPN no es “una aplicación que cifra el tráfico”. En Linux, es un conjunto de interfaces de red, rutas, reglas de firewall
y a menudo cambios de DNS. Cuando se activa, normalmente hace tres cosas que te pueden dejar fuera:

  1. Crea una nueva interfaz (p. ej., wg0, tun0) que se convierte en la nueva vía para parte o todo el tráfico.
    Si tu firewall está ligado a interfaces específicas (muchos lo están), acabas de mover el tráfico fuera de las reglas existentes.
  2. Cambia el enrutamiento (ruta por defecto, policy routing, o rutas por prefijo). Tus paquetes de respuesta pueden salir por una interfaz distinta
    a la que llegó la petición. Conntrack no te salvará del enrutamiento asimétrico si te disparas en la rodilla.
  3. Cambia las necesidades de traducción de direcciones (NAT/mascaradeo) cuando el tráfico se reenvía a través del equipo o cuando la VPN asigna
    direcciones desconocidas para los routers aguas arriba.

UFW y nftables no “entienden VPNs.” Entienden paquetes, interfaces, estados y rutas. Si configuras una VPN y luego esperas que el firewall “lo resuelva”,
estás apostando tu acceso a un pensamiento mágico.

La cruda verdad: la mayoría de los bloqueos no son causados por una regla mala aislada. Son causados por una regla correcta aplicada a
la interfaz equivocada o a la dirección equivocada (INPUT vs OUTPUT vs FORWARD), combinada con una ruta que no notaste que fue reemplazada.

Hechos interesantes y contexto histórico (para que lo raro tenga sentido)

  • iptables fue el predeterminado durante años, pero nftables es la sustitución moderna; muchos sistemas Ubuntu/Debian ahora ejecutan
    comandos iptables sobre el backend nft sin que te des cuenta.
  • UFW es una interfaz diseñada originalmente para hacer iptables accesible; no expone todos los matices del filtrado de paquetes,
    especialmente alrededor de policy routing y forwarding complejo.
  • Conntrack (seguimiento de estado) es un subsistema del kernel que recuerda flujos. Si olvidas permitir ESTABLISHED,RELATED,
    bloquearás respuestas aunque el paquete inicial entrante hubiera sido permitido.
  • WireGuard es “solo UDP” con una interfaz en el kernel y enrutamiento por clave criptográfica. No usa un canal de control separado como
    muchas VPN antiguas, lo que cambia cómo se ve el “tráfico permitido”.
  • OpenVPN suele usar un dispositivo tun/tap y puede empujar rutas y DNS. Si aceptas la ruta por defecto empujada, puedes fácilmente
    enrutar las respuestas SSH dentro del túnel por accidente.
  • Reverse path filtering (rp_filter) es una característica anti-spoofing del kernel que puede descartar paquetes cuando las rutas parecen asimétricas—
    justo lo que algunas configuraciones VPN crean intencionalmente.
  • Policy routing de Linux (ip rule) existe desde hace décadas. Los clientes VPN lo usan cada vez más para split tunneling, lo que significa
    que tu “ruta por defecto” puede no contar toda la historia.
  • El comportamiento de “kill switch” (bloquear tráfico fuera de la VPN) es básicamente una decisión de política de firewall, no una característica de la VPN. Muchos clientes
    lo implementan con reglas que son fáciles de equivocarse.

Guía de diagnóstico rápido

Cuando pierdes conectividad tras activar una VPN (o el tráfico se detiene misteriosamente), no tienes tiempo para un
debate filosófico sobre firewalls. Verifica esto en orden, porque cada paso reduce el problema rápidamente.

Primero: ¿cambió el enrutamiento bajo tus pies?

  • Mira la ruta por defecto y las reglas de policy (ip route, ip rule).
  • Confirma qué interfaz usa la IP de tu SSH para alcanzarte (ip route get).
  • Decide: ¿problema de ruta o de firewall? Si las respuestas salen por la interfaz equivocada, arregla el enrutamiento primero.

Segundo: ¿estás descartando en INPUT/OUTPUT o en FORWARD?

  • Chequea el estado de UFW y las políticas por defecto (ufw status verbose).
  • Chequea el ruleset de nftables y contadores de cadenas (nft list ruleset).
  • Decide: el bloqueo suele ser INPUT/OUTPUT; “la VPN funciona pero la LAN detrás del servidor no” suele ser FORWARD/NAT.

Tercero: ¿el manejo de conntrack/estado es correcto?

  • Verifica que la aceptación de established/related exista en las cadenas correctas.
  • Busca reglas “drop invalid” que sean demasiado agresivas.
  • Decide: si las respuestas están bloqueadas, verás SYNs llegar pero no SYN-ACK saliendo.

Cuarto: ¿rp_filter o sysctl bloquea rutas asimétricas?

  • Verifica los ajustes de rp_filter y ajústalos para casos de uso VPN.
  • Decide: si los paquetes llegan pero se descartan antes de que los contadores del firewall se muevan, sospecha de rp_filter.

Quinto: confirma con captura de paquetes, no con intuiciones

  • Ejecuta tcpdump en la NIC física y en la interfaz VPN simultáneamente.
  • Decide: si los paquetes entran pero no salen, es firewall/enrutamiento. Si nunca entran, es un problema de upstream/red.

Tareas prácticas (comandos, salidas, decisiones)

Estos son los ejercicios exactos que ejecuto en Ubuntu/Debian cuando alguien dice “la VPN mató la máquina”. Cada tarea incluye
qué suele significar la salida y la decisión que tomas a partir de ella. Ejecútalas desde consola, acceso fuera de banda,
o una sesión SSH existente antes de tocar cualquier otra cosa.

Tarea 1: Identifica interfaces y qué se creó con la VPN

cr0x@server:~$ ip -brief link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
ens3             UP             52:54:00:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
wg0              UNKNOWN        3a:2b:1c:0d:ee:ff <POINTOPOINT,NOARP,UP,LOWER_UP>

Significado: Tienes una NIC física (ens3) y una interfaz WireGuard (wg0).
Muchos bloqueos ocurren porque las reglas se aplican solo a ens3.
Decisión: Si existe una interfaz nueva, audita las reglas del firewall por alcance de interfaz (iifname/oifname, reglas ufw route).

Tarea 2: Revisa direcciones IP para ver qué redes están involucradas

cr0x@server:~$ ip -brief addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens3             UP             203.0.113.10/24 2001:db8:10::10/64
wg0              UNKNOWN        10.6.0.2/32

Significado: IP pública en ens3, dirección VPN en wg0.
Observa el /32 en WireGuard—común y válido, pero cambia las expectativas de enrutamiento/NAT.
Decisión: Si esperas enrutar otras subredes a través de este host, necesitarás rutas explícitas y a menudo NAT.

Tarea 3: Encuentra la ruta por defecto y si se movió a la VPN

cr0x@server:~$ ip route show
default dev wg0 scope link
203.0.113.0/24 dev ens3 proto kernel scope link src 203.0.113.10
10.6.0.0/24 dev wg0 proto kernel scope link src 10.6.0.2

Significado: La ruta por defecto ahora va vía wg0. Eso es un setup de túnel completo.
Si tu cliente SSH se conecta a 203.0.113.10, la petición llega por ens3, pero tus respuestas podrían intentar salir por wg0.
Decisión: Si este es un servidor que gestionas de forma remota, no aceptes enrutamiento de túnel completo a menos que hayas fijado las respuestas SSH o permitido la ruta. Considera túnel dividido o policy routing para tráfico de gestión.

Tarea 4: Revisa reglas de policy routing (el túnel dividido suele vivir aquí)

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

Significado: Algunas rutas usan marcas (fwmark 0xca6c) y una tabla de enrutamiento especial. Eso es típico de configuraciones wg-quick
para policy routing o modos kill switch.
Decisión: Si ves marcas/reglas que no añadiste, inspecciona los hooks PostUp/PreDown del cliente VPN o las unidades systemd. Tu firewall debe permitir tráfico marcado fuera por la interfaz correcta, o crearás agujeros negros.

Tarea 5: Confirma qué ruta usará el kernel para la IP de administración

cr0x@server:~$ ip route get 198.51.100.25
198.51.100.25 dev wg0 src 10.6.0.2 uid 0
    cache

Significado: Las respuestas a la IP de tu estación administrativa saldrían vía wg0 usando origen 10.6.0.2.
Esa es la firma clásica de “SSH muere tras levantar la VPN”.
Decisión: Añade una ruta host o una regla de policy para que el tráfico de gestión vuelva por ens3, o evita el túnel completo en servidores.

Tarea 6: Revisa el estado de UFW, defaults y si el forwarding está permitido

cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
22/tcp                     ALLOW IN    198.51.100.0/24
51820/udp                  ALLOW IN    Anywhere

Significado: El reenvío/forwarded está deshabilitado. Eso rompe setups “el servidor enruta la LAN a través de la VPN”.
Además, SSH solo está permitido desde una subred específica; si tu IP de origen cambia al conectar mediante una VPN o bastión, te puedes quedar fuera.
Decisión: Si necesitas forwarding, habilita la política routed y añade reglas ufw route allow explícitas. Si necesitas acceso de administración resistente,
mantén al menos un camino de gestión seguro (consola, IP secundaria o una allowlist más amplia con MFA).

Tarea 7: Ver qué generó realmente UFW (las “before rules” son donde ocurre la magia)

cr0x@server:~$ sudo grep -nE 'DEFAULT_FORWARD_POLICY|ufw-before-input|ufw-before-output|wg0|tun0' /etc/default/ufw /etc/ufw/before.rules
/etc/default/ufw:9:DEFAULT_FORWARD_POLICY="DROP"
/etc/ufw/before.rules:20:*filter
/etc/ufw/before.rules:28:-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

Significado: La política de forwarding es DROP. Conntrack established está presente (bien).
Decisión: Si piensas enrutar tráfico por este host, cambia DEFAULT_FORWARD_POLICY y añade reglas de ruta estrechas en lugar de volver todo permisivo.

Tarea 8: Revisa el ruleset de nftables y las políticas de cadenas (Ubuntu puede usar nft por debajo)

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iifname "lo" accept
    tcp dport 22 ip saddr 198.51.100.0/24 accept
    udp dport 51820 accept
    counter drop
  }
  chain forward {
    type filter hook forward priority filter; policy drop;
  }
  chain output {
    type filter hook output priority filter; policy accept;
  }
}

Significado: Política de input DROP, output ACCEPT. Forward DROP. Si tu VPN requiere forwarding entre interfaces, fallará.
También observa que SSH está restringido por IP de origen; la VPN puede cambiar lo que significa “origen”.
Decisión: No toques reglas a ciegas. Primero confirma si el flujo roto es INPUT, OUTPUT o FORWARD, luego añade el accept más pequeño posible.

Tarea 9: Mira los contadores de reglas para ver qué se está descartando

cr0x@server:~$ sudo nft -a list chain inet filter input
table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iifname "lo" accept
    tcp dport 22 ip saddr 198.51.100.0/24 accept
    udp dport 51820 accept
    counter packets 41 bytes 2460 drop # handle 12
  }
}

Significado: El contador de drop se mueve. Los paquetes llegan y son descartados por la política por defecto o la regla final de drop.
Decisión: Añade registro temporal para drops, o permite temporalmente desde tu origen actual para recuperar acceso y luego aprieta.

Tarea 10: Confirma si rp_filter está descartando paquetes antes de que lleguen al firewall

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

Significado: Reverse path filtering estricto está habilitado. Con enrutamiento asimétrico (común con VPN + acceso público), Linux puede descartar
paquetes porque la “mejor ruta de retorno” no coincide con la interfaz entrante.
Decisión: Para gateways multi-homed/VPN, pon rp_filter a 2 (loose) en las interfaces relevantes, o desactívalo con cuidado donde haga falta.
Hazlo intencionalmente; no desactives controles de seguridad sin entender la topología.

Tarea 11: Verifica que el reenvío IP esté habilitado cuando esperas enrutamiento

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

Significado: El host no reenviará paquetes IPv4 ni IPv6. Incluso las reglas de firewall perfectas no lo harán enrutar.
Decisión: Si este host debe ser gateway (LAN-a-VPN, sitio-a-sitio, etc.), habilita el reenvío y persístelo en sysctl.

Tarea 12: Revisa si existe NAT/mascaradeo para tráfico saliente por la VPN

cr0x@server:~$ sudo nft list table ip nat
table ip nat {
  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
  }
}

Significado: La tabla nat existe pero no tiene regla de masquerade. Si reenvías una LAN privada a través de la VPN, el lado remoto puede no saber cómo enrutar de vuelta.
Decisión: Añade masquerade dirigida para la red origen LAN saliendo por wg0 (o mejor: añade rutas en el extremo remoto si lo controlas).

Tarea 13: Usa tcpdump para ver dónde muere el flujo

cr0x@server:~$ sudo tcpdump -ni ens3 tcp port 22 -c 5
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens3, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:01:03.101234 IP 198.51.100.25.53122 > 203.0.113.10.22: Flags [S], seq 1234567890, win 64240, options [mss 1460], length 0
12:01:04.104567 IP 198.51.100.25.53122 > 203.0.113.10.22: Flags [S], seq 1234567890, win 64240, options [mss 1460], length 0

Significado: Llegan SYNs por ens3. Si no ves SYN-ACK saliendo por ens3, o bien el firewall descarta en INPUT, o las respuestas se enrutan a otro lado.
Decisión: Ejecuta tcpdump también en wg0. Si el SYN-ACK sale por wg0, tienes un problema de enrutamiento/policy routing, no de filtro entrante.

Tarea 14: Inspecciona unidades systemd y hooks PostUp de la VPN que modifiquen firewall/enrutamiento

cr0x@server:~$ systemctl status wg-quick@wg0 --no-pager
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
     Loaded: loaded (/lib/systemd/system/wg-quick@.service; enabled; preset: enabled)
     Active: active (exited) since Fri 2025-12-27 11:59:12 UTC; 3min ago
       Docs: man:wg-quick(8)
             man:wg(8)
    Process: 1256 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)

Significado: wg-quick está en juego. Puede añadir rutas, ip rules y fragmentos nft/iptables según tu configuración.
Decisión: Revisa /etc/wireguard/wg0.conf en busca de PostUp/PreDown y de AllowedIPs que puedan estar secuestrando la ruta por defecto.

Tarea 15: Valida el registro de UFW y revisa los drops recientes del kernel

cr0x@server:~$ sudo journalctl -k -g 'UFW BLOCK' -n 5 --no-pager
Dec 27 12:00:41 server kernel: [UFW BLOCK] IN=ens3 OUT= MAC=52:54:00:12:34:56 SRC=198.51.100.25 DST=203.0.113.10 LEN=60 TOS=0x00 PREC=0x00 TTL=51 ID=55233 DF PROTO=TCP SPT=53122 DPT=22 WINDOW=64240 SYN

Significado: UFW está bloqueando explícitamente SSH entrante desde tu origen actual. Eso no es “la VPN lo rompió”; tu lista de permitidos está ahora equivocada.
Decisión: Amplía temporalmente el acceso SSH desde un rango seguro o desde un jump host, recupera el control y luego rediseña el acceso de gestión para que sobreviva a cambios de VPN.

Tarea 16: Red de seguridad de emergencia—programa un rollback del firewall

cr0x@server:~$ echo "ufw disable" | sudo at now + 2 minutes
warning: commands will be executed using /bin/sh
job 7 at Fri Dec 27 12:04:00 2025

Significado: Has programado una desactivación automática de UFW en 2 minutos. Si te quedas fuera, la máquina acabará recuperándose.
Decisión: Usa esto antes de aplicar cambios de firewall arriesgados en sistemas remotos. Cancela el job una vez verifiques la conectividad.

Broma #1: Los firewalls son como los cinturones de seguridad—hasta que intentas salir por la ventana mientras el coche va en marcha.

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

1) “SSH muere inmediatamente cuando levanto la VPN”

Síntomas: La sesión SSH existente se congela; nuevas conexiones SSH agotan el tiempo; la interfaz VPN se levanta correctamente.

Causa raíz: La ruta por defecto se movió a wg0/tun0, por lo que las respuestas SSH entran en el túnel con la IP de origen equivocada; o rp_filter descarta tráfico asimétrico.

Solución: Fija rutas de gestión vía la interfaz pública o usa policy routing para que el tráfico hacia tu subred administrativa use ens3. Ajusta rp_filter a loose donde corresponda.

cr0x@server:~$ sudo ip route add 198.51.100.0/24 via 203.0.113.1 dev ens3
cr0x@server:~$ sudo sysctl -w net.ipv4.conf.ens3.rp_filter=2
net.ipv4.conf.ens3.rp_filter = 2

2) “La VPN se conecta, pero nada accede a internet”

Síntomas: El túnel está arriba; el handshake funciona; DNS puede resolver; no pasa tráfico saliente.

Causa raíz: Un kill switch o una chain OUTPUT demasiado restrictiva bloquea todo excepto el puerto UDP de la VPN. Común con políticas “deny outgoing” por defecto que no pusieron en lista el tráfico de wg0.

Solución: Permite salida en la interfaz VPN y mantén OUTPUT con estado. Si usas UFW, añade reglas allow out explícitas y verifica la selección de tabla de rutas.

cr0x@server:~$ sudo ufw allow out on wg0
Rule added

3) “WireGuard hace handshake, pero no pasa tráfico”

Síntomas: wg show muestra tiempo de handshake actualizado; ping/ssh a través del túnel falla.

Causa raíz: Mismatch de AllowedIPs, rutas faltantes, o firewall bloqueando FORWARD entre interfaces; a veces MTU/PMTU pero empieza por rutas/reglas.

Solución: Verifica AllowedIPs y rutas; permite forwarding; asegura NAT si hace falta.

cr0x@server:~$ sudo wg show wg0
interface: wg0
  public key: 3m...redacted...9Q=
  listening port: 51820

peer: 8A...redacted...k=
  endpoint: 192.0.2.50:51820
  allowed ips: 10.6.0.0/24
  latest handshake: 1 minute, 4 seconds ago
  transfer: 92.14 KiB received, 88.22 KiB sent

4) “Mi servidor VPN funciona para la máquina, pero los clientes no alcanzan la LAN detrás”

Síntomas: El servidor puede hacer ping por el túnel; los clientes se conectan; los clientes no alcanzan subredes internas.

Causa raíz: Chain FORWARD por defecto en drop (UFW “routed disabled”), reenvío IP apagado, falta de masquerade, o rutas faltantes en el lado LAN.

Solución: Habilita IP forwarding; ajusta la política de forwarding de UFW; añade ufw route allow; añade NAT dirigido o rutas en el router LAN.

5) “UFW dice que permite 51820/udp, pero la VPN sigue sin conectar”

Síntomas: El cliente no puede hacer handshake; el servidor no muestra nada; UFW parece “correcto”.

Causa raíz: La regla existe en IPv4 pero no en IPv6 (o viceversa); el endpoint es v6; o nftables está activo con un ruleset distinto al que crees.

Solución: Verifica las direcciones de escucha; revisa ambas familias; confirma el backend real del firewall; prueba con tcpdump en la NIC.

6) “Todo funciona… hasta que activo UFW”

Síntomas: La VPN está bien con el firewall apagado; se rompe cuando el firewall está activo; a menudo solo falla el forwarding.

Causa raíz: Defaults de UFW: routed traffic deshabilitado; faltan reglas ufw route; reglas por interfaz demasiado específicas; falta permitir la interfaz VPN.

Solución: Trata el forwarding como un producto separado. Configura DEFAULT_FORWARD_POLICY, añade reglas de ruta explícitas y prueba los flujos de extremo a extremo.

7) “El DNS falla solo cuando la VPN está arriba”

Síntomas: Puedes hacer ping a IPs; los nombres no se resuelven; o la resolución es lenta/inestable.

Causa raíz: El cliente VPN empuja DNS; systemd-resolved cambia upstream; el firewall bloquea UDP/TCP 53 en la interfaz equivocada; o fuerzas todo el tráfico al túnel pero el DNS está afuera.

Solución: Decide dónde debe vivir el DNS (dentro de la VPN o fuera). Luego permítelo explícitamente y verifica resolvectl y el enrutamiento hacia los servidores DNS.

8) “Después de añadir un ruleset ‘simple’ de nftables, UFW dejó de funcionar”

Síntomas: Los comandos de UFW tienen éxito, pero el comportamiento no coincide; los contadores no se mueven donde esperabas.

Causa raíz: Rulesets o prioridades de cadenas en conflicto. UFW puede gestionar sus propias tablas/cadenas; tus reglas nft personalizadas pueden enmascararlas o aplicarse antes.

Solución: Elige un controlador. O gestionas nftables directamente (y deshabilitas UFW), o dejas que UFW controle el filtrado y solo añades hooks soportados.

Tres micro-historias corporativas desde el terreno

Micro-historia #1: El incidente causado por una suposición errónea

Una empresa mediana operaba una pequeña flota de gateways Ubuntu que terminaban VPNs sitio-a-sitio. Un equipo añadió WireGuard
para reemplazar un OpenVPN antiguo. El plan de migración parecía limpio: levantar wg0, permitir UDP 51820 entrante,
y listo.

La suposición errónea fue sutil: “Si el handshake funciona, el plano de datos funcionará”. Los handshakes funcionaron. Los
gráficos parecían tranquilizadores. Entonces los usuarios internos empezaron a quejarse de que solo algunos destinos eran alcanzables.
El ingeniero on-call vio “latest handshake: 30 seconds ago” y perdió tiempo persiguiendo fantasmas de MTU.

El problema real fue el forwarding. UFW tenía routed deshabilitado. La máquina podía alcanzar subredes remotas porque OUTPUT estaba permitido,
pero los paquetes de la LAN eran descartados en FORWARD. La VPN no estaba rota; la función de gateway sí.

La solución no fue heroica. Habilitaron IP forwarding, configuraron la política de forwarding de UFW y añadieron reglas de ruta estrechas:
solo la subred interna hacia la subred VPN, solo vía wg0. De repente todo funcionó y la narrativa “WireGuard es inestable”
murió en silencio.

Micro-historia #2: La optimización que se voló en la cara

Otra organización estandarizó en nftables y quiso “reglas limpias y mínimas”. Alguien reescribió el firewall del servidor como un
único ruleset con policy drop con solo unos pocos accept: SSH, el puerto VPN y established/related. También
endurecieron OUTPUT a una whitelist porque “los servidores no deberían hablar con Internet.”

La optimización fue eliminar lo que parecía redundante y fiarse de que “solo tenemos unos pocos servicios”. Funcionó en staging. Producción tuvo una vuelta más: el cliente VPN usaba policy routing y fwmarks, y el resolvedor DNS estaba fuera del camino VPN. Los drops en OUTPUT empezaron a bloquear DNS y los keepalives de la VPN de formas que no eran obvias al revisar las reglas iniciales.

El modo de fallo no fue un corte total; fue peor. Comportamiento intermitente. Algunas peticiones funcionaban con caches calientes, luego fallaban cuando expiraban los TTL. La gente culpó al proveedor de VPN, luego al DNS, luego a “la red Linux”. Clásico.

La solución fue dejar de optimizar prematuramente y modelar los flujos. Crearon permisos OUTPUT explícitos para la interfaz VPN,
para DNS a los resolvers seleccionados y para NTP. También añadieron contadores y logging para la última regla de drop, porque un drop silencioso
es la receta para un informe de incidente de una semana.

Micro-historia #3: La práctica aburrida pero correcta que salvó el día

Un equipo de servicios financieros mantenía bastion hosts Debian con políticas de firewall estrictas y una VPN obligatoria para acceso administrativo.
Tenían una regla: cualquier cambio de firewall/VPN debía incluir un temporizador de rollback automatizado y un plan de acceso fuera de banda.
Nadie amaba esa regla. Todos se beneficiaron de ella.

Durante una ventana de cambios, un ingeniero ajustó reglas de UFW para aplicar un kill switch de VPN. El comportamiento previsto: solo permitir
salida por wg0, bloquear todo lo demás. Aplicaron el cambio y de inmediato perdieron su sesión SSH.
Predecible, pero aún estresante.

Dos minutos después, el rollback programado se ejecutó y UFW se desactivó. SSH volvió. No hubo llamadas frenéticas al datacenter,
ni “alguien puede reiniciarlo”, ni ediciones a medias desde una sesión moribunda. Se reconectaron, arreglaron la excepción de policy routing
para la subred de gestión y probaron otra vez—esta vez con pruebas.

Práctica aburrida, gran recompensa. También cambió la cultura del equipo: la gente se volvió más dispuesta a mejorar seguridad porque
el plan de recuperación quitó el impuesto del miedo.

Broma #2: La forma más rápida de demostrar que tienes un firewall es demostrarlo accidentalmente sobre ti mismo.

Listas de verificación / plan paso a paso (despliegues seguros)

Checklist A: Antes de habilitar una VPN en un servidor remoto

  1. Consigue una vía de recuperación. Acceso por consola, IPMI, consola serial cloud, o al menos una segunda ruta SSH desde una red distinta.
  2. Programa un rollback automático. Usa at para desactivar UFW o restaurar nftables tras 2–5 minutos.
  3. Snapshot de la configuración. Copia /etc/ufw, reglas nft y configs de la VPN a un lugar seguro.
  4. Anota las IPs origen de gestión. Si tu IP cambia por una VPN corporativa, tu allowlist te traicionará.
  5. Decide túnel completo vs túnel dividido. Rara vez los servidores quieren túnel completo para todo; sé explícito sobre excepciones.

Checklist B: Si necesitas un kill switch de VPN (y aún necesitas SSH)

  1. Permite SSH entrante en la interfaz física desde rangos confiables.
  2. Permite salida de respuestas de gestión vía la interfaz física (policy routing/rutas host).
  3. Permite salida en la interfaz VPN de forma amplia, luego restringe destinos si hace falta.
  4. Mantén la aceptación de established,related en INPUT/OUTPUT.
  5. Añade logging/contadores en los drops finales para ver qué rompiste.

Checklist C: Si el host es gateway VPN para otras redes

  1. Habilita net.ipv4.ip_forward=1 (y forwarding IPv6 si se usa).
  2. Decide NAT vs subredes enroutadas (preferir rutas si controlas ambos extremos).
  3. Permite flujos FORWARD explícitamente (LAN → VPN, VPN → LAN según necesites).
  4. Asegura que exista enrutamiento de retorno en ambos extremos (NAT lo oculta; enrutado lo requiere).
  5. Prueba desde un cliente detrás del gateway, no solo desde el gateway mismo.

Temporizador de rollback: cancélalo cuando estés seguro

cr0x@server:~$ atq
7	Fri Dec 27 12:04:00 2025 a root
cr0x@server:~$ sudo atrm 7

Significado: Eliminas el job programado de rollback una vez confirmes que puedes reconectar.
Decisión: No lo canceles pronto. Espera hasta haber probado desde una sesión nueva.

Patrones de trabajo: kill switch, túnel dividido, reenvío en el lado servidor

Patrón 1: Mantén el tráfico de gestión fuera de la VPN (recomendado para servidores)

Si el servidor tiene una IP pública y lo administras por SSH, trata la gestión como un plano de control separado.
No la incluyas en un túnel completo a menos que estés listo para diseñar el enrutamiento con precisión.

El enfoque más simple y estable es: la VPN maneja tráfico de aplicaciones o subredes específicas, pero las respuestas SSH siempre salen
por la interfaz por la que entró el SSH.

En la práctica, eso significa o:
(a) no cambies la ruta por defecto cuando se active la VPN; añade rutas específicas para destinos VPN; o
(b) usa policy routing para que solo tráfico seleccionado use la VPN.

Patrón 2: Un kill switch sensato que no mate tu acceso

Un kill switch es simplemente “drop todo lo que no vaya por wg0/tun0.” Lo peligroso es que tu sesión SSH también se convierte en ‘todo’
si no haces excepciones.

La excepción correcta no es “permitir puerto 22.” Es “asegurar que las respuestas a mis redes administrativas se enruten y pasen por la interfaz correcta,
incluso cuando la ruta por defecto sea la VPN.” Eso es enrutamiento más filtrado, no solo filtrado.

Patrón 3: Gateway VPN para una LAN (forwarding + NAT o rutas)

Aquí es donde UFW sorprende a la gente. La postura por defecto de UFW sobre tráfico routed es conservadora. Está bien.
Pero si construyes un gateway, debes configurar forwarding explícitamente.

Si no controlas el enrutamiento en el extremo remoto, NAT es práctico. Si controlas ambos extremos, las subredes enroutadas son más limpias.
NAT oculta IPs de origen; enrutar las conserva pero necesita anuncios/entradas de rutas reales.

Habilita forwarding (persistentemente)

cr0x@server:~$ sudo tee /etc/sysctl.d/99-vpn-forwarding.conf >/dev/null <<'EOF'
net.ipv4.ip_forward=1
net.ipv6.conf.all.forwarding=1
EOF
cr0x@server:~$ sudo sysctl --system
* Applying /etc/sysctl.d/99-vpn-forwarding.conf ...
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

Significado: El kernel reenviará paquetes.
Decisión: Haz esto solo en hosts destinados a enrutar tráfico; cambia la postura de seguridad.

UFW: permite tráfico enrutado entre LAN y VPN (ejemplo)

cr0x@server:~$ sudo ufw route allow in on ens3 out on wg0 from 192.168.50.0/24 to 0.0.0.0/0
Rule added
cr0x@server:~$ sudo ufw route allow in on wg0 out on ens3 from 0.0.0.0/0 to 192.168.50.0/24
Rule added

Significado: Permitiste forwarding en ambas direcciones para esa subred LAN.
Decisión: Ajusta destinos si puedes. “LAN hacia cualquier lugar” está bien para salida a Internet, pero no para tráfico este-oeste en redes corporativas.

nftables: masquerade dirigido para LAN saliendo por wg0 (ejemplo)

cr0x@server:~$ sudo nft add table ip nat
cr0x@server:~$ sudo nft 'add chain ip nat postrouting { type nat hook postrouting priority srcnat; policy accept; }'
cr0x@server:~$ sudo nft add rule ip nat postrouting oifname "wg0" ip saddr 192.168.50.0/24 masquerade

Significado: Los clientes LAN aparecerán ante el lado remoto como la IP de la interfaz VPN, simplificando el enrutamiento de retorno.
Decisión: Si necesitas auditabilidad por host, prefiere subredes enroutadas en vez de NAT.

Fija el tráfico de gestión con policy routing (ejemplo)

Si la VPN insiste en controlar la ruta por defecto, aún puedes mantener la gestión estable usando una tabla de enrutamiento separada
para tráfico hacia tus redes administrativas.

cr0x@server:~$ echo "100 mgmt" | sudo tee -a /etc/iproute2/rt_tables
100 mgmt
cr0x@server:~$ sudo ip route add default via 203.0.113.1 dev ens3 table mgmt
cr0x@server:~$ sudo ip rule add to 198.51.100.0/24 lookup mgmt priority 1000

Significado: El tráfico destinado a tu subred administrativa usa la puerta física, incluso si la tabla principal tiene la ruta por defecto apuntando a la VPN.
Decisión: Este es el enfoque adulto cuando debes combinar túnel completo con gestión remota.

Una cita de fiabilidad (idea parafraseada)

“La esperanza no es una estrategia.” — idea parafraseada atribuida a la cultura de operaciones/SRE (presente en discusiones de ingeniería de fiabilidad)

Esa línea aparece en todas partes porque es dolorosamente aplicable a cambios de firewall en máquinas remotas.

UFW vs nftables: elige tu veneno, evita mezclar metáforas

UFW: bueno para políticas simples, peligroso cuando asumes que cubre forwarding por defecto

UFW es agradable cuando tus necesidades son: permitir SSH, permitir un par de puertos, denegar todo lo demás. Te evita
escribir 200 líneas de reglas para una política de 4 reglas. Eso es win.

Donde UFW quema a los ingenieros es en tráfico enrutado y rutas basadas en interfaz para VPNs. Si el sistema actúa como gateway,
debes razonar sobre FORWARD. UFW lo hace posible, pero no te obliga a pensarlo. Ahí está la trampa.

nftables: poder explícito, consecuencias explícitas

nftables es limpio y expresivo. También hace exactamente lo que le dices, incluso si lo que le dices es un auto-sabotaje.
Con nftables deberías familiarizarte con:

  • Políticas de cadena (policy drop significa que necesitas accepts explícitos).
  • Manejo de estado (ct state established,related no es opcional en la mayoría de diseños).
  • Coincidencia por interfaz (iifname/oifname)—especialmente con interfaces VPN.
  • Contadores y logging (un drop silencioso es una fábrica de incidentes).

No pongas dos capitanes en el mismo barco

Si UFW está activo y también cargas un ruleset nft personalizado, puedes acabar con tablas superpuestas y prioridades de cadena.
A veces funciona por accidente. Eso no es diseño.

Elige uno:
mantén UFW para políticas, o gestiona nftables directamente y deshabilita UFW. Mezclar es cómo obtienes un ruleset que nadie on-call puede explicar.

Audita quién posee realmente el filtrado de paquetes en tu host

cr0x@server:~$ sudo ufw status
Status: active
cr0x@server:~$ sudo systemctl is-active nftables
inactive
cr0x@server:~$ sudo update-alternatives --display iptables | sed -n '1,6p'
iptables - auto mode
  link best version is /usr/sbin/iptables-nft
  link currently points to /usr/sbin/iptables-nft
  link iptables is /usr/sbin/iptables

Significado: UFW está activo; los comandos iptables mapean al backend nft. Incluso si nftables.service está inactivo, nft puede seguir siendo el motor subyacente.
Decisión: Al depurar, siempre inspecciona nft list ruleset como la verdad en sistemas modernos.

Preguntas frecuentes

1) ¿Por qué permitir el puerto UDP de la VPN no arregló nada?

Porque el puerto UDP cubre solo el transporte externo del túnel. Tu tráfico real pasa por una interfaz diferente
(wg0/tun0), toca cadenas distintas (FORWARD/OUTPUT) y puede requerir NAT o rutas.

2) ¿Por qué SSH se rompe solo después de que la VPN cambia la ruta por defecto?

Porque las respuestas siguen la tabla de enrutamiento. Si las respuestas salen por la VPN, la IP de origen cambia y tu cliente no lo acepta
(o el camino lo descarta). Soluciona fijando rutas de gestión o usando policy routing.

3) ¿Puedo simplemente establecer UFW en permitir salida por defecto y olvidarme?

En un servidor básico, quizá. En un gateway VPN o setup con kill-switch, no. Las restricciones de OUTPUT interactúan con enrutamiento VPN,
DNS y keepalives de formas no obvias. Si restringes OUTPUT, hazlo con permisos explícitos y contadores.

4) ¿Cuál es la forma más limpia de prevenir bloqueos durante cambios de firewall?

Programa un temporizador de rollback (at now + 2 minutes), aplica el cambio, prueba desde una sesión nueva y luego cancela el temporizador.
También mantén acceso por consola si la máquina es importante.

5) ¿Por qué WireGuard muestra handshakes pero sigue sin conectividad?

El éxito del handshake prueba que los peers pueden intercambiar claves por UDP. No prueba que tus rutas, AllowedIPs, políticas de forwarding
o NAT estén correctas. Trátalo como “el transporte está vivo”, no como “la red está lista”.

6) ¿Necesito NAT para tráfico VPN?

Si reenvías una LAN privada por la VPN y el extremo remoto no tiene ruta de vuelta a esa LAN, NAT es la solución práctica.
Si controlas ambos extremos, prefiere rutas y evita NAT para mejor observabilidad y menos sorpresas.

7) ¿Por qué IPv6 empeora esto?

Porque puedes permitir IPv4 y bloquear IPv6 (o viceversa) y el cliente elegirá la familia que “funcione”. Luego falla. Audita sockets de escucha y reglas del firewall para ambas familias si IPv6 está habilitado.

8) ¿Es seguro deshabilitar rp_filter?

rp_filter ayuda a prevenir spoofing. Deshabilitarlo a ciegas es pereza. Para gateways VPN y enrutamiento asimétrico, ponlo en modo loose
(2) en las interfaces relevantes para que el tráfico asimétrico legítimo no se descarte.

9) ¿Debo usar UFW o nftables nativo para sistemas VPN?

Si el sistema es simple, UFW está bien. Si necesitas policy routing, forwarding complejo, múltiples VPNs o kill switches estrictos,
nftables suele ser más claro porque puedes expresar la intención con precisión—suponiendo que tu equipo sepa operarlo.

10) ¿Cuál es el error más común de UFW con gateways VPN?

Olvidar que el tráfico enrutado está deshabilitado por defecto. Puedes permitir el puerto VPN todo el día; el forwarding seguirá sin ocurrir.
Solución: habilita forwarding y añade reglas ufw route allow.

Conclusión: siguientes pasos para seguir online

El tema recurrente es poco glamuroso: las VPN cambian rutas e interfaces, y tu firewall no conoce tus intenciones.
Si tratas la “conectividad VPN” como un problema de abrir puertos, seguirás quedándote fuera.

Pasos siguientes que yo realmente haría en un host Ubuntu/Debian en producción:

  1. Decide si el servidor debe usar túnel completo o túnel dividido. Si es un servidor administrado remotamente, por defecto elige túnel dividido.
  2. Implementa el hábito de temporizador de rollback para cada cambio de firewall en sistemas remotos.
  3. Audita el enrutamiento (ip route, ip rule) y confirma explícitamente las rutas de retorno de gestión.
  4. Elige un plano de control de firewall (UFW o nftables) y deja de mezclarlos salvo que disfrutes la arqueología.
  5. Añade contadores/logging a tus reglas de drop para que la depuración sea basada en evidencia, no en rituales.

Si solo haces una cosa: haz de ip route get tu reflejo antes y después de levantar una VPN. Te dice por dónde irán tus respuestas.
Esa es la diferencia entre “servidor seguro” y “servidor seguro pero inalcanzable”.

← Anterior
ZFS vs btrfs: Dónde btrfs resulta agradable y dónde duele
Siguiente →
VPN + RDP/SSH: Acceso remoto sin abrir puertos a Internet

Deja un comentario