ping6.net
Mejores Prácticas

IPv6 para desarrolladores web

Lo que los desarrolladores web necesitan saber sobre IPv6: URLs con corchetes, almacenamiento en bases de datos, programación de sockets y errores comunes a evitar.

ping6.net14 de diciembre de 20247 min read
IPv6web developmentprogramaciónbases de datossockets

IPv6 para desarrolladores web#

Si has estado ignorando IPv6 porque "será un problema para después", después es ahora. Las redes móviles funcionan con IPv6 primero. Algunos usuarios detrás de NAT64 solo pueden alcanzarte vía IPv6. Incluso localhost en tu máquina de desarrollo probablemente resuelve a ::1 antes de 127.0.0.1.

Esta guía cubre lo que realmente necesitas saber: manejar IPv6 en URLs, almacenar direcciones en bases de datos, programación de sockets y los errores que te morderán si no tienes cuidado.

TL;DR - Resumen rápido

Puntos clave:

  • Usa corchetes en URLs: http://[2001:db8::1]:8080/ — dos puntos necesitan delimitación
  • Almacena como INET en PostgreSQL o VARBINARY(16) en MySQL — nunca como VARCHAR
  • Vincula sockets a :: para dual-stack (escucha tanto IPv4 como IPv6 en la mayoría de sistemas)
  • Usa bibliotecas para parsing y validación — no escribas regex para direcciones IPv6
  • Prueba con direcciones IPv6 reales — localhost (::1) no cubre casos extremos

Ir a: URLs | Bases de datos | Sockets | Errores comunes


IPv6 en URLs#

Las direcciones IPv6 contienen dos puntos, lo que entra en conflicto con el separador de puerto en URLs. La solución es la notación de corchetes:

http://[2001:db8::1]:8080/api/users
https://[2606:2800:220:1:248:1893:25c8:1946]/

Sin corchetes, los analizadores no pueden distinguir dónde termina la dirección y comienza el puerto. Esto aplica a:

  • URLs HTTP/HTTPS
  • Conexiones WebSocket (ws://[::1]:3000)
  • Cadenas de conexión a bases de datos
  • Cualquier esquema URI

Al generar URLs programáticamente, envuelve las direcciones IPv6 en corchetes. Al analizar, elimínalos antes de validación o almacenamiento.

Almacenamiento en bases de datos#

El error clásico es usar VARCHAR(15) para direcciones IP. Eso encaja IPv4 (máximo 15 caracteres: 255.255.255.255) pero no IPv6.

PostgreSQL tiene un tipo nativo INET que maneja tanto IPv4 como IPv6:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  ip_address INET NOT NULL
);
 
-- Validación y normalización automática
INSERT INTO users (ip_address) VALUES ('2001:db8::1');
INSERT INTO users (ip_address) VALUES ('192.0.2.1');

El tipo INET almacena direcciones eficientemente, las valida al insertar y soporta operaciones de red como coincidencia de subredes con operadores << y >>.

MySQL carece de un tipo nativo, así que usa:

  • VARBINARY(16) - almacena la representación binaria (16 bytes para IPv6, 4 para IPv4)
  • VARCHAR(45) - almacena la representación de cadena (longitud máxima de IPv6 expandido)

El almacenamiento binario es más eficiente pero requiere funciones de conversión:

-- Almacenar
INSERT INTO users (ip_address) VALUES (INET6_ATON('2001:db8::1'));
 
-- Recuperar
SELECT INET6_NTOA(ip_address) FROM users;

La normalización importa. Las direcciones IPv6 tienen múltiples representaciones válidas:

  • 2001:0db8:0000:0000:0000:0000:0000:0001
  • 2001:db8::1 (comprimida)
  • 2001:db8:0:0:0:0:0:1 (parcialmente comprimida)

Siempre normaliza antes de comparar o indexar. La mayoría de las bibliotecas tienen una función de forma canónica.

Programación de sockets#

La API de sockets trata IPv4 e IPv6 como familias de direcciones separadas. Las aplicaciones modernas deberían soportar ambas.

Node.js usa sockets de pila dual por defecto:

const http = require('http');
 
// Se enlaza a :: (todas las direcciones IPv6) y acepta IPv4 vía mapeo
const server = http.createServer((req, res) => {
  res.end(`Your IP: ${req.socket.remoteAddress}`);
});
 
server.listen(3000, '::');

La dirección :: es el equivalente IPv6 de 0.0.0.0, aceptando conexiones en todas las interfaces. La mayoría de los sistemas soportan direcciones IPv6 mapeadas a IPv4 (::ffff:192.0.2.1), permitiendo que un solo socket IPv6 maneje ambos protocolos.

Python requiere manejo explícito de pila dual:

