为什么要自编译 Nginx?

Ubuntu 默认 apt 源里的 nginx 不支持 HTTP/3(QUIC)
官方仓库里的也不支持,必须:

  • 使用 Nginx 1.25+(我用的是 1.27.2)
  • 使用 OpenSSL 的 QUIC 分支(QuicTLS)
  • 自己编译带 http_v3_module

此外很多人也会顺便编译:

  • ngx_brotli(Google Brotli 压缩)
  • zstd-nginx-module(Zstandard 压缩)
  • headers-more(更灵活控制响应头)
  • http_slice_module(针对大文件 Range 分片)

本文全部涵盖。


编译环境准备

1
2
3
4
sudo apt update
sudo apt install -y build-essential git curl wget \
libpcre3 libpcre3-dev zlib1g-dev libxslt1-dev \
libxml2-dev libgd-dev libgeoip-dev libjemalloc-dev

下载源码(推荐统一目录)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
mkdir ~/nginx-http3
cd ~/nginx-http3

# 下载 Nginx 最新版本
wget https://nginx.org/download/nginx-1.27.2.tar.gz
tar xf nginx-1.27.2.tar.gz

# 下载 QuicTLS(OpenSSL 的 QUIC 分支)
git clone https://github.com/quictls/openssl.git quictls

# 下载三方模块
git clone https://github.com/google/ngx_brotli.git
git clone https://github.com/tokers/zstd-nginx-module.git
git clone https://github.com/openresty/headers-more-nginx-module.git

# 初始化 brotli 子模块
cd ngx_brotli
git submodule update --init --recursive
cd ..

此时目录结构应为:

1
2
3
4
5
6
~/nginx-http3/
├── nginx-1.27.2/
├── quictls/
├── ngx_brotli/
├── zstd-nginx-module/
└── headers-more-nginx-module/

编译 Nginx + QuicTLS(最关键一步)

进入 nginx 源码目录:

1
2
cd ~/nginx-http3/nginx-1.27.2
make clean || true

执行 configure:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
./configure \
--prefix=/usr/local/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_v3_module \
--with-http_slice_module \
--with-pcre-jit \
--with-threads \
--with-file-aio \
--with-http_gzip_static_module \
--with-http_sub_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_secure_link_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--with-stream_ssl_preread_module \
--add-module=../ngx_brotli \
--add-module=../zstd-nginx-module \
--add-module=../headers-more-nginx-module \
--with-openssl=../quictls \
--with-openssl-opt=enable-ktls \
--with-cc-opt='-O2 -fPIC' \
--with-ld-opt='-ljemalloc'

编译 + 安装:

1
2
make -j"$(nproc)"
sudo make install

验证:

1
/usr/local/nginx/sbin/nginx -V

如果看到:

1
2
--with-http_v3_module
built with OpenSSL 3.x.x+quic

则说明成功支持 HTTP/3。


配置 systemd 服务(替代 apt 安装的 nginx)

创建:

1
sudo nano /etc/systemd/system/nginx-quic.service

写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=Nginx QUIC (self-built)
After=network.target

[Service]
Type=forking
PIDFile=/run/nginx.pid

ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /etc/nginx/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit

[Install]
WantedBy=multi-user.target

启用:

1
2
sudo systemctl daemon-reload
sudo systemctl enable --now nginx-quic

HTTP/3 多域名正确写法(关键)

HTTP/3(QUIC)在 Nginx 的限制:

同一个 IP:443 上,多个 server 块可以同时支持 HTTP/3,但只有一个 server 可以用 reuseport
其他 server 只能用 listen 443 quic;

主域名(带 reuseport):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;

# 只有一个 vhost 可以用 reuseport
listen 443 quic reuseport;
listen [::]:443 quic reuseport;

add_header Alt-Svc 'h3=":443"; ma=86400' always;
server_name example.com;

# 证书、业务配置……
}

第二个域名(不带 reuseport):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;

# 不加 reuseport,但依旧支持 H3
listen 443 quic;
listen [::]:443 quic;

add_header Alt-Svc 'h3=":443"; ma=86400' always;
server_name example1.com;

root /var/www/music-api;
index index.html;

# 静态 & API …
}

为什么这样写能让两个域名都支持 HTTP/3?

因为:

  • QUIC 的 socket(UDP)只需要一个 reuseport 入口;
  • 其余 server 共享该 socket,内部按 TLS SNI 分配给正确的 vhost。

检查 HTTP/3 是否生效

浏览器检查:

  • Chrome 地址栏输入:chrome://net-internals/#http2
  • 或 F12 → Network → Protocol

命令行验证:

1
curl -I --http3-only https://你的域名

返回 HTTP/3 表示成功。


踩坑总结

duplicate listen options?

原因:

同一个 IP:443 多次写 listen 443 quic reuseport

解决:

只有一个 server 支持 reuseport,其余写成:
listen 443 quic;


HTTP/3 访问走错域名?

原因:

你给所有域名都加了 Alt-Svc,但 QUIC 监听只在一个 server。

解决:

按本文的主域名(reuseport)+ 副域名(no reuseport)模式写。