HTTP/2 delivers significant performance improvements over HTTP/1.1 through features such as header compression, request multiplexing, and server push — all over a single TCP connection. Nginx has supported HTTP/2 since version 1.9.5, and on RHEL 8 the AppStream version of Nginx is compiled with the necessary OpenSSL support to enable it. Because browsers only implement HTTP/2 over TLS (HTTPS), a valid SSL certificate is a prerequisite. This tutorial walks you through enabling HTTP/2 in Nginx on RHEL 8, configuring the required TLS settings, and verifying that the protocol is negotiated correctly.
Prerequisites
- A RHEL 8 server with
sudoaccess - Nginx installed from the RHEL 8 AppStream repository
- A valid SSL/TLS certificate and private key (e.g., from Let’s Encrypt or a commercial CA)
- Port 443 open in
firewalld - A domain name resolving to your server’s public IP
Step 1 — Verify Nginx Supports HTTP/2 and Check OpenSSL Version
HTTP/2 negotiation in browsers uses the ALPN (Application-Layer Protocol Negotiation) TLS extension, which requires OpenSSL 1.0.2 or later. Verify that your Nginx build includes the required flags before proceeding.
nginx -V 2>&1 | grep -E "version|OpenSSL|http_v2"
You should see --with-http_v2_module in the configure arguments and an OpenSSL version of 1.1.1 or higher. On RHEL 8, the default AppStream build of Nginx includes this module. If --with-http_v2_module is absent, you will need to compile Nginx from source or use a different package source.
Step 2 — Configure the HTTPS Server Block with HTTP/2
HTTP/2 is enabled by adding the http2 parameter to the listen directive on port 443. Create or edit your site’s server block configuration file.
sudo nano /etc/nginx/conf.d/example.com.conf
Add the following configuration, replacing the certificate paths and domain name with your own values:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Step 3 — Open Firewall Port 443 and Test the Configuration
Ensure HTTPS traffic is allowed through firewalld, then validate the Nginx configuration syntax before applying it.
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo nginx -t
sudo systemctl reload nginx
Step 4 — Understand ALPN Negotiation
HTTP/2 is negotiated transparently through ALPN, a TLS extension where the client and server agree on the application protocol during the TLS handshake. The client sends a list of supported protocols (e.g., h2, http/1.1), and the server selects h2 if it supports HTTP/2. This means no separate port or additional handshake round trip is needed. You can inspect the negotiated protocol with openssl s_client:
openssl s_client -connect example.com:443 -alpn h2 2>&1 | grep -E "ALPN|Protocol"
A successful negotiation shows ALPN protocol: h2 in the output.
Step 5 — Verify HTTP/2 is Active with curl
Use curl with the --http2 flag to request your site and confirm that the server responds using the HTTP/2 protocol.
curl --http2 -I https://example.com
curl -svo /dev/null --http2 https://example.com 2>&1 | grep -E "ALPN|HTTP/"
The first command’s output should begin with HTTP/2 200 rather than HTTP/1.1 200, confirming that HTTP/2 is being served. You can also verify via browser DevTools: open the Network tab, reload the page, and check the Protocol column (Chrome) or the Transferred column (Firefox) — it should show h2.
Step 6 — Harden TLS for HTTP/2 Compliance
HTTP/2 over TLS mandates that the TLS 1.2 cipher suite used must not be on the HTTP/2 cipher blacklist defined in RFC 7540 Appendix A. The cipher list in Step 2 already satisfies this requirement. Additionally, enable HSTS to instruct browsers to always use HTTPS for future visits, and add OCSP stapling to reduce TLS handshake latency.
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
sudo nginx -t && sudo systemctl reload nginx
Conclusion
HTTP/2 is now enabled on your Nginx server on RHEL 8, providing your visitors with a faster and more efficient browsing experience through multiplexing and header compression. The TLS configuration restricts negotiation to TLSv1.2 and TLSv1.3 with strong cipher suites, satisfying both the HTTP/2 RFC requirements and modern security best practices. ALPN ensures the protocol upgrade is transparent to clients, with older browsers automatically falling back to HTTP/1.1.
Next steps: How to Configure Nginx Load Balancing on RHEL 8, How to Configure Nginx as a Reverse Proxy on RHEL 8, and How to Secure Nginx with Let’s Encrypt on RHEL 8.