目录

基于ALinux3的Let’s Encrypt,实现泛域名配置并自动续订

之前的时候因为阿里云证书的有效期变短,证书方面改为Let’s Encrypt。近期因为要迁移服务器,操作系统也换了,一些服务需要调整,关于Let’s Encrypt的部署顺带记录一下。

1. Certbot插件安装

1.1 启用 EPEL 仓库:

EPEL (Extra Packages for Enterprise Linux) 仓库提供了 certbot 软件包。首先需要安装并启用它。

1
sudo dnf install -y epel-release

1.2 安装pip3

1
2
# 1. 先安装 pip3
sudo yum install -y python3-pip

由于本人的新服务器是ALinux,自带了python3和pip3,跳过上述步骤。

1.3 安装第三方插件

Let’s Encrypt 官方 certbot 项目没有为阿里云DNS提供官方的插件,所以选择安装第三方插件certbot-dns-aliyun

1
2
# 1. 使用 pip 安装第三方开发的阿里云DNS插件
sudo pip3 install certbot-dns-aliyun

安装第三方插件的时候报错

1
2
3
4
5
6
7
pip3 install certbot-dns-aliyun
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting certbot-dns-aliyun
  Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/b3/b0/aed9384ee7f0850218ccd2ea9ad2b9993cb6216b5faa242555681799123a/certbot_dns_aliyun-2.0.0-py2.py3-none-any.whl
Collecting acme>=2.0.0 (from certbot-dns-aliyun)
  Could not find a version that satisfies the requirement acme>=2.0.0 (from certbot-dns-aliyun) (from versions: 0.0.0.dev20151006, 0.0.0.dev20151008, 0.0.0.dev20151017, 0.0.0.dev20151020, 0.0.0.dev20151021, 0.0.0.dev20151024, 0.0.0.dev20151030, 0.0.0.dev20151104, 0.0.0.dev20151107, 0.0.0.dev20151108, 0.0.0.dev20151114, 0.0.0.dev20151123, 0.0.0.dev20151201, 0.1.0, 0.1.1, 0.2.0, 0.3.0, 0.4.0, 0.4.1, 0.4.2, 0.5.0, 0.6.0, 0.7.0, 0.8.0, 0.8.1, 0.9.0, 0.9.1, 0.9.2, 0.9.3, 0.10.0, 0.10.1, 0.10.2, 0.11.0, 0.11.1, 0.12.0, 0.13.0, 0.14.0, 0.14.1, 0.14.2, 0.15.0, 0.16.0, 0.17.0, 0.18.0, 0.18.1, 0.18.2, 0.19.0, 0.20.0, 0.21.0, 0.21.1, 0.22.0, 0.22.1, 0.22.2, 0.23.0, 0.24.0, 0.25.0, 0.25.1, 0.26.0, 0.26.1, 0.27.0, 0.27.1, 0.28.0, 0.29.0, 0.29.1, 0.30.0, 0.30.1, 0.30.2, 0.31.0, 0.32.0, 0.33.0, 0.33.1, 0.34.0, 0.34.1, 0.34.2, 0.35.0, 0.35.1, 0.36.0, 0.37.0, 0.37.1, 0.37.2, 0.38.0, 0.39.0, 0.40.0, 0.40.1, 1.0.0, 1.1.0, 1.2.0, 1.3.0, 1.4.0, 1.5.0, 1.6.0, 1.7.0, 1.8.0, 1.9.0, 1.10.0, 1.10.1, 1.11.0, 1.12.0, 1.13.0, 1.14.0, 1.15.0, 1.16.0, 1.17.0, 1.18.0, 1.19.0, 1.20.0, 1.21.0, 1.22.0, 1.23.0)
No matching distribution found for acme>=2.0.0 (from certbot-dns-aliyun)

查了一下pip3的版本,是9.0.3版本,太旧了,进行更新后正常安装

1
2
3
4
5
6
7
8
9
pip3 -V
pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
pip3 install --upgrade pip
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting pip
  Downloading http://mirrors.cloud.aliyuncs.com/pypi/packages/a4/6d/6463d49a933f547439d6b5b98b46af8742cc03ae83543e4d7688c2420f8b/pip-21.3.1-py3-none-any.whl (1.7MB)
    100% |████████████████████████████████| 1.7MB 23.5MB/s 
Installing collected packages: pip
Successfully installed pip-21.3.1

2. 获取阿里云API凭证

2.1 登录阿里云控制台

2.2 创建凭证文件

创建一个配置文件(例如 aliyun.ini)来安全存储这些信息。

1
2
sudo mkdir -p /etc/letsencrypt/secrets
sudo vim /etc/letsencrypt/secrets/aliyun.ini

文件内容如下,替换为你自己的密钥:

1
2
3
# 阿里云 API 凭据
dns_aliyun_access_key = YOUR_AccessKey_ID
dns_aliyun_access_key_secret = YOUR_AccessKey_Secret

2.3 设置严格的文件权限

