Problema
En entornos domésticos donde se publican servicios mediante IPv6 (por ejemplo, una aplicación Docker expuesta en el puerto 443), es frecuente observar que la dirección AAAA funciona perfectamente desde la LAN, pero que clientes externos, monitores de uptime o usuarios en distintas regiones experimentan “unreachable” de forma intermitente. El síntoma típico es:
- Algunas regiones (p.ej. Frankfurt, Madrid) reciben respuestas HTTP 200.
- Otras (Berlin, Tokio, Chicago) devuelven timeout o “connection refused”.
- El comportamiento varía con el tiempo sin cambios en la configuración del servidor.
Este patrón indica que el problema no está en la aplicación (Immich, Nextcloud, etc.) sino en la capa de red que lleva el tráfico IPv6 desde el ISP hasta el host.
Causa
1. Ruta IPv6 inestable o fragmentada
Los proveedores de cable (Vodafone, etc.) a menudo asignan un prefijo /64 y enrutan el tráfico a través de múltiples puntos de peering. Si alguno de esos enlaces tiene alta pérdida o MTU inconsistente, los paquetes pueden descartarse antes de llegar al servidor. La fragmentación de paquetes grandes (TLS handshake) es particularmente sensible.
2. Filtrado implícito en el router doméstico
Muchos routers de ISP aplican filtros de estado “stateful” solo a IPv4 y dejan pasar IPv6 sin inspección, pero pueden bloquear paquetes que no coinciden con una tabla de estados válida (por ejemplo, paquetes de retorno de una conexión iniciada por el cliente). Cambiar de modelo (Vodafone a FritzBox) a menudo altera la política de filtrado.
3. Problemas de Neighbor Discovery (ND) y SLAAC
Si el router no responde correctamente a los mensajes Neighbor Solicitation/Advertisement, algunos nodos externos no pueden resolver la dirección MAC del gateway, provocando pérdida intermitente. Esto suele verse en routers que usan firmware antiguo o configuraciones de “privacy extensions”.
4. Configuración de firewall a nivel del host
Aunque UFW esté desactivado, iptables o nftables pueden contener reglas implícitas que afectan a IPv6 (ip6tables). Un salto de regla “DROP” en la cadena INPUT o FORWARD bloqueará tráfico que llegue de ciertos rangos.
5. Política de Cloudflare y DNS AAAA
Cloudflare puede aplicar “proxy” (orange cloud) a registros AAAA. Cuando el proxy está activo, Cloudflare actúa como terminador TLS y reenvía tráfico a la dirección IPv6 del origen. Si la ruta entre Cloudflare y tu ISP es inestable, la disponibilidad varía. Además, la caché DNS TTL puede servir una dirección antigua después de un cambio de prefijo.
6. Problemas de MTU y Path MTU Discovery (PMTUD)
TLS sobre IPv6 necesita paquetes de ~1500 bytes. Si el camino tiene una MTU menor (p.ej. 1280 bytes en algunos enlaces) y los ICMP v6 “Packet Too Big” son filtrados, la negociación PMTUD falla y la conexión se queda colgada.
Solución
Paso 1 – Verificar la ruta global con traceroute6
Ejecuta desde varias ubicaciones (puedes usar servicios como ping.pe o mtr online) y busca saltos con pérdida o latencia alta.
traceroute6 -n -A <tu-dirección-IPv6>
Si aparecen “* * *” en varios hops, la ruta es sospechosa. Anota los AS involucrados; si siempre se pierde después de un mismo AS, el problema está fuera de tu control y puedes abrir ticket con tu ISP.
Paso 2 – Confirmar que el router responde a ND
Desde una máquina externa (puede ser una VM en la nube) ejecuta:
ping6 -c 3 <tu-dirección-IPv6>
Si recibes “Destination unreachable” pero tcpdump en el servidor muestra paquetes entrantes, el router está bloqueando la respuesta ARP/ND. En ese caso, habilita “IPv6 RA Guard” o actualiza el firmware del router.
Paso 3 – Auditar reglas IPv6 en el host
sudo ip6tables -L -v -n
Busca reglas con DROP o REJECT en INPUT/FORWARD. Si no necesitas filtrado, limpia la tabla:
sudo ip6tables -F
sudo ip6tables -X
Asegúrate de que no exista una política por defecto DROP:
sudo ip6tables -P INPUT ACCEPT
sudo ip6tables -P FORWARD ACCEPT
Paso 4 – Probar sin Cloudflare proxy
Crea un sub‑dominio “directo” en Cloudflare y desactiva el proxy (gris cloud). Verifica que la conectividad mejora. Si la diferencia es notable, mantén el registro sin proxy o usa un CNAME apuntando directamente a la AAAA.
Paso 5 – Ajustar MTU y habilitar PMTUD
En el servidor, establece una MTU segura (por ejemplo 1280) en la interfaz de salida:
sudo ip link set dev eth0 mtu 1280
Luego, habilita la generación de ICMP v6 “Packet Too Big”:
sudo sysctl -w net.ipv6.conf.all.accept_ra=1
sudo sysctl -w net.ipv6.conf.all.accept_redirects=1
Si el ISP bloquea ICMP v6, fuerza una MTU menor en el contenedor Docker:
docker run --network host --env MTU=1280 ...
Paso 6 – Cambiar de router o actualizar firmware
Si el router de Vodafone muestra logs de “IPv6 firewall” o “ICMPv6 blocked”, prueba con un router de terceros (FritzBox, OpenWrt, OPNsense). Configura el router en modo “bridge” para que el servidor reciba directamente el prefijo /64 y maneje RA.
Paso 7 – Monitoreo continuo
Implementa un script que haga curl -6 -s -o /dev/null -w "%{http_code}" https://<tu‑dominio> desde varios nodos (por ejemplo, usando cron en una VM en Hetzner, Linode y una VPS en Japón). Registra los códigos y tiempos; si la tasa de fallos supera el 5 % durante 24 h, el problema persiste y necesita escalado al ISP.
Cuándo aplicar esta solución
- Síntomas: conectividad IPv6 intermitente, respuestas HTTP 200 solo desde ciertas regiones, logs de
tcpdumpque muestran paquetes entrantes pero sin respuesta. - Entorno: servicios auto‑alojados en Docker, exposición directa del puerto 443, uso de DNS AAAA gestionado por Cloudflare o similar.
- No aplica: cuando el problema es exclusivamente IPv4, o cuando la aplicación devuelve errores internos (500) pese a que la conexión TCP se establece correctamente.
Código
# 1. Ver ruta IPv6
traceroute6 -n -A $(dig +short AAAA tu-dominio.com)
# 2. Chequear reglas IPv6
sudo ip6tables -L -v -n
# 3. Resetear tabla IPv6 (solo si no usas firewall)
sudo ip6tables -F
sudo ip6tables -X
sudo ip6tables -P INPUT ACCEPT
sudo ip6tables -P FORWARD ACCEPT
# 4. Forzar MTU en la interfaz
sudo ip link set dev eth0 mtu 1280
# 5. Habilitar PMTUD
sudo sysctl -w net.ipv6.conf.all.accept_ra=1
sudo sysctl -w net.ipv6.conf.all.accept_redirects=1
Verificación
- Ping global:
ping6 -c 5 <tu‑IPv6>desde al menos tres proveedores diferentes. Todos deben responder sin “unreachable”. - Curl HTTPS:
curl -6 -I https://<tu‑dominio>debe devolver200 OKen menos de 500 ms. - MTR IPv6:
mtr -6 -r -c 100 <tu‑IPv6>; la pérdida debe estar < 1 % en todos los hops. - Cloudflare: verifica que el registro AAAA tenga icono gris (no proxy). Si lo cambias a naranja, revisa los logs de Cloudflare para errores de “origin unreachable”.
Notas adicionales
- Algunos ISPs asignan prefijos /56 o /60 y utilizan prefix delegation. Asegúrate de que el prefijo anunciado por el router coincida con la dirección AAAA publicada; de lo contrario, la ruta puede colapsar cuando el router renueva el prefijo.
- Si usas Docker Compose, agrega
network_mode: hostpara evitar la doble NAT que a veces rompe la tabla de vecinos IPv6. - En entornos con privacy extensions, la dirección de enlace (link‑local) cambia frecuentemente; mantén una dirección estática para el registro AAAA.
- Cuando el router soporta IPv6 firewall avanzado, habilita reglas de “allow established, related” y bloquea todo lo demás, pero siempre permite tráfico entrante a los puertos que expones.
- Si el problema persiste después de todos los pasos, solicita a tu ISP un diagnóstico de ruta IPv6 indicando el prefijo y la dirección de destino; algunos proveedores ofrecen herramientas de trazado interno.