我记得很清楚,上个月帮一个老同学迁移他的博客服务器。他打开手机日历给我看:下周三,SSL 证书到期,这是他今年第三次设提醒。我说,你不如直接把服务器换成 Caddy,他先是愣住,然后问我:这跟证书有什么关系?关系太大了——Caddy 这个在 GitHub 上 75K Star 的 Web 服务器,最大的招牌就是让 HTTPS 变成默认行为,证书的申请、部署、续期全部自动完成,你几乎感觉不到它的存在。
这篇文章不是 Caddy 的官方文档翻译,是我自己从手动配置 Nginx + Certbot、再逐步迁到 Caddy 后的一些真实体验。如果你也受够了手动处理 SSL 证书,或者刚被某个ssl证书过期的线上事故折腾过,又或者只是想知道http和https的区别之外,还能不能有更省心的 Web 服务器方案,那这篇应该对你有用。我会把 Caddy 的自动 HTTPS 原理、实际配置、内网开发场景以及我踩过的一些坑都讲清楚。
1. 手动续证书到底烦在哪:申请、验证、部署、续期四条链路拆开看
1.1 传统的证书流程为什么总是让人焦虑
先说个背景。在没有自动化工具之前,一个 Web 服务器要上 HTTPS,流程基本是这样:
- 生成私钥和证书签名请求(CSR),也就是那个
.csr文件。 - 去证书颁发机构(CA)提交申请,比如 Let's Encrypt、阿里云 SSL 免费证书,或者其他商业 CA。
- 等待域名验证通过。验证方式要么是在域名解析里加一条 TXT 记录,要么是在网站根目录放一个指定文件。
- 下载证书文件,常见是
.crt、.pem、.key。这里最容易出问题,因为同一张证书可能包含域名证书、中间证书、根证书三段链,很多人搞不清到底该把哪个内容填进ssl_certificate。 - 把文件传到服务器,配置 Nginx 或 Apache 的证书路径,然后重载服务。
- 设置定时任务自动续期,通常是
certbot renew配合 cron。 - 每过几个月手动检查一次过期时间,命令一般是
openssl x509 -enddate -noout -in your.crt,或者到证书管理后台看。
你有没有发现,这里面每一步都有可能导致线上事故。生成 CSR 时私钥权限没设好,部署后 Nginx 起不来;验证域名时 DNS 解析没生效,申请一直卡在 pending;续期脚本的 cron 路径不对,结果证书悄悄过期,等到用户截图报错才发现。更隐蔽的问题是中间证书链:有些 CA 给你的是两个 PEM 文件,你得先cat拼接再填进配置,不然安卓手机上会一片红。
我自己就经历过一次SSL连接错误的故障,查了半天,最后发现是续期脚本更新了证书文件,但 Nginx 的进程还缓存着旧的 OCSP 响应,必须 reload 才生效。这种问题不难解决,但它会消耗你本不该消耗的精力。
1.2 自动化的意义不是省事,而是减少"人为失误"这个变量
很多人觉得,证书自动化不就是少敲几条命令吗?我用下来最大的感受是:自动化的核心价值不是省事,而是把"人记性不好"这个变量从系统里拿掉。
证书过期是最典型的例子。Let's Encrypt 证书有效期是 90 天,很多人设了 cron 后以为一劳永逸,结果 cron 里 certbot 路径写错了,或者 Python 版本升级后 certbot 崩溃,证书就这么在你看不见的地方过期了。还有更常见的场景:你申请证书的时候用的是一台服务器,后来迁移到另一台,只拷了.key和.crt,忘了迁移续期用的账号配置和 challenge 目录,新机器上证书照样过期。
Caddy 的做法是把证书生命周期整个收进自己的进程里:启动时检查现有证书,不够 30 天有效期就自动续期,续完自动重载,重载失败还能回滚到旧证书。你不需要写 cron,不需要关心 certbot 装在哪,甚至不需要知道证书文件存在哪个目录。对多数中小站点来说,这种"默认值就是正确值"的设计,比任何文档都管用。
1.3 说点大实话:不是所有项目都需要自动化
不过在推荐自动化之前,我也得说句公道话:如果你的场景是每年只需要配一次证书、网站访问量极小、也没有多域名需求,那手动跑一次 certbot 也不是不行。自动化带来的复杂度在于,你引入了一个更「黑盒」的系统,一旦它出问题,排查起来可能比手动流程更吃力。
所以我的判断标准是:只要你的站点数量超过两个,或者域名有子域名扩展的可能,或者你经常在本地和服务器之间切换环境,那 Caddy 这类自动化 Web 服务器就值得上。它的配置成本几乎为零,后面省下的时间却是指数级的。
2. Caddy 的自动 HTTPS 为什么靠谱:ACME 客户端与证书生命周期管理
2.1 Caddy 的定位不是普通反代,而是"默认安全的 Web 服务器"
Caddy 的自我介绍通常是一句话:Web 服务器,自动 HTTPS。很多人第一反应是"又一个 Nginx 替代品",但这个定位其实说小了。Nginx 可以看作是"什么都能干的高性能发动机",配置自由度极高,但也正因如此,HTTPS 只是它众多配件里的一个,需要你自己组装。Caddy 则相反,它把"安全"做成出厂默认,最常见的使用方式就是你只写清楚"哪个域名对应哪个目录或后端",剩下的 80 端口、443 端口、证书、跳转、协议版本,它自己全搞定。
举两个对比例子。Nginx 里你想要一个纯静态站点的 HTTPS,至少要配 server 块、listen 443、ssl_certificate、ssl_certificate_key、ssl_protocols、ssl_ciphers、location 根目录、try_files,还得单独处理 80 端口到 443 的跳转。而 Caddy 的配置长这样:
example.com { root * /var/www/example file_server }你甚至不用写tls指令。Caddy 看到example.com这个域名,会自动向证书颁发机构申请证书,并帮你把 80 端口的所有请求 301 到 443。这里面涉及http和https的区别中最核心的一点:前者是明文传输,后者在 TLS 握手后建立加密通道。绝大多数业务并不需要自己处理加密细节,Caddy 的价值就是把这个通道变成默认项。
2.2 ACME 协议与挑战方式:Caddy 是怎么证明"域名是你的"
要理解 Caddy 自动 HTTPS,必须先理解它使用的 ACME 协议。ACME 是自动化证书管理环境的缩写,Let's Encrypt 是它最著名的公共 CA。整个流程可以简化成三步:
- Caddy 生成一对公私钥,并把公钥、域名信息打包成 CSR。
- Caddy 向 CA 证明你拥有该域名,这一步叫"挑战"。
- CA 验证通过后签发证书,Caddy 自动保存并加载。
Caddy 支持三种主流的挑战方式:HTTP-01、TLS-ALPN-01、DNS-01。
HTTP-01 是最常见的:CA 会访问http://你的域名/.well-known/acme-challenge/xxx,Caddy 需要在 80 端口响应这个请求。这意味着 Caddy 必须监听 80 端口,防火墙不能挡。
TLS-ALPN-01 是在 443 端口上通过 TLS 握手附带一个特殊的 ALPN 协议来验证,适合只能用 443 端口的环境。
DNS-01 是给你要验证的域名添加一条 TXT 记录。这种方式不需要开放 80 或 443 端口,也支持通配符域名*.example.com。Caddy 里配置 DNS 挑战通常需要装对应的 DNS 插件,因为证书申请服务需要通过 API 帮你自动添加解析记录。
默认情况下,Caddy 会依次尝试 HTTP-01 和 TLS-ALPN-01,这两种都不需要你干预。只有当你的服务器没有公网 80/443 访问权限,或者需要通配符证书时,才需要去折腾 DNS 插件。
2.3 生命周期管理:证书续期、OCSP 与自动重载
证书不是申请下来就完事了。Caddy 内部有一个证书管理器,会定期检查已加载证书的有效期。按照我的实测,它在证书剩余 30 天左右就会触发自动续期。续期成功后,Caddy 在线更新证书,不需要重启进程,也不会中断现有的连接。
还有一个很多人没注意的细节:OCSP。OCSP 是用于实时校验证书吊销状态的一个协议。Caddy 会自动查询证书的 OCSP 响应,并缓存到本地。如果你的证书 CA 的 OCSP 服务出问题,Caddy 会保留上一次有效的 OCSP 响应,而不是直接拒绝用户访问,这个策略很务实。
相比之下,手动配置 Nginx + Certbot 时,ssl_stapling、ssl_stapling_verify这些参数经常被忽略。有些人甚至不知道 OCSP 是什么,导致证书明明有效,某些严格校验的客户端却报ssl错误,排查起来非常玄学。Caddy 把这些都做了默认值,所以会少很多这类疑难杂症。
2.4 与 Nginx + Certbot 的对比:差距不在功能,而在默认值
我整理过一张对比表,可以直观看出两者的差异:
| 项目 | Nginx + Certbot | Caddy 自动 HTTPS |
|---|---|---|
| 证书申请 | 手动运行 certbot 或脚本 | 首次加载域名时自动完成 |
| 证书续期 | cron 定时调用 certbot | 内置调度器自动检查续期 |
| 续期后生效 | 需要 reload 或手动处理 | 自动热加载 |
| HTTP 跳转 HTTPS | 手动配置 return 301 | 默认开启 |
| HTTP/2、HTTP/3 | 需单独配置 | 默认支持 |
| 中间证书链处理 | 经常需要手动拼接 | 自动处理 |
| 本地自签证书 | 手动 openssl 生成 | 内置 CA 自动签发 |
| 配置文件复杂度 | 较长,易出错 | 几行即可 |
这张表不是说 Nginx 不好。恰恰相反,Nginx 允许你做非常精细的控制,包括复杂的负载均衡策略、lua 扩展、权限控制等。但如果你只是想让 HTTPS 顺利跑起来,Nginx 那套配置确实太重了。
3. 实战 Caddyfile:三行配置让 HTTPS 自动到起飞
3.1 安装 Caddy 的几种姿势,以及我推荐哪种
Caddy 的安装有很多种,覆盖 Linux、macOS、Windows、Docker。我个人比较推荐的方式是直接用官方静态二进制,因为它依赖很少,放到/usr/local/bin就能跑。以 Ubuntu/Debian 为例:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy装完以后,systemd 会帮你注册caddy服务,默认的配置目录在/etc/caddy/Caddyfile。如果是 Docker 环境,官方镜像也很好用,我经常这么起:
docker run -d \ -p 80:80 -p 443:443 \ -v $PWD/Caddyfile:/etc/caddy/Caddyfile \ -v caddy_data:/data \ -v caddy_config:/config \ caddy:latest注意一定要把/data目录持久化,因为证书文件、ACME 账号私钥都存在这里。如果你忘了挂载这块,容器每次重建都会重新申请证书,容易触发 CA 的速率限制。
3.2 最简静态站点:域名解析好之后,什么都不用管
假设你在云服务商买了一个域名,同时也买了一台服务器,那么把这套配置放到 Caddyfile 里就能跑通 HTTPS:
blog.example.com { root * /home/user/www/blog file_server encode zstd gzip }把blog.example.com解析到服务器 IP 后,执行caddy reload,Caddy 会立刻开始证书申请。第一次申请通常几秒钟就完成,期间你可以看日志:
journalctl -u caddy -f正常情况下你会看到类似这样的日志:成功获取证书、证书已保存、HTTP 端口自动跳转等。然后就可以直接用https://blog.example.com访问了。
这里有个容易踩的坑:如果域名解析还没生效,或者服务器 80/443 端口被防火墙挡了,Caddy 申请证书会失败,日志里会提示 ACME challenge 无法完成。你要先确认dig blog.example.com返回的 IP 是这台服务器,再检查云服务商的安全组规则。别问我为什么知道,我第一台服务器就是这么折腾了半小时。
3.3 反向代理场景:给没有证书能力的应用自动套上 HTTPS
更常见的场景是后端有一个自建服务,比如 Node.js、Java、Gitea、GitLab 之类。这些应用本身能跑 HTTP,但你要么不想在应用层折腾证书,要么应用根本不支持。Caddy 可以一句话搞定:
git.example.com { reverse_proxy 127.0.0.1:3000 } api.example.com { reverse_proxy 127.0.0.1:8080 }Caddy 收到api.example.com的 HTTPS 请求后,会把流量转发给本机8080端口。对于后端的 Node.js/Java 进程来说,它永远只看到 HTTP 请求,完全不知道 HTTPS 的存在,所以不需要改任何代码。这就是反向代理的意义:把 TLS 终止在最外层。
这种方法对多应用共用一个服务器特别友好。你只需要维护 Caddy 一个入口,按域名分流到不同端口,每个域名都能自动获得独立的证书。
3.4 验证是不是真的"自动续期":用命令确认证书状态
很多人迁移过来后最大的疑问是:它真的会自动续期吗?你可以这么验证。第一步,看证书文件:
caddy cert-info --domain blog.example.com这个命令会显示证书的签发时间、过期时间、发行人等信息。第二步,用 openssl 直接从线上抓证书:
openssl s_client -connect blog.example.com:443 -servername blog.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates可以看到服务器正在使用的证书的notAfter时间。过两三个月再跑一次,如果证书到期时间自动往后延了,说明续期生效。我自己的站点跑了近一年,证书只更新过两次,完全没有人工干预。
还有一个小技巧:如果你想测试 Caddy 的续期逻辑,可以把系统时间往后调几天(最好在独立测试环境里),或者在 Caddyfile 里临时设置tls指令的有效期阈值。但我不建议在生产环境做这种实验,容易把自己吓一跳。
4. 开发环境和内网 IP 的证书怎么搞:Caddy 内置 CA 的完整玩法
4.1 内网开发环境比生产环境更麻烦的原因
很多人在本地开发时也会遇到SSL证书的困惑:公网证书只能签域名,不能签localhost,更不能签192.168.1.100这种内网 IP。你要么在浏览器里点"继续访问"绕过证书警告,要么自己生成自签证书并手动导入信任库,整个过程非常繁琐。
Caddy 对这类场景做了一个很聪明的处理:当检测到localhost、内网 IP 或内网主机名时,它不会去请求公共 CA,而是使用自己内置的 CA 来签发证书。也就是说,Caddy 内部会生成一个根证书,然后基于这个根证书给本地服务签发证书。浏览器不信任这个根证书,所以会报NET::ERR_CERT_AUTHORITY_INVALID或类似的错误,这是正常现象,因为根证书还没有加到系统信任库。
4.2 把 Caddy 内置 CA 加入系统信任库
Caddy 2.7 之后提供了一个非常好用的命令:
caddy trust这条命令会把 Caddy 的本地根证书安装到系统信任库。之后再用https://localhost访问,浏览器就不会再有红色警告了。如果是开发团队多人协作,还可以把你机器上生成的根证书导出给同事,让大家统一信任同一个 CA,这样整个团队本地环境都通用。
具体操作如下:
- 先让 Caddy 启动一次,确保它已经生成了内部 CA,存储路径一般在
/var/lib/caddy/.local/share/caddy/或~/.local/share/caddy/。 - 找到
root.crt或类似名称的 CA 证书。 - 在开发机上执行
caddy trust,或者手动导入该证书到系统信任区。
如果你用的是 macOS,手动导入时记得设置为"始终信任";Windows 上则是导入到"受信任的根证书颁发机构";Linux 下需要执行update-ca-certificates。
4.3 内网 IP 场景:用 Caddy 服务局域网应用
公司内网经常有这样的需求:有一台开发服务器,其他人要通过http://192.168.1.50:8080访问某个工具。如果你只想在这台服务器上统一暴露一个 HTTPS 端口,Caddy 可以这么配:
192.168.1.50 { tls internal reverse_proxy 127.0.0.1:8080 }tls internal的意思是强制使用内置 CA 签发证书,而不是尝试向公共 CA 申请。因为公共 CA 一般不会给内网 IP 签发证书。然后你把内网的 CA 根证书分发到每台客户端,就能以https://192.168.1.50访问,不会有警告。
这里有个细节要注意:Caddy 对纯 IP 地址的默认处理可能和我们以为的不一样。如果你不加tls internal,Caddy 会尝试申请公共证书,大概率失败。所以涉及 IP 或非公网域名时,建议显式写上tls internal,避免日志里刷一堆不明不白的报错。
4.4 用本地域名代替 localhost 更顺手
如果你开发时同时开了多个应用,全是localhost:3000、localhost:8080会很难记。我习惯在本地系统 hosts 文件里加几条假的开发域名:
127.0.0.1 myapp.test 127.0.0.1 api.myapp.test然后在 Caddyfile 里写:
myapp.test, api.myapp.test { tls internal reverse_proxy 127.0.0.1:3000 }第一次用https://myapp.test访问并信任根证书后,后面每次启动都是绿色锁。cookie 的 Secure 属性、Service Worker、CORS 这类对 HTTPS 有要求的浏览器特性,也都能在本地正常调试。我之前用污染过的 http 协议调试一些接口,经常遇到浏览器拦截 Cookie 的情况,换成 HTTPS 后全部正常。
5. 从 Nginx 迁到 Caddy 的排错手册
5.1 端口冲突:为什么 Caddy 起不来
迁移最常遇到的第一个问题就是端口被占。如果你在 80 或 443 端口上还跑着 Nginx,那 Caddy 启动会报address already in use。解决办法不是让两个服务同时监听 443,而是先停掉旧的:
sudo systemctl stop nginx sudo systemctl disable nginx然后再启动 Caddy。有时候你明明停了 Nginx,端口还是被占用,可以用:
sudo lsof -i :443看到底是哪个进程占着端口。我遇到过云服务器上自带的一个 Web 管理面板占用了 443,排查了很久才找到。如果生产环境不能立刻切换,也可以让 Caddy 先监听其他端口测试:
example.com { reverse_proxy 127.0.0.1:8080 }然后在 Caddyfile 开头临时加上:8443来指定端口。但正式的自动 HTTPS 还是建议老老实实使用 443,因为 ACME 挑战大概率还是要走这两个标准端口。
5.2 "no required ssl certificate was sent" 到底是谁的问题
迁移过程中,很多人会在客户端连接时看到no required ssl certificate was sent或者SSL: certificate_verify_failed这类报错。这里要分两种情况。
第一种,是客户端要求服务端提供证书而服务端没给。这通常出现在设置了双向 TLS 的场景,但如果你只是在做普通 HTTPS 访问,那更可能是客户端和服务端的 TLS 配置不匹配。比如有些老客户端不支持 TLS 1.2 以上,而 Caddy 默认启用了更严格的加密套件。这种情况下,你可以在站点配置里临时放宽:
example.com { tls { protocols tls1.2 tls1.3 ciphers ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-GCM-SHA256 } }但我的建议是:先用 openssl 探测一下到底是什么阶段失败的:
openssl s_client -connect example.com:443 -servername example.com </dev/null如果握手成功,会输出证书链、session id、verify return code 等信息;如果中断,就看报错在哪一步。
第二种情况是certificate_verify_failed,意思是客户端在验证服务端证书链时失败。这通常是因为 Caddy 给出的证书链不完整,或者客户端缺少对应的根证书。Caddy 默认会补全中间证书,所以如果你用自签 CA 或者内部 CA,那就要确保客户端信任对应的根证书。我在 Linux 服务器上遇到过好多次curl报证书验证失败,而浏览器却正常,原因就是系统里没有装根证书,需要执行:
sudo apt install ca-certificates5.3 从 Nginx 迁到 Caddy 时,证书文件和私钥怎么处理
很多人担心一个问题:我已经有 Nginx 用的证书了,迁到 Caddy 是不是要重新申请?其实不用。如果你之前在 Nginx 里已经配好了一个域名的.crt和.key文件,Caddy 可以直接"接管"现有证书,只要在 Caddyfile 里指定路径:
example.com { tls /etc/certs/example.crt /etc/certs/example.key root * /var/www/example file_server }这样 Caddy 会用这个现有证书完成 HTTPS 握手,同时它可以继续用 ACME 自动续期吗?这里要说明一下:如果你显式指定了证书文件,Caddy 会把这当成"手动管理"的证书,不会再自动申请和续期。它只是单纯地加载这两个文件。所以更推荐的方式是:直接让 Caddy 自动申请新证书,不要纠结于旧证书。确认新证书申请成功后,旧的.key和.crt文件就可以归档删除了。
5.4 日志和 debug:排错时最有用的三招
Caddy 的默认日志比较克制,但在排错时需要把日志级别调高。比较实用的做法是临时加上全局配置:
{ log { output stderr level DEBUG } }然后执行:
caddy reload --config /etc/caddy/Caddyfile journalctl -u caddy -f这样能看到每一步证书申请的细节,包括 ACME 目录请求、挑战类型、CA 返回的错误。如果日志显示 ACCOUNT_THROTTLED 或 RATE_LIMITED,说明证书申请太频繁,需要等一段时间或者检查是不是/data目录没有持久化。
第二招是直接用curl模拟请求:
curl -v https://example.com这个命令会打印 TLS 握手过程中的证书链,以及最终请求响应。如果curl成功但浏览器不行,常见原因是中间证书链顺序或完整性有问题,可以考虑openssl s_client再次确认。
第三招是检查/data/caddy/certificates目录。Caddy 会把申请的证书和账号信息都存在这里。如果你看到证书文件存在但站点配置不生效,多半是配置文件里有其他tls配置覆盖了默认逻辑,比如你写着tls off或者tls internal,那自然不会有公共证书。
5.5 迁移过程中的兼容性注意点
最后说几个从 Nginx 迁过来时常被忽略的地方。
第一是location规则。Nginx 的location /api、try_files这些写法,在 Caddyfile 里不能直接照搬。Caddy 用的是路径匹配器和指令组合。比如:
example.com { handle /api/* { reverse_proxy 127.0.0.1:8080 } handle { root * /var/www/example file_server } }第二是 rewrite 规则。Nginx 里有大量rewrite ^/old/(.*)$ /new/$1 break;这种写法,Caddy 使用@命名匹配器加redir指令,更直观但语法不同。
第三是 WebSocket。如果你在反代一个带 WebSocket 的应用,Caddy 不需要单独打开什么proxy_set_header Upgrade,它默认就会处理必要的 Upgrade 头。这一点比 Nginx 还要省心,因为 Nginx 需要你显式写:
proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";Caddy 就不需要。
第四是访问控制。Nginx 里你可能用allow/deny做 IP 白名单。Caddy 里可以用@blocked匹配器:
@blocked { remote_ip 192.168.1.2 } respond @blocked 403语法不复杂,但思路要跟着 Caddy 的匹配器模型走一遍。
6. 我的最终建议:什么项目值得切到 Caddy
写了这么多,最后说点个人经验。我现在的处理方式是:新项目一律直接上 Caddy,除非明确知道需要 Nginx 的某些高扩展性能力。老项目我一般建议按以下标准评估:
如果你的站点属于这几类,那么 Caddy 可以无缝替代。一是博客、文档站、企业官网这类内容型站点,Caddy 的file_server和自动 HTTPS 是绝配;二是内部工具平台、API 网关、多应用反代,反向代理一行搞定域名和 TLS;三是个人 NAS、家庭宽带下的服务,Caddy 在内网证书和端口复用上比 Nginx 省心得多。
如果你的业务涉及非常复杂的负载均衡策略、基于 Lua 的运维脚本、或者需要和现有 Nginx 生态的模块深度集成,那可以继续保留 Nginx,但至少可以在边缘层加一个 Caddy 来处理证书和 HTTPS,把 Nginx 专心用在业务逻辑上。
还有一点,Caddy 不止能当 Web 服务器,它还有caddy file-server这样的一键静态文件服务器命令,适合临时分享文件:
caddy file-server --domain files.example.com还有caddy reverse-proxy命令,不想写配置文件的时候可以直接试:
caddy reverse-proxy --from example.com --to 127.0.0.1:8080这些命令对于快速验证一个想法非常方便。
回到标题那句话:HTTPS 自动起飞。我觉得 Caddy 真正做到的不只是把证书流程自动化,而是把"安全通信"这件事从运维人员的负担清单里整个划掉了。我第一次在服务器上caddy start之后,看着日志里自动生成的证书,心里确实有点感慨:原来 HTTPS 也可以这么安静。如果你现在还在为证书过期设日历提醒,不妨抽一个下午,把 Nginx 换成 Caddy 试试。你可能会发现,以前那些关于证书的焦虑,在换完配置后真的就消失了。