HTTP/3 es la versión de HTTP que funciona sobre QUIC, un transporte basado en UDP que establece la conexión cifrada en menos viajes de ida y vuelta y evita que un paquete perdido bloquee todas las peticiones de la conexión. La mejora se nota sobre todo en redes móviles y con pérdida de paquetes. En este tutorial activarás HTTP/3 en Ubuntu 24.04 con Nginx desde el repositorio oficial de nginx.org, verás la alternativa con Caddy y comprobarás que los clientes lo usan de verdad.

Requisitos previos

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo.
  • Un dominio (tudominio.com) con registros A (y AAAA si usas IPv6) apuntando al servidor.
  • Los puertos 80/tcp, 443/tcp y 443/udp accesibles desde Internet.

Cómo funciona la negociación de HTTP/3

El navegador no puede saber de antemano si un servidor habla QUIC. La primera visita se hace por TCP con HTTP/2 o HTTP/1.1, y el servidor responde con la cabecera Alt-Svc: h3=":443". A partir de ahí el navegador intenta QUIC por UDP 443 y, si el puerto está bloqueado, sigue usando TCP sin que el usuario note nada. Por eso HTTP/3 siempre se configura junto a HTTP/2, nunca en su lugar.

Paso 1: Instalar Nginx desde el repositorio oficial

El paquete nginx de Ubuntu 24.04 es la versión 1.24, que no incluye QUIC: el soporte llegó en Nginx 1.25. Los paquetes de nginx.org sí se compilan con el módulo http_v3.

Instala las dependencias y la clave de firma del repositorio:

sudo apt update
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/nginx.gpg

Añade el repositorio de la rama estable y dale prioridad sobre el paquete de Ubuntu:

echo "deb [signed-by=/etc/apt/keyrings/nginx.gpg] https://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
  | sudo tee /etc/apt/sources.list.d/nginx.list
printf "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
  | sudo tee /etc/apt/preferences.d/99nginx

Instala Nginx y comprueba que incluye el módulo:

sudo apt update
sudo apt install nginx
nginx -V 2>&1 | grep -o with-http_v3_module
with-http_v3_module

Arranca el servicio:

sudo systemctl enable --now nginx

Paso 2: Abrir los puertos en el firewall

QUIC usa UDP, así que no basta con el 443/tcp habitual. Con UFW:

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
sudo ufw enable
sudo ufw status
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
443/udp                    ALLOW       Anywhere

Si tu proveedor aplica un firewall externo o grupos de seguridad, abre también allí el 443/udp.

Paso 3: Obtener el certificado TLS

HTTP/3 exige TLS 1.3, que Nginx negocia automáticamente con un certificado válido. Crea el directorio del sitio y un bloque HTTP mínimo que Certbot pueda usar para validar el dominio:

sudo mkdir -p /var/www/tudominio.com
echo '<h1>HTTP/3 funciona</h1>' | sudo tee /var/www/tudominio.com/index.html
sudo mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.disabled
sudo nano /etc/nginx/conf.d/tudominio.com.conf
server {
    listen 80;
    listen [::]:80;
    server_name tudominio.com www.tudominio.com;
    root /var/www/tudominio.com;
}

Recarga Nginx, instala Certbot con el plugin de Nginx y pide solo el certificado, sin que Certbot modifique la configuración:

sudo nginx -t && sudo systemctl reload nginx
sudo apt install certbot python3-certbot-nginx
sudo certbot certonly --nginx -d tudominio.com -d www.tudominio.com
Certificate is saved at: /etc/letsencrypt/live/tudominio.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/tudominio.com/privkey.pem

Paso 4: Configurar HTTP/3 en Nginx

Sustituye el contenido de /etc/nginx/conf.d/tudominio.com.conf por la configuración completa:

sudo nano /etc/nginx/conf.d/tudominio.com.conf
server {
    listen 80;
    listen [::]:80;
    server_name tudominio.com www.tudominio.com;
    return 301 https://$host$request_uri;
}

server {
    # HTTP/1.1 y HTTP/2 sobre TCP
    listen 443 ssl;
    listen [::]:443 ssl;

    # HTTP/3 sobre QUIC (UDP)
    listen 443 quic reuseport;
    listen [::]:443 quic reuseport;

    http2 on;
    http3 on;

    server_name tudominio.com www.tudominio.com;
    root /var/www/tudominio.com;
    index index.html;

    ssl_certificate     /etc/letsencrypt/live/tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    # Anuncia HTTP/3 a los navegadores durante 24 horas
    add_header Alt-Svc 'h3=":443"; ma=86400' always;

    location / {
        try_files $uri $uri/ =404;
    }
}

