--- title: "Cómo configurar HTTP 103 Early Hints con Nginx en Ubuntu" description: "Configura HTTP 103 Early Hints con Nginx 1.29+ como proxy inverso en Ubuntu 24.04 para que el navegador precargue CSS y fuentes mientras tu aplicación responde." category: "Rendimiento Web" language: es source: https://cubepath.com/es/docs/rendimiento-web/configuracion-de-early-hints-codigo-103 updated: 2026-09-25 --- # Cómo configurar HTTP 103 Early Hints con Nginx en Ubuntu HTTP 103 Early Hints es una respuesta informativa que el servidor envía antes de la respuesta definitiva. Lleva cabeceras `Link` con `rel=preload` o `rel=preconnect`, de modo que el navegador empieza a descargar el CSS, las fuentes o a abrir conexiones con otros dominios mientras la aplicación todavía está generando el HTML. En este tutorial pondrás una aplicación de ejemplo que emite 103 detrás de Nginx en Ubuntu 24.04, activarás la directiva `early_hints` y comprobarás con `curl` que el 103 llega al cliente. Early Hints es útil cuando el servidor tarda en generar la página (consultas a base de datos, renderizado en servidor). Si tu HTML sale en pocos milisegundos, la mejora será mínima. ## Cómo funciona Early Hints en Nginx Nginx no genera respuestas 103 por sí mismo. Desde la versión 1.29.0 puede **reenviar al cliente los 103 que emite el backend** cuando actúa como proxy inverso, y la directiva `early_hints` decide para qué peticiones se hace. El flujo es este: 1. El navegador pide `/` a Nginx. 2. Nginx reenvía la petición a tu aplicación con `proxy_pass`. 3. La aplicación responde enseguida con `103 Early Hints` y cabeceras `Link`, y sigue trabajando. 4. Nginx reenvía el 103 al navegador, que empieza a precargar los recursos. 5. La aplicación termina y envía el `200 OK` con el HTML. Por eso necesitas dos piezas: una aplicación o framework capaz de emitir 103 (Node.js, por ejemplo, con `response.writeEarlyHints()`) y Nginx 1.29.0 o posterior. Ubuntu 24.04 trae Nginx 1.24, así que instalarás el paquete oficial de nginx.org. > Nota: HTTP/2 Server Push (`http2_push`, `http2_push_preload`) no tiene nada que ver con Early Hints. Nginx eliminó el soporte de Server Push en la versión 1.25.1 y los navegadores también lo han retirado, así que no lo uses. ## Requisitos previos - Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. - Un usuario no root con privilegios `sudo`. - Un dominio (en esta guía, **your_domain**) con un registro DNS A apuntando a la IP del servidor. Early Hints solo se envía a clientes HTTP/2 o HTTP/3, y los navegadores solo usan HTTP/2 sobre TLS. - Los puertos 80 y 443 abiertos. Con UFW: `sudo ufw allow 'Nginx Full'` después de instalar Nginx, o `sudo ufw allow 80,443/tcp`. ## Paso 1: Instalar Nginx desde el repositorio oficial Si tienes instalado el Nginx de Ubuntu, elimínalo primero (tus ficheros de `/etc/nginx` se conservan con `remove`, pero haz copia de tus sitios si los tienes): ```bash sudo apt remove nginx nginx-common ``` Instala las herramientas para añadir el repositorio: ```bash sudo apt update sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring ``` Descarga la clave de firma de nginx.org en `/etc/apt/keyrings`: ```bash 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-archive-keyring.gpg ``` Añade el repositorio de la rama mainline, que es la que incorpora antes las funciones nuevas como `early_hints`: ```bash echo "deb [signed-by=/etc/apt/keyrings/nginx-archive-keyring.gpg] https://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list ``` Da prioridad a este repositorio sobre el de Ubuntu para que `apt` no instale la versión 1.24: ```bash printf 'Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n' | sudo tee /etc/apt/preferences.d/99nginx ``` Instala Nginx, arráncalo y comprueba la versión: ```bash sudo apt update sudo apt install nginx sudo systemctl enable --now nginx nginx -v ``` ```output nginx version: nginx/1.29.x ``` Cualquier versión igual o superior a 1.29.0 sirve. El paquete de nginx.org no usa `sites-available`/`sites-enabled`: los sitios se configuran en `/etc/nginx/conf.d/*.conf`. ## Paso 2: Crear una aplicación de ejemplo que emita 103 Para probar el flujo de forma reproducible usarás un pequeño servidor en Node.js que envía un 103 y tarda medio segundo en generar la página, como haría una aplicación real que consulta una base de datos. El Node.js de Ubuntu 24.04 (versión 18) ya incluye `writeEarlyHints()`: ```bash sudo apt install nodejs ``` Crea el directorio de la aplicación y el fichero principal: ```bash sudo mkdir -p /opt/demo-hints sudo nano /opt/demo-hints/server.js ``` ```javascript const http = require('node:http'); const links = [ '; rel=preload; as=style', '; rel=preload; as=font; type="font/woff2"; crossorigin', '; rel=preconnect', ]; http.createServer((req, res) => { // 1. Enviar el 103 en cuanto llega la petición res.writeEarlyHints({ link: links }); // 2. Simular 500 ms de trabajo en el servidor setTimeout(() => { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', // Repetir los Link en el 200 para clientes que ignoran el 103 'Link': links.join(', '), }); res.end('

