https域名证书:Certbot申请和管理Let’s Encrypt证书方案
Author:zhoulujun Date:
之前 阿里与腾讯云提供的第三方免费域名证书,都能用一年,现在基本回归到一个季度(90天)了。
Let's Encrypt 是一个非营利性组织(Internet Security Research Group, ISRG),它的核心商业模式是“不盈利”。它不通过销售证书赚钱,而是通过接受捐赠和赞助来维持运营。
Let's Encrypt证书优势
Let’s Encrypt 的目标就是让 HTTPS 成为默认标准,因此证书完全免费并自动化发行。
完全免费
自动签发 + 自动续期
被所有浏览器信任
支持:
单域名
多域名
通配符证书(*.example.com)
所以采用Let's Encrypt,是我这种草根网站的解决方案。
当然如果选择 Cloudflare 免费 SSL方案也是可以的,但是你最好还是先申请Let's Encrypt证书打底:Cloudflare + Let's Encrypt 同时使用
✅ Let's Encrypt(服务器真实证书)
✅ Cloudflare(外层代理)
普通 HTTPS 和免费证书安全性完全一样。
Reddit sysadmin 社区甚至直接说:不要为 SSL 付钱,免费证书已经足够。
Let's Encrypt证书布署
像阿里云、腾讯云等国内云厂商合作的域名证书供应商FreeSSL 、 TrustAsia等,都要不断地去申请,非常麻烦!
——可能目的就是要让交钱!因为,不是大企业做官网,我根本不需要啥 OV(企业验证)
真正可长期运行的生产级方案,肯定是自动申请、自动续期的方案,比如:
Certbot:最老牌、文档最全的工具,支持几乎所有 Linux 发行版。
acme.sh:轻量级 Shell 脚本,功能强大,支持多种 DNS API 自动验证,国内用户使用较多。
Nginx Proxy Manager / 1Panel / 宝塔面板:这些可视化管理面板内置了 ACME 客户端,点几下鼠标即可自动申请和续期。
设计思路(先理解)
读取 nginx 配置
↓
解析 server_name
↓
检测是否已有证书
↓
没有 → 自动申请
已有 → 自动续期
↓
安装证书
↓
reload nginx
acme.sh
acme.sh 本身已经支持自动续期。所以外贸需要写个脚本负责:发现新域名并自动签发。
自动证书脚本
#!/bin/bash
set -euo pipefail # 增强错误检测,避免脚本静默失败
# ================= 配置区域(适配你的实际环境)=================
NGINX_CONF_DIR="/etc/nginx"
# 改为你实际的证书目录:/etc/nginx/ssl_certificate/
SSL_BASE_DIR="/etc/nginx/ssl_certificate"
ACME_SH="$HOME/.acme.sh/acme.sh"
LOG_FILE="/var/log/auto_ssl_update.log"
# DNS 提供商设置 ( dns_ali=阿里云, dns_tc=腾讯云, dns_cf=Cloudflare )
DNS_PROVIDER="dns_ali"
# 你的邮箱(用于ACME账户注册和证书过期提醒)
ACME_EMAIL="[email protected]"
# ===========================================
# 加载环境变量 (API Keys)
if [ -f /etc/profile.d/acme_env.sh ]; then
source /etc/profile.d/acme_env.sh
else
echo "错误: 未找到 API 环境变量文件 /etc/profile.d/acme_env.sh" | tee -a "$LOG_FILE"
exit 1
fi
# 检查 acme.sh
if [ ! -x "$ACME_SH" ]; then
echo "错误: acme.sh 未找到或未执行权限: $ACME_SH" | tee -a "$LOG_FILE"
exit 1
fi
# 创建证书目录并检查权限
mkdir -p "$SSL_BASE_DIR"
if [ ! -w "$SSL_BASE_DIR" ]; then
echo "错误: 无写入权限到 $SSL_BASE_DIR" | tee -a "$LOG_FILE"
exit 1
fi
# 日志函数
log() {
echo "[$(date '+%F %T')] $1" | tee -a "$LOG_FILE"
}
log "===== 开始自动 SSL 证书维护 ====="
# 1. 解析 Nginx 配置(修复include/注释问题,适配你的配置)
log "正在解析 Nginx 配置文件(包含include)..."
# 先拼接所有Nginx配置内容(解决include嵌套)
nginx_config_content=$(find "$NGINX_CONF_DIR" -name "*.conf" -type f -exec cat {} \;)
# 解析server块,过滤注释/无效域名,按组输出
grouped_domains=$(echo "$nginx_config_content" | awk '
BEGIN { in_server=0; names="" }
# 跳过注释行(// 或 # 开头)
/^[[:space:]]*\/\// || /^[[:space:]]*#/ { next }
# 移除行内注释
{ gsub(/\/\/.*$/, ""); gsub(/#.*$/, "") }
# 进入server块
/server\s*\{/ { in_server=1; names="" }
# 提取server_name,过滤空值/下划线/localhost
in_server && /server_name/ {
gsub(/server_name/, "");
gsub(/;/, "");
for(i=1; i<=NF; i++) {
if($i != "" && $i !~ /^_$/ && $i !~ /localhost/) {
names = names " " $i
}
}
}
# 退出server块,输出域名组
in_server && /^\s*\}/ {
if(names != "") {
gsub(/^ +| +$/, "", names)
print names
}
in_server=0
}
')
# 检查是否解析到域名
if [ -z "$grouped_domains" ]; then
log "未在 Nginx 配置中发现有效的 server_name 域名。"
exit 0
fi
# 打印解析结果(便于调试)
log "解析到的域名组:"
echo "$grouped_domains" | while read -r line; do
log " - $line"
done
# 初始化acme.sh(首次运行需要,设置正式Let's Encrypt服务器)
log "初始化acme.sh配置..."
"$ACME_SH" --set-default-ca --server letsencrypt >> "$LOG_FILE" 2>&1
"$ACME_SH" --register-account -m "$ACME_EMAIL" --agree-tos >> "$LOG_FILE" 2>&1
# 2. 遍历每一组域名申请/更新证书
echo "$grouped_domains" | while IFS= read -r domain_line; do
[ -z "$domain_line" ] && continue
# 获取主域名(组内第一个)
main_domain=$(echo "$domain_line" | awk '{print $1}')
log "处理域名组: [$domain_line] (主域名: $main_domain)"
# 创建证书目录(适配你的路径:/etc/nginx/ssl_certificate/主域名/)
CERT_DIR="$SSL_BASE_DIR/$main_domain"
mkdir -p "$CERT_DIR"
chmod 700 "$CERT_DIR" # 安全权限:仅root可访问
# 构建acme.sh命令(用数组替代eval,避免安全风险)
ACME_CMD=(
"$ACME_SH"
--issue
--dns "$DNS_PROVIDER"
--log "$LOG_FILE"
--log-level 2
--force-renew 0 # 仅证书快过期时续期(默认60天)
)
# 添加所有域名到命令参数
for d in $domain_line; do
ACME_CMD+=("-d" "$d")
done
# 执行证书申请/更新
if "${ACME_CMD[@]}"; then
log "成功:$main_domain 证书已更新/无需更新"
# 部署证书(适配你的Nginx配置文件名:xxx_bundle.crt / xxx.key)
deploy_success=0
if "$ACME_SH" --install-cert -d "$main_domain" \
--fullchain-file "$CERT_DIR/${main_domain}_bundle.crt" \ # 匹配你的bundle.crt
--key-file "$CERT_DIR/${main_domain}.key" \ # 匹配你的.key
--reloadcmd "systemctl reload nginx" >> "$LOG_FILE" 2>&1; then
# 设置证书文件权限(Nginx要求只读,避免权限过大)
chmod 600 "$CERT_DIR/${main_domain}_bundle.crt"
chmod 600 "$CERT_DIR/${main_domain}.key"
deploy_success=1
fi
if [ $deploy_success -eq 1 ]; then
log "部署成功:$main_domain 证书已替换到 $CERT_DIR"
else
log "错误:$main_domain 证书部署失败"
fi
else
log "错误:$main_domain 证书申请/更新失败"
fi
done
log "===== 自动 SSL 证书维护结束 ====="Certbot
Certbot 比 acme.sh 简单太多,而且更稳、更省心。
Nginx
多域名
有各种 include
希望自动读域名 → 自动申请证书 → 自动替换 → 自动续期
| 方式 | 难度 | 是否需要自己解析 Nginx | 是否需要处理 DNS/API | 是否自动续期 |
|---|---|---|---|---|
| Certbot + Nginx 插件 | ⭐ 极简单 | 自动 | 不需要 | 全自动 |
| acme.sh + 你写的脚本 | ⭐⭐⭐⭐⭐ 复杂 | 需要自己写 awk | 需要配置 DNS API | 要自己写定时 |
CentOS Stream 9 + Certbot + 腾讯云泛域名
# 1. 安装 Certbot (如果未安装) sudo dnf install -y certbot python3-certbot-nginx # 2. 安装腾讯云 DNS 插件 (关键步骤) # 注意:插件包名通常是 certbot-dns-tencentcloud pip3 install certbot-dns-tencentcloud # 验证插件是否安装成功 certbot plugins | grep tencent # 应该能看到 dns-tencentcloud 字样
登录 腾讯云控制台。
点击右上角头像 -> 访问管理 -> 访问密钥 -> API 密钥管理。
新建密钥,获取 SecretId 和 SecretKey。
重要:确保该密钥关联的 CAM 用户拥有 DNSPodFullAccess 或 QcloudDNSFullAccess 权限(否则无法添加 TXT 记录)。
为了安全,不要直接在命令行输入密钥,而是创建一个配置文件。
sudo mkdir -p /etc/letsencrypt/credentials sudo vi /etc/letsencrypt/credentials/tencent-creds.ini
填入以下内容(替换为你的真实密钥):
dns_tencentcloud_secret_id = 你的SecretId dns_tencentcloud_secret_key = 你的SecretKey
设置严格权限(非常重要,否则 Certbot 会报错拒绝运行):
sudo chmod 600 /etc/letsencrypt/credentials/tencent-creds.ini
使用以下命令申请 zhoulujun.cn 的泛域名证书(包含主域名和所有子域名):
sudo certbot certonly \ --dns-tencentcloud \ --dns-tencentcloud-credentials /etc/letsencrypt/credentials/tencent-creds.ini \ -d zhoulujun.cn \ -d "*.zhoulujun.cn" \ --agree-tos \ --non-interactive \ --email [email protected]
证书生成后,通常位于 /etc/letsencrypt/live/zhoulujun.cn/。
修改你的 Nginx 配置指向这些文件:
ssl_certificate /etc/letsencrypt/live/zhoulujun.cn/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/zhoulujun.cn/privkey.pem;
Certbot 自带续期命令。由于使用了 DNS 插件,续期时也需要指定凭证文件。
sudo crontab -e
添加以下行(每天凌晨 3 点检查并续期,如需重载 nginx 可加 --deploy-hook):
0 3 * * * /usr/bin/certbot renew --dns-tencentcloud --dns-tencentcloud-credentials /etc/letsencrypt/credentials/tencent-creds.ini --quiet --post-hook "systemctl reload nginx"
当然,Let's Encrypt 单张证书支持最多 100 个域名,完全可以把 zhoulujun.cn、zhoulujun.com、zhoulujun.net 这三个域名的泛域名(包括主域名)都打包到同一张 Let's Encrypt 证书里,这是 Let's Encrypt 明确支持的,且对你的场景来说更省心(少管理多张证书)。
但是,这里面有个坑:
Let’s Encrypt 规则:一张证书里的所有域名,必须全部验证通过,证书才能颁发 / 续期。
最安全、最稳定、最适合你的方案:每个主域名,单独一张泛域名证书
转载本站文章《https域名证书:Certbot申请和管理Let’s Encrypt证书方案》,
请注明出处:https://www.zhoulujun.cn/html/tools/webServer/nginx/2026_0228_9768.html