Fix "unknown directive http2" in Nginx
Updated 4 November 2026 · By Brent Alexis
Short answer: nginx -t says unknown directive "http2" because your Nginx is older than 1.25.1. The separate http2 on; line only exists from 1.25.1 (June 2023). On older versions, delete http2 on; and turn HTTP/2 on in the listen line instead: listen 443 ssl http2;. Check your version with nginx -v.
Both forms were tested on Nginx 1.24, 1.25.0, 1.25.1, 1.27, 1.30 (stable) and 1.31 (mainline), and on the Nginx packages of eight Linux distros: 128 checks, with real HTTP/2 requests. How it's tested
- What you'll see
- Which Nginx do you have?
- Fix: Nginx older than 1.25.1
- Nginx 1.25.1 and newer
- One site or every site on the port
- Related: unknown directive "ssl"
- Check HTTP/2 is working
What you'll see
nginx: [emerg] unknown directive "http2" in /etc/nginx/sites-enabled/example.com:24
nginx: configuration file /etc/nginx/nginx.conf test failed
The file and line number point at the http2 on; line. Nginx refuses the whole config, so if you run systemctl reload nginx anyway, it keeps running the old one.
Most configs online, including ProxyForge's default output, use the newer http2 on; form, so this error usually means the config was written for a newer Nginx than the one your distro installed.
Which Nginx do you have?
nginx -v
It prints something like nginx version: nginx/1.24.0 (Ubuntu). These are the versions each distro's own package installs, checked in the lab:
| System | Nginx | HTTP/2 goes in |
|---|---|---|
| Ubuntu 22.04 | 1.18.0 | the listen line |
| Ubuntu 24.04 | 1.24.0 | the listen line |
| Ubuntu 26.04 | 1.28.3 | http2 on; |
| Debian 12 | 1.22.1 | the listen line |
| Debian 13 | 1.26.3 | http2 on; |
| AlmaLinux 9 (RHEL 9 family) | 1.20.1 | the listen line |
| AlmaLinux 10 (RHEL 10 family) | 1.26.3 | http2 on; |
| Amazon Linux 2023 | 1.30.6 | http2 on; |
| nginx.org packages and the official Docker image | 1.30.6 stable, 1.31.8 mainline | http2 on; |
Checked on 4 November 2026 with each distro's own nginx package, no extra repositories. Versions move with updates, so trust nginx -v on your server. Rocky Linux and RHEL use the same packages as AlmaLinux. On AlmaLinux 9, dnf module list nginx also offers 1.22, 1.24 and 1.26; only 1.26 is new enough for http2 on;.
Fix: Nginx older than 1.25.1
Remove the http2 on; line and add http2 to the HTTPS listen line:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2; # only if the site also listens on IPv6
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;
# ...the rest of your server block stays the same
}
Then test and reload:
sudo nginx -t && sudo systemctl reload nginx
In the Config Generator or SSL Generator, tick Older Nginx (before 1.25.1) and the output uses this form. In the lab, that output passed nginx -t and served HTTP/2 on Nginx 1.24 and 1.25.0, and the default output did the same on 1.25.1 and newer.
Nginx 1.25.1 and newer
Here http2 on; is the right form. It goes in the server block (or in http to turn it on for every site), and the listen line has no http2:
server {
listen 443 ssl;
http2 on;
server_name example.com www.example.com;
# ...
}
The old listen 443 ssl http2; form still works on newer versions, but nginx -t warns about it:
nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/sites-enabled/example.com:23
It's a warning, not an error: the test still passes and HTTP/2 still works (checked on 1.25.1, 1.27, 1.30 and 1.31). Switch to http2 on; when you upgrade, so the warning doesn't hide a real one. If one config file has to work on both old and new servers, the old form is the one that runs on both.
One site or every site on the port
The two forms behave differently when several sites share port 443:
http2 on;is per site. In the lab, the site withhttp2 on;got HTTP/2, and a second site on the same port without it stayed on HTTP/1.1.- The old listen form is per port. With
listen 443 ssl http2;on one site, the other site on port 443 got HTTP/2 too, even though its own listen line had nohttp2. That happened on 1.24, and it still happens on 1.25.1 and newer.
So when you switch to http2 on;, take http2 off every listen line on that port and add http2 on; to each site that should keep HTTP/2 (or once in the http block for all of them). One leftover old line keeps HTTP/2 on for every site, along with the warning.
Related: unknown directive "ssl"
Nginx 1.25.1 also removed the ssl on; directive, which had been deprecated for years. Older guides still use it:
listen 443;
ssl on;
On 1.25.1 and newer that gives unknown directive "ssl". On 1.24 and 1.25.0 it still works, with a warning: the "ssl" directive is deprecated, use the "listen ... ssl" directive instead. The fix is the same on every version: delete ssl on; and put ssl on the listen line, listen 443 ssl;.
The same release removed HTTP/2 server push. An old http2_push line doesn't break anything: nginx -t passes with the "http2_push" directive is obsolete, ignored, so you can simply delete it.
Check HTTP/2 is working
curl -s --http2 -o /dev/null -w '%{http_version}\n' https://example.com/
It prints 2 when HTTP/2 is on and 1.1 when it isn't. If it prints 1.1 everywhere, check that your curl supports HTTP/2: curl -V should list HTTP2 under Features. In a browser, open the developer tools, go to Network and show the Protocol column: it says h2.
If the change seems to do nothing after a reload, see reload said OK, but my change didn't apply.
Generate your Nginx HTTPS config →
How to use ProxyForge · FAQ: common errors · Guides · What's new · About