SSL 证书自动化系统架构文档

SSL 证书自动化系统架构文档

📋 目录

  • [1. 系统概述](#1. 系统概述)
  • [2. 架构设计](#2. 架构设计)
  • [3. 核心脚本说明](#3. 核心脚本说明)
  • [4. 技术实现细节](#4. 技术实现细节)
  • [5. 部署流程](#5. 部署流程)
  • [6. 配置说明](#6. 配置说明)
  • [7. 使用示例](#7. 使用示例)
  • [8. 工作流程](#8. 工作流程)
  • [9. 故障处理](#9. 故障处理)
  • [10. 最佳实践](#10. 最佳实践)
  • [11. 安全建议](#11. 安全建议)
  • [12. 监控和维护](#12. 监控和维护)

1. 系统概述

1.1 目标

构建一个完整的 SSL 证书自动化管理系统,实现:

  • ✅ 自动申请 Let's Encrypt SSL 证书
  • ✅ 自动配置 Nginx SSL
  • ✅ 自动续签即将过期的证书
  • ✅ 支持单域名、多域名和通配符证书
  • ✅ 完善的监控和告警机制
  • ✅ 详细的日志记录

1.2 技术栈

组件 技术选型 说明
证书颁发机构 Let's Encrypt 免费的 SSL/TLS 证书
证书客户端 Certbot 官方推荐的 Let's Encrypt 客户端
Web 服务器 Nginx 反向代理和 SSL 终止
Web 服务器 Apache 可选的 Web 服务器支持
DNS 提供商 阿里云/腾讯云/Cloudflare 用于通配符证书的 DNS 验证
定时任务 Cron 自动续签的定时任务
日志系统 Syslog + 独立日志文件 详细的操作日志

1.3 支持的场景

场景 验证方式 适用性
单域名证书 HTTP-01 ✅ 推荐,最简单
多域名证书 (SAN) HTTP-01 ✅ 推荐,支持多个域名
通配符证书 DNS-01 ✅ 推荐,支持所有子域名
内网域名 DNS-01 ⚠️ 需要外部 DNS
动态 IP DNS-01 ✅ 推荐

2. 架构设计

2.1 系统架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    SSL 自动化管理系统                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────┐      ┌──────────────┐      ┌──────────┐ │
│  │ ssl-apply.sh │──────▶│   Certbot    │──────▶│  Let's   │ │
│  │  证书申请     │      │  证书客户端   │      │ Encrypt  │ │
│  └──────────────┘      └──────────────┘      └──────────┘ │
│         │                                           │       │
│         │                                           ▼       │
│         │                                   ┌──────────┐   │
│         │                                   │ 证书文件  │   │
│         │                                   └──────────┘   │
│         │                                           │       │
│         ▼                                           ▼       │
│  ┌──────────────┐                          ┌──────────────┐│
│  │ ssl-renew.sh │◀─────────────────────────│  Nginx SSL   ││
│  │  证书续签     │                          │  配置自动化  ││
│  └──────────────┘                          └──────────────┘│
│         │                                           │       │
│         │                                           │       │
│         ▼                                           ▼       │
│  ┌──────────────┐                          ┌──────────────┐│
│  │ssl-wildcard  │                          │  HTTP/HTTPS  ││
│  │通配符证书     │                          │  自动重定向   ││
│  └──────────────┘                          └──────────────┘│
│         │                                           │       │
│         ▼                                           ▼       │
│  ┌──────────────┐                          ┌──────────────┐│
│  │ ssl-info.sh  │                          │  HTTPS 访问  ││
│  │ 证书信息查询  │                          │   (443)     ││
│  └──────────────┘                          └──────────────┘│
│                                                              │
└─────────────────────────────────────────────────────────────┘

2.2 目录结构

复制代码
deploy/
├── ssl-apply.sh          # SSL 证书申请脚本
├── ssl-renew.sh          # SSL 证书续签脚本
├── ssl-wildcard.sh       # 通配符证书申请脚本
├── ssl-info.sh           # 证书信息查询脚本
├── ssl-config.sh         # SSL 配置文件
└── ssl-README.md         # SSL 使用文档

/etc/letsencrypt/         # Let's Encrypt 根目录
├── live/                 # 活跃证书(符号链接)
│   └── example.com/
│       ├── cert.pem      # 服务器证书
│       ├── chain.pem     # 中间证书
│       ├── fullchain.pem # 完整证书链
│       └── privkey.pem   # 私钥
├── archive/              # 证书归档
└── renewal/              # 续签配置

/etc/nginx/
├── sites-available/      # 可用站点配置
│   └── example.com-ssl.conf
└── sites-enabled/        # 启用站点配置(符号链接)
    └── example.com-ssl.conf -> ../sites-available/example.com-ssl.conf

/var/log/
├── ssl-automation/       # SSL 自动化日志
│   ├── apply.log         # 申请日志
│   ├── renew.log         # 续签日志
│   └── error.log         # 错误日志
└── nginx/                # Nginx 日志
    ├── example.com-access.log
    └── example.com-error.log

2.3 数据流程图

复制代码
用户请求
   │
   ▼
HTTP (80) ────────────────────┐
   │                         │
   ▼                         │
Nginx                        │
   │                         │
   ├── /.well-known/ ────────▶ Let's Encrypt 验证
   │   /acme-challenge/            (HTTP-01)
   │
   └── 其他请求 ───────────────▶ 重定向到 HTTPS
                                   (301)
                                        │
                                        ▼
                                HTTPS (443)
                                        │
                                        ▼
                                    Nginx
                                        │
                                        ▼
                                    反向代理
                                        │
                                        ▼
                                    应用服务

3. 核心脚本说明

3.1 ssl-apply.sh - 证书申请脚本

功能描述:

  • 自动检测和安装 Certbot
  • 检查 DNS 解析和端口占用
  • 申请 Let's Encrypt SSL 证书
  • 自动配置 Nginx SSL
  • 配置 HTTP 到 HTTPS 重定向
  • 开放防火墙端口

输入参数:

bash 复制代码
./ssl-apply.sh [domain] [email]
参数 说明 示例 必填
domain 域名(支持多域名,逗号分隔) example.com,www.example.com
email 证书续签提醒邮箱 admin@example.com ❌ (默认: admin@domain)

主要流程:

复制代码
开始
  │
  ├─▶ 检查 root 权限
  │
  ├─▶ 检查参数完整性
  │
  ├─▶ 检查 Certbot 安装状态 ──▶ 未安装则安装
  │
  ├─▶ 检查 DNS 解析
  │
  ├─▶ 检查端口 80/443
  │
  ├─▶ 检查 Nginx 安装状态 ──▶ 未安装则询问是否安装
  │
  ├─▶ 检查防火墙 ──▶ 开放 80/443 端口
  │
  ├─▶ 申请 SSL 证书
  │
  ├─▶ 配置 Nginx SSL
  │
  ├─▶ 测试 Nginx 配置
  │
  ├─▶ 重载 Nginx
  │
  └─▶ 显示证书信息

支持的验证方式:

  • HTTP-01: 通过 Web 服务器验证(默认)
  • Standalone: 临时启动独立服务器验证

输出示例:

bash 复制代码
$ sudo ./ssl-apply.sh example.com admin@example.com

╔════════════════════════════════════════════════════════════╗
║           SSL 证书自动申请脚本                            ║
║           Let's Encrypt Certificate Automation             ║
╚════════════════════════════════════════════════════════════╝

[INFO] 域名: example.com
[INFO] 邮箱: admin@example.com
[SUCCESS] Certbot 已安装
[SUCCESS] DNS 解析正确: example.com -> 1.2.3.4
[SUCCESS] 80 端口正在监听
[INFO] 开始申请 SSL 证书...
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
[SUCCESS] SSL 证书申请成功!
[SUCCESS] Nginx SSL 配置文件已创建
[SUCCESS] Nginx 配置测试通过
[SUCCESS] Nginx 已重新加载

3.2 ssl-renew.sh - 证书续签脚本

功能描述:

  • 自动检查所有证书的有效期
  • 自动续签即将过期的证书
  • 续签后自动重载 Nginx
  • 续签失败时发送邮件通知
  • 支持测试模式(dry-run)
  • 设置自动续签的 Cron 任务

输入参数:

bash 复制代码
./ssl-renew.sh [domain] [--dry-run] [--setup] [--email]
参数 说明 示例 必填
domain 指定域名(不指定则续签所有) example.com
--dry-run 测试模式,不实际续签 --dry-run
--setup 设置 Cron 定时任务 --setup
--email 发送续签通知邮件 --email admin@example.com

主要流程:

复制代码
开始
  │
  ├─▶ 检查 root 权限
  │
  ├─▶ 检查 Certbot 安装状态
  │
  ├─▶ 检查是否为测试模式
  │   ├── 是 ──▶ 运行 certbot renew --dry-run
  │   └── 否 ──▶ 继续执行续签
  │
  ├─▶ 检查证书有效期
  │   ├── 所有证书都有效 ──▶ 退出
  │   └── 存在即将过期证书 ──▶ 继续
  │
  ├─▶ 执行证书续签
  │
  ├─▶ 检查续签结果
  │   ├── 成功 ──▶ 重载 Nginx
  │   └── 失败 ──▶ 记录错误 + 发送邮件通知
  │
  └─▶ 记录续签日志

自动续签策略:

  • Certbot 默认在证书有效期少于 30 天时才续签
  • 建议设置每日检查一次(凌晨 3 点)
  • 续签失败会保留旧证书,不影响服务

Cron 配置示例:

bash 复制代码
# 每天凌晨 3 点检查续签
0 3 * * * /path/to/deploy/ssl-renew.sh >> /var/log/ssl-automation/renew.log 2>&1

# 或每周一凌晨 2 点检查续签
0 2 * * 1 /path/to/deploy/ssl-renew.sh >> /var/log/ssl-automation/renew.log 2>&1

输出示例:

bash 复制代码
$ sudo ./ssl-renew.sh

[INFO] 开始检查证书续签...
[INFO] 检查到 2 个证书
[INFO] example.com - 剩余 89 天(无需续签)
[WARN] old-domain.com - 剩余 25 天(即将过期)
[INFO] 开始续签证书...
Processing /etc/letsencrypt/renewal/old-domain.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/old-domain.com/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[SUCCESS] 证书续签成功
[INFO] 重新加载 Nginx...
[SUCCESS] Nginx 已重新加载

3.3 ssl-wildcard.sh - 通配符证书申请脚本

功能描述:

  • 申请通配符证书(*.example.com
  • 支持 DNS-01 验证
  • 支持多个 DNS 提供商(阿里云、腾讯云、Cloudflare)
  • 自动添加和删除 DNS TXT 记录
  • 自动配置 Nginx

输入参数:

bash 复制代码
./ssl-wildcard.sh [domain] [email] [--dns-provider provider] [--api-key key] [--secret-key key]
参数 说明 示例 必填
domain 域名 example.com
email 证书续签提醒邮箱 admin@example.com
--dns-provider DNS 提供商 aliyun, tencent, cloudflare ❌ (默认: aliyun)
--api-key API 访问密钥 your-api-key ✅ (DNS 验证需要)
--secret-key API 密钥(部分服务商需要) your-secret-key

支持的 DNS 提供商:

提供商 参数说明 获取地址
阿里云 --api-key AccessKeyID, --secret-key AccessKeySecret 访问控制台
腾讯云 --api-key SecretId, --secret-key SecretKey 访问控制台
Cloudflare --api-key API Token API Token

主要流程:

复制代码
开始
  │
  ├─▶ 检查 root 权限
  │
  ├─▶ 检查参数完整性
  │
  ├─▶ 检查 DNS 提供商 API 凭证
  │
  ├─▶ 生成 DNS 验证用的 TXT 记录
  │
  ├─▶ 调用 DNS API 添加 TXT 记录
  │
  ├─▶ 等待 DNS 生效(最多 60 秒)
  │
  ├─▶ 执行证书申请
  │
  ├─▶ 检查申请结果
  │   ├── 成功 ──▶ 继续
  │   └── 失败 ──▶ 清理 DNS TXT 记录并退出
  │
  ├─▶ 配置 Nginx SSL
  │
  ├─▶ 删除 DNS TXT 记录
  │
  └─▶ 显示证书信息

DNS 记录示例:

bash 复制代码
# Certbot 会生成类似这样的记录
_acme-challenge.example.com.  IN  TXT  "xxxxxxxxxxxxxxxxxxxxx"

# 阿里云 API 添加记录示例
aliyun dns add RecordType=TXT \
                  DomainName=example.com \
                  RR=_acme-challenge \
                  Value=xxxxxxxxxxxxxxxxxxxxx

输出示例:

bash 复制代码
$ sudo ./ssl-wildcard.sh example.com admin@example.com --dns-provider aliyun --api-key LTAIxxxx --secret-key xxxxxx

[INFO] 域名: example.com
[INFO] 邮箱: admin@example.com
[INFO] DNS 提供商: aliyun
[INFO] 开始申请通配符证书...
[INFO] 生成 DNS 验证记录...
[INFO] DNS 记录: _acme-challenge.example.com -> xxxxxxxxxxxxxxxxxxxxx
[INFO] 添加 DNS TXT 记录...
[SUCCESS] DNS 记录已添加
[INFO] 等待 DNS 生效...
[INFO] DNS 已生效(耗时 5 秒)
[INFO] 申请证书...
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
[SUCCESS] 通配符证书申请成功!
[SUCCESS] 清理 DNS TXT 记录...
[SUCCESS] DNS 记录已删除

3.4 ssl-info.sh - 证书信息查询脚本

功能描述:

  • 查看所有已安装的证书
  • 查看指定域名的证书详情
  • 检查证书是否即将过期
  • 显示证书的到期时间
  • 导出证书信息

输入参数:

bash 复制代码
./ssl-info.sh [domain] [--check-expiry] [--export format] [--output file]
参数 说明 示例 必填
domain 指定域名 example.com
--check-expiry 检查即将过期证书(30天内) --check-expiry
--export 导出格式(json, csv) --export json
--output 输出文件 --output /path/to/file.json

主要流程:

复制代码
开始
  │
  ├─▶ 检查 root 权限
  │
  ├─▶ 检查是否有指定域名
  │   ├── 有 ──▶ 显示该域名证书信息
  │   └── 无 ──▶ 显示所有证书列表
  │
  ├─▶ 检查是否启用到期检查
  │   ├── 是 ──▶ 检查并显示即将过期的证书
  │   └── 否 ──▶ 跳过
  │
  ├─▶ 检查是否需要导出
  │   ├── 是 ──▶ 导出证书信息到文件
  │   └── 否 ──▶ 显示到终端
  │
  └─▶ 完成

证书信息输出格式:

bash 复制代码
$ sudo ./ssl-info.sh example.com

╔════════════════════════════════════════════════════════════╗
║                    SSL 证书信息                            ║
╚════════════════════════════════════════════════════════════╝

域名: example.com
证书状态: 有效
颁发机构: Let's Encrypt
颁发日期: 2025-01-12 00:00:00 UTC
到期日期: 2025-04-12 00:00:00 UTC
剩余天数: 90 天

证书文件:
  - 证书文件: /etc/letsencrypt/live/example.com/fullchain.pem
  - 私钥文件: /etc/letsencrypt/live/example.com/privkey.pem
  - 证书链:   /etc/letsencrypt/live/example.com/chain.pem

Nginx 配置:
  - 配置文件: /etc/nginx/sites-available/example.com-ssl.conf

导出 JSON 格式示例:

bash 复制代码
$ sudo ./ssl-info.sh --export json --output certs.json

{
  "certificates": [
    {
      "domain": "example.com",
      "status": "valid",
      "issuer": "Let's Encrypt",
      "issued_date": "2025-01-12T00:00:00Z",
      "expiry_date": "2025-04-12T00:00:00Z",
      "days_remaining": 90,
      "cert_path": "/etc/letsencrypt/live/example.com/fullchain.pem",
      "key_path": "/etc/letsencrypt/live/example.com/privkey.pem"
    }
  ]
}

4. 技术实现细节

4.1 Certbot 核心命令

证书申请

HTTP-01 验证(推荐,最简单):

bash 复制代码
# 使用 Nginx 插件自动配置
certbot certonly --nginx \
  --email user@example.com \
  --agree-tos \
  --no-eff-email \
  -d example.com \
  -d www.example.com

# 使用 Webroot 模式(手动指定 Web 根目录)
certbot certonly --webroot \
  --webroot-path /var/www/html \
  --email user@example.com \
  --agree-tos \
  --no-eff-email \
  -d example.com

DNS-01 验证(通配符证书):

bash 复制代码
# 手动模式(需要手动添加 DNS TXT 记录)
certbot certonly --manual \
  --preferred-challenges dns \
  --email user@example.com \
  --agree-tos \
  --no-eff-email \
  -d "*.example.com" \
  -d example.com

# 使用 DNS 插件(需要安装对应插件)
certbot certonly --dns-aliyun \
  --dns-aliyun-credentials /path/to/aliyun.ini \
  --email user@example.com \
  --agree-tos \
  --no-eff-email \
  -d "*.example.com" \
  -d example.com

Standalone 模式(临时独立服务器):

bash 复制代码
certbot certonly --standalone \
  --email user@example.com \
  --agree-tos \
  --no-eff-email \
  -d example.com
证书续签

基本续签:

bash 复制代码
# 续签所有即将过期的证书
certbot renew

# 续签指定证书
certbot renew --cert-name example.com

# 强制续签(即使未到期)
certbot renew --force-renewal

续签后操作:

bash 复制代码
# 续签后重载 Nginx
certbot renew --post-hook "systemctl reload nginx"

# 续签后重启服务
certbot renew --post-hook "systemctl restart nginx"

# 续签后执行自定义脚本
certbot renew --post-hook "/path/to/script.sh"

测试续签:

bash 复制代码
# 模拟续签(不实际续签)
certbot renew --dry-run

# 显示续签过程详细信息
certbot renew --dry-run --force-renewal
证书管理

查看证书信息:

bash 复制代码
# 查看所有证书
certbot certificates

# 查看指定证书
certbot certificates --cert-name example.com

# 删除证书
certbot delete --cert-name example.com

# 撤销证书
certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem

4.2 Nginx SSL 配置详解

完整的 SSL 配置示例
nginx 复制代码
# HTTP - 重定向到 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    # Let's Encrypt 验证路径
    location /.well-known/acme-challenge/ {
        root /var/www/html;
        try_files $uri =404;
    }

    # 其他请求重定向到 HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

# HTTPS - 主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com www.example.com;

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

    # SSL 协议和加密套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # DH 参数(增强安全性)
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    # SSL 会话缓存
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # HSTS (HTTP Strict Transport Security)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 日志配置
    access_log /var/log/nginx/example.com-access.log;
    error_log /var/log/nginx/example.com-error.log;

    # Gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;

    # 客户端上传大小限制
    client_max_body_size 20M;

    # 超时配置
    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 60s;

    # 反向代理配置(后端服务)
    location /api {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 静态文件
    location /static {
        alias /var/www/html/static;
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # 默认代理
    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
生成 DH 参数(推荐)
bash 复制代码
# 生成 2048 位 DH 参数(需要几分钟)
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

# 或生成 4096 位 DH 参数(更安全,需要更长时间)
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 4096

4.3 防火墙配置

UFW (Ubuntu/Debian)
bash 复制代码
# 开放 HTTP 和 HTTPS 端口
ufw allow 80/tcp
ufw allow 443/tcp

# 查看防火墙状态
ufw status

# 重新加载防火墙
ufw reload
firewalld (CentOS/RHEL)
bash 复制代码
# 开放 HTTP 和 HTTPS 端口
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --reload

# 查看开放的端口
firewall-cmd --list-ports
iptables (通用)
bash 复制代码
# 开放 HTTP 和 HTTPS 端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 保存规则
iptables-save > /etc/iptables/rules.v4

4.4 日志系统

日志目录结构
bash 复制代码
/var/log/ssl-automation/
├── apply.log         # 证书申请日志
├── renew.log         # 证书续签日志
└── error.log         # 错误日志

/var/log/nginx/
├── example.com-access.log  # Nginx 访问日志
└── example.com-error.log   # Nginx 错误日志
日志轮转配置

创建 /etc/logrotate.d/ssl-automation:

bash 复制代码
/var/log/ssl-automation/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
    postrotate
        # 重启相关服务(如果需要)
    endscript
}

4.5 邮件通知配置

安装邮件发送工具
bash 复制代码
# Ubuntu/Debian
apt install mailutils

# CentOS/RHEL
yum install mailx
配置邮件发送

在脚本中添加邮件通知功能:

bash 复制代码
# 发送邮件函数
send_email() {
    local subject="$1"
    local body="$2"
    local to="$3"

    echo "$body" | mail -s "$subject" "$to"
}

# 续签失败时发送邮件
if [ $renewal_result -ne 0 ]; then
    send_email "SSL 证书续签失败" "证书续签失败:$domain" "admin@example.com"
fi

5. 部署流程

5.1 首次部署流程



开始首次部署
准备服务器环境
安装必要软件
配置域名 DNS
执行 ssl-apply.sh
申请证书成功?
检查错误并重试
配置 Nginx
设置自动续签
测试访问
完成部署

5.2 详细步骤

步骤 1: 准备服务器环境
bash 复制代码
# 更新系统
apt update && apt upgrade -y  # Ubuntu/Debian
# 或
yum update -y                 # CentOS/RHEL

# 安装基础工具
apt install -y curl wget git vim net-tools  # Ubuntu/Debian
# 或
yum install -y curl wget git vim net-tools  # CentOS/RHEL
步骤 2: 配置域名 DNS
  1. 登录域名服务商(阿里云、腾讯云、Cloudflare 等)
  2. 添加 A 记录,指向服务器公网 IP
  3. 等待 DNS 生效(通常 10-30 分钟)
bash 复制代码
# 检查 DNS 解析
dig +short example.com

# 或使用 nslookup
nslookup example.com

# 或使用 host
host example.com
步骤 3: 安装 Nginx(如果未安装)
bash 复制代码
# Ubuntu/Debian
apt install -y nginx

# CentOS/RHEL
yum install -y nginx

# 启动 Nginx
systemctl start nginx
systemctl enable nginx

# 检查 Nginx 状态
systemctl status nginx
步骤 4: 开放防火墙端口
bash 复制代码
# UFW (Ubuntu/Debian)
ufw allow 80/tcp
ufw allow 443/tcp
ufw reload

# firewalld (CentOS/RHEL)
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --permanent --add-port=443/tcp
firewall-cmd --reload
步骤 5: 申请 SSL 证书
bash 复制代码
# 进入部署脚本目录
cd /path/to/deploy

# 设置脚本执行权限
chmod +x ssl-*.sh

# 申请证书
sudo ./ssl-apply.sh example.com admin@example.com
步骤 6: 设置自动续签
bash 复制代码
# 设置 Cron 定时任务
sudo ./ssl-renew.sh --setup

# 或手动添加到 crontab
sudo crontab -e

# 添加以下内容(每天凌晨 3 点检查续签)
0 3 * * * /path/to/deploy/ssl-renew.sh >> /var/log/ssl-automation/renew.log 2>&1
步骤 7: 测试访问
bash 复制代码
# 检查 HTTP 是否重定向到 HTTPS
curl -I http://example.com

# 检查 HTTPS 是否正常
curl -I https://example.com

# 检查 SSL 证书
openssl s_client -connect example.com:443 -servername example.com

6. 配置说明

6.1 ssl-config.sh 配置文件

所有脚本使用统一的配置文件 ssl-config.sh,方便集中管理。

bash 复制代码
#!/bin/bash

################################################################################
# SSL 自动化系统配置文件
################################################################################

# ===== 基础配置 =====

# 项目根目录
PROJECT_ROOT="/www/wwwroot/nuxt3-wu-code"
DEPLOY_DIR="${PROJECT_ROOT}/deploy"

# 日志目录
LOG_DIR="/var/log/ssl-automation"

# ===== 邮件配置 =====

# 邮件发送地址
NOTIFICATION_EMAIL="admin@example.com"

# 邮件主题前缀
EMAIL_SUBJECT_PREFIX="[SSL Automation]"

# ===== 证书配置 =====

# Let's Encrypt 环境(生产环境:production,测试环境:staging)
LETSENCRYPT_ENV="production"

# 证书续签提前天数(默认 30 天)
RENEWAL_DAYS_BEFORE=30

# 证书有效期提醒天数(默认 15 天)
EXPIRY_WARNING_DAYS=15

# ===== DNS 配置(用于通配符证书) =====

# 默认 DNS 提供商(aliyun, tencent, cloudflare)
DEFAULT_DNS_PROVIDER="aliyun"

# DNS API 凭证目录
DNS_CREDENTIALS_DIR="/etc/letsencrypt/dns-credentials"

# 阿里云配置
ALIYUN_ACCESS_KEY_ID=""
ALIYUN_ACCESS_KEY_SECRET=""

# 腾讯云配置
TENCENT_SECRET_ID=""
TENCENT_SECRET_KEY=""

# Cloudflare 配置
CLOUDFLARE_API_TOKEN=""

# ===== Nginx 配置 =====

# Nginx 配置目录
NGINX_CONF_DIR="/etc/nginx"

# Nginx 站点可用目录
NGINX_SITES_AVAILABLE="${NGINX_CONF_DIR}/sites-available"

# Nginx 站点启用目录
NGINX_SITES_ENABLED="${NGINX_CONF_DIR}/sites-enabled"

# 如果系统使用 conf.d 而不是 sites-available/sites-enabled
NGINX_CONF_D="${NGINX_CONF_DIR}/conf.d"

# Web 根目录(用于 ACME 验证)
WEB_ROOT="/var/www/html"

# ===== 安全配置 =====

# DH 参数文件路径
DH_PARAM_FILE="/etc/nginx/ssl/dhparam.pem"

# DH 参数位数(2048 或 4096)
DH_PARAM_BITS=2048

# 是否启用 HSTS
ENABLE_HSTS=true

# HSTS max-age(秒)
HSTS_MAX_AGE=31536000

# 是否启用 OCSP Stapling
ENABLE_OCSP_STAPLING=true

# ===== 监控配置 =====

# 是否启用证书过期监控
ENABLE_EXPIRY_MONITOR=true

# 监控检查频率(天)
MONITOR_CHECK_INTERVAL=1

# 过期证书通知方式(email, log, both)
EXPIRY_NOTIFY_METHOD="both"

# ===== 备份配置 =====

# 是否启用证书自动备份
ENABLE_CERT_BACKUP=true

# 备份目录
BACKUP_DIR="${PROJECT_ROOT}/backups/ssl"

# 备份保留天数
BACKUP_RETENTION_DAYS=30

# ===== 日志配置 =====

# 日志级别(DEBUG, INFO, WARN, ERROR)
LOG_LEVEL="INFO"

# 日志文件最大大小(MB)
LOG_MAX_SIZE=10

# 日志文件保留数量
LOG_MAX_FILES=10

6.2 修改配置

编辑 ssl-config.sh 文件:

bash 复制代码
# 使用 vim 编辑
vim /path/to/deploy/ssl-config.sh

# 或使用 nano 编辑
nano /path/to/deploy/ssl-config.sh

重要配置项说明:

配置项 说明 默认值 建议值
NOTIFICATION_EMAIL 接收通知的邮箱 admin@example.com 实际管理员邮箱
RENEWAL_DAYS_BEFORE 提前续签天数 30 30
EXPIRY_WARNING_DAYS 过期警告天数 15 15
DEFAULT_DNS_PROVIDER 默认 DNS 提供商 aliyun 根据实际情况
ENABLE_HSTS 是否启用 HSTS true true
DH_PARAM_BITS DH 参数位数 2048 20484096
LOG_LEVEL 日志级别 INFO INFO

6.3 配置验证

修改配置后,可以运行验证脚本:

bash 复制代码
# 创建配置验证脚本
cat > /path/to/deploy/ssl-verify-config.sh << 'EOF'
#!/bin/bash

source /path/to/deploy/ssl-config.sh

echo "验证 SSL 配置..."
echo ""

echo "1. 检查日志目录..."
if [ ! -d "$LOG_DIR" ]; then
    echo "   [WARN] 日志目录不存在: $LOG_DIR"
    mkdir -p "$LOG_DIR"
    echo "   [INFO] 已创建日志目录"
else
    echo "   [OK] 日志目录存在"
fi

echo ""
echo "2. 检查 DNS 凭证目录..."
if [ ! -d "$DNS_CREDENTIALS_DIR" ]; then
    echo "   [WARN] DNS 凭证目录不存在: $DNS_CREDENTIALS_DIR"
    mkdir -p "$DNS_CREDENTIALS_DIR"
    echo "   [INFO] 已创建 DNS 凭证目录"
else
    echo "   [OK] DNS 凭证目录存在"
fi

echo ""
echo "3. 检查 Nginx 配置目录..."
if [ -d "$NGINX_SITES_AVAILABLE" ]; then
    echo "   [OK] Nginx sites-available 目录存在"
elif [ -d "$NGINX_CONF_D" ]; then
    echo "   [OK] Nginx conf.d 目录存在"
else
    echo "   [WARN] Nginx 配置目录不存在"
fi

echo ""
echo "4. 检查备份目录..."
if [ ! -d "$BACKUP_DIR" ]; then
    echo "   [WARN] 备份目录不存在: $BACKUP_DIR"
    mkdir -p "$BACKUP_DIR"
    echo "   [INFO] 已创建备份目录"
else
    echo "   [OK] 备份目录存在"
fi

echo ""
echo "配置验证完成!"
EOF

# 运行验证
chmod +x /path/to/deploy/ssl-verify-config.sh
./ssl-verify-config.sh

7. 使用示例

7.1 场景 1: 申请单域名证书

需求:example.com 申请 SSL 证书

bash 复制代码
sudo ./ssl-apply.sh example.com admin@example.com

预期输出:

复制代码
╔════════════════════════════════════════════════════════════╗
║           SSL 证书自动申请脚本                            ║
║           Let's Encrypt Certificate Automation             ║
╚════════════════════════════════════════════════════════════╝

[INFO] 域名: example.com
[INFO] 邮箱: admin@example.com
[SUCCESS] Certbot 已安装
[SUCCESS] DNS 解析正确: example.com -> 1.2.3.4
[SUCCESS] 80 端口正在监听
[INFO] 开始申请 SSL 证书...
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
[SUCCESS] SSL 证书申请成功!
[SUCCESS] Nginx SSL 配置文件已创建
[SUCCESS] Nginx 配置测试通过
[SUCCESS] Nginx 已重新加载

7.2 场景 2: 申请多域名证书

需求:example.comwww.example.com 同时申请证书

bash 复制代码
sudo ./ssl-apply.sh example.com,www.example.com admin@example.com

说明:

  • 多个域名使用逗号分隔
  • 证书会包含所有列出的域名
  • Nginx 会自动配置多个域名

7.3 场景 3: 申请通配符证书

需求:*.example.com 申请通配符证书

前置条件:

  1. 准备阿里云 API 凭证
  2. 域名 DNS 解析到阿里云
bash 复制代码
sudo ./ssl-wildcard.sh example.com admin@example.com \
  --dns-provider aliyun \
  --api-key LTAIxxxx \
  --secret-key xxxxxx

说明:

  • 通配符证书会覆盖所有子域名
  • 需要使用 DNS-01 验证
  • 需要 DNS 提供商的 API 凭证

7.4 场景 4: 手动续签证书

需求: 手动续签所有即将过期的证书

bash 复制代码
# 查看所有证书状态
sudo ./ssl-info.sh

# 续签所有证书
sudo ./ssl-renew.sh

# 或续签指定证书
sudo ./ssl-renew.sh example.com

7.5 场景 5: 测试续签

需求: 测试续签流程(不实际续签)

bash 复制代码
sudo ./ssl-renew.sh --dry-run

说明:

  • --dry-run 参数表示测试模式
  • 不会实际续签证书
  • 用于验证续签流程是否正常

7.6 场景 6: 检查证书过期情况

需求: 检查所有证书是否即将过期(30天内)

bash 复制代码
sudo ./ssl-info.sh --check-expiry

输出示例:

复制代码
╔════════════════════════════════════════════════════════════╗
║                  证书过期检查                              ║
╚════════════════════════════════════════════════════════════╝

检查到 2 个证书

[OK] example.com - 剩余 90 天(未过期)
[WARN] old-domain.com - 剩余 25 天(即将过期,建议续签)

7.7 场景 7: 导出证书信息

需求: 导出所有证书信息到 JSON 文件

bash 复制代码
sudo ./ssl-info.sh --export json --output /path/to/certs.json

输出文件内容:

json 复制代码
{
  "certificates": [
    {
      "domain": "example.com",
      "status": "valid",
      "issuer": "Let's Encrypt",
      "issued_date": "2025-01-12T00:00:00Z",
      "expiry_date": "2025-04-12T00:00:00Z",
      "days_remaining": 90,
      "cert_path": "/etc/letsencrypt/live/example.com/fullchain.pem",
      "key_path": "/etc/letsencrypt/live/example.com/privkey.pem"
    },
    {
      "domain": "*.example.com",
      "status": "valid",
      "issuer": "Let's Encrypt",
      "issued_date": "2025-01-10T00:00:00Z",
      "expiry_date": "2025-04-10T00:00:00Z",
      "days_remaining": 88,
      "cert_path": "/etc/letsencrypt/live/example.com/fullchain.pem",
      "key_path": "/etc/letsencrypt/live/example.com/privkey.pem"
    }
  ],
  "total_count": 2,
  "expiring_count": 0,
  "check_time": "2025-01-12T10:00:00Z"
}

7.8 场景 8: 设置自动续签

需求: 设置每天凌晨 3 点自动检查续签

bash 复制代码
# 方法 1: 使用脚本自动设置
sudo ./ssl-renew.sh --setup

# 方法 2: 手动添加 Cron 任务
sudo crontab -e

# 添加以下内容
0 3 * * * /path/to/deploy/ssl-renew.sh >> /var/log/ssl-automation/renew.log 2>&1

# 查看 Cron 任务
sudo crontab -l

7.9 场景 9: 删除证书

需求: 删除不再需要的证书

bash 复制代码
# 查看所有证书
sudo ./ssl-info.sh

# 使用 Certbot 删除证书
sudo certbot delete --cert-name old-domain.com

# 或手动删除(不推荐)
sudo rm -rf /etc/letsencrypt/live/old-domain.com
sudo rm -rf /etc/letsencrypt/archive/old-domain.com
sudo rm -f /etc/letsencrypt/renewal/old-domain.com.conf

7.10 场景 10: 回滚证书

需求: 回滚到之前的证书版本

bash 复制代码
# 查看证书历史
ls -lh /etc/letsencrypt/archive/example.com/

# 复制旧版本证书到 live 目录
sudo cp /etc/letsencrypt/archive/example.com/cert1.pem \
      /etc/letsencrypt/live/example.com/cert.pem

# 重载 Nginx
sudo systemctl reload nginx

8. 工作流程

8.1 证书申请流程

DNS 服务器 Let's Encrypt Certbot Nginx ssl-apply.sh 用户 DNS 服务器 Let's Encrypt Certbot Nginx ssl-apply.sh 用户 alt [HTTP-01 验证] [DNS-01 验证] 执行脚本 检查权限和参数 检查 DNS 解析 检查端口占用 配置 ACME 验证路径 请求证书 发起 HTTP-01 验证 访问 /.well-known/acme-challenge/ 返回验证信息 验证通过 返回证书 请求证书 返回 DNS TXT 记录 添加 TXT 记录 等待 DNS 生效 发起 DNS-01 验证 查询 TXT 记录 返回记录 验证通过 返回证书 删除 TXT 记录 配置 SSL 重载服务 显示证书信息

8.2 证书续签流程

邮件系统 Nginx Let's Encrypt Certbot ssl-renew.sh Cron 定时任务 邮件系统 Nginx Let's Encrypt Certbot ssl-renew.sh Cron 定时任务 alt [续签成功] [续签失败] alt [证书即将过期] [证书未过期] 触发续签检查 检查证书有效期 请求续签 申请新证书 颁发新证书 返回新证书 重载服务 记录日志 发送失败通知 记录错误日志 跳过续签 生成续签报告

8.3 证书监控流程







开始监控
检查证书有效期
是否即将过期?
发送预警通知
继续监控
是否需要续签?
执行自动续签
续签是否成功?
更新证书信息
发送失败通知

8.4 完整生命周期

复制代码
1. 证书申请
   ├── 域名 DNS 解析
   ├── 检查环境(Certbot、Nginx、端口)
   ├── 申请证书
   ├── 配置 Nginx
   └── 测试访问

2. 证书使用
   ├── Nginx 反向代理
   ├── HTTPS 加密传输
   ├── HSTS 强制 HTTPS
   └── OCSP Stapling 优化

3. 证书监控
   ├── 每日检查有效期
   ├── 即将过期预警
   └── 续签状态监控

4. 证书续签
   ├── 自动检测(Cron)
   ├── 申请新证书
   ├── 更新 Nginx 配置
   └── 重载服务

5. 证书失效
   ├── 证书过期
   ├── 网站无法访问
   └── 需要手动处理

9. 故障处理

9.1 常见问题及解决方案

Q1: DNS 解析失败

错误信息:

复制代码
[ERROR] 无法解析域名 example.com

可能原因:

  1. 域名未添加 DNS A 记录
  2. DNS 记录未生效
  3. 域名拼写错误

解决方案:

bash 复制代码
# 1. 检查 DNS 解析
dig +short example.com
nslookup example.com

# 2. 确认域名 A 记录已添加到域名服务商
#    - 阿里云: https://dns.console.aliyun.com
#    - 腾讯云: https://console.cloud.tencent.com/cns
#    - Cloudflare: https://dash.cloudflare.com/

# 3. 等待 DNS 生效(通常 10-30 分钟)
#    可以使用在线工具查询全球 DNS 生效情况:
#    https://www.whatsmydns.net/

# 4. 清除本地 DNS 缓存
#    Windows
ipconfig /flushdns

#    Linux
sudo systemd-resolve --flush-caches
# 或
sudo service dnsmasq restart
Q2: 端口被占用

错误信息:

复制代码
[ERROR] 80 端口已被占用

可能原因:

  1. Nginx 未启动
  2. 其他服务占用 80 端口
  3. 防火墙未开放端口

解决方案:

bash 复制代码
# 1. 检查端口占用
netstat -tuln | grep :80
# 或
ss -tuln | grep :80
# 或
lsof -i :80

# 2. 查看占用端口的进程
ps aux | grep nginx

# 3. 停止占用端口的进程
sudo kill -9 <PID>

# 4. 启动 Nginx
sudo systemctl start nginx
sudo systemctl enable nginx

# 5. 检查防火墙
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
Q3: 证书申请失败

错误信息:

复制代码
[ERROR] SSL 证书申请失败

可能原因:

  1. 域名未解析到服务器
  2. 80 端口无法访问
  3. 防火墙阻止 Let's Encrypt 访问
  4. 达到 Let's Encrypt 速率限制

解决方案:

检查 1: 验证域名解析

bash 复制代码
# 从外部检查域名解析(使用本地网络)
dig +short example.com

# 从服务器内部检查
curl -s ifconfig.me  # 获取服务器 IP
dig +short example.com  # 查看域名解析 IP

检查 2: 验证 80 端口可访问

bash 复制代码
# 从外部访问
curl http://example.com

# 从服务器内部访问
curl http://localhost

检查 3: 检查防火墙

bash 复制代码
# UFW
sudo ufw status

# firewalld
sudo firewall-cmd --list-all

# 开放端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

检查 4: 使用 Staging 环境测试

bash 复制代码
# Let's Encrypt 有速率限制(例如每周最多 5 次失败)
# 可以使用 Staging 环境测试配置
sudo certbot certonly --test-cert --nginx -d example.com
Q4: Nginx 配置测试失败

错误信息:

复制代码
[ERROR] Nginx 配置测试失败

可能原因:

  1. 证书路径错误
  2. 证书文件不存在
  3. 配置文件语法错误

解决方案:

bash 复制代码
# 1. 测试 Nginx 配置
sudo nginx -t

# 2. 查看详细错误信息
sudo nginx -t 2>&1

# 3. 检查证书文件是否存在
ls -la /etc/letsencrypt/live/example.com/

# 4. 检查证书文件权限
sudo chmod 644 /etc/letsencrypt/live/example.com/fullchain.pem
sudo chmod 600 /etc/letsencrypt/live/example.com/privkey.pem

# 5. 检查 Nginx 配置文件
cat /etc/nginx/sites-available/example.com-ssl.conf
Q5: 证书续签失败

错误信息:

复制代码
[ERROR] 证书续签失败

可能原因:

  1. 域名解析变更
  2. 80/443 端口无法访问
  3. Nginx 配置错误
  4. DNS 记录失效(通配符证书)

解决方案:

检查 1: 查看续签日志

bash 复制代码
# 查看续签日志
sudo cat /var/log/ssl-automation/renew.log

# 查看 Certbot 日志
sudo cat /var/log/letsencrypt/letsencrypt.log

检查 2: 手动测试续签

bash 复制代码
# 测试续签(不实际续签)
sudo certbot renew --dry-run

# 查看详细输出
sudo certbot renew --dry-run --verbose

检查 3: 检查域名解析

bash 复制代码
# 检查所有域名的解析
dig +short example.com
dig +short www.example.com

检查 4: 强制续签

bash 复制代码
# 强制续签所有证书
sudo certbot renew --force-renewal

# 强制续签指定证书
sudo certbot renew --cert-name example.com --force-renewal
Q6: 证书已过期

症状:

  • 浏览器显示"连接不安全"
  • 访问网站出现 SSL 错误

解决方案:

紧急修复:

bash 复制代码
# 1. 检查证书状态
sudo certbot certificates

# 2. 强制续签
sudo certbot renew --force-renewal

# 3. 如果续签失败,删除旧证书重新申请
sudo certbot delete --cert-name example.com
sudo ./ssl-apply.sh example.com admin@example.com

临时禁用 SSL(不推荐):

bash 复制代码
# 修改 Nginx 配置,临时禁用 SSL
sudo vim /etc/nginx/sites-available/example.com-ssl.conf

# 注释掉 SSL 相关配置
# ssl_certificate ...
# ssl_certificate_key ...

# 修改监听端口为 80
# listen 80;

# 重载 Nginx
sudo systemctl reload nginx
Q7: 通配符证书申请失败

错误信息:

复制代码
[ERROR] DNS TXT 记录验证失败

可能原因:

  1. DNS API 凭证错误
  2. DNS 记录未生效
  3. DNS 提供商配置错误

解决方案:

检查 1: 验证 DNS API 凭证

bash 复制代码
# 测试阿里云 API
# 安装阿里云 CLI
curl https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz -o aliyun-cli.tgz
tar -xzf aliyun-cli.tgz
sudo mv aliyun /usr/local/bin/

# 配置凭证
aliyun configure

# 测试 DNS 解析
aliyun alidns DescribeDomainRecords --DomainName example.com

检查 2: 手动添加 DNS TXT 记录

bash 复制代码
# 手动添加 TXT 记录到域名服务商
# 记录名: _acme-challenge.example.com
# 记录值: xxxxxxxxxxxxxxxxxxxxx

# 验证记录是否生效
dig +short txt _acme-challenge.example.com

检查 3: 使用手动 DNS 验证

bash 复制代码
# 使用 Certbot 的手动模式
sudo certbot certonly --manual --preferred-challenges dns -d "*.example.com"

# 按提示手动添加 DNS TXT 记录

9.2 日志分析

查看日志位置
bash 复制代码
# SSL 自动化日志
ls -lh /var/log/ssl-automation/

# Certbot 日志
ls -lh /var/log/letsencrypt/

# Nginx 日志
ls -lh /var/log/nginx/

# 系统日志
journalctl -xe
实时监控日志
bash 复制代码
# 实时查看续签日志
tail -f /var/log/ssl-automation/renew.log

# 实时查看 Nginx 错误日志
tail -f /var/log/nginx/example.com-error.log

# 实时查看系统日志
journalctl -f
日志搜索
bash 复制代码
# 搜索错误日志
grep -i error /var/log/ssl-automation/*.log

# 搜索续签日志
grep -i renew /var/log/ssl-automation/renew.log

# 搜索特定域名的日志
grep "example.com" /var/log/ssl-automation/*.log

9.3 故障排查流程图

复制代码
开始故障排查
    │
    ├─▶ 检查证书状态
    │   ├── 查看证书信息: sudo certbot certificates
    │   └─▶ 证书是否存在?
    │       ├── 是 ──▶ 继续检查
    │       └── 否 ──▶ 申请证书: sudo ./ssl-apply.sh
    │
    ├─▶ 检查域名解析
    │   ├── 检查 DNS: dig +short example.com
    │   └─▶ 解析是否正确?
    │       ├── 是 ──▶ 继续检查
    │       └── 否 ──▶ 修正 DNS 记录
    │
    ├─▶ 检查端口占用
    │   ├── 检查端口: netstat -tuln | grep :80
    │   └─▶ 端口是否开放?
    │       ├── 是 ──▶ 继续检查
    │       └── 否 ──▶ 开放端口/防火墙
    │
    ├─▶ 检查 Nginx 配置
    │   ├── 测试配置: sudo nginx -t
    │   └─▶ 配置是否正确?
    │       ├── 是 ──▶ 继续检查
    │       └── 否 ──▶ 修正配置
    │
    ├─▶ 检查证书续签
    │   ├── 测试续签: sudo certbot renew --dry-run
    │   └─▶ 续签是否正常?
    │       ├── 是 ──▶ 继续检查
    │       └── 否 ──▶ 检查续签日志
    │
    └─▶ 查看详细日志
        ├── 查看 Certbot 日志: cat /var/log/letsencrypt/letsencrypt.log
        ├── 查看 Nginx 日志: cat /var/log/nginx/error.log
        └── 查看系统日志: journalctl -xe

10. 最佳实践

10.1 证书管理

1. 定期检查证书状态
bash 复制代码
# 每周检查一次证书状态
sudo ./ssl-info.sh --check-expiry

# 或设置 Cron 任务
0 0 * * 1 /path/to/deploy/ssl-info.sh --check-expiry >> /var/log/ssl-automation/monitor.log 2>&1
2. 备份证书
bash 复制代码
# 创建证书备份脚本
cat > /path/to/deploy/ssl-backup.sh << 'EOF'
#!/bin/bash

BACKUP_DIR="/www/wwwroot/nuxt3-wu-code/backups/ssl"
DATE=$(date +%Y%m%d%H%M%S)

mkdir -p "$BACKUP_DIR"

# 备份所有证书
for cert in /etc/letsencrypt/live/*/; do
    domain=$(basename "$cert")
    echo "备份证书: $domain"
    tar -czf "$BACKUP_DIR/$domain-$DATE.tar.gz" -C /etc/letsencrypt/live "$domain"
done

echo "备份完成: $BACKUP_DIR"

# 清理 30 天前的备份
find "$BACKUP_DIR" -type f -mtime +30 -delete
EOF

chmod +x /path/to/deploy/ssl-backup.sh

# 设置每周备份
0 0 * * 0 /path/to/deploy/ssl-backup.sh >> /var/log/ssl-automation/backup.log 2>&1
3. 使用测试环境

在申请正式证书前,先在 Staging 环境测试:

bash 复制代码
# Staging 环境测试
sudo certbot certonly --test-cert --nginx -d example.com

# 确认无误后,申请正式证书
sudo ./ssl-apply.sh example.com admin@example.com

10.2 安全配置

1. 启用 HSTS
nginx 复制代码
# 在 Nginx 配置中添加
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

说明:

  • max-age=31536000: 强制 HTTPS 有效期 1 年
  • includeSubDomains: 包含所有子域名
  • preload: 允许浏览器预加载(需要注册到 HSTS 预加载列表)
2. 生成 DH 参数
bash 复制代码
# 生成 DH 参数
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

# 在 Nginx 配置中使用
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
3. 配置强加密套件
nginx 复制代码
# 使用现代加密套件
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
4. 启用 OCSP Stapling
nginx 复制代码
# 启用 OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
5. 配置安全头
nginx 复制代码
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self'" always;

10.3 性能优化

1. 启用 HTTP/2
nginx 复制代码
# Nginx 1.9.5+ 默认支持 HTTP/2
listen 443 ssl http2;
2. 配置 SSL 会话缓存
nginx 复制代码
# SSL 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
3. 启用 Gzip 压缩
nginx 复制代码
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
4. 启用缓存
nginx 复制代码
# 静态资源缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 30d;
    add_header Cache-Control "public, immutable";
}

10.4 监控和告警

1. 设置证书过期监控
bash 复制代码
# 创建监控脚本
cat > /path/to/deploy/ssl-monitor.sh << 'EOF'
#!/bin/bash

WARNING_DAYS=15
EMAIL="admin@example.com"

# 检查所有证书
certbot certificates | grep -A 2 "Certificate Name:" | while read -r line; do
    if [[ $line =~ "Certificate Name:" ]]; then
        domain=$(echo "$line" | awk '{print $3}')
    elif [[ $line =~ "Expiry Date:" ]]; then
        expiry_date=$(echo "$line" | awk '{print $4}')
        expiry_timestamp=$(date -d "$expiry_date" +%s)
        current_timestamp=$(date +%s)
        days_remaining=$(( (expiry_timestamp - current_timestamp) / 86400 ))

        if [ $days_remaining -lt $WARNING_DAYS ]; then
            echo "警告: $domain 证书将在 $days_remaining 天后过期"
            echo "发送邮件通知..."
            echo "$domain 证书将在 $days_remaining 天后过期" | mail -s "SSL 证书过期警告" $EMAIL
        fi
    fi
done
EOF

chmod +x /path/to/deploy/ssl-monitor.sh

# 设置每日监控
0 8 * * * /path/to/deploy/ssl-monitor.sh >> /var/log/ssl-automation/monitor.log 2>&1
2. 监控 SSL 连接
bash 复制代码
# 使用 OpenSSL 监控 SSL 连接
openssl s_client -connect example.com:443 -servername example.com </dev/null

# 检查 SSL 证书有效期
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
3. 监控 Nginx SSL 错误
bash 复制代码
# 监控 Nginx 错误日志
tail -f /var/log/nginx/error.log | grep --line-buffered -i ssl

# 统计 SSL 错误数量
grep -i ssl /var/log/nginx/error.log | wc -l

10.5 自动化建议

1. 使用 Git 管理 Nginx 配置
bash 复制代码
# 初始化 Git 仓库
cd /etc/nginx
sudo git init
sudo git add .
sudo git commit -m "Initial commit"

# 每次修改后提交
sudo git add sites-available/example.com-ssl.conf
sudo git commit -m "Update SSL config for example.com"
2. 使用配置管理工具

推荐使用以下工具管理 SSL 证书:

  • Ansible: 自动化部署和配置
  • Terraform: 基础设施即代码
  • Docker: 容器化部署
3. 集成到 CI/CD 流程
yaml 复制代码
# GitHub Actions 示例
name: SSL Certificate Check

on:
  schedule:
    - cron: '0 0 * * *'  # 每天检查

jobs:
  check-ssl:
    runs-on: ubuntu-latest
    steps:
      - name: Check SSL expiry
        run: |
          # 使用 curl 检查证书
          curl -I https://example.com
          
          # 检查证书有效期
          openssl s_client -connect example.com:443 -servername example.com </dev/null | openssl x509 -noout -dates

11. 安全建议

11.1 证书安全

1. 保护私钥
bash 复制代码
# 私钥文件权限应该是 600
sudo chmod 600 /etc/letsencrypt/live/*/privkey.pem

# 证书文件权限应该是 644
sudo chmod 644 /etc/letsencrypt/live/*/fullchain.pem
2. 定期更新证书
bash 复制代码
# 设置自动续签
sudo ./ssl-renew.sh --setup

# 定期检查续签状态
sudo certbot certificates
3. 不要共享私钥
  • 私钥文件不应复制到其他服务器
  • 不要将私钥上传到公开仓库
  • 使用加密工具保护私钥(如 GPG)

11.2 服务器安全

1. 配置防火墙
bash 复制代码
# 只开放必要的端口
sudo ufw allow 22/tcp   # SSH
sudo ufw allow 80/tcp   # HTTP
sudo ufw allow 443/tcp  # HTTPS
sudo ufw enable
2. 禁用弱 SSL/TLS 协议
nginx 复制代码
# 只启用 TLS 1.2 和 TLS 1.3
ssl_protocols TLSv1.2 TLSv1.3;
3. 使用强加密套件
nginx 复制代码
# 使用强加密套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;

11.3 系统安全

1. 定期更新系统
bash 复制代码
# Ubuntu/Debian
sudo apt update && sudo apt upgrade -y

# CentOS/RHEL
sudo yum update -y
2. 配置自动安全更新
bash 复制代码
# Ubuntu/Debian
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades

# CentOS/RHEL
sudo yum install yum-cron
sudo systemctl enable yum-cron
sudo systemctl start yum-cron
3. 配置日志轮转
bash 复制代码
# 配置 SSL 日志轮转
cat > /etc/logrotate.d/ssl-automation << 'EOF'
/var/log/ssl-automation/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0640 root adm
    sharedscripts
}
EOF

12. 监控和维护

12.1 日常检查清单

每日检查
bash 复制代码
# 1. 检查证书状态
sudo certbot certificates

# 2. 检查 Nginx 状态
sudo systemctl status nginx

# 3. 检查错误日志
sudo tail -n 50 /var/log/nginx/error.log

# 4. 检查 SSL 连接
curl -I https://example.com
每周检查
bash 复制代码
# 1. 检查证书过期情况
sudo ./ssl-info.sh --check-expiry

# 2. 测试续签流程
sudo certbot renew --dry-run

# 3. 检查磁盘空间
df -h

# 4. 检查系统更新
sudo apt list --upgradable
每月检查
bash 复制代码
# 1. 备份所有证书
sudo /path/to/deploy/ssl-backup.sh

# 2. 审查 Nginx 配置
sudo nginx -t

# 3. 更新系统
sudo apt update && sudo apt upgrade -y

# 4. 清理旧日志
find /var/log/ssl-automation/ -type f -mtime +30 -delete

12.2 监控指标

关键指标
指标 说明 告警阈值
证书剩余天数 证书有效期 < 15 天
续签成功率 续签是否成功 < 100%
Nginx 启动时间 Nginx 启动耗时 > 5 秒
SSL 错误率 SSL 连接错误率 > 1%
磁盘使用率 日志目录磁盘使用率 > 80%
监控脚本
bash 复制代码
# 创建综合监控脚本
cat > /path/to/deploy/ssl-health-check.sh << 'EOF'
#!/bin/bash

WARNING_DAYS=15
DISK_THRESHOLD=80
EMAIL="admin@example.com"
REPORT_FILE="/tmp/ssl-health-report.txt"

echo "SSL 证书健康检查报告" > "$REPORT_FILE"
echo "检查时间: $(date)" >> "$REPORT_FILE"
echo "================================" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 1. 检查证书状态
echo "1. 证书状态检查:" >> "$REPORT_FILE"
certbot certificates >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 2. 检查即将过期的证书
echo "2. 即将过期的证书:" >> "$REPORT_FILE"
certbot certificates | grep -A 2 "Certificate Name:" | while read -r line; do
    if [[ $line =~ "Certificate Name:" ]]; then
        domain=$(echo "$line" | awk '{print $3}')
    elif [[ $line =~ "Expiry Date:" ]]; then
        expiry_date=$(echo "$line" | awk '{print $4}')
        expiry_timestamp=$(date -d "$expiry_date" +%s)
        current_timestamp=$(date +%s)
        days_remaining=$(( (expiry_timestamp - current_timestamp) / 86400 ))

        if [ $days_remaining -lt $WARNING_DAYS ]; then
            echo "警告: $domain 证书将在 $days_remaining 天后过期" >> "$REPORT_FILE"
        fi
    fi
done
echo "" >> "$REPORT_FILE"

# 3. 检查 Nginx 状态
echo "3. Nginx 状态:" >> "$REPORT_FILE"
systemctl status nginx | head -n 5 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 4. 检查磁盘使用率
echo "4. 磁盘使用率:" >> "$REPORT_FILE"
df -h | grep -E "^/dev/" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 5. 检查最近的 SSL 错误
echo "5. 最近的 SSL 错误:" >> "$REPORT_FILE"
tail -n 20 /var/log/nginx/error.log | grep -i ssl >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"

# 发送报告
cat "$REPORT_FILE" | mail -s "SSL 证书健康检查报告" "$EMAIL"

# 清理临时文件
rm -f "$REPORT_FILE"
EOF

chmod +x /path/to/deploy/ssl-health-check.sh

12.3 维护计划

定期维护任务
频率 任务 脚本/命令
每日 检查证书状态 sudo certbot certificates
每日 检查 Nginx 日志 sudo tail -f /var/log/nginx/error.log
每周 测试续签流程 sudo certbot renew --dry-run
每周 检查过期证书 sudo ./ssl-info.sh --check-expiry
每月 备份证书 sudo ./ssl-backup.sh
每月 更新系统 sudo apt update && sudo apt upgrade -y
每月 清理旧日志 find /var/log/ssl-automation/ -type f -mtime +30 -delete
每季度 安全审计 检查配置和安全设置
每年 证书策略审查 审查证书策略和配置
自动化维护
bash 复制代码
# 创建维护脚本
cat > /path/to/deploy/ssl-maintenance.sh << 'EOF'
#!/bin/bash

echo "开始 SSL 自动化维护..."

# 1. 检查证书状态
echo "1. 检查证书状态..."
sudo certbot certificates

# 2. 测试续签
echo "2. 测试续签流程..."
sudo certbot renew --dry-run

# 3. 备份证书
echo "3. 备份证书..."
sudo /path/to/deploy/ssl-backup.sh

# 4. 清理旧日志
echo "4. 清理旧日志..."
find /var/log/ssl-automation/ -type f -mtime +30 -delete

# 5. 检查磁盘空间
echo "5. 检查磁盘空间..."
df -h | grep -E "^/dev/"

echo "维护完成!"
EOF

chmod +x /path/to/deploy/ssl-maintenance.sh

# 设置每月维护
0 0 1 * * /path/to/deploy/ssl-maintenance.sh >> /var/log/ssl-automation/maintenance.log 2>&1

附录

A. 常用命令速查表

Certbot 命令
命令 说明
certbot --version 查看 Certbot 版本
certbot certificates 查看所有证书
certbot renew 续签所有证书
certbot renew --dry-run 测试续签
certbot delete --cert-name example.com 删除证书
certbot revoke --cert-path /path/to/cert.pem 撤销证书
Nginx 命令
命令 说明
nginx -t 测试配置
systemctl start nginx 启动 Nginx
systemctl stop nginx 停止 Nginx
systemctl restart nginx 重启 Nginx
systemctl reload nginx 重载 Nginx
systemctl status nginx 查看 Nginx 状态
SSL 测试命令
命令 说明
curl -I https://example.com 测试 HTTPS 访问
openssl s_client -connect example.com:443 检查 SSL 连接
`echo openssl s_client -connect example.com:443

B. 参考资料

官方文档
在线工具
推荐阅读
相关推荐
Aaron_9452 小时前
Chrome DevTools MCP:为AI编程助手提供浏览器自动化能力的完整指南
自动化·ai编程·chrome devtools
CHENKONG_CK2 小时前
晨控CK-FR09EIP与汇川H5U系列PLC配置EtherNet/IP通讯连接手册
网络·网络协议·自动化·rfid
缺点内向2 小时前
C#: 如何自动化创建Word可填写表单,告别手动填写时代
c#·自动化·word
元媛媛2 小时前
UiPath |5个基础自动化场景
android·java·自动化
shenghuiping20012 小时前
OPSWAT https enable 问题解决
nginx·https·ssl·443·opswat
Allen_LVyingbo2 小时前
面向“病历生成 + CDI/ICD”多智能体系统的选型策略与落地实践(二)
人工智能·算法·系统架构·知识图谱·健康医疗
2501_941982053 小时前
行业实践:如何利用 RPA 自动化技术提升企业微信外部群的运营效率?
自动化·企业微信·rpa
宇钶宇夕3 小时前
CoDeSys入门实战一起学习(五):CoDeSys V3 车库门控制编程全解析系列(手册基础第二篇)
运维·自动化·软件工程
霍格沃兹软件测试开发3 小时前
大语言模型提示词工程教程:实现自动化工具推理
microsoft·语言模型·自动化