Nginx启用HTTP/3

多年前,我们启用了HTTP/2,今天,终于轮到HTTP/3了。

更新Nginx

Nginx 1.25.0以上版本才支持HTTP/3,因此首先要升级Nginx。如果发行版的官方软件卷中的Nginx版本较低,可以使用Nginx官方提供的包。下面以Debian为例(Ubuntu可参考)。如果之前没有安装过发行版官方的Nginx,建议先安装并配置好,然后再安装Nginx官方的包,这样可以继承发行版官方的配置文件。

首先安装必要的包:

sudo apt update
sudo apt install -y curl gnupg lsb-release ca-certificates

然后要下载密钥,/etc/apt/keyrings是官方推荐的密钥存储目录,如果目录不存在需要创建目录:

sudo mkdir -p /etc/apt/keyrings

然后下载密钥到目录下,命名为nginx.gpg,下面是一条命令,须一次执行:

curl -fsSL https://nginx.org/keys/nginx_signing.key | \
  sudo gpg --dearmor -o /etc/apt/keyrings/nginx.gpg

然后写入APT软件源配置到/etc/apt/sources.list.d/nginx.sources文件,下面是一条命令,须一次执行:

cat <<EOF | sudo tee /etc/apt/sources.list.d/nginx.sources
Types: deb
URIs: http://nginx.org/packages/mainline/debian
Suites: $(lsb_release -cs)
Components: nginx
Signed-By: /etc/apt/keyrings/nginx.gpg
EOF

URIs一行是软件源地址,如果是Ubuntu须要把最后的debian改成ubuntu$(lsb_release -cs)是获取发行版代号,如Debian的trixie或Ubuntu的nobleSigned-By一行就是上面下载的密钥。

最后更新并安装nginx即可:

sudo apt update
sudo apt install nginx

如果之前装过Nginx,会询问是否覆盖当前的配置文件(\etc\nginx\nginx.conf),建议不要覆盖,保留旧版配置文件,以继承原来的配置。

Nginx相关配置

提高读写文件限制

首先查看硬限制:

ulimit -Hn

然后修改Nginx的systemd服务文件,提高软限制(不能超过硬限制数量,不知道怎么设置就和硬限制保持一致即可)

sudo systemctl edit nginx

