Certbot+Letsencrypt+腾讯云DNS验证自动续期证书
本文基于Ubuntu
安装certbot
sudo apt-get install certbot
申请脚本
通过腾讯云域名解析的dns验证域名归属,并申请通配符域名证书
certbot certonly --manual --preferred-challenges dns -d example.com -d *.example.com \
--email your_email \
--agree-tos \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual-auth-hook dnspod-add.sh \
--manual-cleanup-hook dnspod-rm.sh \
--deploy-hook reload-ssl.sh
- certbot certonly:这个子命令用于获取证书,而不是安装或配置证书。它是
Certbot
提供的最基础的证书获取方式。 - --manual:指定以手动模式运行
Certbot
。在这种模式下,Certbot
会提示你手动完成一些操作以验证域名所有权,而不是自动处理这些操作。 - --preferred-challenges dns:指定优先使用 DNS 验证方式。
Let's Encrypt
提供多种验证域名所有权的方式,如 HTTP 验证(通过在服务器上放置文件)和 DNS 验证(通过更新 DNS TXT 记录)。这里选择 DNS 验证。 - -d example.com, -d *.example.com:指定要获取证书的域名。这里不仅为
example.com
获取证书,还为*.example.com
(即所有example.com
的子域名)获取通配符证书。 - --email your_email:提供电子邮件地址,用于接收证书相关的重要通知,如证书续订通知、证书吊销通知等。
- --agree-tos:自动同意
Let's Encrypt
的服务条款(Terms of Service)。这表示你已经阅读并同意Let's Encrypt
的条款和条件。 - --server https://acme-v02.api.letsencrypt.org/directory:指定
Let's Encrypt
的 ACME 服务器 URL。这是Let's Encrypt
的生产环境服务器,用于获取正式的证书。可以先用测试环境调试。 - --manual-auth-hook dnspod-add.sh:指定手动认证钩子(hook)脚本。当
Certbot
需要进行 DNS 验证时,它会调用这个脚本自动添加 DNS TXT 记录。这里假设脚本dnspod-add.sh
用于与 DNS 服务提供商(如 DNSPod)交互,添加所需的 TXT 记录。 - --manual-cleanup-hook dnspod-rm.sh:指定手动清理钩子脚本。当验证完成后,
Certbot
会调用这个脚本自动删除之前添加的 DNS TXT 记录。脚本dnspod-rm.sh
用于从 DNS 服务提供商处删除这些记录。 - --deploy-hook reload-ssl.sh:指定部署钩子脚本。当证书获取或续订成功后,
Certbot
会调用这个脚本。这里假设reload-ssl.sh
脚本用于重新加载 Web 服务器的 SSL/TLS 配置,使新证书生效。
执行脚本并验证证书是否生成
ls /etc/letsencrypt/live/example.com/
更新脚本
certbot renew --manual --preferred-challenges dns -d example.com -d *.example.com \
--email your_email \
--agree-tos \
--server https://acme-v02.api.letsencrypt.org/directory \
--manual-auth-hook dnspod-add.sh \
--manual-cleanup-hook dnspod-rm.sh \
--deploy-hook reload-ssl.sh
和上方的申请脚本一致,将certonly
换为renew
记录添加脚本
#!/bin/bash
# 填入你的 DNSPod API 密钥和域名
API_KEY="YOUR_API_KEY"
DOMAIN="example.com"
SUB_DOMAIN="_acme-challenge"
RECORD_TYPE="TXT"
DOMAIN_ID="YOUR_DOMAIN_ID"
REMOTE_URL="https://dnsapi.cn"
# 读取环境变量
# VALIDATION_DOMAIN=$CERTBOT_DOMAIN
VALIDATION_VALUE=$CERTBOT_VALIDATION
# 在这里添加你的代码,使用这些变量在你的DNS提供商处添加TXT记录
echo "Adding DNS record for $DOMAIN with $VALIDATION_VALUE"
# 使用 curl 添加 DNS 记录
curl -X POST "$REMOTE_URL/Record.Create" \
-d "login_token=$API_KEY" \
-d "format=json" \
-d "domain=$DOMAIN" \
-d "domain_id=$DOMAIN_ID" \
-d "sub_domain=$SUB_DOMAIN" \
-d "record_type=$RECORD_TYPE" \
-d "record_line=默认" \
-d "value=$VALIDATION_VALUE"
- API_KEY:DNSPod API 密钥,用于身份验证。
- DOMAIN:主域名,如
example.com
。 - SUB_DOMAIN:子域名,对于 Let's Encrypt 的 DNS 验证通常是
_acme-challenge
。 - RECORD_TYPE:DNS 记录类型,这里是
TXT
,因为 Let's Encrypt 使用 TXT 记录进行验证。 - DOMAIN_ID:DNSPod 上域名的 ID,可以在 DNSPod 的域名列表中找到。
- REMOTE_URL:DNSPod API 的基础 URL。
- CERTBOT_DOMAIN(注释中):Certbot 提供的环境变量,表示当前要验证的域名。
- CERTBOT_VALIDATION:Certbot 提供的环境变量,表示用于验证的 TXT 记录值。
记录删除脚本
#!/bin/bash
# 填入你的 DNSPod API 密钥和域名
API_KEY="YOUR_API_KEY"
DOMAIN="example.com"
SUB_DOMAIN="_acme-challenge"
RECORD_TYPE="TXT"
DOMAIN_ID="YOUR_DOMAIN_ID"
REMOTE_URL="https://dnsapi.cn"
# 使用 curl 删除 DNS 记录
RESPONSE=$(curl -X POST "$REMOTE_URL/Record.List" \
-d "login_token=$API_KEY" \
-d "format=json" \
-d "domain_id=$DOMAIN_ID" \
-d "sub_domain=$SUB_DOMAIN" \
-d "record_type=$RECORD_TYPE")
echo "Response id: $RESPONSE"
# 从返回的 JSON 中提取 RECORD_ID 并删除记录
# 这里需要解析 JSON 并提取 RECORD_ID,然后调用 Record.Delete
# 解析 JSON 响应以找到 RECORD_ID
RECORD_ID=$(echo $RESPONSE | jq -r '.["records"][].id')
echo -e "Record ID to delete: $RECORD_ID"
# 删除找到的记录
if [ ! -z "$RECORD_ID" ]; then
readarray -t ids <<< "$RECORD_ID" # 将 RECORD_ID 转换为数组
for id in "${ids[@]}"; do
curl -s -X POST "$REMOTE_URL/Record.Remove" \
-d "login_token=$API_KEY" \
-d "format=json" \
-d "domain=$DOMAIN" \
-d "domain_id=$DOMAIN_ID" \
-d "record_id=$id"
done
else
echo "No record found to delete."
fi
查找_acme-challenge
记录并删除记录
总结
在以上申请脚本执行一次后,系统会自动在/etc/letsencrypt/renewal
下生成example.com.conf
以自动执行更新证书程序,默认每天两次,且指定了验证前、后以及完成后的钩子脚本地址,实现自动续期。
拓展
更新雷池的证书
#!/bin/bash
# 定义文件路径
LOCAL_FILE_PATH_CRT="/etc/letsencrypt/live/example.com/fullchain.pem"
LOCAL_FILE_PATH_KEY="/etc/letsencrypt/live/example.com/privkey.pem"
# API端点
API_ENDPOINT="https://example.com/api/open/cert"
SAFE_LINE_TOKEN="YOUR_TOKEN"
# 更新长亭雷池中证书
# 读取证书和密钥文件内容
CRT_CONTENT=""
KEY_CONTENT=""
# 读取文件内容,保留换行符
while IFS= read -r line; do
CRT_CONTENT+="$line\n"
done < "$LOCAL_FILE_PATH_CRT"
while IFS= read -r line; do
KEY_CONTENT+="$line\n"
done < "$LOCAL_FILE_PATH_KEY"
# 清除最后一个换行符
CRT_CONTENT=${CRT_CONTENT%'\n'}
KEY_CONTENT=${KEY_CONTENT%'\n'}
# 创建JSON体,id根据实际控制台请求数据来,type-2表示更新
JSON_BODY=$(cat <<EOF
{
"id": 1,
"manual": {
"crt": "$CRT_CONTENT",
"key": "$KEY_CONTENT"
},
"type": 2
}
EOF
)
# 发送POST请求
echo "Sending POST request to API endpoint..."
RESPONSE=$(curl -s -X POST "$API_ENDPOINT" -H "Content-Type: application/json" -H "X-SLCE-API-TOKEN: $SAFE_LINE_TOKEN" -d "$JSON_BODY")
# 检查响应
echo "POST request and response is: $RESPONSE"
发送证书到指定服务器(Nginx)
#!/bin/bash
# 定义主机地址
HOST="192.168.1.4"
# 私钥地址
PRIVATE_KEY_PATH=/root/.ssh/id_rsa
# 定义文件路径
LOCAL_FILE_PATH_CRT="/etc/letsencrypt/live/example.com/fullchain.pem"
LOCAL_FILE_PATH_KEY="/etc/letsencrypt/live/example.com/privkey.pem"
REMOTE_FILE_PATH_CRT="path_to_example.com_bundle.crt"
REMOTE_FILE_PATH_KEY="path_to_example.com.key"
# SSH 用户名和密码和端口
SSH_USER="root"
PORT=3800
# 第一步:使用sshpass和scp命令发送文件到MK-J
echo "Sending file to $HOST..."
scp -P $PORT -i $PRIVATE_KEY_PATH $LOCAL_FILE_PATH_CRT $SSH_USER@$HOST:$REMOTE_FILE_PATH_CRT
scp -P $PORT -i $PRIVATE_KEY_PATH $LOCAL_FILE_PATH_KEY $SSH_USER@$HOST:$REMOTE_FILE_PATH_KEY
注意:需要将本机的无密码公钥添加至对端服务器的authorized_keys中才能传输文件和执行命令。
评论