利用 Docker + Caddy 开启谷歌 QUIC 快速网络连接协议支持

小助手读文章 00:00 / 00:00

温馨提示:
本文所述内容不具普遍性,可能因操作环境差异而与实际有所出入,故请勿照搬照抄,仅供参考。

使用 QUIC 协议网站可以大大提升访问速度,今天我们一起来看看如何让网站支持 QUIC 协议。

名词解释

QUIC 协议

QUIC 协议即快速 UDP 网络连接(Quick UDP Internet Connections)协议,是一种实验性的网络传输协议,位于 OSI 模型的传输层。由 Google 开发,在 2013 年实现。

由于 TCP 是在操作系统内核和中间件中实现的,因此对 TCP 进行重大更改几乎是不可能的,但 UDP 属于不可靠传输,相比 TCP 减少了握手过程,连接时间大大减少。QUIC 协议基于 UDP 协议,它在两个端点间创建连线,且支持多路复用连线,能够提供等同于 SSL/TLS 层级的网络安全保护,减少握手数据传输及创建连线时的延迟时间,可以实现双向控制带宽,以避免网络拥塞。

QUIC 协议与现有 TCP + TLS + HTTP/2 方案相比,有以下几点主要特征:

  • 利用缓存,显著减少连接建立时间
  • 改善拥塞控制,拥塞控制从内核空间到用户空间
  • 没有 head of line 阻塞的多路复用
  • 前向纠错,减少重传
  • 连接平滑迁移,网络状态的变更不会影响连接断线

Caddy

Caddy 是一个开源的、使用 Golang 编写、支持 HTTP/2 的 Web 服务端。Caddy 支持各种包括 QUIC 协议等 Web 技术,可以作为反向代理和负载均衡器,提供静态编译的单二进制文件,即下即用,支持 i386、amd64 和 ARM 架构上的 Windows、Mac、Linux、Android 和 BSD 操作系统。

Docker

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。

部署

Caddy 是现在除 Chromium 本身外仍在更新的,支持 QUIC 协议的 Web 服务端软件。

相对于 Nginx、Apache 等老牌服务端软件,Caddy 在流控、权限等功能上尚不能相比,故 TCP 下仍然使用 Nginx/Apache,维持不变,UDP 使用 Caddy 来支持 QUIC 协议。 当然了,如果没有管控需求,TCP 下也可以直接使用 Caddy。

由于 Caddy 并不能单独开启 UDP 端口,而是会同时占用 UDP 和 TCP 端口,这就与 Nginx/Apache 造成端口冲突而无法开启,故使用 Docker 容器来实现。

23/07/06 更新
由于组件更新,本方案可能已失效。可参考思路,勿直接生搬硬套。

制作容器

安装 Docker

使用 Docker 官方的一键安装命令:

root@az-jp:~# wget -qO- https://get.docker.com/ | sh
# Executing docker install script, commit: 2f4ae48
+ sh -c apt-get update -qq >/dev/null
+ sh -c apt-get install -y -qq apt-transport-https ca-certificates curl >/dev/null
+ sh -c curl -fsSL "https://download.docker.com/linux/ubuntu/gpg" | apt-key add -qq - >/dev/null
Warning: apt-key output should not be parsed (stdout is not a terminal)
+ sh -c echo "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" > /etc/apt/sources.list.d/docker.list
+ sh -c apt-get update -qq >/dev/null
+ [ -n  ]
+ sh -c apt-get install -y -qq --no-install-recommends docker-ce >/dev/null
+ sh -c docker version
Client:
 Version:           18.09.7
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        2d0083d
 Built:             Thu Jun 27 17:56:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.7
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       2d0083d
  Built:            Thu Jun 27 17:23:02 2019
  OS/Arch:          linux/amd64
  Experimental:     false
......

编写 Dockerfile

这里使用 Ubuntu 18.04 为底层,并安装 Caddy 软件:

root@az-jp:~# vim Dockerfile 

FROM ubuntu:18.04
  
RUN apt-get update -y