Hola

'); }, 500); }).listen(3000, '127.0.0.1'); ``` Crea una unidad de systemd para ejecutarla como servicio con un usuario sin privilegios: ```bash sudo nano /etc/systemd/system/demo-hints.service ``` ```ini [Unit] Description=Demo HTTP 103 Early Hints After=network.target [Service] ExecStart=/usr/bin/node /opt/demo-hints/server.js DynamicUser=yes Restart=on-failure [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now demo-hints ``` Comprueba que la aplicación envía el 103 directamente, sin pasar por Nginx: ```bash curl -sv -o /dev/null http://127.0.0.1:3000/ 2>&1 | grep -E '^< (HTTP|[Ll]ink)' ``` ```output < HTTP/1.1 103 Early Hints < Link: ; rel=preload; as=style, ; rel=preload; as=font; type="font/woff2"; crossorigin, ; rel=preconnect < HTTP/1.1 200 OK < Link: ; rel=preload; as=style, ; rel=preload; as=font; type="font/woff2"; crossorigin, ; rel=preconnect ``` Si usas otro backend, el principio es el mismo: tu framework debe escribir el 103 antes de empezar el trabajo pesado. ## Paso 3: Obtener un certificado TLS Instala Certbot con su plugin de Nginx: ```bash sudo apt install certbot python3-certbot-nginx ``` Crea primero un sitio mínimo en el puerto 80 para que Certbot pueda validar el dominio: ```bash sudo nano /etc/nginx/conf.d/your_domain.conf ``` ```nginx server { listen 80; server_name your_domain; } ``` ```bash sudo nginx -t && sudo systemctl reload nginx sudo certbot certonly --nginx -d your_domain ``` Certbot guarda el certificado en `/etc/letsencrypt/live/your_domain/` y programa su renovación automática. ## Paso 4: Activar early_hints en el proxy inverso La directiva `early_hints` acepta una o varias variables: si alguna no está vacía y no vale `0`, Nginx reenvía el 103 del backend. Los clientes HTTP/1.1 antiguos pueden gestionar mal las respuestas 1xx, así que lo habitual es activarlo solo para HTTP/2 y HTTP/3 con un `map`. Sustituye el contenido de `/etc/nginx/conf.d/your_domain.conf`: ```bash sudo nano /etc/nginx/conf.d/your_domain.conf ``` ```nginx # Activar Early Hints solo para clientes HTTP/2 o HTTP/3 map $http2$http3 $early_hints { "" 0; default 1; } server { listen 80; server_name your_domain; return 301 https://$host$request_uri; } server { listen 443 ssl; http2 on; server_name your_domain; ssl_certificate /etc/letsencrypt/live/your_domain/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/your_domain/privkey.pem; location / { early_hints $early_hints; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://127.0.0.1:3000; } } ``` Desde Nginx 1.25.1 HTTP/2 se activa con `http2 on;` y no con el parámetro `http2` de `listen`. Comprueba la sintaxis y recarga: ```bash sudo nginx -t && sudo systemctl reload nginx ``` ```output nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` ## Paso 5: Verificar que el cliente recibe el 103 Haz una petición HTTP/2 desde tu equipo o desde el propio servidor. `curl -v` muestra las respuestas informativas: ```bash curl -sv --http2 -o /dev/null https://your_domain/ 2>&1 | grep -E '^< (HTTP|link)' ``` ```output < HTTP/2 103 < link: ; rel=preload; as=style, ; rel=preload; as=font; type="font/woff2"; crossorigin, ; rel=preconnect < HTTP/2 200 < link: ; rel=preload; as=style, ; rel=preload; as=font; type="font/woff2"; crossorigin, ; rel=preconnect ``` El `103` aparece antes del `200`. Repite la petición forzando HTTP/1.1 para confirmar que el `map` lo desactiva: ```bash curl -sv --http1.1 -o /dev/null https://your_domain/ 2>&1 | grep -E '^< HTTP' ``` ```output < HTTP/1.1 200 OK ``` En el navegador, abre las herramientas de desarrollo de Chrome o Edge, pestaña **Network**: las peticiones de `app.css` y `inter.woff2` deben arrancar antes de que termine la descarga del documento. Chrome y Edge soportan Early Hints desde la versión 103; el soporte en Firefox y Safari es más reciente y más limitado, y los navegadores que no lo entienden simplemente ignoran el 103. ## Paso 6: Elegir bien qué recursos indicar Cada recurso que precargas compite por ancho de banda con el HTML, así que limita la lista a lo que bloquea el primer renderizado: | Valor de `rel` | Qué hace el navegador | Cuándo usarlo | |---|---|---| | `preload` | Descarga el recurso con prioridad alta | CSS crítico, fuente principal, imagen LCP | | `preconnect` | Abre DNS, TCP y TLS con otro origen, sin descargar nada | CDN de imágenes o fuentes en otro dominio | Reglas prácticas: - Indica 2 a 5 recursos como máximo. Precargar todo anula la ventaja. - Las fuentes necesitan `as=font` y `crossorigin`, aunque sean del mismo dominio, o el navegador las descargará dos veces. - Las rutas deben coincidir exactamente con las del HTML (incluido el hash de versión, como `/css/app.3f9a1c.css`). Si no coinciden, Chrome mostrará en la consola el aviso de recurso precargado sin usar. - Mantén las cabeceras `Link` también en el `200`, para clientes que no procesan el 103. ## Solución de problemas **El 103 no aparece a través de Nginx pero sí en el puerto 3000.** Comprueba la versión con `nginx -v` (debe ser 1.29.0 o superior) y que la petición es HTTP/2: si `curl` muestra `HTTP/1.1`, revisa que el bloque `server` incluye `http2 on;`. Confirma también que la directiva está cargada: ```bash sudo nginx -T 2>/dev/null | grep -n early_hints ``` **`nginx -t` devuelve `unknown directive "early_hints"`.** Sigues usando el Nginx de Ubuntu. Revisa que el pin de `/etc/apt/preferences.d/99nginx` existe y ejecuta `apt policy nginx` para ver de qué repositorio sale la versión candidata. **Hay una CDN o balanceador delante de Nginx.** Muchos proxies descartan las respuestas 1xx. Algunas CDN, como Cloudflare, generan sus propios Early Hints a partir de las cabeceras `Link` del `200` si activas la función en su panel; en ese caso basta con que tu origen envíe esas cabeceras. ## Conclusión Has instalado Nginx 1.29+ desde el repositorio oficial, has puesto una aplicación que emite `103 Early Hints` detrás de él y has activado `early_hints` solo para clientes HTTP/2 y HTTP/3. A partir de aquí puedes medir el efecto con Lighthouse o WebPageTest comparando el LCP antes y después, aplicar el mismo patrón a tu aplicación real y combinarlo con la compresión Brotli o la caché de Nginx para reducir aún más el tiempo de carga.