Puntos importantes:

  • reuseport solo puede aparecer una vez por dirección y puerto en toda la configuración. Si alojas más sitios, pon listen 443 quic; sin reuseport en los demás bloques server.
  • La cabecera Alt-Svc es la que hace que el navegador pruebe HTTP/3. Si algún location define sus propios add_header, repite ahí también Alt-Svc, porque Nginx no hereda las cabeceras del nivel superior en ese caso.
  • No actives ssl_early_data (0-RTT) salvo que tu aplicación sea inmune a peticiones repetidas: permite ataques de repetición.

Comprueba y recarga:

sudo nginx -t
sudo systemctl reload nginx

Verifica que Nginx escucha también en UDP:

sudo ss -ulnp | grep ':443'
UNCONN 0  0   0.0.0.0:443   0.0.0.0:*   users:(("nginx",pid=2231,fd=8),...)
UNCONN 0  0      [::]:443      [::]:*   users:(("nginx",pid=2231,fd=9),...)

Paso 5: Comprobar que los clientes usan HTTP/3

Primero confirma que el servidor anuncia HTTP/3:

curl -sI https://tudominio.com/ | grep -i alt-svc
alt-svc: h3=":443"; ma=86400

El curl de Ubuntu 24.04 no está compilado con soporte QUIC. Compruébalo con curl -V | grep HTTP3; si tu equipo local tiene un curl con HTTP3 (por ejemplo el de Homebrew en macOS), puedes forzar la conexión por QUIC:

curl --http3-only -sI https://tudominio.com/ | head -n 1
HTTP/3 200

En el navegador, abre las herramientas de desarrollo, pestaña Red, activa la columna Protocolo y recarga la página dos veces: la primera petición llega por h2 y las siguientes por h3. En el servidor, el log de acceso muestra el protocolo en cada petición:

sudo tail -n 5 /var/log/nginx/access.log
203.0.113.25 - - [25/Sep/2026:10:12:03 +0000] "GET / HTTP/3.0" 200 24 "-" "Mozilla/5.0 ..."

Alternativa: HTTP/3 con Caddy

Caddy activa HTTP/3 por defecto, junto con el certificado automático de Let's Encrypt. Si prefieres Caddy a Nginx en un servidor nuevo, instálalo desde su repositorio oficial:

sudo apt install debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Edita el Caddyfile:

sudo nano /etc/caddy/Caddyfile
tudominio.com, www.tudominio.com {
    root * /var/www/tudominio.com
    file_server
    encode zstd gzip
}

No hace falta ninguna directiva para HTTP/3. Recarga y comprueba el puerto UDP:

sudo systemctl reload caddy
sudo ss -ulnp | grep caddy

Con los mismos puertos abiertos del paso 2, la verificación del paso 5 funciona igual.

Solución de problemas

La cabecera Alt-Svc aparece, pero el navegador sigue en h2. Casi siempre es el UDP 443 bloqueado en un firewall externo o en la red del cliente (algunas redes corporativas filtran QUIC). Prueba desde otra red y revisa el firewall del proveedor.

nginx: [emerg] duplicate listen options for 0.0.0.0:443. Has puesto reuseport en más de un bloque server. Déjalo solo en uno.

unknown directive "http3". Sigues usando el Nginx de Ubuntu 1.24. Comprueba el origen con apt policy nginx y revisa el archivo de preferencias del paso 1.

Caddy avisa de failed to sufficiently increase receive buffer size. El kernel limita el buffer UDP que necesita QUIC. Auméntalo:

printf "net.core.rmem_max=7500000\nnet.core.wmem_max=7500000\n" | sudo tee /etc/sysctl.d/60-quic.conf
sudo sysctl --system
sudo systemctl restart caddy

Conclusión

Tu servidor sirve ahora HTTP/3 sobre QUIC con respaldo automático a HTTP/2, lo que reduce la latencia de conexión en redes móviles sin afectar a los clientes antiguos. Como siguientes pasos, activa la compresión Brotli, configura cabeceras de caché largas para los estáticos y mide el TTFB antes y después con PageSpeed Insights.