// Engineering Log

HTTP, HTTPS y TLS: Parte 3 — HTTP/1.1, HTTP/2 y HTTP/3: ¿en qué se diferencian las versiones?

Publicado el 30.09.2026

// Ruta rapida

Este articulo pertenece al tema Servidores e infraestructura.

HTTP tiene tres versiones en uso activo: HTTP/1.1, HTTP/2 y HTTP/3. Métodos, encabezados y códigos de estado son los mismos, por lo que a la aplicación normalmente le da igual por qué versión llegó la petición. La diferencia está en cómo se empaquetan y transmiten los mensajes por la red, y de eso depende la velocidad de carga de páginas con decenas de recursos y el comportamiento en una mala conexión móvil.

HTTP/1.1

Versión de 1997 (actualmente — RFC 9112). Los mensajes son texto; la conexión TCP se mantiene abierta entre peticiones (keep-alive).

La principal limitación es la cola. No se puede enviar una segunda petición por la misma conexión hasta que no llegue la respuesta a la primera. El mecanismo de pipelining, que permitía enviar varias peticiones seguidas, estaba en el estándar, pero las respuestas igualmente debían ir en orden, y una imagen lenta retrasaba todo lo demás. Los navegadores nunca lo activaron.

Soluciones de la época de HTTP/1.1:

  • hasta seis conexiones a un mismo host en el navegador;
  • sharding de dominios — servir la estática desde static1.example.ru, static2.example.ru para obtener más conexiones;
  • concatenar scripts y estilos en un solo archivo, sprites de imágenes.

Cada nueva conexión es un handshake de TCP y TLS, un slow start de TCP independiente y una carga adicional para el servidor.

HTTP/2

Estándar de 2015 (actualmente — RFC 9113), derivado del protocolo SPDY de Google.

Tramas binarias en lugar de texto. El mensaje se divide en tramas (frames): trama de encabezados, tramas de datos. Cada trama lleva un identificador de stream.

Multiplexación. En una conexión TCP circulan simultáneamente decenas de streams, uno por petición. Las tramas de distintas respuestas se entrelazan, y una respuesta lenta no bloquea las demás. Al navegador le basta una conexión por sitio, y el sharding de dominios y la concatenación de archivos se vuelven innecesarios e incluso perjudiciales: varios dominios significan varias conexiones y más consultas DNS.

Compresión de encabezados HPACK. En HTTP/1.1 cada petición vuelve a enviar User-Agent, Cookie, Accept — cientos de bytes que se repiten. HPACK mantiene en ambos extremos una tabla de encabezados ya enviados y envía sólo referencias a ella.

Pseudocabeceras. La línea inicial se reemplazó por los campos :method, :path, :scheme, :authority (en lugar de Host) en la petición y :status en la respuesta. Todos los nombres de encabezados son en minúsculas.

Server push — envío por parte del servidor de recursos que el cliente aún no ha solicitado. En la práctica apenas ahorraba, y Chrome lo desactivó en la versión 106 (2022). En lugar de push se usan la respuesta 103 Early Hints y <link rel="preload">.

Sólo con TLS en los navegadores. El estándar permite HTTP/2 sin cifrado (h2c), pero ningún navegador lo soporta. La versión se elige durante el handshake de TLS mediante la extensión ALPN: el cliente propone h2, http/1.1, el servidor elige. h2c se encuentra en redes internas, por ejemplo en gRPC entre servicios.

Problema que permanece. La multiplexación eliminó la cola a nivel HTTP, pero no a nivel TCP. TCP entrega los bytes estrictamente en orden, y si se pierde un paquete, todos los streams en la conexión esperan a que se retransmita, incluso los que no tenían datos en ese paquete. Esto se denomina bloqueo head-of-line (head-of-line blocking). En canales estables pasa desapercibido, pero con pérdidas del 1–2 % en redes móviles HTTP/2 con una sola conexión puede funcionar peor que HTTP/1.1 con seis.

HTTP/3 y QUIC

HTTP/3 (RFC 9114, 2022) funciona sobre QUIC (RFC 9000) — un protocolo de transporte sobre UDP que asumió las tareas de TCP y TLS.

Streams a nivel de transporte. QUIC conoce los streams por sí mismo, y la pérdida de un paquete retrasa sólo el stream cuyos datos iban en él. El bloqueo head-of-line desaparece.

TLS 1.3 integrado. El cifrado en QUIC es obligatorio; no hay un handshake TLS separado sobre el transporte — las claves se negocian en los primeros paquetes QUIC. Una conexión nueva se establece en un intercambio de ida y vuelta (1-RTT) en lugar de dos para TCP + TLS 1.3; una reconexión puede enviar datos inmediatamente (0-RTT). También se cifran los campos de transporte de control visibles en TCP: números de paquete, acknowledgements.

Migración de conexión. Una conexión QUIC se identifica no por la pareja IP:puerto sino por un identificador de conexión. Cuando un teléfono pasa de Wi-Fi a la red móvil, la descarga continúa sin un nuevo handshake.

Compresión de encabezados QPACK — una variante de HPACK adaptada a que los streams no llegan en orden.

Cómo sabe el navegador de HTTP/3. La primera conexión al sitio se hace por TCP (HTTP/2 o 1.1). El servidor anuncia soporte de HTTP/3 con el encabezado:

alt-svc: h3=":443"; ma=86400

