SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-24

UFW y IPv6: puertos abiertos en tu VPS

En Ubuntu 24.04, UFW suele filtrar IPv6, pero el firewall cloud puede no hacerlo. Comprueba qué servicios quedan expuestos y cierra la brecha en tu VPS.

La trampa del firewall IPv6 en una frase

Tu firewall protege IPv4. Tu VPS casi seguro también tiene una dirección IPv6 pública, y muchos servicios escuchan en ella de forma predeterminada. Si tu firewall sólo cubre IPv4, o si dependes de un firewall del proveedor cloud que sólo filtra IPv4, todos esos servicios son accesibles desde Internet mediante IPv6, aunque el lado IPv4 parezca protegido. Compruebas un puerto con curl, ves que la conexión es rechazada y te sientes seguro. Un atacante se conecta al mismo puerto mediante IPv6 y entra.

Esta guía muestra de dónde procede esa brecha en un VPS normal con Ubuntu 24.04, cómo ver exactamente qué estás exponiendo y cómo cerrarlo. UFW no es el problema aquí. En una instalación moderna de Ubuntu, UFW ya gestiona IPv6. La exposición procede de las capas que lo rodean y de servicios que no sabías que estaban escuchando.

Por qué tu VPS usa IPv6 desde el principio

Casi todos los VPS actuales se entregan con una dirección IPv6 pública, a menudo un /64 completo, además de su dirección IPv4. Comprueba el tuyo:

ip -6 addr show scope global
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet6 2001:db8:2a::1/64 scope global

Ese 2001:db8:2a::1 es enrutable desde cualquier lugar de Internet, exactamente igual que tu dirección IPv4. Ahora comprueba qué está escuchando:

sudo ss -tlnp
State   Recv-Q  Local Address:Port   Process
LISTEN  0       0.0.0.0:22           sshd
LISTEN  0       [::]:22              sshd
LISTEN  0       127.0.0.1:5432       postgres
LISTEN  0       [::]:8080            docker-proxy

Revisa detenidamente la columna Local Address. 0.0.0.0:22 significa «escuchar en todas las direcciones IPv4». [::]:22 significa «escuchar en todas las direcciones IPv6». 127.0.0.1:5432 está asociado a la interfaz de loopback y no es público, por lo que la línea de Postgres es segura. Las dos líneas [::] responden a todo Internet mediante IPv6, y la línea docker-proxy corresponde al tipo de servicio que puedes olvidar que has iniciado.

La mayoría de los daemons se asocian a :: de forma predeterminada, porque en Linux un socket :: normalmente también acepta IPv4. Por tanto, la configuración predeterminada de un servidor recién instalado es «responder en ambas pilas y en todas partes». El firewall es lo único que se interpone, por lo que un firewall que sólo inspecciona una de las pilas es un problema real.

De dónde procede realmente la brecha de IPv6

Hay cuatro fuentes habituales. En un servidor concreto puede haber una o varias al mismo tiempo.

1. Un firewall en la nube que filtra sólo IPv4. Muchos firewalls de proveedores y productos de grupos de seguridad surgieron en torno a IPv4 y no tienen en cuenta IPv6 o necesitan reglas de IPv6 independientes que debe añadir manualmente. Si el único firewall que tiene es el del panel del proveedor y no cubre IPv6, sus servicios [::] están expuestos, independientemente de lo que indique sobre el puerto 22 en IPv4. Consulte la documentación del firewall del proveedor y busque específicamente la palabra IPv6.

2. iptables configurado manualmente sin ip6tables. El comando iptables sólo modifica las tablas de IPv4. IPv6 tiene un comando completamente independiente, ip6tables, con sus propias reglas. Si escribió un script de firewall lleno de líneas iptables -A INPUT ... y nunca creó las reglas ip6tables equivalentes, el firewall de IPv6 está vacío, y una cadena INPUT vacía con una política predeterminada ACCEPT permite todo:

sudo ip6tables -L INPUT -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Esa salida muestra todo el problema en una sola pantalla. IPv4 está filtrado, mientras IPv6 acepta conexiones desde cualquier origen.

