如何对网站启动QUIC协议
最近在研究QUIC协议,如何让笔者的博客网站也支持QUIC呢?
背景
梳理下本网站的架构
| 1 | client -> nginx(https) -> hexo server(127.0.0.1:4000) | 
- 负载均衡器: 使用nginx作为反向代理
- 博客服务: 使用hexo,并监听在127.0.0.1
- SSL证书: 使用acme.sh安装证书到对应的路径
实践
1. Nginx支持Quic
Nginx官方已在1.25.0以后支持Quic,需要手动编译和部署。
本物理机仍然是ubuntu16.04,综合考虑下,直接使用Docker的方式来运行,那么就需要考虑acme.sh如何将证书更新后reload docker中的nginx服务
acme.sh支持nginx docker
参考acme.sh的wiki部署相关acme.sh的docker和nginx docker
- 启动nginx docker - 1 - docker run --rm -it -d --label=sh.acme.autoload.domain=example.com nginx:latest 
- 启动acme.sh docker - 1 
 2
 3
 4
 5
 6- docker run --rm -itd \ 
 -v "$(pwd)/out":/acme.sh \
 --net=host \
 --name=acme.sh \
 -v /var/run/docker.sock:/var/run/docker.sock \
 neilpang/acme.sh daemon
- 申请证书 - 1 
 2
 3
 4- docker exec \ 
 -e CF_Email=xxx@exmaple.com \
 -e CF_Key=xxxxxxxxxx \
 acme.sh --issue -d example.com --dns dns_cf
- 发布证书并reload nginx - 1 
 2
 3
 4
 5
 6
 7
 8- docker exec \ 
 -e DEPLOY_DOCKER_CONTAINER_LABEL=sh.acme.autoload.domain=example.com \
 -e DEPLOY_DOCKER_CONTAINER_KEY_FILE=/etc/nginx/certs/example-com.key.pem \
 -e DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/certs/example-com.one.cert.pem" \
 -e DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/certs/example-com.ca.pem" \
 -e DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/certs/example-com.cert.pem" \
 -e DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload" \
 acme.sh --deploy -d example.com --deploy-hook docker- 大家这里可以猜测下acme.sh的docker是如何将nginx docker中的服务reload的? 
- docker.sock是docker间通讯的关键 
- 通过DEPLOY_DOCKER_CONTAINER_LABEL找到对应的nginx docker 
- 发送DEPLOY_DOCKER_CONTAINER_RELOAD_CMD命令将nginx reload 
- 整体的配置如下: - 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
 26
 27
 28
 29
 30
 31
 32- version: "2.0" 
 services:
 nginx:
 image: nginx:1.25.2
 container_name: docker_nginx
 restart: unless-stopped
 labels:
 - "docker_nginx"
 volumes:
 - ./nginx/nginx.conf:/etc/nginx/nginx.conf
 - ./nginx/conf.d:/etc/nginx/conf.d
 ports:
 - "80:80"
 - "443:443"
 - "443:443/udp"
 extra_hosts:
 - "host.docker.internal:xxx.xxx.xxx.xxx"
 acme-blogs:
 image: neilpang/acme.sh
 container_name: acme-blogs
 command: daemon
 volumes:
 - /data/acmeout:/acme.sh
 - /var/run/docker.sock:/var/run/docker.sock
 environment:
 - DEPLOY_DOCKER_CONTAINER_LABEL=docker_nginx
 - DEPLOY_DOCKER_CONTAINER_KEY_FILE="/etc/nginx/certs/example-com.key.pem"
 - DEPLOY_DOCKER_CONTAINER_CERT_FILE="/etc/nginx/certs/example-com.one.cert.pem"
 - DEPLOY_DOCKER_CONTAINER_CA_FILE="/etc/nginx/certs/example-com.ca.pem"
 - DEPLOY_DOCKER_CONTAINER_FULLCHAIN_FILE="/etc/nginx/certs/example-com.cert.pem"
 - DEPLOY_DOCKER_CONTAINER_RELOAD_CMD="service nginx force-reload"
2. Nginx支持QUIC
参考nginx的文档配置server
| 1 | server { | 
3. Nginx访问宿主机的hexo服务
方法一
一般docker是使用bridge的方式来启动的,这时会在宿主机中启动一个docker0的网卡,将nginx中的upstream的server ip改为这里的172.17.0.1即可实现docker访问宿主机网络
| 1 | $ ifconfig | 
nginx upstream配置如下:
| 1 | upstream hexo-backend { | 
方法二
docker v20.10+提供了一种支持方案,可通过指向 host.docker.internal 来指向宿主机的 IP。参见文档:从容器连接到主机上的服务
配置 docker-compose.yaml
| 1 | version: '2.0' | 
在nginx docker中执行相关语句后,应该是可以联通到宿主机。由于笔者的docker环境是v20.4,无法实验,暂无法确定本方法是否可行
| 1 | $ curl http://host.docker.internal:4000 | 
方法三
以host方式启动nginx docker,这样nginx仍然在宿主机网络下
总结
笔者最后使用方法一来打通docker和宿主机的网络。至此,整体架构改为以下方式。
| 1 | client -> nginx docker(443:443, 443:443/udp) -> hexo(172.17.0.1:4000) |