Certbot 实现 HTTPS 免费证书(Let‘s Encrypt)自动续期
安装 Certbot
sudo snap install --classic certbot
如果提示:sudo: snap:找不到命令。因为 CentOS 默认不支持 snap 包管理工具,因此你需要使用 Certbot 的其他安装方式来申请 SSL 证书。对于 CentOS,通常使用 EPEL(Extra Packages for Enterprise Linux)存储库和 dnf 或 yum 包管理器来安装 Certbot
安装 Certbot 的步骤(适用于 CentOS 7/8):
启用 EPEL 存储库:
首先需要安装 EPEL 存储库,Certbot 依赖这个存储库中的一些工具。
sudo yum install epel-release
安装 Certbot:
安装 Certbot 和 Nginx 插件,一路按 y 回车(如有):
sudo yum install certbot python3-certbot-nginx
验证是否成功安装 Certbot
certbot --version
#输出:certbot 2.11.0
准备 Certbot 命令
sudo ln -s /snap/bin/certbot /usr/bin/certbot
手动运行方式
certbot -d 域名(可以使用*.代表所有二级域名) --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly
我的域名是 seasir.top,命令格式如下:
certbot -d seasir.top -d *.seasir.top --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly
#将调试日志保存到/root/logs/letsencrypt.log输入电子邮件地址(用于紧急续订和安全通知)(输入“c”取消):2429016980@q9.com
Saving debug log to /root/logs/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel):2429016980@qq.com(输入自己的邮箱)
#请阅读服务条款,网址为nttps://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf。您必须同意才能在ACME服务器注册。您同意吗?(Y)是/(N)或:y
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
#旦您成功获得第一张证书,您是否愿意与电子前沿基金会共享您的电子邮件地址?电子前沿基金会是 Let'sEncrypt项目的创始合作伙伴,也是开发 Certbot的非营利组织。我们希望向您发送有关我们为网络加密的工作、EFF 新闻、活动以及支持数字自由方式的电子邮件
#(Y)是/(N)否:
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y
根据提示部署 DNS TXT 记录
操作步骤:
登录 DNS 服务提供商控制台:通常是你在注册域名时使用的服务商,可能是腾讯云、阿里云、Cloudflare 等。我自己的是阿里云
找到域名解析设置:在控制台中找到你的域名 seasir.top
的解析设置(通常叫做 "DNS" 或 "域名解析")
添加 TXT 记录:
记录类型:选择
TXT
记录。主机记录:输入
_acme-challenge
(完整的记录将变成_acme-challenge.seasir.top
)记录值:输入 Certbot 返回的 value 值,比如:
hMPUVxWJ_SfLRabX7xpE1OJ_blSEzrvaxuabkNwKPyc
警告
使用 DNS 验证可以很方便的手动生成 SSL 证书,但是每次续期的时候要求填写的 TXT 记录都不同
,这意味着基于 DNS 验证的自动续期必须动态修改
DNS 的 TXT 记录。
提示
每次重新运行记录值会发生改变,以自己实际为准!
certbot -d seasir.top -d *.seasir.top --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly
- TTL:可以选择默认值(例如 10 分钟或 600 秒)。
Successfully received certificate. #成功领取证书。
Certificate is saved at: /root/config/live/seasir.top/fullchain.pem #证书保存为位置--关键文件
Key is saved at: /root/config/live/seasir.top/privkey.pem #证书保存为位置--关键文件
This certificate expires on 2025-01-03. #证书有效日期
These files will be updated when the certificate renews.
Nginx 配置
拷贝文件
由于我的服务器是本地虚拟机 frp 出去的,所以在云服务器/etc/nginx/ssl
新建 ssl 目录
#进入/etc/nginx/目录
cd /etc/nginx/
#创建ssl文件夹
mkdir ssl
进入云服务器文件路径:/root/config/live/seasir.top
把这两个fullchain.pem
和privkey.pem
文件 copy 进刚刚创建的 ssl 文件夹:/etc/nginx/ssl
可使用Xftp
软件进行拷贝操作,可视化界面,对小白友好,当然使用 linux 命令拷贝也行~
[root@VM-4-16-centos nginx]# cd ssl
[root@VM-4-16-centos ssl]# ll
总用量 8
-rw-r--r-- 1 root root 2843 10月 5 17:12 fullchain.pem
-rw-r--r-- 1 root root 241 10月 5 17:12 privkey.pem
设置fullchain.pem
和privkey.pem
文件权限
sudo chmod 644 fullchain.pem
sudo chmod 600 privkey.pem
创建 SSL 和反向代理公共配置文件
创建common_configs
文件夹
#进入/etc/nginx/目录
cd /etc/nginx/
#创建common_configs文件夹
mkdir common_configs
在common_configs
文件夹下分别创建common_proxy_params.conf
和common_ssl_params.conf
#进入/etc/nginx/common_configs目录
cd /etc/nginx/common_configs
#创建common_proxy_params.conf和common_ssl_params.conf文件
sudo touch /etc/nginx/common_configs/common_proxy_params.conf
sudo touch /etc/nginx/common_configs/common_ssl_params.conf
填入common_proxy_params.conf
和common_ssl_params.conf
配置,如下:
#common_proxy_params.conf
# 定义反向代理公用参数
client_max_body_size 100M; # 设置客户端最大请求体大小为 100M
proxy_set_header Host $host; # 转发 Host 头
proxy_set_header X-Real-IP $remote_addr; # 转发客户端真实 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 转发代理链中的 IP
proxy_set_header X-Forwarded-Proto $scheme; # 转发请求协议
#common_ssl_params.conf
# 定义 SSL 配置的公用参数
ssl_certificate "ssl/fullchain.pem"; # SSL 证书路径
ssl_certificate_key "ssl/privkey.pem"; # SSL 私钥路径
ssl_session_cache shared:SSL:1m; # SSL 会话缓存
ssl_session_timeout 10m; # SSL 会话超时时间
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; # 加密套件
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; # 支持的 TLS 协议版本
ssl_prefer_server_ciphers on; # 优先使用服务器端的加密套件
使用 chmod 命令来为 common_proxy_params.conf
和 common_ssl_params.conf
这两个文件设置 644 权限。以下是具体命令:
chmod 644 common_proxy_params.conf common_ssl_params.conf
Nginx.conf 配置文件
ecs 的 Nginx.conf 路径:/etc/nginx.nginx.conf,配置如下:
user root; # 设置 Nginx 运行的用户为 root
worker_processes auto; # 自动设置工作进程的数量
error_log /var/log/nginx/error.log; # 错误日志文件的路径
pid /run/nginx.pid; # Nginx 进程的 PID 文件路径
# 加载动态模块
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024; # 每个工作进程允许的最大连接数
}
http {
gzip on; # 启用 gzip 压缩
gzip_vary on; # 根据请求中的 `Accept-Encoding` 响应头决定是否启用 gzip
gzip_proxied any; # 在所有代理请求中启用压缩
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; # 指定需要压缩的响应类型
gzip_comp_level 5; # 压缩等级(1-9)
gzip_min_length 256; # 只对超过指定长度的响应启用压缩
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'; # 定义日志格式
access_log /var/log/nginx/access.log main; # 访问日志的路径
sendfile on; # 启用高效文件传输
tcp_nopush on; # 优化 TCP 数据包传输
tcp_nodelay on; # 关闭 Nagle 算法,减少延迟
keepalive_timeout 65; # 设置保持连接的超时时间
types_hash_max_size 4096; # 设置 MIME 类型哈希表的最大大小
include /etc/nginx/mime.types; # 包含 MIME 类型定义文件
default_type application/octet-stream; # 默认的响应类型
# 从 /etc/nginx/conf.d 目录加载模块化配置文件
include /etc/nginx/conf.d/*.conf; # 加载其他配置文件
charset utf-8; # 设置字符集为 UTF-8
# 公共配置文件引入
include /etc/nginx/common_configs/common_ssl_params.conf; # 引入 SSL 公用参数
include /etc/nginx/common_configs/common_proxy_params.conf; # 引入反向代理公用参数
# 其他 server 块可以类似配置...
}
blog.conf 配置文件
ecs 的 blog.conf 路径:/etc/nginx/conf.d/blog.conf,配置如下:
# 定义一个公共的 error_page 配置
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# HTTP 服务器块
server {
listen 80; # 监听 80 端口
server_name blog.seasir.top; # 前台域名
# 配置 HTTP 到 HTTPS 的重定向
return 301 https://$host$request_uri; # 重定向到 HTTPS
}
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
listen [::]:443 ssl; # 支持 IPv6
server_name blog.seasir.top; # 前台域名
location / {
proxy_pass http://云服务器IP:8082/; # 反向代理到实际后台路径
include /etc/nginx/common_configs/common_proxy_params.conf; # 引入反向代理公用参数
}
include /etc/nginx/common_configs/common_ssl_params.conf; # 引入 SSL 公用参数
}
# 后台域名的 HTTP 服务器块
server {
listen 80; # 监听 80 端口
server_name admin.seasir.top; # 后台域名
# 配置 HTTP 到 HTTPS 的重定向
return 301 https://$host$request_uri; # 重定向到 HTTPS
}
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
listen [::]:443 ssl; # 支持 IPv6
server_name admin.seasir.top; # 后台域名
location / {
proxy_pass http://云服务器IP:8083/; # 反向代理到实际后台路径
include /etc/nginx/common_configs/common_proxy_params.conf; # 引入反向代理公用参数
}
include /etc/nginx/common_configs/common_ssl_params.conf; # 引入 SSL 公用参数
}
# Minio 域名的 HTTP 服务器块
server {
listen 80; # 监听 80 端口
server_name minio.seasir.top; # Minio 域名
# 配置 HTTP 到 HTTPS 的重定向
return 301 https://$host$request_uri; # 重定向到 HTTPS
}
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
listen [::]:443 ssl; # 支持 IPv6
server_name minio.seasir.top; # Minio 域名
location / {
proxy_pass http://云服务器IP:9000/; # 反向代理到实际后台路径
include /etc/nginx/common_configs/common_proxy_params.conf; # 引入反向代理公用参数
}
include /etc/nginx/common_configs/common_ssl_params.conf; # 引入 SSL 公用参数
}
# Hitokoto 域名的 HTTP 服务器块
server {
listen 80; # 监听 80 端口
server_name hitokoto.seasir.top; # Hitokoto 域名
# 配置 HTTP 到 HTTPS 的重定向
return 301 https://$host$request_uri; # 重定向到 HTTPS
}
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
listen [::]:443 ssl; # 支持 IPv6
server_name hitokoto.seasir.top; # Hitokoto 域名
location / {
proxy_pass http://云服务器IP:8084/; # 反向代理到实际后台路径
include /etc/nginx/common_configs/common_proxy_params.conf; # 引入反向代理公用参数
}
include /etc/nginx/common_configs/common_ssl_params.conf; # 引入 SSL 公用参数
}
ecs 里的 nginx 配置目录和文件(配置后的
)
[root@VM-4-16-centos nginx]# ll
总用量 40
drwxr-xr-x 2 root root 4096 12月 22 22:49 common_configs
drwxr-xr-x 2 root root 4096 2月 28 23:28 conf.d
-rw-r--r-- 1 root root 1007 5月 30 2024 fastcgi_params
-rw-r--r-- 1 root root 5349 5月 30 2024 mime.types
-rw-r--r-- 1 root root 2374 1月 4 23:34 nginx.conf
-rw-r--r-- 1 root root 2109 10月 9 22:49 nginx.conf.bak
-rw-r--r-- 1 root root 636 5月 30 2024 scgi_params
drwxr-xr-x 2 root root 4096 10月 5 17:12 ssl
-rw-r--r-- 1 root root 664 5月 30 2024 uwsgi_params
CND 证书配置
警告
如果二级域名
配置了CND加速
,也需要前往CND服务商
配置下HTTPS证书
,否则访问网站还是之前过期的证书,会提示不安全!
配置详细步骤如下: 进入CND 服务商后台,找到您的二级域名
进入管理-HTTPS 配置-更新证书-上传新证书
- 把
/etc/nginx/ssl
目录下的fullchain.pem
文件全部内容复制到证书内容
,把privkey.pem
文件全部内容复制到私钥内容
,最后等待部署,访问网站查看证书是否是最新的
以上配置完成重启 Nginx,命令如下:
nginx -s reload
#或
sudo systemctl reload nginx
测试成功(24.10.5)
访问:博客前台
自动续期(指定)
通过 http 验证生成 SSL 证书,适用于指定域名ssl自动续期
教程来源:https://blog.csdn.net/as604049322/article/details/134957466
# 使用 vi 编辑器打开 Nginx 虚拟主机配置文件 proj.conf
vi /usr/local/nginx/conf/vhost/proj.conf
添加 nginx 配置
# 全局错误页面配置
# 当服务器返回 404 状态码时,将请求重定向到 /404.html 页面
error_page 404 /404.html;
# 当服务器返回 500、502、503、504 这些状态码时,将请求重定向到 /50x.html 页面
error_page 500 502 503 504 /50x.html;
# proj.seasir.top 域名的 HTTP -> HTTPS 重定向
server {
# 监听 IPv4 的 80 端口,用于接收 HTTP 请求
listen 80;
# 监听 IPv6 的 80 端口,用于接收 IPv6 地址的 HTTP 请求
listen [::]:80;
# 指定该虚拟主机所处理的域名,这里是 proj.seasir.top
server_name proj.seasir.top;
# 配置 HTTP 到 HTTPS 的重定向
# 当接收到 HTTP 请求时,返回 301 永久重定向状态码,将请求重定向到对应的 HTTPS 地址
# $host 表示请求的域名,$request_uri 表示请求的 URI 路径
return 301 https://$host$request_uri;
}
# proj.seasir.top 域名的 HTTPS 反向代理
server {
# 监听 IPv4 的 443 端口,用于接收 HTTPS 请求,并且启用 SSL 加密
listen 443 ssl;
# 监听 IPv6 的 443 端口,用于接收 IPv6 地址的 HTTPS 请求,并且启用 SSL 加密
listen [::]:443 ssl;
# 指定该虚拟主机所处理的域名,这里是 proj.seasir.top
server_name proj.seasir.top;
# 设置该虚拟主机的根目录,即网站文件所在的目录
root /root/rsync/rsync-vue/dist;
# 配置请求的根路径匹配规则
location / {
# 当访问根路径时,默认尝试访问的文件列表,按顺序查找,找到第一个存在的文件则返回
index index.html index.htm;
}
# 此处缺少 SSL 证书和私钥的配置,后续需要添加类似如下配置
# ssl_certificate /etc/letsencrypt/live/proj.seasir.top/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/proj.seasir.top/privkey.pem;
}
- 重载配置
service nginx reload
# 输出
[root@VM-4-16-centos ~]# service nginx reload
Redirecting to /bin/systemctl reload nginx.service
添加解析记录
- 去域名解析添加好您的二级域名解析记录,然后通过 http 验证生成证书:
certbot certonly --email seasir666@gmail.com --webroot -w /root/rsync/rsync-vue/dist --preferred-challenges http-01 -d proj.seasir.top
参数说明:
--email seasir666@gmail.com:这里的
seasir666@gmail.com
是用于接收 Let's Encrypt 证书相关通知(如证书即将到期提醒等)的电子邮件地址,你需要将其替换为你自己有效的电子邮件地址-w /root/rsync/rsync-vue/dist:
-w
选项后面指定的是 Web 服务器的根目录,Certbot 会在这个目录下创建一个临时文件以完成 ACME(自动证书管理环境)的 HTTP-01 挑战验证。你需要将其替换为你实际网站文件所在的根目录。-d proj.seasir.top:
-d
指定要申请证书的域名,你可以添加多个 -d 参数来为多个域名申请通配符证书或多域名证书,例如 -d example.com -d www.example.com。你需要将proj.seasir.top
替换为你自己的域名。
输出:
# 以 root 权限运行 Certbot 命令,用于申请 SSL 证书
# --email seasir666@gmail.com:指定用于接收证书相关通知的电子邮件地址
# --webroot:指定使用 webroot 验证方式,Certbot 会在指定的 Web 根目录下创建临时文件以完成验证
# -w /root/rsync/rsync-vue/dist:指定 Web 根目录,Certbot 会在该目录下创建验证文件
# --preferred-challenges http-01:指定优先使用 HTTP-01 挑战方式进行验证
# -d proj.seasir.top:指定要为其申请证书的域名
[root@VM-4-16-centos ~]# sudo certbot certonly --email seasir666@gmail.com --webroot -w /root/rsync/rsync-vue/dist --preferred-challenges http-01 -d proj.seasir.top
# 提示将调试日志保存到指定文件,方便后续排查问题
Saving debug log to /var/log/letsencrypt/letsencrypt.log
# 显示正在为指定域名申请证书
Requesting a certificate for proj.seasir.top
# 提示成功获取到证书
Successfully received certificate.
# 显示证书文件的保存路径,fullchain.pem 包含了服务器证书和中间证书链
Certificate is saved at: /etc/letsencrypt/live/proj.seasir.top/fullchain.pem
# 显示私钥文件的保存路径,私钥用于加密和解密与客户端的通信
Key is saved at: /etc/letsencrypt/live/proj.seasir.top/privkey.pem
# 显示证书的过期时间,提醒用户需要在该日期前进行证书更新
This certificate expires on 2025-05-29.
# 提示当证书需要续期时,这些文件会自动更新
These files will be updated when the certificate renews.
# 提示 Certbot 已经设置了定时任务,会在后台自动续期证书,无需用户手动干预
Certbot has set up a scheduled task to automatically renew this certificate in the background.
# 分割线及提示信息,鼓励用户支持 Let's Encrypt 和电子前沿基金会(EFF)的工作
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
然后可以看到 ssl 生成成功的提示Successfully received certificate.
。
配置 SSL 证书
# 全局错误页面配置
# 当服务器返回 404 状态码时,将请求重定向到 /404.html 页面
error_page 404 /404.html;
# 当服务器返回 500、502、503、504 这些状态码时,将请求重定向到 /50x.html 页面
error_page 500 502 503 504 /50x.html;
# proj.seasir.top 域名的 HTTP -> HTTPS 重定向
server {
#此处省略,可以复制上面的
}
# proj.seasir.top 域名的 HTTPS 反向代理
server {
#此处省略,可以复制上面的
# 此处缺少 SSL 证书和私钥的配置,后续需要添加类似如下配置
ssl_certificate /etc/letsencrypt/live/proj.seasir.top/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/proj.seasir.top/privkey.pem;
}
再次重载配置nginx -s reload
nginx -s reload
自动更新证书
#使用以下命令即可更新证书:
certbot renew
#输出:
# 执行 certbot renew 命令,该命令用于检查已有的证书是否需要续期,并在需要时自动进行续期操作
[root@VM-4-16-centos ~]# certbot renew
# 提示将调试日志保存到指定文件,方便后续排查可能出现的问题
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 表示 Certbot 正在处理 proj.seasir.top 域名对应的续期配置文件
# 该配置文件中记录了证书申请时的相关配置信息,如验证方式、域名等
Processing /etc/letsencrypt/renewal/proj.seasir.top.conf
# 分割线,用于区分不同信息块
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 提示当前检查的 proj.seasir.top 域名的证书还未到需要续期的时间
# Let's Encrypt 证书有效期一般为 90 天,Certbot 通常会在证书有效期还剩 30 天左右时尝试续期
Certificate not yet due for renewal
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 列出所有尚未到续期时间的证书信息
The following certificates are not due for renewal yet:
# 具体指出 proj.seasir.top 域名的证书文件 fullchain.pem 未到期
# 显示该证书的到期时间为 2025-05-29,因此本次检查会跳过该证书的续期操作
/etc/letsencrypt/live/proj.seasir.top/fullchain.pem expires on 2025-05-29 (skipped)
# 提示由于所有证书都未到续期时间,本次没有尝试进行任何证书的续期操作
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
但有效期超过一个月的会自动跳过。我们将该命令配置为 crontab 定时任务即可实现自动续签
添加定时任务
首先执行crontab -e
,然后添加以下配置:
0 0 * * 1 /usr/bin/certbot renew >> /var/log/certbot-renew.log
crontab 从左至右分别是:分钟、小时、日期、月份、星期几,以上配置代表每周一执行一次证书更新。
表示每周一的凌晨 0 点执行任务。/usr/bin/certbot renew:这是要执行的具体命令,即调用 Certbot 工具的 renew 命令来检查并尝试续期证书。>> /var/log/certbot-renew.log:这部分是重定向操作,>> 表示以追加的方式将命令的输出结果写入到指定的日志文件 /var/log/certbot-renew.log 中。
crontab -e
在 /var/spool/cron
目录下
/var/spool/cron 目录下原本有这个命令:_/5 _ * * * flock -xn /tmp/stargate.lock -c '/usr/local/qcloud/stargate/admin/start.sh > /dev/null 2>&1 &'
现在需要添加新的命令:0 0 * * 1 /usr/bin/certbot renew >> /var/log/certbot-renew.log
完整合并如下:
*/5 * * * * flock -xn /tmp/stargate.lock -c '/usr/local/qcloud/stargate/admin/start.sh > /dev/null 2>&1 &'
0 0 * * 1 /usr/bin/certbot renew >> /var/log/certbot-renew.log
完成上述操作后,系统会自动加载新的 crontab
配置,定时任务就会按照设定的时间规则执行。
自动续期(推荐)
通过 dns 通配符去实现自动续期
这里推荐 @justjavac 大佬写的:https://github.com/justjavac/certbot-dns-aliyun 参考大佬资料:http://blog.mnxz.fun/index.html?model=articleInfo&id=10
当我们使用 certbot 申请通配符证书时,需要手动添加 TXT 记录。每个 certbot 申请的证书有效期为 3 个月,虽然 certbot 提供了自动续期命令,但是当我们把自动续期命令配置为定时任务时,我们无法手动添加新的 TXT 记录用于 certbot 验证。
好在 certbot 提供了一个 hook,可以编写一个 Shell 脚本。在续期的时候让脚本调用 DNS 服务商的 API 接口动态添加 TXT 记录,验证完成后再删除此记录。
前提条件
- 你已经有一个域名,并且域名解析托管在阿里云。
- 服务器上已经安装了 Certbot。
- 你已经配置了 alidns 脚本,用于自动添加和清理 DNS 记录
- 拥有阿里云的访问密钥(
AccessKey ID
和AccessKey Secret
),用于操作阿里云 DNS 服务。获取阿里云访问密钥(AccessKey ID 和 AccessKey Secret)请参考官方文档:https://help.aliyun.com/zh/acr/create-and-obtain-an-accesskey-pair
环境
:
- 系统: centos7
- 域名: 阿里云购买的域名
- python
- nginx 提供反向代理
安装 aliyun cli 工具
wget https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
tar xzvf aliyun-cli-linux-latest-amd64.tgz
sudo cp aliyun /usr/local/bin
rm aliyun
验证 aliyun cli 工具是否成功:
打开终端,输入
aliyun
命令并回车。如果安装成功,会显示阿里云 CLI 的帮助信息,包含可用的命令和选项shaliyun
示例输出如下:
详细信息
sh[root@VM-4-16-centos certbot-alicli]# aliyun 阿里云CLI命令行工具 3.0.255 Usage: aliyun <product> <operation> [--parameter1 value1 --parameter2 value2 ...] Commands: configure 配置身份认证和其他信息 oss 阿里云OSS对象存储 auto-completion 启用自动完成 Flags: --mode 使用 `--mode {AK|StsToken|RamRoleArn|EcsRamRole|RsaKeyPair|RamRoleArnWithRoleName}` 指定认证方式 --profile,-p 使用 `--profile <profileName>` 指定操作的配置集 --language 使用 `--language [en|zh]` 来指定语言 --region 使用 `--region <regionId>` 来指定访问大区 --config-path 使用 `--config-path` 指定配置文件路径 --access-key-id 使用 `--access-key-id <AccessKeyId>` 指定AccessKeyId --access-key-secret 使用 `--access-key-secret <AccessKeySecret>` 指定AccessKeySecret --sts-token 使用 `--sts-token <StsToken>` 指定StsToken --sts-region 使用 `--sts-region <StsRegion>` 指定StsRegion --ram-role-name 使用 `--ram-role-name <RamRoleName>` 指定RamRoleName --ram-role-arn 使用 `--ram-role-arn <RamRoleArn>` 指定RamRoleArn --role-session-name 使用 `--role-session-name <RoleSessionName>` 指定RoleSessionName --private-key 使用 `--private-key <PrivateKey>` 指定RSA私钥 --key-pair-name 使用 `--key-pair-name <KeyPairName>` 指定KeyPairName --read-timeout 使用 `--read-timeout <seconds>` 指定I/O超时时间(秒) --connect-timeout 使用 `--connect-timeout <seconds>` 指定请求连接超时时间(秒) --retry-count 使用 `--retry-count <count>` 指定重试次数 --skip-secure-verify 使用 `--skip-secure-verify` 跳过https的证书校验 [不推荐使用] --expired-seconds 使用 `--expired-seconds <seconds>` 指定凭证过期时间 --process-command 使用 `--process-command <ProcessCommand>` 指定外部程序运行命令 --oidc-provider-arn 使用 `--oidc-provider-arn <OIDCProviderARN>` 来指定 OIDC 提供者 ARN --oidc-token-file 使用 `--oidc-token-file <OIDCTokenFile>` 来指定 OIDC Token 文件路径 --secure 使用 `--secure` 开关强制使用https方式调用 --force 添加 `--force` 开关可跳过API与参数的合法性检查 --endpoint 使用 `--endpoint <endpoint>` 来指定接入点地址 --version 使用 `--version <YYYY-MM-DD>` 来指定访问的API版本 --header 使用 `--header X-foo=bar` 来添加特定的HTTP头, 可多次添加 --body 使用 `--body $(cat foo.json)` 来指定在RESTful调用中的HTTP包体 --pager 使用 `--pager` 在访问分页的API时合并结果分页 --output,-o 使用 `--output cols=Field1,Field1 [rows=jmesPath]` 使用表格方式打印输出 --waiter 使用 `--waiter expr=<jmesPath> to=<value>` 来轮询调用OpenAPI,直到返回期望的值 --dryrun 使用 `--dryrun` 在执行校验后打印请求包体,跳过实际运行 --quiet,-q 使用 `--quiet` 关闭正常输出 --method 使用 `--method {GET|POST}` 来指定 RPC 请求的 Method --help 打印帮助信息 Sample: aliyun ecs DescribeRegions Use `aliyun --help` for more information.
配置凭证
安装完成后,你需要对阿里云 CLI 进行配置,使其能够访问你的阿里云账户。可以使用以下命令进行配置:
shaliyun configure set --profile AkProfile --mode AK --access-key-id 替换为你自己的真实 AccessKey ID --access-key-secret 替换为你自己的真实 AccessKey Secret --region 替换为你希望使用的阿里云地域的 ID
示例命令
shaliyun configure set --profile AkProfile --mode AK --access-key-id LTAI5txxxxxx --access-key-secret k71Bxxxxxx --region cn-guangzhou
按照提示输入你的阿里云访问密钥(AccessKey ID 和 AccessKey Secret)、默认的地域 ID 等信息,配置完成后就可以使用阿里云 CLI 工具来管理你的阿里云资源了。
如何获取阿里云访问密钥(AccessKey ID 和 AccessKey Secret)请参考官方文档:https://help.aliyun.com/zh/acr/create-and-obtain-an-accesskey-pair
获取 Region Id 请参考官方文档:https://help.aliyun.com/zh/cli/configure-credentials?spm=a2c4g.11186623.0.i1#41e7063556zzq或者使用
aliyun ecs DescribeRegions
命令获取阿里云 ECS 支持的地域信息输出:
详细信息
sh[root@VM-4-16-centos ~]# aliyun configure Configuring profile 'default' in 'AK' authenticate mode... Access Key Id []: #输入您的AccessKey ID Access Key Secret []: #输入您的AccessKey Secret Default Region Id []: cn-guangzhou #地域id选择离您最近的地区 Default Output Format [json]: json (Only support json) #默认输出格式,仅支持json格式! Default Language [zh|en] zh: zh #选择语言,输入zh即可 Saving profile[default] ...Done. #以下是配置凭证-交互事配置完整提示信息 Configure Done!!! ..............888888888888888888888 ........=8888888888888888888D=.............. ...........88888888888888888888888 ..........D8888888888888888888888I........... .........,8888888888888ZI: ...........................=Z88D8888888888D.......... .........+88888888 ..........................................88888888D.......... .........+88888888 .......Welcome to use Alibaba Cloud.......O8888888D.......... .........+88888888 ............. ************* ..............O8888888D.......... .........+88888888 .... Command Line Interface(Reloaded) ....O8888888D.......... .........+88888888...........................................88888888D.......... ..........D888888888888DO+. ..........................?ND888888888888D.......... ...........O8888888888888888888888...........D8888888888888888888888=........... ............ .:D8888888888888888888.........78888888888888888888O ..............
验证配置
配置完成后,你可以使用以下命令来验证配置是否生效:
aliyun configure list
输出:
[root@VM-4-16-centos certbot-alicli]# aliyun configure list
Profile | Credential | Valid | Region | Language
--------- | ------------------ | ------- | ---------------- | --------
default | AK:***MHb | Valid | cn-guangzhou | zh
AkProfile * | AK:***MHb | Valid | cn-guangzhou | zh
#目前存在两个配置文件,分别是 default 和 AkProfile。其中 AkProfile 后面带有 * 号,这表明当前使用的默认配置文件是 AkProfile。
安装 certbot-dns-aliyun 插件
#下载、部署并配置一个名为 alidns.sh 的脚本
wget https://cdn.jsdelivr.net/gh/justjavac/certbot-dns-aliyun@main/alidns.sh
sudo cp alidns.sh /usr/local/bin
sudo chmod +x /usr/local/bin/alidns.sh
sudo ln -s /usr/local/bin/alidns.sh /usr/local/bin/alidns
如果下载失败手动前往 github 下载:https://github.com/justjavac/certbot-dns-aliyun/blob/main/alidns.sh
申请证书
测试是否能正确申请:
警告
.seasir.top 请换成自己的主域名
certbot certonly -d *.seasir.top --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
#输出
[root@VM-4-16-centos bin]# certbot certonly -d *.seasir.top --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Simulating a certificate request for *.seasir.top
Hook '--manual-auth-hook' for seasir.top ran with output:
{
"RecordId": "1895874534617010176",
"RequestId": "D634D1CA-6CD8-5278-BED9-A1BFDF967B03"
}
Hook '--manual-cleanup-hook' for seasir.top ran with output:
{
"RecordId": "1895874534617010176",
"RequestId": "E73F9702-88E5-5950-BAD2-751F59432AA1"
}
The dry run was successful.
#看到"The dry run was successful."模拟成功!
正式申请时去掉 --dry-run
参数:
certbot certonly -d *.seasir.top --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"
参数说明
- -d example.com:指定域名(可以指定多个域名)。
- manual:手动模式。
- preferred-challenges dns:使用 DNS 挑战。
- manual-auth-hook “alidns”:在 DNS 挑战时调用 alidns 脚本。
- manual-cleanup-hook “alidns clean”:在 DNS 挑战完成后调用 alidns clean 脚本。
- —dry-run:模拟续期过程,不会实际续期证书。正式申请时去掉—dry-run 参数:
证书续期
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run
如果以上命令没有错误,把 --dry-run
参数去掉。
certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"
检查证书状态
运行以下命令查看证书的到期时间:
certbot certificates
自动续期
添加定时任务 crontab。
crontab -e
然后添加以下配置:
1 1 */1 * * root certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --deploy-hook "nginx -s reload"
上面脚本中的 --deploy-hook "nginx -s reload"
表示在续期成功后自动重启 nginx。
常见问题排查
1.没有日志输出,如果 /var/log/certbot-renew.log 没有日志输出,可能是以下原因: 权限问题:确保日志文件可写:
sudo touch /var/log/certbot-renew.log
sudo chmod 644 /var/log/certbot-renew.log
cron 任务未执行:检查 cron 日志:
grep CRON /var/log/syslog
2.证书未到期
如果证书未到期,Certbot 会跳过续期。可以通过以下命令强制续期:
certbot renew --force-renewal --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"
通过 Certbot 和阿里云 DNS 的集成,我们可以轻松实现 SSL 证书的自动续期。只需设置一次 cron 任务,Certbot 就会在证书到期前自动续期,并调用 alidns 脚本处理 DNS 挑战。