RUN apt-get install curl iputils-ping net-tools netcat -y && \
    curl https://getcaddy.com | bash -s personal http.cache,http.expires,http.filter,http.forwardproxy,http.realip

Docker 里的 Ubuntu 18.04 不带 curl、ping、nc、netstat 等命令,所以我们先安装,然后再利用 curl 命令安装 Caddy,Caddy 支持自定义模块,参考官方下载页

ping 命令是为了确认服务器地址,nc 命令是为了确认 UDP 端口是否通畅,netstat 是为了确认端口是否成功开启监听。

生成 Docker

root@az-jp:~# docker build --no-cache --tag vcloud/ubuntu-caddy:v1 . 
Sending build context to Docker daemon  2.048kB
Step 1/3 : FROM ubuntu:18.04
18.04: Pulling from library/ubuntu
......
Successfully built 4fe840c42868
Successfully tagged vcloud/ubuntu-caddy:v1

配置 Caddyfile

Caddyfile 是 Caddy 的配置文件,我们在这里定义网站相关配置,由于我们只是开启 QUIC,所以以反代的形式实现:

root@az-jp:~# vim /usr/local/nginx/conf/Caddyfile
http://vircloud.net {
 redir https://vircloud.net{url}  #自动 https
}
https://vircloud.net {
 tls vircloud.net.crt vircloud.net.key  #指定证书
 proxy / https://vircloud.net {   #反代域名标准配置
   transparent
 }
}

端口测试

运行之前,我们先确认下宿主机端口是否开放,参考《Linux 下测试 TCP|UDP 连通性》。

运行容器

Docker 已经安装好了,Caddy 反代配置也已经准备好,端口也已经开放,我们将 Caddy 容器运行起来:

root@az-jp:~# docker run -d --name quic-blog --add-host vircloud.net:1.1.1.1.1 -p 80:80/udp -p 443:443/udp -v /usr/local/nginx:/usr/local/nginx vcloud/ubuntu-caddy:v1 caddy -quic -conf /usr/local/nginx/conf/Caddyfile
3ee0bb786c97f016f6ae6d49c1e53b658082dcd73e2acf7e7e1a2b8964aaf372

--name:指定 docker 名称;
-- add-host:添加到 /etc/hosts,因为我们是反代,所以要指定反代域名实际 IP;
-p:指定容器与宿主机关联端口,我们开放 80/udp、443/udp 即可;
-v:宿主机要映射到容器的目录,为方便修改 Caddy 等配置,我们把这些文件放到宿主机,以映射方式给容器使用;
caddy -quic -conf:caddy 运行命令,开启 QUIC,并制定配置文件位置。

容器状态

如无意外,现在 QUIC 已经成功开启,可以用以下命令查看 Caddy 容器运行日志:

root@az-jp:~# docker ps -as
CONTAINER ID        IMAGE                         COMMAND                  CREATED             STATUS              PORTS                                      NAMES               SIZE
3ee0bb786c97        vcloud/ubuntu-caddy:v1   "caddy -quic -conf /…"   11 seconds ago      Up 8 seconds        0.0.0.0:80->80/udp, 0.0.0.0:443->443/udp   quic-blog           471B (virtual 183MB)
ocker logs 3ee0bb786c97
Activating privacy features... done.

Serving HTTP on port 80 
http://vircloud.net


Serving HTTPS on port 443 
https://vircloud.net

用以下命令查看宿主机端口监听情况:

root@az-jp:~# netstat -antlp|grep nginx
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      31635/nginx: worker 
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      31635/nginx: worker 
tcp6       0      0 :::443                  :::*                    LISTEN      31635/nginx: worker 
tcp6       0      0 :::80                   :::*                    LISTEN      31635/nginx: worker 
root@az-jp:~# netstat -anulp|grep docker
udp6       0      0 :::80                   :::*                                33863/docker-proxy  
udp6       0      0 :::443                  :::*                                33851/docker-proxy  

甚至于,你还可以进入 Caddy 容器操作:

