Nginx 开启 HTTP3 与 DNS SVCB 的设置

发布时间:

最后更新:

最近给本站升级 HTTP3,这个东西出来有两年了,浏览器和很多平台都支持完毕,可惜本站所用的 Node.js 仍没支持,没办法还得在前头整个 Nginx。

升级完成之后的效果还是很可观的:

原来 HTTP2 的用时原来 HTTP2 的用时

升级 HTTP3 之后升级 HTTP3 之后

可以看出 h3 协议的首屏图片加载用时在 200ms 左右,而 h2 的在 400ms 到 500ms 之间,说实话提升这么大我是没想到的,应该跟本站服务器在美国有关,这也展现出了 HTTP3 的威力,新技术,赶紧冲!

Nginx 配置 #

开启 HTTP3 的过程其实不复杂,本文以本站使用的 Nginx 反代为例,同时它也是最流行的 HTTP 服务器,要是你用的库还没支持的话也可以搞一个放前面反代。

Nginx 从 1.25 版本开始才支持 HTTP3,可以使用以下命令先检查一下:

shell
nginx -V 2>&1

Nginx-VNginx-V

打印的输出中有--with-http_v3_module即支持 HTTP3,也可以用grep命令来搜索。在写本文时 Nginx 官方源的版本是 1.26,Debian stable 才到 1.24,如果你的源太旧可以切过去。

至于怎么反代就不讲了,教程到处都是,这里仅说下如何开启 HTTP3 。给反代加上 HTTP3 只需两行:

dockerfile
# 这是 Nginx 的站点配置文件。
server {
	server_name  blog.kaciras.com;

	listen 443 ssl;
	listen 443 quic reuseport;

	http2  on;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

   add_header Alt-Svc 'h3=":443"';

    # 其它的反代设置照旧……
}

首先用listen配置端口监听,协议写quic,由于跟 HTTP 1/2 使用同样的端口所以还要加上个reuseport

然后再加一个 HTTP 头,表明服务器支持 h3,端口还是 443,这样浏览器访问过一次之后就会记住,下次直接就用 QUIC 协议连接了。

最后注意看一下 nginx.conf 里 ssl_protocols 是否写了 TLSv1.3,这是 HTTP3 支持的最低版本。

是否配置成功可以用 https://http3check.net 之类的工具检查:

HTTP3 CheckHTTP3 Check

DNS 配置 #

到此为止就差不多了,但还有一点瑕疵,就是首次访问的时候无法确定握手的方式。

这是由于 HTTP3 跟之前的版本在传输层的协议是不一样的,HTTP3 使用 UDP 而之前的都是 TCP。这就有个问题:当首次访问一个网站时,还不知道它支不支持 HTTP3,应该发那种包?

经测试 Firefox 对首次访问的站点仅使用 TCP 握手,其它浏览器也有不同的处理方式

Chrome 在 HTTP/3 可用时,总是优先使用 HTTP/3 协议,当失败后再回退至 HTTP/2。而 Safari 则是并发尝试使用 HTTP/2 和 HTTP/3,并优先选择最先完成连接建立过程的连接。这可能使得在测试时发现 Safari 经常甚至永不使用 HTTP/3。

要解决这个问题,就得在建立连接之前就获知服务器是否支持 HTTP3,于是 DNS 成为了最好的选择,新的 SVCB 和 HTTPS 记录运营而生。

SVCB 记录能够给一个域名定义多个“服务”,每个“服务”都有一个域名和一组参数,客户端可以通过参数来选择服务,以及提前得知一些信息。

HTTPS 记录属于 SVCB 的一种,专门用于 HTTP,配置都是一样的。

Cloudflare 早就支持啦Cloudflare 早就支持啦

上图是本站的 DNS HTTPS 记录:

综合一下就是从blog.kaciras.com能查询到一个 HTTPS 服务,域名就是自己,支持 HTTP3 和 HTTP2,IP 地址是 66.103.210.238,是不是通俗易懂?

从输入 URL 到建立连接发生了什么从输入 URL 到建立连接发生了什么

经测试 Edge 浏览器能够发送 HTTPS 查询,并在第一次就走 h3 连接;Firefox 也会查但并不一定使用 HTTP3,不知道怎么回事。

为什么有了 ipv4hint 还要查 A 记录?

上图确实能看到有两个 DNS 查询,分别是 HTTPS 和 A,这是因为 ipv4hint 只是提示(Hint),根据 RFC 9460 Section 7.3 的描述:

The "ipv4hint" and "ipv6hint" keys convey IP addresses that clients MAY use to reach the service. If A and AAAA records for TargetName are locally available, the client SHOULD ignore these hints. Otherwise, clients SHOULD perform A and/or AAAA queries for TargetName per Section 3, and clients SHOULD use the IP address in those responses for future connections. Clients MAY opt to terminate any connections using the addresses in hints and instead switch to the addresses in response to the TargetName query.

客户端可以先建立 ipv4hint 的连接,但同时也要查询服务域名的 A 记录,最终仍以 A 记录为准,ipv4hint 仅用于加速。

另外 SVCB 记录还有很多强大的用途,比如让 HTTP 使用任何端口,不在卡死 80 和 443,也终于不用靠反代来复用端口了;以及 ECH 加密。这些超出了本文的范围,就不说了。

基建有待升级 #

最后还有一点可惜的是 SVCB 属于较新的协议,很多老古董都不支持,比如我这默认的 DNS 是联通的 218.104.111.114,根本就查不了:

查不到啊查不到啊

遇到这种情况可以考虑换大厂的公共 DNS,比如:

换了之后就可以了换了之后就可以了

但是换了之后延迟会高一点,ping 时间从 4ms 变成了 32 ms,到底值不值得还有待观察。

评论加载中