Allow HTTP/2 with HTTP/1.1 Fallback
This guide explains how to configure Apache to prefer HTTP/2 (h2) while still allowing fallback to HTTP/1.1 for clients that do not support the newer protocol. This ensures optimal performance for modern browsers while maintaining compatibility with legacy systems. Alternatively, if you want to enforce HTTP/2 only and completely disable HTTP/1.1, the guide also shows how to configure Apache, ensuring that only clients supporting HTTP/2 can connect.
It includes all necessary steps, explanations, configuration examples, and verification commands based on the official Apache documentation.
This setup applies to Linux-based systems, especially Debian-based distributions such as Ubuntu, where Apache is installed via package managers and modules are managed using a2enmod.
It may also be adapted for other Unix-like systems (e.g. CentOS, Fedora, Arch), but paths and module management commands may differ slightly.
Prerequisites
- Apache version 2.4.17 or higher (required for HTTP/2 support)
- SSL certificate already configured
- Root access to your server
Summary: If the HTTP/2 module is active, you can view an example of how the configuration file default-ssl.conf might look.
Step 1: Verify if mod_http2 is Installed and Enabled
Apache requires the mod_http2 module to support HTTP/2. To check if it’s enabled, open a terminal on your server and run:
apache2ctl -M | grep http2
If you see http2_module (shared), it means the module is active, and you can proceed to Step 2.
If there is no output, enable the module with:
sudo a2enmod http2
sudo systemctl restart apache2
On Ubuntu/Debian systems, enabling the module via a2enmod automatically loads it, so you don’t need to manually add the LoadModule line. However, for reference, the module is loaded via:
LoadModule http2_module modules/mod_http2.so
Step 2: Understand the Protocols Directive
Note: This chapter is for informational purposes. If you are already familiar with Apache’s protocol negotiation and the Protocols directive, you may safely skip Step 2 and move directly to Step 3 or just read the Apache Protocol Selection Overview.
Apache’s Protocols directive controls which HTTP versions your server supports and in which order.
The official documentation often shows configurations like:
Protocols h2 http/1.1
You might also see:
Protocols h2 h2c http/1.1
You can place the Protocols directive globally or inside specific virtual hosts. For example:
Protocols http/1.1
<VirtualHost *:443>
ServerName test.example.org
Protocols h2 http/1.1
</VirtualHost>
test.example.org SSL host. If you want a particular site to use a different protocol setup, you can override the global settings within its <VirtualHost> block.
You can also add the ProtocolsHonorOrder directive together with Protocols, which controls whether Apache strictly enforces your preferred protocol order or allows clients to choose their preferred protocol.
Protocols http/1.1
ProtocolsHonorOrder off
<VirtualHost *:443>
ServerName test.example.org
Protocols h2
ProtocolsHonorOrder On
</VirtualHost>
This configuration sets HTTP/2 and HTTP/1.1 as globally available protocols, with ProtocolsHonorOrder off, meaning Apache allows clients to choose their preferred protocol rather than strictly following the server’s order. In practice, this means a client that supports both HTTP/2 and HTTP/1.1 might still choose to use HTTP/1.1 globally — even if HTTP/2 is listed first.
However, for the virtual host test.example.org, the configuration explicitly enables only HTTP/2 and sets ProtocolsHonorOrder On. This instructs Apache to strictly enforce the server’s protocol preference for that host, ensuring that clients connecting to test.example.org will use HTTP/2 if they support it, regardless of their own preferences.
This setup is useful when you want to offer flexible protocol negotiation globally, while enforcing modern protocol usage like HTTP/2 for specific hosts or services.
Apache Protocol Selection Overview
To clarify how Apache selects the protocol based on your configuration, here’s a summary of common Protocols directive setups:
| Protocols Directive | Behavior |
|---|---|
Protocols h2 http/1.1 |
Prefers HTTP/2, allows fallback to HTTP/1.1 |
Protocols http/1.1 h2 |
Prefers HTTP/1.1, uses HTTP/2 only if client insists |
Protocols h2 |
Allows only HTTP/2, disables HTTP/1.1 completely |
The following table explains how the ProtocolsHonorOrder directive affects enforcement of your protocol preferences:
| ProtocolsHonorOrder | Effect |
|---|---|
ProtocolsHonorOrder On |
Apache enforces your specified protocol order, ignoring client preferences |
ProtocolsHonorOrder Off |
Client may override your order and choose a different protocol (e.g., HTTP/1.1) |
Step 3: Prefer HTTP/2 with HTTP/1.1 Fallback
Open a terminal on your server and edit the SSL VirtualHost configuration file with your preferred editor (e.g. nano, vim, code):
sudo nano /etc/apache2/sites-available/default-ssl.conf
Inside the <VirtualHost *:443> block, add or modify the following lines to enable only HTTP/2:
-
Protocols h2 http/1.1 -
ProtocolsHonorOrder On
Make sure you are editing the correct
default-ssl.conf
Use the following as a reference for your configuration:
<VirtualHost *:443>
ServerName example.com
Protocols h2 http/1.1
ProtocolsHonorOrder On
# Additional SSL and server configurations...
</VirtualHost>
sudo apachectl configtest
Syntax OK, restart Apache to apply the changes:
sudo systemctl restart apache2
Step 4: Check if HTTP/2 is Active
Option 1: Using curl
Open a terminal and run the following command to test whether your server is using HTTP/2:
curl --http2 -sI https://your-server-ip -w '%{http_version}\n'
your-server-ip with your actual server's IP address or domain name (e.g., example.com or 192.168.1.100). This command will return the HTTP version used in the response, allowing you to verify if HTTP/2 is active.
Note: If you're using a self-signed certificate, the -k option disables certificate verification, allowing the request to proceed without validating the SSL certificate.
curl --http2 -k -sI https://your-server-ip -w '%{http_version}\n'
Output meanings:
2→ ✅ HTTP/2 is active1.1→ ⚠️ HTTP/1.1 is in use0orerror→ ❌ Certificate not accepted or HTTP/2 not enabled
Option 2: Using openssl
Open a terminal and run the following command to test whether your server is using HTTP/2:
openssl s_client -connect your-server-ip:443 -alpn h2 </dev/null 2>/dev/null | grep -i "ALPN"
your-server-ip with the actual IP address or domain name of your server (e.g., example.com or 192.168.1.100).
Expected output:
ALPN protocol: h2→ ✅ HTTP/2 is active- No output or different protocol → ❌ HTTP/2 not supported or not negotiated