import socket
 
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
sock.bind(('::', 8080))
sock.listen(5)

La bandera IPV6_V6ONLY controla si el socket acepta solo IPv6 o tanto IPv4 como IPv6.

Go hace de pila dual el predeterminado:

listener, err := net.Listen("tcp", ":8080")
// Automáticamente escucha en IPv4 e IPv6

Para conexiones de cliente, siempre usa getaddrinfo() (o su equivalente en tu lenguaje) en lugar de resolver direcciones manualmente. Maneja escenarios IPv4, IPv6 y pila dual correctamente:

import socket
 
# No hagas esto
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('example.com', 80))
 
# Haz esto - funciona para IPv4 e IPv6
addr_info = socket.getaddrinfo('example.com', 80, socket.AF_UNSPEC, socket.SOCK_STREAM)
sock = socket.socket(addr_info[0][0], addr_info[0][1])
sock.connect(addr_info[0][4])

Pruebas locales#

La mayoría de los sistemas resuelven localhost a ambos ::1 (IPv6) y 127.0.0.1 (IPv4). Verifica tu /etc/hosts:

127.0.0.1       localhost
::1             localhost

Si tu aplicación se enlaza solo a 127.0.0.1, no aceptará conexiones IPv6. Enlázate a :: para pila dual o explícitamente enlázate a ambas direcciones.

Para probar comportamiento solo IPv6, deshabilita IPv4 en tu interfaz loopback o usa [::1] explícitamente en tu cliente HTTP:

curl http://[::1]:3000/

Para pruebas realistas, usa una red de prueba solo IPv6. Muchos proveedores de nube ofrecen instancias solo IPv6 que te fuerzan a manejar casos extremos como NAT64/DNS64.

CDN y servidores de origen#

La mayoría de los CDN (Cloudflare, Fastly, AWS CloudFront) soportan IPv6 por defecto. Servirán contenido sobre IPv6 a clientes y traducirán a IPv4 para tu origen si es necesario.

La trampa: si expones APIs directamente (evitando el CDN), tu servidor de origen debe soportar IPv6. Verifica que tu DNS tenga registros AAAA y tu firewall permita tráfico IPv6.

Errores comunes#

Validación con regex. Los patrones regex IPv6 son notoriamente complejos y usualmente incorrectos:

// No hagas esto
const ipv6Regex = /^([0-9a-f]{1,4}:){7}[0-9a-f]{1,4}$/i;
// Falla con compresión ::, direcciones mapeadas a IPv4, IDs de zona...

Usa una biblioteca de análisis adecuada en su lugar. Cada lenguaje principal tiene una que maneja IPv6 correctamente. Para validación, usa nuestra herramienta de validación IPv6.

Direcciones IPv4 codificadas. Busca en tu código patrones como:

const API_SERVER = 'http://192.168.1.100:3000';  // No funcionará con IPv6

Usa nombres de host en su lugar, o soporta ambas familias de direcciones.

Limitación de velocidad basada en IP. Las direcciones IPv6 cambian frecuentemente debido a extensiones de privacidad. La limitación por dirección exacta fallará. Limita por subred /64 en su lugar:

// Malo
const key = `rate:${ipAddress}`;
 
// Mejor para IPv6
const key = `rate:${ipv6ToSubnet64(ipAddress)}`;

Bibliotecas sin soporte IPv6. Clientes HTTP más antiguos, drivers de base de datos y bibliotecas de red podrían no manejar IPv6. Prueba con direcciones IPv6 reales, no solo localhost. Si una biblioteca falla, busca actualizaciones o alternativas.

Casos extremos de análisis de URL. Asegúrate de que tu router/framework maneje direcciones IPv6 entre corchetes:

GET http://[2001:db8::1]:8080/api/users
Host: [2001:db8::1]:8080

Algunos analizadores incluyen incorrectamente los corchetes en el encabezado Host o fallan al extraer la dirección correctamente.

Lista de verificación#

Tu aplicación está lista para IPv6 cuando:

  • Las columnas de base de datos pueden almacenar cadenas de 45 caracteres o usar tipos IP nativos
  • Los servidores se enlazan a :: o escuchan explícitamente en IPv4 e IPv6
  • El código cliente usa getaddrinfo() o equivalente para resolución de nombres
  • La validación de IP no depende de regex
  • No hay direcciones IPv4 codificadas en la configuración
  • La limitación de velocidad y geolocalización manejan subredes IPv6
  • El análisis de URL maneja notación con corchetes

IPv6 ya no es opcional. Constrúyelo desde el principio y evitarás la migración dolorosa después.

Artículos relacionados#

Valida direcciones IPv6

Usa nuestro Validador IPv6 y herramienta Ping para probar el soporte IPv6 de tu aplicación.