root@az-jp:~# docker exec -it 3ee0bb786c97 /bin/bash
root@3ee0bb786c97:/# netstat -antlp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp6       0      0 :::443                  :::*                    LISTEN      1/caddy             
tcp6       0      0 :::80                   :::*                    LISTEN      1/caddy             
root@3ee0bb786c97:/# netstat -anulp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
udp6       0      0 :::443                  :::*                                1/caddy             
udp6       0      0 :::80                   :::*                                1/caddy             
root@3ee0bb786c97:/# ps -ef|grep caddy
root          1      0  0 01:17 ?        00:00:00 caddy -quic -conf /usr/local/nginx/conf/Caddyfile

开启 QUIC 响应

因为我们使用 Nginx/Apache 作为 TCP 响应,而浏览器第一次总是会默认以 TCP 先尝试连接,所以我们要告诉浏览器,网站支持 QUIC,方法就是在 Nginx/Apache 响应头加上 QUIC 标志,以 Nginx 为例,在网站配置新增:

server{
......
add_header alt-svc 'quic=":443"; ma=2592000; v="44,43,39"';
......
}

这个头信息就是告诉浏览器,服务端端口 443 上支持 QUIC,且支持的版本号是 44、43、39、35(最新 Caddy 均支持),max-age 为 2592000 秒。

QUIC 测试

现在除 Chrome 浏览器外,基本不支持 QUIC 协议,所以我们用 Chrome 浏览器访问网站看下效果。

开启前(TCP)

TCP.png

开启后(QUIC)

QUIC.png

对比分析

可以看到,开启 QUIC 后,Chrome 优先使用了 QUIC 协议去连接网站,这是因为发出请求后,Chrome 将采取 QUIC 和 TCP 竞争的方式与服务端建立连接(建立连接,但不发送请求)。如果第一个请求通过 TCP 发出,TCP 赢得竞争,第二个请求将通过 TCP 发出,在随后的某个时刻,QUIC 如果一旦连接成功,将来所有请求都将通过 QUIC 连接发送。由于 QUIC 的 0-RTT 握手,QUIC 几乎总能立即获胜,因此支持 QUIC 的网站,Chrome 总会使用 QUIC 来连接。

问题分析

浏览器仍然使用 TCP 连接

出现这种情况,可能是因为客户端无法与服务端进行 UDP 通信,可以参考《Linux 下测试 TCP|UDP 连通性》确认下。

还可能使客户端不支持 QUIC 协议,目前仅 Chrome 浏览器支持 QUIC,且需要手动开启:

地址栏输入 chrome://flags/,然后搜索 quic,将 default 改为 enable,重启浏览器重新访问:

Chrome.png

还可能是 Chrome 版本过低不支持,更新一下并开启 QUIC 支持即可。

出现 SSL 证书错误

可以先停止 Nginx/Apache 在本机直接运行 Caddy 看看是否报错,如果没报错,说明 Caddy 容器有问题,可以进入容器 ping 一下域名,看看 IP 是不是源站 IP,不是的话重新运行容器,修改 hosts 指定 IP。

本站部分 CDN 节点已经开启 QUIC 协议,有分配到该节点的可以试试速度的变化。


参考文章:

1、《快速UDP网络连接
2、《Caddy
3、《Docker
4、《利用 Nginx 反向代理和缓存功能自建及优化 CDN 加速节点详细教程
5、《本站开始支持 QUIC


ArmxMod for Typecho
个性化、自适应、功能强大的响应式主题

推广

 继续浏览关于 Google部署教程nginx教程dockercaddyquic支持 的文章

 本文最后更新于 2023/07/06 11:31:20,可能因经年累月而与现状有所差异

 引用转载请注明: VirCloud's Blog > 建站 > 利用 Docker + Caddy 开启谷歌 QUIC 快速网络连接协议支持

精选评论

  1. quic新手
    quic新手 回复

    Windows 10Chrome 64.0.3282.140来自 北京市 的大神

    我想知道为什么我用NGINX配置了addhead,chrome在响应头里面也收到了addhead但是却不把alt-svc记录下来