1
sudo chmod 600 /etc/letsencrypt/secrets/aliyun.ini

3. 生成证书

3.1 使用第三方阿里云DNS插件执行命令

1
2
3
4
5
6
sudo certbot certonly \
  --authenticator dns-aliyun \
  --dns-aliyun-credentials /etc/letsencrypt/secrets/aliyun.ini \
  -d "*.example.com" \
  -d example.com \
  --server https://acme-v02.api.letsencrypt.org/directory
  • –authenticator dns-aliyun: 指定使用 dns-aliyun 这个认证器。
  • –dns-aliyun-credentials: 指向你刚创建的阿里云API凭证文件。

执行此命令后:
a. Certbot 会暂停,并在终端显示一条提示,要求你在域名 _acme-challenge.example.com 下添加一条特定的 TXT 记录。

b. 不要立即按回车! 你需要打开阿里云DNS控制台,手动添加这条TXT记录。

c. 等待DNS记录传播(通常几十秒,可以使用 dig -t TXT _acme-challenge.example.com @8.8.8.8 命令检查是否生效)。

d. DNS记录生效后,返回终端按回车键,Certbot 会继续完成验证并颁发证书。

e. 注意:此方式无法自动续订,因为续订时仍需手动操作此过程。

3.2 注意事项

  • 如果是第一次使用Let’s Encrypt,会要求你输入邮箱进行注册,输入完按回车,后续根据提示接着按回车即可。
1
2
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel):you-mail@example.com
  • 如果你使用的是 –authenticator dns-aliyun(或其他 DNS 插件)并提供了正确的 API 凭证时,可能不会出现要求你在域名 _acme-challenge.example.com 下添加一条特定的 TXT 记录的操作。而是直接等个几十秒就会成功生成证书。
1
2
3
Waiting 30 seconds for DNS changes to propagate

Successfully received certificate. 

4. 配置 Web 服务器(以 Nginx 为例)

Alibaba Cloud Linux 上的 Nginx 配置与其他 Linux 发行版完全相同。

4.1 编辑 Nginx 配置文件

1
2
3
sudo vim /etc/nginx/nginx.conf
# 或者更常见的,编辑在 /etc/nginx/conf.d/ 目录下的自定义配置文件
sudo vim /etc/nginx/conf.d/your-website.conf

4.2 在 server 块中指定证书路径

1
2
3
4
5
6
7
8
9
server {
    listen 443 ssl;
    server_name your-site.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # ... 其他配置 ...
}

4.3 检查配置并重新加载 Nginx

1
2
sudo nginx -t
sudo systemctl reload nginx

4.4 配置泛域名证书

对于使用泛域名证书的 Nginx 配置,server_name 可以有两种设置方式,适用于不同场景:

  • 为每个子域名创建独立的 server 块(推荐、更清晰):server_name 填写具体的子域名(如 blog.example.com)。
    示例:/etc/nginx/conf.d/blog.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
server {
    listen 443 ssl http2;
    # 这里写具体的子域名
    server_name blog.example.com; 

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/blog;
    index index.html;

    # 其他特定于博客的配置...
}