y el navegador en solicitudes siguientes intenta QUIC en el puerto UDP 443. La segunda vía es un registro DNS tipo HTTPS con el parámetro alpn="h3": entonces el navegador puede ir por HTTP/3 de entrada.

Limitaciones. UDP/443 está bloqueado en algunas redes corporativas, y en algunas redes QUIC es recortado o ralentizado de forma deliberada. En ese caso los navegadores vuelven a TCP sin que el usuario lo note, por eso HTTP/3 siempre se habilita además de HTTP/2, no en su lugar. Procesar QUIC en espacio de usuario consume más CPU en el servidor que TCP en el kernel.

Tabla resumen

HTTP/1.1HTTP/2HTTP/3
TransporteTCPTCPQUIC (UDP)
Formatotextotramas binariastramas binarias
Peticiones por conexión simultáneamente1muchasmuchas
Compresión de encabezadosnoHPACKQPACK
Cifradoopcionalobligatorio en navegadoressiempre, TLS 1.3
La pérdida de un paquete retrasauna conexióntodos los streams de la conexiónsólo su propio stream
Selección de versiónpor defectoALPN h2Alt-Svc o DNS HTTPS, ALPN h3

Habilitar en Nginx

HTTP/2 en Nginx 1.25.1 y posteriores se habilita con una directiva aparte (la forma antigua listen 443 ssl http2 está obsoleta). HTTP/3 — mediante listen ... quic; el módulo ngx_http_v3_module está en los paquetes oficiales de nginx.org desde la 1.25:

nginx
server {
    listen 443 ssl;
    listen 443 quic reuseport;   # reuseport — solo en un bloque server por puerto
    listen [::]:443 ssl;
    listen [::]:443 quic reuseport;

    http2 on;
    http3 on;

    server_name example.ru;
    ssl_certificate     /etc/letsencrypt/live/example.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.ru/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;   # para QUIC se necesita TLSv1.3

    add_header Alt-Svc 'h3=":443"; ma=86400' always;
}

No olvide abrir UDP/443 en el firewall — esta es la causa más frecuente por la que HTTP/3 “no se activa”:

bash
ufw allow 443/udp

Caddy habilita HTTP/2 y HTTP/3 por sí mismo, sin configuración. En HAProxy HTTP/3 está disponible desde la versión 2.6 (bind quic4@:443 ssl crt ... alpn h3).

Cómo comprobar la versión

curl muestra la versión negociada en la salida de -v y en la variable http_version:

bash
curl -sI --http2 https://example.ru/ -o /dev/null -w '%{http_version}\n'
# 2

curl -sI --http3 https://example.ru/ -o /dev/null -w '%{http_version}\n'
# 3 — si curl fue compilado con soporte para HTTP/3

Si su curl soporta HTTP/3 se ve en la línea Features de la salida de curl --version (la palabra HTTP3). El curl del sistema en macOS y en muchas distribuciones está compilado sin él. Puede probar con una imagen de Docker donde curl venga compilado con HTTP/3, o mediante el navegador: en las herramientas de desarrollador, en la pestaña Network active la columna Protocol — allí verá h2 o h3.

La opción --http3 intenta QUIC, pero paralelamente lanza un intento por TCP y vuelve a él si QUIC no responde. Para probar QUIC sin retroceder, use --http3-only.

Errores típicos

  • HTTP/3 está habilitado en la configuración, pero UDP/443 está cerrado en el servidor o por el proveedor — los navegadores silenciosamente permanecen en HTTP/2.
  • reuseport indicado en varios bloques server para la misma dirección — Nginx no arrancará con un error de parámetro duplicado.
  • Servicios internos detrás del proxy esperan HTTP/2 (gRPC), y el proxy les pide por HTTP/1.1 — en Nginx para esto se necesita grpc_pass, no proxy_pass.
  • Concatenar todos los scripts en un solo archivo enorme por costumbre de la época de HTTP/1.1 — con HTTP/2 los archivos pequeños se cargan en paralelo y se cachean mejor por separado.

// Tarea parecida

Si estas resolviendo algo parecido

Este articulo pertenece a uno de los temas principales de trabajo. Puedes seguir leyendo sobre el tema, ir a la pagina principal para entender a que me dedico o abrir directamente los servicios.

Tema del articulo

Servidores e infraestructura

VPS, Linux, stack web, migraciones, hosting, bases de datos y operacion base.

Tareas frecuentes de esta tema

  • Migrar un sitio o servicio a un nuevo servidor
  • Configurar Linux, Nginx, base de datos y copias de seguridad
  • Entender por que el sistema funciona de forma inestable

// Siguiente paso

Si necesitas ayuda con este tema y no solo otro articulo, es mejor ir directo a la pagina del servicio. La pagina principal y la seleccion de materiales quedan como rutas secundarias.

Abrir servicios

// Reviews

Reseñas relacionadas

apande

apande

Configuración de Nginx y OpenCart

07.09.2024 · ★ 5/5

Un comprador muy poderoso
kireevk

kireevk

Diagnóstico de Nginx Proxy Manager en un contenedor Docker y solución del problema

15.03.2024 · ★ 5/5

Comprador acostumbrado

// Contact

¿Necesitas ayuda?

Escríbeme y te ayudaré a resolver el problema

Respondo en un día laborable (03:00-13:00 GMT)

Или оставьте заявку здесь:

Confirme que no es un bot.

Escribir y recibir una respuesta rápida