# HTTP/2 and HTTP/3 — what they change and how to turn them on

> HTTP/1.1 loads six files at a time and queues the rest. HTTP/2 sends them all over one connection; HTTP/3 removes the slow handshake. This guide tests which one your site negotiates and shows the one-line change on each host, server and CDN.

Updated 2026-09-25 · Speed & Core Web Vitals · HTML version: https://getreport.app/guides/http2-and-http3

A page with 80 files over HTTP/1.1 downloads them in batches of six per host, each batch waiting for the previous one. HTTP/2 sends all of them at once over one connection and compresses the headers; HTTP/3 does the same over QUIC, with a shorter handshake and better behaviour on mobile networks that lose packets. On most hosts and every major CDN, enabling them is a checkbox. This guide tests what your site negotiates, explains what the result means and gives the setting for each server.

## Quick answer

- Run the [HTTP/2 test](https://getreport.app/tools/http2-test). The ALPN row says what the server chose: `h2` is HTTP/2; `http/1.1` means it is off.
- **nginx**: `listen 443 ssl; http2 on;` (1.25+) or `listen 443 ssl http2;` on older versions.
- **Apache**: `a2enmod http2` and `Protocols h2 http/1.1` in the virtual host; needs the event MPM.
- **Caddy**: on by default, HTTP/3 too.
- **Cloudflare, Netlify, Vercel, most managed hosts**: already on; HTTP/3 is a toggle in Cloudflare's Network tab.
- Everything needs HTTPS: browsers only speak HTTP/2 and HTTP/3 over TLS.

## Why HTTP/2 and HTTP/3 matter

HTTP/1.1 uses one request per connection at a time, and browsers open at most six connections per host. Everything else queues. Sites used to work around that with sprites, domain sharding and inlining; HTTP/2 makes those tricks unnecessary by multiplexing every request over one connection, prioritising them, and compressing headers (which matters when every request carries cookies).

HTTP/3 keeps the multiplexing but replaces TCP with QUIC on UDP. Two things improve: the connection sets up in one round trip instead of two or three (TLS is built in), and a lost packet only stalls the stream it belonged to, not all of them. On a good wired connection the difference is small; on a phone on the move it is visible.

Both are all-or-nothing per connection, which is why third-party files still on HTTP/1.1 show up in the per-file table: a font host or a chat widget on `http/1.1` adds a connection with the old limits.

## How getReport checks it

> **Free tool:** [HTTP/2 and HTTP/3 test](https://getreport.app/tools/http2-test): Check whether a site negotiates HTTP/2 during the TLS handshake and advertises HTTP/3, which protocol every file on the page actually used, plus compression, caching and CDN detection.

The test has two parts. First, a TLS handshake with your server that offers `h2` and `http/1.1` through ALPN (the extension browsers use to agree on a protocol) and records which one the server picks, plus the TLS version and cipher. The page response's `Alt-Svc` header says whether HTTP/3 is advertised:

> **Check: HTTP/2 server support.** Without HTTP/2 the browser opens up to six connections and queues everything else. Turning it on is a server or CDN setting and makes pages with many files load faster with no code change.
>
> 1. Enable HTTP/2 in your web server (nginx 1.25.1+: "http2 on;" in the server block, older: "listen 443 ssl http2"; Apache mod_http2) or put the site behind a CDN that speaks it.
> 2. Check the host's control panel; on Cloudflare, Netlify, Vercel and most managed WordPress hosts it is already on.

> **Check: HTTP/3 is advertised via Alt-Svc.** HTTP/3 (QUIC) shortens the connection setup and copes better with flaky mobile networks. Servers announce it with an Alt-Svc header; without it browsers never try.
>
> 1. Enable HTTP/3 in your CDN or server (Cloudflare toggle, Caddy default, Nginx 1.25+ "listen 443 quic").
> 2. Make sure UDP port 443 is open in the firewall.

Then the page is loaded in Chromium and every response is grouped by the protocol it actually used, so third-party files are covered too:

> **Check: Every request uses HTTP/2 or HTTP/3.** HTTP/2 and HTTP/3 load many files over one connection at once; HTTP/1.1 queues them six at a time. Switching usually makes a page with many images or scripts noticeably faster with no code change.
>
> 1. Turn on HTTP/2 or HTTP/3 in your hosting or CDN panel; on Cloudflare and most managed hosts it is a checkbox.
> 2. Move assets that are still served over HTTP/1.1 (see the technical detail) to a host that supports HTTP/2.

![Protocol details table: HTTP/2 negotiated h2, HTTP/3 not advertised, Alt-Svc header empty, TLS 1.3 with the cipher, and a chip per protocol counting the responses from the Chromium run](https://getreport.app/guides/img/http2-and-http3/protocol.webp "The ALPN result of the handshake, the Alt-Svc header and the responses per protocol from the browser run.")

Compression, cache headers and CDN detection are in the same panel because they live in the same configuration.

## Step by step

### 1. Read the ALPN row

- **negotiated h2**: HTTP/2 is on for your origin. Move to step 3.
- **server chose http/1.1**: HTTP/2 is off. Step 2.
- **not tested (plain http)**: the page is served over http://. Move to HTTPS first; there is no HTTP/2 without it. See [Security headers from zero](https://getreport.app/guides/security-headers-from-zero) for the redirect.
- **could not test**: the handshake failed (a firewall, an odd port). Check the SSL/TLS findings.

### 2. Turn on HTTP/2 at the server

**nginx** (1.25.1 and newer):

```nginx
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com;
    # certificates …
}
```

Older nginx: `listen 443 ssl http2;`. Reload with `nginx -t && systemctl reload nginx`.

**Apache** 2.4.17+: enable the module and the event MPM (prefork does not support HTTP/2 well):

```bash
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event http2
sudo systemctl restart apache2
```

Then in the virtual host:

```apache
<VirtualHost *:443>
    Protocols h2 http/1.1
    # …
</VirtualHost>
```

PHP under Apache then runs as PHP-FPM instead of `mod_php`; most distributions handle that with `a2enconf php8.3-fpm`.

**Caddy**: nothing to do; HTTP/1.1, HTTP/2 and HTTP/3 are on by default with automatic certificates.

**Managed hosting**: look for "HTTP/2" in the hosting panel; on cPanel it depends on the server's Apache build, and the host's support can confirm. Or put Cloudflare in front, which terminates HTTP/2 and HTTP/3 regardless of the origin.

### 3. Turn on HTTP/3

**Cloudflare**: dashboard → Network → HTTP/3 (with QUIC) → on. It also enables 0-RTT.

**nginx** 1.25+ built with QUIC:

```nginx
server {
    listen 443 quic reuseport;
    listen 443 ssl;
    http2 on;
    http3 on;
    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    ssl_early_data on;
}
```

And open UDP 443 in the firewall: `ufw allow 443/udp`.

**Caddy**: on by default; the firewall needs UDP 443.

**Apache**: no stable HTTP/3 support as of this writing; use a CDN or a reverse proxy in front.

### 4. Check the per-file table

The "Responses by protocol" chips count what the browser actually used. `http/1.1: 12` on a site that negotiates h2 means those twelve files came from somewhere else: a font host, an analytics script, an image CDN on a plan without HTTP/2. Open the `http2` finding to see the URLs. Replace the host, self-host the file (fonts especially), or accept it if it is one small file.

## What HTTP/2 changes in how you build

Some HTTP/1.1 habits hurt on HTTP/2:

- **Domain sharding** (`img1.`, `img2.`) forces extra connections; consolidate to one host.
- **Sprites and inlining** save requests that no longer cost much; separate cacheable files are better.
- **Bundling everything** into one 2 MB JavaScript file means one change invalidates the whole cache; smaller bundles are fine now.

And one thing stays true: fewer bytes is still faster than fewer requests. HTTP/2 does not make a 1.8 MB image smaller. See [Image sizes that do not hurt](https://getreport.app/guides/image-sizes-that-do-not-hurt).

## Verify

- The ALPN row reads "negotiated h2"; the Alt-Svc row shows `h3=":443"` if you enabled HTTP/3.
- The `http2` finding reports the document over h2 (or h3) and few or no HTTP/1.1 responses.
- In the browser's dev tools → Network, add the Protocol column: `h2` or `h3` on your files.
- HTTP/3 needs one visit to be advertised and a second visit to be used; browsers cache the Alt-Svc hint.

## Common mistakes

- **Enabling HTTP/2 on port 80.** Browsers ignore it; only the TLS port counts.
- **Apache with prefork.** `Protocols h2` is accepted but silently downgraded; switch to the event MPM.
- **UDP 443 closed.** HTTP/3 is advertised, the browser tries QUIC, times out and falls back. Slower than not advertising it.
- **A proxy in the middle.** Varnish or an old load balancer speaks HTTP/1.1 to the origin; that is fine, as long as the edge that talks to browsers speaks h2.
- **Expecting a big score jump.** HTTP/2 helps pages with many files; a page with one large image and one large script gains little. Fix the bytes too.