示例:/etc/nginx/conf.d/api.conf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
server {
    listen 443 ssl http2;
    # 这里写具体的子域名
    server_name api.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 反向代理到本地的应用服务器
    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
  • 创建一个捕获所有子域名的 server 块:server_name 使用通配符(如 *.example.com)。

你的泛域名证书(*.example.com)在这两种配置方式下都能正常工作。

4.5 80端口和443端口的配置

那么配置了https的443端口后,还需要配置80端口么?
需要,而且非常重要。 配置 443 端口(HTTPS)后,你必须也要配置 80 端口(HTTP),但这不是为了提供内容,而是为了以下两个关键目的:

a. HTTP 到 HTTPS 的重定向(最主要、最推荐的做法) 这是现代网站的最佳实践。当用户通过 http://example.com(明文传输,不安全)访问你的网站时,你需要自动将他们永久重定向到安全的 https://example.com 地址。

这能确保:

  • 用户体验:用户无论输入哪个地址,最终都会到达安全的 HTTPS 版本。

  • SEO 优化:搜索引擎(如 Google)会将 HTTPS 视为排名信号,并会将被重定向的 HTTP 页面的权重传递给 HTTPS 版本。

  • 安全性:避免用户在不安全的连接上传输任何数据。

Nginx 配置示例(/etc/nginx/conf.d/redirect.conf):

1
2
3
4
5
6
# 这个文件专门处理所有到80端口的请求,并将它们重定向到HTTPS
server {
    listen 80;
    server_name example.com *.example.com;
    return 301 https://$host$request_uri;
}

HTTPS 主配置 (例如:/etc/nginx/conf.d/blog.conf)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 这个文件处理具体子域名的HTTPS请求
server {
    listen 443 ssl http2;
    server_name blog.example.com;

    # SSL 证书配置
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # 网站根目录和其他具体配置
    root /var/www/blog;
    index index.html;
    # ... 其他location规则等 ...
}

b. 用于 Certbot 的 HTTP-01 挑战续订证书

虽然你这次使用 DNS-01 挑战方式申请了证书,但 Certbot 的自动续订机制 (certbot renew) 在某些情况下可能会回退或需要使用 HTTP-01 挑战方式。如果 80 端口完全关闭,续订过程有可能失败。

保持 80 端口开放并配置好重定向,可以确保证书的自动续订在任何情况下都能顺利进行,保证你的网站长期可用。

5. 配置自动续订

5.1 测试自动续订

1
sudo certbot renew --dry-run

如果测试成功,说明自动化配置正确。

5.2 设置续订后钩子

为了让 Nginx 在证书续订后自动重新加载新证书,我们需要修改续订配置文件。 找到你的域名配置文件(/etc/letsencrypt/renewal/example.com.conf)并确保包含类似内容,或者更简单的方法是直接在命令行中安装证书时添加钩子,但也可以手动编辑: 你可以直接在 certbot renew 的钩子目录中创建脚本,或者更简单的方法是在 renewal 配置文件中添加 post_hook:

1
2
3
[renewalparams]
...
post_hook = systemctl reload nginx

5.3 Certbot 已自动创建定时任务

安装 certbot 后,它会自动创建一个 systemd timer 或 cron 作业(通常位于 /etc/cron.d/certbot),每天运行两次 certbot renew 命令。你无需手动设置。

5.4 定时任务不存在或没自动创建

对于基于 Systemd 的系统(包括 Alibaba Cloud Linux),Certbot 更倾向于使用 systemd timer 而不是 cron job。

直接查看 timer 单元

1
sudo systemctl status certbot.timer

如果 timer 存在且激活,你应该看到类似这样的输出:

1
2
3
4
5
● certbot.timer - Run certbot twice daily
     Loaded: loaded (/usr/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Tue 2023-08-15 10:43:22 CST; 1 weeks 0 days ago
    Trigger: Wed 2023-08-23 06:32:51 CST; 8h left
   Triggers: ● certbot.service

这表示系统有一个 timer,会定期触发 certbot.service 来执行续订任务。

虽然可能性较小,但还是检查一下所有常见的 cron 目录:

1
2
3
4
5
6
7
8
# 检查系统级的cron目录
sudo ls -la /etc/cron.d/ | grep -i certbot
sudo ls -la /etc/cron.daily/ | grep -i certbot
sudo ls -la /etc/cron.weekly/ | grep -i certbot
sudo ls -la /etc/cron.monthly/ | grep -i certbot

# 检查root用户的crontab
sudo crontab -l | grep -i certbot

如果都没找到的话,自行手动创建定时任务,以cron为例子:

1
2
# 每天凌晨0点和中午12点随机时间运行,检查并续订证书
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew --quiet --post-hook "systemctl reload nginx"

6. 其它事项

6.1 证书不被信任

生成的证书是泛域名的,访问主域名提示证书不被信任,通常不是证书本身的问题,而是配置或访问方式的问题。

6.1.1 排查步骤

a. 检查证书详情

  • 在 Chrome/Firefox 中,点击锁图标 -> “连接是安全的” -> “证书有效”。

  • 检查颁发给 (Issued To): 这里应该显示 *.example.com 或 example.com。

  • 检查颁发者 (Issued By): 这里应该显示 Let’s Encrypt 或 R3。

  • 检查有效期: 确认证书在有效期内。

  • 检查证书层次: 确保你看到的是一个完整的证书链,而不是只有叶子证书。

如果这里显示的不是你的域名或颁发者不对,说明 Nginx 配置指向了错误的证书。

b. 使用 SSL 检测工具

在线工具能给出更专业的诊断。

  • SSLLabs Test:访问 https://www.ssllabs.com/ssltest/,输入你的主域名(如 example.com)进行分析。它会详细告诉你证书、协议、套件等所有信息,并明确指出证书问题所在。

  • 命令行检查:在服务器上或本地使用 OpenSSL 命令检查:

1
openssl s_client -connect example.com:443 -servername example.com

在输出中寻找 Verify return code: 0 (ok)。如果返回其他错误代码,会指明问题方向。

6.1.1 常见原因

  • Nginx 配置错误(最常见),配置nginx的时候ssl_certificatessl_certificate_key地址不对。
  • 证书链不完整,确保你使用的是 fullchain.pem,而不是 cert.pem。前者包含了你的网站证书 + 中间证书(Let’s Encrypt R3)。这是必须使用的文件。
  • 浏览器或系统缓存了旧证书,这个最坑爹,可尝试清理浏览器历史记录、使用隐私/无痕模式测试访问(这可以排除大部分扩展和缓存的影响)、重启浏览器甚至重启电脑、换其它电脑等操作进行尝试。
  • 服务器时间不同步,如果你的服务器系统时间错误(比实际时间慢很多),浏览器会认为证书尚未生效,从而拒绝信任。