Traefik 踩坑记录.
Traefik 可以配置自动生成证书的 ACME 供应商, 比如Let’s Encrypt.
官方文档提到会自动更新证书. 但实际情况是, 到期了证书有时并没有更新, 导致出现证书过期的情况.
这里记录下在服务器上配置 Traefik 时, 改用 acme.sh 来签证书并自动更新的步骤.
前置条件
默认服务器为Ubuntu, traefik 已启用, 对应的docker-compose.yml 存放在/opt/global目录下.
其中/opt/global/docker-compose.yml
的具体内容如下.
version: '3' |
我们挂载了/opt/global 目录下的 traefik.toml
, 该文件存放了一些默认的配置, 内容如下:
[entryPoints] |
可以看到我们声明了一个证书解析器 (certificatesResolvers) lets-encrypt.
而 我们需要使用 acme.sh 生成证书的 Web项目, 存放在/opt/web/ 下, 其 docker-compose.yml
内容如下:
version: '3' |
这里可以看到, 我们给 web 配置的 certresolver 配置为之前定义的 lets-encrypt.
如果查看 acme.json
文件, 你会看到类似如下内容, Certificates 部分有我们的 example.com
及子域名api.example.com
:
{ |
此时, 网站正常访问.
现在我们来更改 example.com
的 tls 配置, 证书改用 acme.sh 来签发.
改用 acme.sh
acme 验证的主要方式是 standalone 和 webroot.
鉴于 standalone 需要占用80或者443端口, 导致需要暂停服务器,这里我们使用 webroot 方式来验证域名.
webroot 模式下, acme 会在网站根目录下生成一个临时子目录 .well-known/acme-challenge
,然后服务器会向这个路径发请求,如果请求成功,则验证通过, 随后会删除掉这个临时目录.
我们将根目录web root 默认为 /var/www, 同时在当前目录下, 新增两个文件夹, 用来分别挂载 /var/www 和 /acme.sh 目录.
/opt/global/ 目录下, 新建文件 docker-compose.acme.sh.yml
, 内容如下:
version: '3' |
新增文件夹:
mkdir nginx acme.sh |
生成的证书会存放在acme.sh 目录中, 而 nginx 目录用于验证域名.
这里我们起一个nginx 服务, 使得 traefik 将所有匹配 /.well-known
的路径请求都转发到这个nginx 上. 同时, 将当前目录下的 nginx 目录挂载到 nginx 服务的静态文件默认地址 /usr/share/nginx/html
.
这样, 当使用 webroot 模式验证域名时, acme.sh 就会在 /opt/global/nginx
目录下,生成临时子目录 .well-known/acme-challenge
, 而验证时, 访问 /usr/share/nginx/html
, 也就是访问我们的 /opt/global/nginx
目录.
我们新增文件 /opt/global/docker-compose.nginx.yml
, 添加如下内容:
version: '3' |
这里有一点需要提一下.
我们给 nginx 服务配置 traefik 时, 设置了priority的值为999. 默认情况下, traefik 中路径的 priority是根据rule的长度来决定的. 这里我们希望所有带有 /.well-known
的请求都转发到这个 nginx 上, 所以手动设置了999.
启动 nginx:
docker-compose --file docker-compose.nginx.yml up -d |
nginx 启动后, 我们启动 acme.sh.
docker-compose --file docker-compose.acme.sh.yml up -d |
开始签证书啦.
第一次使用acme.sh时, 需要注册用户邮箱:
docker exec -it acme.sh sh -l |
正常情况下, 会一切顺利. 默认CA是ZeroSSL.com
如果 acme.sh 签发证书时 Timeout了, 请设置代理.
更新配置
证书签发成功后, 我们查看 /opt/global/acme.sh/example.com
目录, 会看到刚刚生成的证书.
现在, 我们把新鲜出炉的证书用起来.
修改 /opt/global/docker-compose.yml
, 将 /opt/global/acme.sh
目录挂载到 traefik 中:
version: '3' |
然后我们在traefik 的动态配置中把证书放进去.
在 /opt/global/providers
目录下, 新增 example_com_certs.toml
文件, 写入我们的证书路径:
[[tls.certificates]] |
同时, 我们需要将 /opt/global/acme.json
文件中 Certificates 部分, 有关 example.com 的证书内容删除.
最后, 修改 /opt/web/docker-compose.yml
, 把tls 部分的配置, 改为options=default.
version: '3' |
重启 traefik.
docker restart traefik |
再次请求 https://example.com, 会发现证书已经签成由ZeroSSL 颁发的证书.
替换完成. 撒花! 🥳