惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
Webroot Blog
Webroot Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Threat Research - Cisco Blogs
V2EX - 技术
V2EX - 技术
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
S
Schneier on Security
I
InfoQ
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The GitHub Blog
The GitHub Blog
S
Security @ Cisco Blogs
O
OpenAI News
W
WeLiveSecurity
Vercel News
Vercel News
阮一峰的网络日志
阮一峰的网络日志
Simon Willison's Weblog
Simon Willison's Weblog
人人都是产品经理
人人都是产品经理
Cloudbric
Cloudbric
The Last Watchdog
The Last Watchdog
The Hacker News
The Hacker News
Google Online Security Blog
Google Online Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
NISL@THU
NISL@THU
T
Tailwind CSS Blog
V
Visual Studio Blog
PCI Perspectives
PCI Perspectives
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
D
DataBreaches.Net
B
Blog RSS Feed
N
News and Events Feed by Topic
N
News and Events Feed by Topic
H
Heimdal Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
腾讯CDC
Latest news
Latest news
V
Vulnerabilities – Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
WordPress大学
WordPress大学
V
V2EX
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Register - Security
The Register - Security
Help Net Security
Help Net Security

Hyde Blog

Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog 关于我 关于我 Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog Hyde Blog
Hyde Blog
Hyde · 2025-10-05 · via Hyde Blog

Certbot 实现 HTTPS 免费证书(Let‘s Encrypt)自动续期 ​

安装 Certbot ​

bash

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): ​

  1. 启用 EPEL 存储库

    首先需要安装 EPEL 存储库,Certbot 依赖这个存储库中的一些工具。

bash

sudo yum install epel-release

安装 Certbot: ​

安装 Certbot 和 Nginx 插件,一路按 y 回车(如有):

bash

sudo yum install certbot python3-certbot-nginx

验证是否成功安装 Certbot ​

bash

certbot --version

#输出:certbot 2.11.0

准备 Certbot 命令 ​

bash

sudo ln -s /snap/bin/certbot /usr/bin/certbot

手动运行方式 ​

bash

certbot -d 域名(可以使用*.代表所有二级域名) --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly

我的域名是 seasir.top,命令格式如下:

bash

certbot -d seasir.top -d *.seasir.top --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly

bash

#将调试日志保存到/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(输入自己的邮箱)

bash

#请阅读服务条款,网址为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

bash

#旦您成功获得第一张证书,您是否愿意与电子前沿基金会共享您的电子邮件地址?电子前沿基金会是 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 记录。

提示

每次重新运行记录值会发生改变,以自己实际为准!

bash

certbot -d seasir.top -d *.seasir.top --manual --config-dir config --work-dir work --logs-dir logs --preferred-challenges dns certonly
  • TTL:可以选择默认值(例如 10 分钟或 600 秒)。

bash

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 目录

bash

#进入/etc/nginx/目录
cd /etc/nginx/

#创建ssl文件夹
mkdir ssl

进入云服务器文件路径:/root/config/live/seasir.top把这两个fullchain.pemprivkey.pem文件 copy 进刚刚创建的 ssl 文件夹:/etc/nginx/ssl

可使用Xftp软件进行拷贝操作,可视化界面,对小白友好,当然使用 linux 命令拷贝也行~

bash

[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.pemprivkey.pem文件权限

bash

sudo chmod 644 fullchain.pem
sudo chmod 600 privkey.pem

创建 SSL 和反向代理公共配置文件 ​

创建common_configs文件夹

bash

#进入/etc/nginx/目录
cd /etc/nginx/

#创建common_configs文件夹
mkdir common_configs

common_configs文件夹下分别创建common_proxy_params.confcommon_ssl_params.conf

bash

#进入/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.confcommon_ssl_params.conf配置,如下:

nginx

#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;  # 转发请求协议

bash

#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.confcommon_ssl_params.conf 这两个文件设置 644 权限。以下是具体命令:

bash

chmod 644 common_proxy_params.conf common_ssl_params.conf

Nginx.conf 配置文件 ​

ecs 的 Nginx.conf 路径:/etc/nginx.nginx.conf,配置如下:

nginx

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,配置如下:

nginx

# 定义一个公共的 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 配置目录和文件(配置后的

bash

[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,命令如下:

bash

nginx -s reload
#或
sudo systemctl reload nginx

测试成功(24.10.5) ​

访问:博客前台

自动续期(指定) ​

通过 http 验证生成 SSL 证书,适用于指定域名ssl自动续期

教程来源:https://blog.csdn.net/as604049322/article/details/134957466

sh

# 使用 vi 编辑器打开 Nginx 虚拟主机配置文件 proj.conf
vi /usr/local/nginx/conf/vhost/proj.conf

添加 nginx 配置 ​

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;
}
  • 重载配置

sh

service nginx reload

# 输出
[root@VM-4-16-centos ~]# service nginx reload
Redirecting to /bin/systemctl reload nginx.service

添加解析记录 ​

  • 去域名解析添加好您的二级域名解析记录,然后通过 http 验证生成证书:

sh

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 替换为你自己的域名。

输出:

sh

# 以 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 证书 ​

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 {
    #此处省略,可以复制上面的
}

# 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

自动更新证书 ​

sh

#使用以下命令即可更新证书:
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,然后添加以下配置:

sh

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 IDAccessKey Secret),用于操作阿里云 DNS 服务。获取阿里云访问密钥(AccessKey ID 和 AccessKey Secret)请参考官方文档:https://help.aliyun.com/zh/acr/create-and-obtain-an-accesskey-pair

环境

  • 系统: centos7
  • 域名: 阿里云购买的域名
  • python
  • nginx 提供反向代理

安装 aliyun cli 工具 ​

sh

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 的帮助信息,包含可用的命令和选项

    示例输出如下:

    详细信息

    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 进行配置,使其能够访问你的阿里云账户。可以使用以下命令进行配置:

    sh

    aliyun configure set  --profile AkProfile --mode AK  --access-key-id 替换为你自己的真实 AccessKey ID --access-key-secret 替换为你自己的真实 AccessKey Secret   --region 替换为你希望使用的阿里云地域的 ID

    示例命令 ​

    sh

    aliyun 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 ..............

验证配置 ​

配置完成后,你可以使用以下命令来验证配置是否生效:

输出:

sh

[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 插件 ​

sh

#下载、部署并配置一个名为 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

申请证书 ​

测试是否能正确申请:

sh

certbot certonly -d *.seasir.top --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run

sh

#输出
[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 参数:

sh

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 参数:

证书续期 ​

sh

certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean" --dry-run

如果以上命令没有错误,把 --dry-run 参数去掉。

sh

certbot renew --manual --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"

检查证书状态 ​

运行以下命令查看证书的到期时间:

自动续期 ​

添加定时任务 crontab。

然后添加以下配置:

sh

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 没有日志输出,可能是以下原因: 权限问题:确保日志文件可写:

sh

sudo touch /var/log/certbot-renew.log
sudo chmod 644 /var/log/certbot-renew.log

cron 任务未执行:检查 cron 日志:

sh

grep CRON /var/log/syslog

2.证书未到期

如果证书未到期,Certbot 会跳过续期。可以通过以下命令强制续期:

sh

certbot renew --force-renewal --preferred-challenges dns --manual-auth-hook "alidns" --manual-cleanup-hook "alidns clean"

通过 Certbot 和阿里云 DNS 的集成,我们可以轻松实现 SSL 证书的自动续期。只需设置一次 cron 任务,Certbot 就会在证书到期前自动续期,并调用 alidns 脚本处理 DNS 挑战。