7.5.2 证书申请与自动续期实践

本节聚焦证书申请与自动续期的实操流程,覆盖域名准备、申请、部署、续期与故障排查,确保 HTTPS 证书持续可用。

原理草图:ACME 申请与续期流程#

文章图片

证书类型与申请方式#

  • 商业证书(DV/OV/EV):适合对品牌可信度要求较高的场景,通常需人工审核。
  • ACME 证书(如 Let’s Encrypt):免费、自动化程度高。
  • 自签名证书:仅用于内网测试或开发环境。

常见验证方式:
- HTTP-01:依赖 80 端口可访问。
- DNS-01:适合通配符证书或无法开放 80 端口场景。
- TLS-ALPN-01:使用 443 端口进行验证。

安装与准备(以 Ubuntu/CentOS 为例)#

安装 certbot#

# Ubuntu
sudo apt update
sudo apt install -y certbot

# CentOS/RHEL
sudo yum install -y epel-release
sudo yum install -y certbot

安装 acme.sh(可选)#

curl https://get.acme.sh | sh
source ~/.bashrc

域名与端口检查#

# 域名解析是否生效
dig +short example.com

# 80端口是否开放
sudo ss -lntp | grep ':80'

基于 certbot 的 HTTP-01 申请与部署示例#

Nginx 站点配置(预置校验目录)#

# /etc/nginx/conf.d/example.com.conf
server {
    listen 80;
    server_name example.com;

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}
# 创建校验目录
sudo mkdir -p /var/www/letsencrypt
sudo nginx -t && sudo systemctl reload nginx

申请证书#

sudo certbot certonly \
  --webroot -w /var/www/letsencrypt \
  -d example.com -d www.example.com \
  --email admin@example.com --agree-tos --no-eff-email

证书生成路径:
- /etc/letsencrypt/live/example.com/fullchain.pem
- /etc/letsencrypt/live/example.com/privkey.pem

HTTPS 部署配置#

# /etc/nginx/conf.d/example.com-https.conf
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

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

    location / {
        root /var/www/html;
        index index.html;
    }
}
sudo nginx -t
sudo systemctl reload nginx

命令解释#

  • certonly:仅申请证书,不修改 Nginx 配置。
  • --webroot -w:指定校验文件写入目录。
  • -d:绑定域名,可多次指定多域名。
  • --agree-tos:自动同意服务条款。

基于 acme.sh 的 DNS-01 通配符示例(以 Cloudflare 为例)#

# 设置API密钥(示例变量名,按DNS服务商文档调整)
export CF_Token="your_cloudflare_token"
export CF_Account_ID="your_account_id"

# 申请通配符证书
acme.sh --issue --dns dns_cf -d example.com -d "*.example.com"

# 安装证书到指定路径
sudo acme.sh --install-cert -d example.com \
  --key-file       /etc/ssl/example.com/privkey.pem \
  --fullchain-file /etc/ssl/example.com/fullchain.pem \
  --reloadcmd     "systemctl reload nginx"

自动续期实践#

certbot 定时任务(cron)#

# /etc/cron.d/certbot-renew
0 3 * * * root certbot renew --quiet --deploy-hook "systemctl reload nginx"

acme.sh 定时任务(systemd timer 示例)#

# /etc/systemd/system/acme-renew.service
[Unit]
Description=Acme.sh renew

[Service]
Type=oneshot
ExecStart=/root/.acme.sh/acme.sh --renew-all --quiet --reloadcmd "systemctl reload nginx"
# /etc/systemd/system/acme-renew.timer
[Unit]
Description=Acme.sh renew timer

[Timer]
OnCalendar=03:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now acme-renew.timer

续期脚本(仅更新时 reload)#

#!/bin/bash
# /usr/local/bin/renew_cert.sh
set -e
LOG=/var/log/renew_cert.log

certbot renew --quiet --deploy-hook "systemctl reload nginx" >> "$LOG" 2>&1
sudo chmod +x /usr/local/bin/renew_cert.sh

权限与安全管理#

# 证书私钥权限
sudo chmod 600 /etc/letsencrypt/live/example.com/privkey.pem
sudo chown root:root /etc/letsencrypt/live/example.com/privkey.pem

# 证书目录限制访问
sudo chmod 700 /etc/letsencrypt/live

常见问题与排查#

1. 验证失败(HTTP-01)#

# 检查校验文件是否可访问
curl -I http://example.com/.well-known/acme-challenge/test

# 查看 Nginx 访问日志
tail -n 50 /var/log/nginx/access.log

2. 证书未生效#

# 确认证书是否更新
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -dates

# 确认 Nginx 是否加载新证书
sudo nginx -T | grep -A2 ssl_certificate

3. 证书链不完整#

确保 Nginx 配置使用 fullchain.pem 而非 cert.pem

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

练习#

  1. 使用 certbot 申请一个包含 example.comwww.example.com 的证书,并部署到 Nginx。
  2. 改用 acme.sh 申请 *.example.com 通配符证书,比较 DNS-01 与 HTTP-01 的差异。
  3. 编写一个续期脚本,在证书更新时记录日志并 reload Nginx。验证日志内容与更新时间。