How to Enable HTTP/2 with Nginx on RHEL 7
HTTP/2 is the major revision of the HTTP network protocol that brings multiplexed streams, header compression, and server push to web traffic. Compared to HTTP/1.1, HTTP/2 dramatically reduces page load times on sites with many assets by eliminating head-of-line blocking and reducing the overhead of repeated TLS handshakes across multiple connections. Nginx has supported HTTP/2 since version 1.9.5, and RHEL 7’s EPEL repository provides a recent-enough version to enable it. Because browsers only implement HTTP/2 over TLS, you must have a working HTTPS configuration in place before this tutorial begins. This guide covers version requirements, adding http2 to your listen directive, verifying ALPN support, and tuning nginx.conf for optimal HTTP/2 performance.
Prerequisites
- RHEL 7 with Nginx installed from EPEL (version 1.10 or later recommended)
- A valid TLS certificate configured in Nginx (Let’s Encrypt or commercial)
- OpenSSL 1.0.2 or later (required for ALPN support)
- Root or sudo access
- Port 443 open in your firewall
Step 1: Verify Nginx Version and HTTP/2 Support
HTTP/2 support in Nginx requires version 1.9.5 or later. Check your installed version:
nginx -v
# nginx version: nginx/1.20.1
If Nginx is not installed or is below 1.9.5, install or update from EPEL:
sudo yum install -y epel-release
sudo yum install -y nginx
Next, verify that the Nginx binary was compiled with the http_v2_module:
nginx -V 2>&1 | grep -o 'http_v2_module'
# Expected output: http_v2_module
If the module is not listed, the package in your repository was not compiled with HTTP/2 support. In practice, the EPEL Nginx package on RHEL 7 includes it by default.
Step 2: Verify OpenSSL Version for ALPN Support
Browsers negotiate HTTP/2 using ALPN (Application-Layer Protocol Negotiation), an extension to the TLS handshake. ALPN requires OpenSSL 1.0.2 or later. RHEL 7 ships OpenSSL 1.0.2 as part of its default package set, so this is typically already satisfied.
openssl version
# OpenSSL 1.0.2k-fips 26 Jan 2017
Verify that Nginx was linked against this OpenSSL version:
nginx -V 2>&1 | grep 'built with OpenSSL'
If OpenSSL is below 1.0.2, ALPN will not work and browsers will silently fall back to HTTP/1.1 even with the http2 directive present.
Step 3: Add http2 to the Listen Directive
HTTP/2 in Nginx is enabled by appending http2 to the SSL listen directive in your server block. Open your site configuration file:
sudo nano /etc/nginx/conf.d/yourdomain.conf
Find the existing HTTPS listen line and add http2:
# Before
listen 443 ssl;
# After
listen 443 ssl http2;
A complete minimal HTTPS server block with HTTP/2 enabled looks like this:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
root /var/www/yourdomain.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
Note that http2 is a listen directive parameter — it is not a standalone directive elsewhere in the block. Each TLS-enabled server block that you want to serve over HTTP/2 needs its own listen 443 ssl http2 line.
Step 4: Apply Nginx Configuration Optimizations for HTTP/2
HTTP/2’s multiplexing changes how responses should be tuned. Add the following directives to the http block in /etc/nginx/nginx.conf for optimal performance:
http {
# ...existing settings...
# HTTP/2 push preload (optional, for assets you know the browser will need)
# http2_push_preload on;
# Increase maximum concurrent streams per connection
http2_max_concurrent_streams 128;
# Idle timeout for HTTP/2 connections
http2_idle_timeout 3m;
# Buffer size for reading the client request body
client_body_buffer_size 128k;
# Allow keep-alive connections to reduce connection overhead
keepalive_timeout 65;
keepalive_requests 1000;
# Sendfile and tcp settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# Gzip compression (HTTP/2 clients support it)
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/json
application/javascript text/xml application/xml
application/xml+rss text/javascript;
}
HTTP/2 multiplexes many requests over a single connection, so keepalive_requests 1000 ensures the connection remains open long enough for the browser to fully utilize multiplexing rather than cycling connections frequently.
Step 5: Test and Reload Nginx
sudo nginx -t
If the test reports syntax is ok and test is successful, reload:
sudo systemctl reload nginx
Step 6: Verify HTTP/2 with curl
Use curl with the --http2 flag to request the page over HTTP/2:
curl -I --http2 https://yourdomain.com/
Look for the protocol version in the output:
HTTP/2 200
server: nginx/1.20.1
content-type: text/html; charset=UTF-8
If you see HTTP/2 200 in the status line, HTTP/2 is working correctly. If you see HTTP/1.1 200, Nginx fell back to HTTP/1.1, which usually indicates a missing http2 in the listen directive or an OpenSSL version that does not support ALPN.
For a more detailed negotiation trace showing the ALPN protocol selection:
curl -v --http2 https://yourdomain.com/ 2>&1 | grep -E 'ALPN|Using HTTP'
Expected output includes lines like:
* ALPN, offering h2
* ALPN, offering http/1.1
* ALPN, server accepted h2
* Using HTTP2, server supports multi-use
Step 7: Verify with Browser Developer Tools
In Google Chrome or Firefox, open Developer Tools (F12), go to the Network tab, and reload the page. Right-click on any column header in the request list and enable the Protocol column. Requests served over HTTP/2 display h2 in that column. Requests still using HTTP/1.1 show http/1.1.
In Chrome, you can also verify ALPN negotiation by visiting chrome://net-internals/#http2 and looking for your domain in the active sessions list.
Step 8: Test TLS and ALPN with openssl s_client
Confirm ALPN negotiation at the TLS level:
openssl s_client -connect yourdomain.com:443
-alpn h2
-servername yourdomain.com
< /dev/null 2>&1 | grep -E 'ALPN|Protocol'
A successful ALPN negotiation shows:
ALPN protocol: h2
If the output shows No ALPN negotiated or shows http/1.1, the server is not advertising HTTP/2 via ALPN, which will prevent browsers from using it regardless of what the listen directive says.
Step 9: Common Troubleshooting
- http2 not recognized in listen directive: Your Nginx binary was compiled without
http_v2_module. Reinstall from EPEL or compile from source with--with-http_v2_module. - Browsers using HTTP/1.1 despite http2 in config: Check OpenSSL version (
openssl version) and confirm it is 1.0.2 or later. Also ensure you are connecting to port 443 with a valid, trusted certificate. - SSL_ERROR_RX_RECORD_TOO_LONG in browser: You have
http2on a non-SSL listen directive. HTTP/2 without TLS (h2c) is not supported by any major browser. - Worker process crashing after enabling http2: Check
/var/log/nginx/error.logfor details. A common cause is a too-smallworker_rlimit_nofilesetting when many concurrent streams are opened.
Enabling HTTP/2 in Nginx on RHEL 7 is a single-line change — adding http2 to your SSL listen directive — but the full benefit requires a properly configured TLS stack with ALPN support, tuned keep-alive and buffer settings, and verification that both the server and clients are successfully negotiating the h2 protocol. With Nginx 1.10+ from EPEL and the system’s OpenSSL 1.0.2 package, RHEL 7 has everything needed to serve a modern, performant HTTP/2 site without rebuilding any packages from source.