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

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:

SystemNginxHTTP/2 goes in
Ubuntu 22.041.18.0the listen line
Ubuntu 24.041.24.0the listen line
Ubuntu 26.041.28.3http2 on;
Debian 121.22.1the listen line
Debian 131.26.3http2 on;
AlmaLinux 9 (RHEL 9 family)1.20.1the listen line
AlmaLinux 10 (RHEL 10 family)1.26.3http2 on;
Amazon Linux 20231.30.6http2 on;
nginx.org packages and the official Docker image1.30.6 stable, 1.31.8 mainlinehttp2 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:

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