HTTP/2 isn’t just a faster HTTP/1.1; it’s a fundamentally different protocol that fixes the core inefficiencies of its predecessor.
Let’s see it in action. Imagine you have a simple Nginx configuration for a website, example.com.
server {
listen 80;
listen [::]:80;
server_name example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
To enable HTTP/2, we’ll modify the listen directive. We don’t just add a flag; we change how Nginx listens for connections.
server {
listen 443 ssl http2; # Added http2 and changed to 443 for SSL
listen [::]:443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
After reloading Nginx (sudo systemctl reload nginx), if you visit https://example.com in a modern browser (which supports HTTP/2 over TLS), you’ll be using the new protocol. You can verify this using your browser’s developer tools (Network tab, look for the "Protocol" column).
The core problem HTTP/1.1 faced was head-of-line blocking. If you requested multiple assets (HTML, CSS, JS, images), each would typically get its own TCP connection. If one of those requests was slow, it would hold up all subsequent requests on that connection, even if the server was ready to send them. Browsers mitigated this by opening multiple connections (usually 6-8 per host), but that added overhead.
HTTP/2 solves this with multiplexing. A single TCP connection can carry multiple, independent request/response streams simultaneously. When the server receives a request for style.css and script.js, it can send them over the same connection without waiting for the first to complete before starting the second. This drastically reduces latency, especially on high-latency networks or when loading many small assets.
The http2 directive tells Nginx to enable the HTTP/2 protocol on that specific listen socket. Crucially, HTTP/2 is almost universally implemented over TLS (HTTPS). Browsers will only negotiate HTTP/2 with you if you’re using HTTPS. This is why the listen directive is typically changed from port 80 to 443 ssl http2. You need to have SSL configured correctly with ssl_certificate and ssl_certificate_key directives for HTTP/2 to work in practice.
The spdy directive, which was an earlier precursor to HTTP/2, is now deprecated in favor of http2. If you see spdy in older configurations, it’s best to replace it with http2.
Beyond multiplexing, HTTP/2 also introduces header compression (HPACK) to reduce overhead, server push to proactively send resources the client might need before it even asks, and stream prioritization, allowing clients to tell the server which resources are more important.
While http2 is the primary directive, the actual negotiation and implementation rely on Nginx’s OpenSSL module. Ensure you have a recent version of OpenSSL installed, as older versions might have limited or no HTTP/2 support. The listen directive is the key lever, but it’s the underlying TLS handshake that enables the HTTP/2 negotiation.
The surprising part about HTTP/2’s performance gains isn’t just the multiplexing itself, but how it fundamentally changes the resource loading strategy for web applications. Because the overhead of opening new connections is eliminated, developers can often simplify their build processes, serving assets individually rather than aggressively concatenating them into giant bundles. This can lead to faster initial page loads and more efficient cache utilization, as only changed files need to be re-downloaded.
The next step is understanding how to leverage server push effectively.