Migration & Upgrades

Migrating from HTTP/1.1 to HTTP/2

A step-by-step guide to migrating your API or web application from HTTP/1.1 to HTTP/2 — prerequisites, server configuration, client compatibility, performance testing, and common pitfalls.

Why Migrate?

HTTP/2 delivers measurable performance improvements for most production workloads:

  • Reduced latencymultiplexing eliminates per-request connection overhead
  • Lower bandwidth — HPACK header compression reduces header overhead by 85–95%
  • Fewer TCP connections — one connection per origin vs six in HTTP/1.1
  • No code changes required — the protocol is semantically identical to HTTP/1.1; existing REST APIs, cookies, and headers work unchanged

Real-world benchmarks show 15–30% improvement in page load time for asset-heavy applications. API endpoints with many small requests benefit most from multiplexing.

Prerequisites: TLS and ALPN

HTTP/2 over TLS (h2) requires TLS 1.2+ and the ALPN extension (Application-Layer Protocol Negotiation, RFC 7301). ALPN allows the client and server to agree on HTTP/2 during the TLS handshake without an extra round trip.

TLS ClientHello → ALPN extension: ['h2', 'http/1.1']
TLS ServerHello → ALPN extension: 'h2'
(TLS handshake complete — HTTP/2 selected)

HTTP/2 cleartext (h2c) exists but browsers do not support it. For all practical purposes, HTTP/2 requires HTTPS. If you don't already have TLS, set it up first with Let's Encrypt or your CDN.

Server Configuration

Nginx

server {
    listen 443 ssl http2;        # Add 'http2' to the listen directive
    listen [::]:443 ssl http2;   # IPv6 too
    
    ssl_certificate /etc/ssl/certs/example.com.pem;
    ssl_certificate_key /etc/ssl/private/example.com.key;
    
    # TLS 1.2+ required for HTTP/2
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    
    # Optional: server push
    http2_push /styles.css;
}

Apache (mod_http2)

LoadModule http2_module modules/mod_http2.so

<VirtualHost *:443>
    Protocols h2 h2c http/1.1
    SSLEngine on
    ...
</VirtualHost>

Caddy

Caddy enables HTTP/2 (and HTTP/3) automatically with automatic HTTPS. No additional configuration is required:

example.com {
    reverse_proxy localhost:8000
    # HTTP/2 and HTTPS enabled automatically
}

Client Compatibility

HTTP/2 client support is excellent:

ClientHTTP/2 Support
Chrome / EdgeSince 2015
FirefoxSince 2015
SafariSince 2015
curlSince 7.43 (with nghttp2)
Python httpxDefault for HTTPS
Python requestsNo (HTTP/1.1 only)
Node.js http2Built-in since Node 8

Clients that do not support HTTP/2 automatically fall back to HTTP/1.1 via ALPN negotiation — backward compatibility is guaranteed.

Testing the Migration

# Verify HTTP/2 with curl
curl -I --http2 https://api.example.com/
# Look for: HTTP/2 200

# Show ALPN negotiation details
curl -v --http2 https://api.example.com/ 2>&1 | grep -E 'ALPN|HTTP/'

# Chrome DevTools → Network → Protocol column → 'h2'

Performance Gains

Measure before and after with consistent methodology:

# Benchmark with wrk (HTTP/2 requires wrk2 or h2load)
h2load -n 10000 -c 100 -m 10 https://api.example.com/
# -m 10: 10 concurrent streams per connection

Expect the biggest gains on endpoints that make multiple parallel subrequests. A page loading 50 assets via HTTP/1.1 (6 parallel connections × multiple round trips) vs HTTP/2 (1 connection, 50 concurrent streams) is a dramatic difference.

Common Pitfalls

1. Domain sharding (anti-pattern): HTTP/1.1 apps often split assets across multiple subdomains (cdn1.example.com, cdn2.example.com) to bypass the 6-connection limit. With HTTP/2, this creates multiple connections instead of one. Remove domain sharding when migrating.

2. Unnecessary resource inlining: HTTP/1.1 performance tips recommend inlining small CSS/JS to avoid round trips. With HTTP/2 multiplexing, separate files are preferable — they can be cached independently.

3. Load balancer HTTP/2 support: Many load balancers terminate HTTP/2 from the client and use HTTP/1.1 to backends — this is fine and common. However, confirm your LB supports HTTP/2 on the frontend.

Monitoring

After deployment, track the protocol distribution in access logs:

log_format main '$remote_addr - [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" $server_protocol';
# server_protocol: 'HTTP/2.0' or 'HTTP/1.1'

Expect 85–95% of modern browser traffic to negotiate HTTP/2. Residual HTTP/1.1 traffic is typically bots, older mobile apps, and server-to-server calls that haven't been updated.

โปรโตคอลที่เกี่ยวข้อง

คำศัพท์ในอภิธานศัพท์ที่เกี่ยวข้อง

เพิ่มเติมใน Migration & Upgrades