之后会打开文本编辑器,在其中的提示行(### Anything between here and the comment below will become the contents of the drop-in file)下添加如下内容:

[Service]
LimitNOFILE=65535

其中65535就是软限制的值。保存退出。

然后重载并重启服务:

sudo systemctl daemon-reload
sudo systemctl restart nginx

SSL设置

因为HTTP/3又进一步加强了安全性,因此需要修改Nginx的SSL设置。下面使用Vim编辑器为例,相关使用方法参见Vim简易操作指南

首先打开/etc/nginx/nginx.conf,将其中的SSL相关行注释掉(这里主要是之前HTTP/2时设置的ssl_protocolsssl_ciphersssl_prefer_server_ciphers):

sudo vim /etc/nginx/nginx.conf

然后新建/etc/nginx/conf.d/ssl.conf文件,把SSL相关设置放到这里面:

sudo vim /etc/nginx/conf.d/ssl.conf

在打开的文本编辑器写入如下内容,然后保存退出:

ssl_protocols TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;

ssl_protocols表示启用的协议,这里仅使用TLSv1.3ssl_ciphers表示启用的算法,这里HIGH表示高强度算法,!aNULL表示排除无认证的套件,!MD5表示排除MD5算法;ssl_prefer_server_ciphers表示是否倾向于使用服务器支持的算法(而不是客户端算法)。

配置好后重载Nginx配置:

sudo systemctl reload nginx

防火墙

如果使用了防火墙,需要开放443的UDP端口(HTTP/3默认端口)的入站连接。这里各个发行版都有所区别,请自行查找相关资料。

站点相关配置

首先要给站点配置过HTTPS(参考在Ubuntu上获取Let’s Encrypt免费证书Nginx启用HTTP/2

设置默认服务器

如果在一个服务器上运行多个站点,推荐设置一个默认服务器(单个站点也可以设置)。

设置这个默认服务器的目的,除了将非合法域名的访问丢弃之外,还是为了设置默认的监听端口参数(即sslreuseport),因为新版Nginx不能多次重复设置这些参数。如果只有一个站点一个server块,需要将这些参数设置到相应的地方。

sudo vim /etc/nginx/sites-available/default

写入如下内容:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name _;

        return 444;
}
server {
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        http2 on;

        listen 443 quic reuseport;
        listen [::]:443 quic reuseport;
        http3 on;

        add_header Alt-Svc 'h3=":443"; ma=86400' always;

        ssl_certificate /etc/nginx/certs/ca.cer;
        ssl_certificate_key /etc/nginx/certs/key.pem;

        server_name _;

        return 444;
}

第一个server配置了默认HTTP服务器,监听80端口;server_name _;表示绑定所有不通过域名的访问;return 444;表示直接丢弃请求,不返回任何内容。

第二个server配置了默认HTTPS服务器,监听443端口,加上ssl表示监听TCP端口(针对HTTP/1.1和HTTP/2),第二处加上quic表示监听UDP端口(针对HTTP/3)、加上reuseport表示复用UDP端口;add_header Alt-Svc 'h3=":443"; ma=86400' always;是告诉浏览器这个服务器支持HTTP/3;ssl_certificatessl_certificate_key分别设置证书路径和私钥路径,因为此处没有绑定域名,因此可以使用OpenSSL创建自签证书,或到一些免费的工具网站生成即可。

站点配置文件

然后打开站点配置文件(以/etc/nginx/sites-available/example.com为例,文件名example.com请根据情况修改):

sudo vim /etc/nginx/sites-available/example.com

然后设置如下:

server {
    listen 80;
    server_name example.com www.example.com;

    rewrite ^(.*)$ https://example.com$1 permanent;
}

server {
    listen 443;
    listen [::]:443;
    http2 on;

    listen 443 quic;
    listen [::]:443 quic;
    http3 on;

    server_name example.com www.example.com;

    root /var/www;
    index index.html;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    add_header Alt-Svc 'h3=":443"; ma=86400' always;
    add_header Strict-Transport-Security "max-age=63072000; preload";
    add_header X-Content-Type-Options  "nosniff";

    location / {
        try_files $uri $uri/ =404;
    }
}

第一个server是将HTTP跳转到对应的HTTPS。第二个server就是真正要配置的站点,和HTTP/3有关的配置详解如下:

  • server_name example.com www.example.com;:站点的域名,请根据实际情况修改;

  • listen 443;listen [::]:443;:HTTP/1.1和HTTP/2的监听设置,如果没有其他服务器配置,可以在后面加上ssl(如listen 443 ssl;);

  • http2 on;,启用HTTP/2;

  • listen 443 quic;listen [::]:443 quic;:HTTP/3的监听设置,如果没有其他服务器配置,可以在后面加上reuseport

    注意:如果在一个Nginx进程中设置多处针对同一端口的sslreuseport会出错(不同IP或不同端口号算不同端口)。所以前面最好设置默认服务器,后面就不用检查是否有错了。

    即:如果启用了多个server块,且这些server块中均监听了同一端口,仅第一个server块可以给监听的端口加上sslreuseport

  • http3 on;:启用HTTP/3;

  • ssl on;:启用SSL;

  • ssl_certificatessl_certificate_key:证书和私钥的路径,参考在Ubuntu上获取Let’s Encrypt免费证书

  • add_header Alt-Svc 'h3=":443"; ma=86400' always;:告诉浏览器支持HTTP/3的头信息,always表示不管什么情况都发送头信息;

  • add_header Strict-Transport-Security "max-age=63072000; preload";:安全设置(HSTS),告诉浏览器这个网站强制启用HTTPS;

  • add_header X-Content-Type-Options "nosniff";:安全设置,禁止浏览器嗅探文件类型,用于防止XSS(跨站脚本攻击攻击)。

再往下是网站的具体访问配置了。

启用站点

配置好后,须要在/etc/nginx/sites-enabled里添加符号链接,以启用配置:

sudo ln -s ../sites-available/default /etc/nginx/sites-enabled/default
sudo ln -s ../sites-available/example.com /etc/nginx/sites-enabled/example.com

如果配置了默认服务器才须要执行第一行命令;第二行的文件名example.com请根据实际情况修改。

然后重启Nginx(有的问题仅仅重载不会暴露,重启更有效):

sudo systemctl restart nginx

验证

因为浏览器可能有缓存,因此最方便的验证是否启用了HTTP/3的手段是使用第三方工具,如HTTP/3 Check

赞赏

微信赞赏支付宝赞赏