Enable http3 for NGINX

NGINX does not support http3 officially, so we need to build from source code to support it.

BTW, the easiest way to enable http3 is to use Caddy as web server (just add experimental_http3 as global option), but NGINX is more efficient. That’s why this post exists.

In this post, we assume the distribution is Debian bullseye and the login user is root.

TL;DR

You can simply download pre-built packages here. Or you can follow instructions below to build by yourself.

Preparation

Run these commands.

1
2
3
4
5
6
7
wget -O /etc/apt/trusted.gpg.d/nginx_signing.asc https://nginx.org/keys/nginx_signing.key
echo -deb-src http://nginx.org/packages/mainline/debian bullseye nginx >> /etc/apt/sources.list
echo -e 'Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900' > /etc/apt/preferences.d/99nginx
apt-get update
apt-get upgrade
apt-get build-dep nginx
apt-get install cmake git golang libunwind-dev mercurial rsync

Get source code

First, we should fetch NGINX and its QUIC branch’s source code. Run these commands.

1
2
3
4
5
apt-get source nginx
mv nginx-1.21.4 nginx
hg clone -b quic https://hg.nginx.org/nginx-quic
rsync -r nginx-quic/ nginx
cd nginx

Note that the version of NGINX might be different. Change that accordingly.

Then we need to get BoringSSL source code and build it as a module. However, NGINX’s OCSP implementation is not compatible with BoringSSL. If you need OCSP stapling, use this patch. The commands below use the patch and solve the issue.

1
2
wget https://raw.githubusercontent.com/kn007/patch/master/Enable_BoringSSL_OCSP.patch
patch -p1 < Enable_BoringSSL_OCSP.patch

Run these commands to deal with BoringSSL.

1
2
3
4
5
6
7
8
mkdir debian/modules
cd debian/modules
git clone https://github.com/google/boringssl
mkdir boringssl/build
cd boringssl/build
cmake ..
make -j$(nproc)
cd ../..

You may also want to add Brotli compression support (since it’s not that easy to build NGINX from source, why not do all things once and for all). Just run this command.

1
git clone --recursive https://github.com/google/ngx_brotli

Edit build rules

Edit rules file in nginx/debian.

1
2
cd ..
nano rules

Find config.env.nginx and make CFLAGS="-Wno-ignored-qualifiers". Then add --add-module="$(CURDIR)/debian/modules/ngx_brotli" right after --sbin-path=/usr/sbin/nginx, and add --with-http_v3_module --with-stream_quic_module --with-cc-opt="-I../modules/boringssl/include $(CFLAGS)" --with-ld-opt="-L../modules/boringssl/build/ssl -L../modules/boringssl/build/crypto $(LDFLAGS)" right after --with-stream_ssl_preread_module. Make sure the original --with-cc-opt and --with-ld-opt are deleted and replaced by the ones above.

Build as deb package

Everything is almost OK. You can build the code as Debian package. Run these commands.

1
2
cd ..
dpkg-buildpackage -b

Then just install it.

1
dpkg -i nginx_1.21.4-1~bullseye_amd64.deb

Note that the name of package might be different.

When you need to make another PC with Debian bullseye has NGINX with http3 support, just copy that package and install it with dpkg. You do not need to build again. So keep that package, since you might need it in the future.

Edit NGINX configuration

Follow this official documentation.

To enable Brotli, simply add brotli on; in http context of NGINX configuration.

For OCSP stapling, use ssl_stapling_file. You can create it by running the command below.

1
openssl ocsp -no_nonce -issuer /path/to/chain.pem -cert /path/to/full.pem -url "$(openssl x509 -in /path/to/full.pem -noout -ocsp_uri)" -respout /path/to/ocsp

You can use this site to test http3 status.