3. Docker publica puertos sin pasar por el firewall. Cuando ejecuta docker run -p 8080:80, Docker inserta sus propias reglas por delante de las de UFW. Por tanto, se puede acceder a un puerto publicado aunque ufw status indique que ese puerto está denegado. En las versiones modernas de Docker, lo mismo se aplica a través de IPv6. Por qué Docker omite UFW y cómo filtrar correctamente los puertos de los contenedores explica el mecanismo y las soluciones. Consulte los conceptos básicos de Docker Compose en un VPS para saber cómo se declaran estos puertos publicados.

4. UFW con IPv6 desactivado. UFW admite IPv6, pero sólo cuando se configura para ello. Compruebe el ajuste:

grep IPV6 /etc/default/ufw

Las versiones modernas de Ubuntu incluyen IPV6=yes, por lo que UFW aplica cada regla a ambas pilas. Si ve IPV6=no, debido a una imagen antigua o a una guía antigua, todas las reglas de UFW que haya escrito se aplican sólo a IPv4 y IPv6 queda sin administrar.

Vea exactamente qué está exponiendo

No haga suposiciones. Mídalo desde el exterior. Primero, enumere los procesos que escuchan y anote todos los que estén vinculados a :::

sudo ss -tlnp | grep '::'

Después, desde otra máquina, conéctese a la dirección IPv6 pública del servidor e intente acceder a un puerto que crea que está cerrado:

curl -6 -v http://[2001:db8:2a::1]:8080/

Si devuelve una página o un banner, el puerto está abierto en IPv6. Un puerto cerrado devuelve Connection refused o agota el tiempo de espera. Esos dos fallos no indican lo mismo, y la diferencia entre una conexión rechazada y una que agota el tiempo de espera indica si el host respondió y rechazó la conexión o si un firewall descartó el paquete en silencio. Para obtener una visión completa, analice la dirección IPv6 con nmap desde fuera del servidor:

nmap -6 2001:db8:2a::1

Cada puerto que nmap indique como abierto mediante IPv6 es un puerto accesible desde todo Internet, independientemente de lo que mostrara el análisis de IPv4. Compare los análisis de IPv4 e IPv6 uno al lado del otro. Es la forma más rápida de encontrar la diferencia: cualquier puerto abierto en -6 pero cerrado en IPv4 corresponde a un servicio que su firewall no está filtrando.

Cierre la brecha

Haga que UFW cubra ambas pilas y establezca la denegación predeterminada. Confirme el cambio. Después, establezca una política predeterminada de denegación de conexiones entrantes y permita sólo lo necesario:

sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

Si UFW ya estaba activo cuando cambió IPV6=yes, el cambio no se aplica hasta ejecutar sudo ufw reload.

ufw status muestra cada regla dos veces: una vez sin cambios y otra con el sufijo (v6). Cuando vea las líneas (v6), UFW está filtrando IPv6:

22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)

Si administra iptables manualmente, replique cada regla en ip6tables o cambie a nftables. Sus tablas inet cubren IPv4 e IPv6 en un solo lugar y eliminan por completo este tipo de error. Una sola tabla de filtrado inet de nftables es la solución más limpia cuando escribe las reglas manualmente. Si su VPS ejecuta Rocky o AlmaLinux en lugar de Ubuntu, no hay UFW que configurar. firewalld es la interfaz que debe administrar en su lugar y aplica sus reglas de zona a ambas pilas a la vez.

Asigne los servicios que no quiera exponer públicamente a la interfaz de loopback. Una base de datos, un panel de administración o un endpoint de métricas rara vez necesitan una dirección pública. Asígnelos a 127.0.0.1 y ::1 para que nunca escuchen en una dirección enrutable. En Postgres, establezca listen_addresses = 'localhost'. En un servidor de aplicaciones, asígnelo a 127.0.0.1 y coloque un reverse proxy delante. Cerrar el listener es mejor que filtrarlo con el firewall, porque así no hay ningún servicio accesible.

No confíe en UFW para proteger los puertos publicados por Docker. Publique los puertos de los contenedores en una dirección específica, no en todas las interfaces. Por ejemplo, use -p 127.0.0.1:8080:80 para que el puerto sólo sea accesible desde el host y desde aquello a lo que lo exponga deliberadamente mediante un proxy. Cuando un contenedor deba ser realmente público, colóquelo detrás de un reverse proxy de Traefik y publique sólo el proxy, no cada aplicación.

