VPS 申请 HTTPS 证书:Cloudflare + acme.sh 实际配置记录
这篇记录我现在更常用的一套证书申请方式:域名 DNS 托管在 Cloudflare,用 acme.sh 调 Cloudflare DNS API 完成 DNS-01 验证,然后把证书安装到 VPS。
它特别适合:
VPS 没有开放 80 端口
服务只监听 443
域名套了 Cloudflare
需要 *.example.com 通配符证书
希望后续自动续期
相比手工添加 _acme-challenge TXT,DNS API 最大的优势是续期时不需要再登录 Cloudflare 手动改记录。
一、先理解这套流程
整个过程实际上只有四步:
acme.sh
↓ 调 Cloudflare API
创建 _acme-challenge TXT
↓
Let's Encrypt 验证域名控制权
↓
签发证书
↓
安装到 Nginx / Caddy / x-ui / 其它服务
Cloudflare 在这里主要负责 DNS,不是证书签发机构。
如果你的网站橙云代理在 Cloudflare 后面,也仍然可以给源站申请 Let’s Encrypt 证书;DNS-01 不依赖 80/443 端口是否公开。
二、安装 acme.sh
Linux 常见安装:
curl https://get.acme.sh | sh -s email=my@example.com
安装后重新加载 shell,或者直接使用:
~/.acme.sh/acme.sh --version
截至本文更新时,acme.sh 主线版本已经到 3.1.6。
这里有一个很容易忽略的变化:acme.sh 默认 CA 不是 Let’s Encrypt,而是 ZeroSSL。
如果本文明确要申请 Let’s Encrypt,可以二选一:
acme.sh --set-default-ca --server letsencrypt
或者每次签发时显式加:
--server letsencrypt
三、创建 Cloudflare API Token
现在优先使用 API Token,不要为了图省事直接把 Global API Key 放到 VPS。
Cloudflare Dashboard:
My Profile
→ API Tokens
→ Create Token
可以从 Edit Zone DNS 模板开始,再把资源范围限制到需要申请证书的那个域名。
建议权限:
Zone → DNS → Edit / Write
Zone → Zone → Read
资源范围:
Include → Specific zone → example.com
这样即使 Token 泄露,影响范围也比 Global API Key 小很多。
Token 创建完成后只会完整显示一次,立即保存到密码管理器,不要截图发群,也不要写进博客仓库。
在 VPS 当前 shell 中设置:
export CF_Token='你的 Cloudflare API Token'
如果你明确知道 Zone ID,也可以额外设置:
export CF_Zone_ID='你的 Zone ID'
acme.sh 当前 dns_cf 同时支持:
CF_Token
CF_Account_ID
CF_Zone_ID
旧式 Global API Key 则使用:
export CF_Key='Global API Key'
export CF_Email='Cloudflare 登录邮箱'
但新部署没有必要优先用这套旧方式。
四、申请普通域名证书
假设域名是:
example.com
www.example.com
使用 Cloudflare DNS API:
acme.sh --issue \
--dns dns_cf \
-d example.com \
-d www.example.com \
--server letsencrypt
acme.sh 会自动:
创建 _acme-challenge TXT
等待 DNS 生效
让 Let's Encrypt 验证
删除自己创建的 TXT
保存证书
当前 dns_cf 的清理逻辑会按:
TXT 名称 + TXT 内容
精确寻找自己创建的记录,然后删除对应记录 ID,不会粗暴删除同名下的所有 TXT。
五、申请通配符证书
如果希望同时覆盖:
example.com
*.example.com
可以:
acme.sh --issue \
--dns dns_cf \
-d example.com \
-d '*.example.com' \
--server letsencrypt
通配符证书必须使用 DNS-01,所以 Cloudflare API 方式非常适合这一场景。
申请成功后查看:
acme.sh --list
六、把证书安装到固定路径
不要让 Nginx、x-ui 或其它服务直接引用 ~/.acme.sh/ 里的内部文件。正确做法是使用 --install-cert 复制到你自己的正式路径,并配置 reload 命令。
先创建目录:
sudo mkdir -p /etc/ssl/example.com
如果申请的是 ECC 证书,可以:
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/ssl/example.com/key.pem \
--fullchain-file /etc/ssl/example.com/fullchain.pem \
--reloadcmd "systemctl reload nginx"
如果不是 ECC,去掉 --ecc。
Nginx 中引用:
ssl_certificate /etc/ssl/example.com/fullchain.pem;
ssl_certificate_key /etc/ssl/example.com/key.pem;
检查配置并重载:
nginx -t
systemctl reload nginx
验证证书:
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null |
openssl x509 -noout -issuer -subject -dates
七、自动续期怎么确认
acme.sh 安装时一般会建立 cron / 定时任务。
可以手动跑一次:
acme.sh --cron --home ~/.acme.sh
也可以强制测试:
acme.sh --renew -d example.com --force
如果是 ECC:
acme.sh --renew -d example.com --ecc --force
真正的自动续期不仅要“证书签出来”,还要确认 --install-cert 保存的 reload 命令能正常执行,否则磁盘上的新证书更新了,服务仍可能继续加载旧证书。
八、Cloudflare Authentication error 怎么排查
我之前就踩过这个坑:TXT 添加阶段直接返回 Cloudflare Authentication error,看起来像 acme.sh 坏了,实际一般是凭据或 Token 权限问题。
按这个顺序查:
1. Token 是否复制完整
2. Token 是否已经被删除/轮换
3. 是否给了目标 Zone 的 DNS Edit / Write
4. 是否给了 Zone Read
5. Resource 是否包含实际域名
6. shell 里的旧 CF_Key / CF_Email / CF_Token 是否互相干扰
查看当前变量名即可,不要直接把值打印到聊天或截图:
env | grep '^CF_'
需要重新绑定 Token 时,推荐重新 export 正确的变量后重新 issue 一次,让 acme.sh 保存新的 DNS API 凭据;不要习惯性手改内部配置文件。
如果旧 Global API Key 方案一直失败,改用最小权限 API Token 往往更清楚:
unset CF_Key
unset CF_Email
export CF_Token='新的 API Token'
然后重新签发。
九、证书撤销和重新签发
撤销证书:
acme.sh --revoke -d example.com --ecc
如果不是 ECC,去掉 --ecc。
但实际运维中,“域名换 VPS / 更换密钥 / 重新绑定服务”并不一定需要先 revoke。很多时候直接重新签发一张新证书并替换服务端文件即可。
如果怀疑私钥泄露,再撤销旧证书并重新生成新的私钥更合理。
十、Cloudflare Origin Certificate 和 Let’s Encrypt 怎么选
如果源站永远只允许 Cloudflare 回源,Cloudflare Origin CA 也可以用,而且有效期很长。
如果源站可能被浏览器、程序、其他 CDN 或非 Cloudflare 客户端直接访问,我更偏向 Let’s Encrypt 这类公开受信任证书。
简单理解:
只给 Cloudflare 看 → Origin Certificate 可以
需要公网客户端直接信任 → Let's Encrypt 更通用
十一、参考资料
- acme.sh:https://github.com/acmesh-official/acme.sh
- Cloudflare DNS hook:https://github.com/acmesh-official/acme.sh/blob/master/dnsapi/dns_cf.sh
- Cloudflare API Token:https://developers.cloudflare.com/fundamentals/api/get-started/create-token/
- Cloudflare API 权限:https://developers.cloudflare.com/fundamentals/api/reference/permissions/
- Let’s Encrypt:https://letsencrypt.org/
评论将在接近此处时加载,也可点击立即加载。