Añada reglas de IPv6 al firewall de su proveedor o acepte que no es su firewall para IPv6 y deje que UFW o nftables en el host se encarguen de esa función.

Verifique que realmente esté cerrado

Vuelva a ejecutar la misma prueba externa después de aplicar los cambios:

curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1

El puerto que respondía antes ahora debería rechazar la conexión o agotar el tiempo de espera, y nmap debería indicarlo como filtrado o cerrado. Si un puerto sigue abierto, revise de nuevo las cuatro fuentes anteriores: un servicio que todavía está enlazado a :: sin ninguna regla delante, una regla de Docker situada antes que UFW o un firewall del proveedor que nunca recibió tráfico IPv6.

Mantener los servicios sensibles completamente fuera de Internet pública es aún más seguro. Coloque SSH y los paneles de administración detrás de una VPN de WireGuard y configure sus puertos para que respondan sólo a través del túnel. Así, la cuestión de la exposición IPv6 deja de aplicarse a esos servicios. Para ralentizar los escaneos de fuerza bruta que alcanzan lo que permanezca público, añada Fail2ban delante de SSH sobre un firewall con denegación predeterminada.

Si los puertos son un concepto nuevo para usted, lea primero qué son los puertos y cómo escuchan los servicios.

FAQ

¿UFW bloquea IPv6 de forma predeterminada?

En una instalación moderna de Ubuntu 24.04, sí. UFW lee IPV6=yes desde /etc/default/ufw y aplica cada regla tanto a IPv4 como a IPv6; además, ufw status muestra las reglas de IPv6 con el sufijo (v6). El problema aparece cuando IPV6=no (por ejemplo, debido a una imagen antigua o a un tutorial antiguo), cuando depende de un firewall del proveedor que sólo filtra IPv4 o cuando Docker publica un puerto sin pasar por UFW. Compruebe este ajuste con grep IPV6 /etc/default/ufw.

¿Cómo compruebo qué está exponiendo mi VPS mediante IPv6?

Ejecute sudo ss -tlnp y anote cada listener cuya dirección local empiece por [::], lo que significa que acepta conexiones en todas las interfaces IPv6. Después, desde otra máquina, pruebe directamente la dirección IPv6 pública del servidor con curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/ o analícela con nmap -6 YOUR:IPV6::ADDR. Cualquier puerto abierto en el análisis de IPv6 pero cerrado en IPv4 indica una brecha.

¿Por qué puedo acceder al puerto de mi contenedor Docker si UFW indica que está bloqueado?

Docker inserta sus propias reglas de firewall antes que las de UFW cuando publica un puerto con -p. Por eso, se puede acceder al puerto publicado aunque ufw status lo muestre como denegado. Esto ocurre en IPv4 y también en IPv6 cuando la compatibilidad de Docker con IPv6 está habilitada. Publique el puerto en una dirección específica, como -p 127.0.0.1:8080:80, o coloque el contenedor detrás de un reverse proxy y publique sólo el proxy.

¿Sigo necesitando un firewall IPv6 si mi firewall IPv4 está bien configurado?

Sí. IPv4 e IPv6 son pilas de red independientes, con reglas de firewall independientes. Un conjunto perfecto de reglas IPv4 no afecta al tráfico IPv6. Si su VPS tiene una dirección IPv6 pública, como ocurre con casi todos, cualquier servicio que escuche en :: seguirá siendo accesible mediante IPv6 hasta que una regla de firewall IPv6 o una vinculación a loopback lo impida.

¿Cómo hago que un servicio escuche sólo en IPv4 o sólo en localhost?

Configure la dirección de enlace del servicio en su propio archivo de configuración. Use 127.0.0.1 para aceptar conexiones sólo en el loopback de IPv4, o 0.0.0.0 para todas las direcciones IPv4 sin un listener IPv6. Postgres usa listen_addresses, SSH usa ListenAddress y la mayoría de los servidores de aplicaciones ofrecen una opción de host o de enlace. Confirme el resultado con sudo ss -tlnp y compruebe que Local Address ya no muestre [::].