最后更新于:2026年07月

⚠️ 重要声明:本文仅从技术研究角度介绍 TLS 证书的自动化管理工具与工程实践。请在遵守当地法律法规的前提下阅读和应用本文内容。

acme.sh 证书自动化
acme.sh:纯 Shell 实现的证书自动化管理

2026 年,Let’s Encrypt 做了两个重大变更:证书有效期从 90 天缩短至 47 天,同时推出全新的 DNS-PERSIST-01 验证方式。这意味着手动续期证书已经完全不现实——每 47 天就要操作一次,稍有不慎就会导致网站证书过期。

在众多 ACME 客户端中,acme.sh 凭借纯 Shell 实现、零依赖、150+ DNS 服务商 API 支持、单文件部署等优势,成为最轻量也最强大的证书管理工具。它不需要 root 权限,不需要 Python 环境,不需要 systemd 服务——一个 .sh 文件搞定一切。

本文将系统讲解 acme.sh 的安装、证书申请、DNS API 自动验证、Nginx/Caddy/HAProxy 部署、自动续期配置以及 2026 年新特性。


🧭 第一部分:acme.sh 是什么?

1.1 ACME 协议与 Let’s Encrypt

PLAINTEXT
┌──────────────────────────────────────────────────────────┐
│              ACME 协议工作流程                            │
│                                                          │
│  你的服务器                Let's Encrypt CA              │
│      │                          │                       │
│  1.  │─── 申请证书 ─────────────→│                       │
│  2.  │←── 返回挑战 (Challenge) ──│                       │
│  3.  │                           │                       │
│      │  ┌── HTTP-01: 在网站放验证文件                    │
│      │  ├── DNS-01: 在 DNS 添加 TXT 记录                 │
│      │  ├── TLS-ALPN-01: 在 TLS 握手中返回验证           │
│      │  └── DNS-PERSIST-01 (2026新): 持久化 DNS 验证     │
│  4.  │                           │                       │
│      │─── 完成挑战 ─────────────→│                       │
│  5.  │←── 签发证书 ──────────────│                       │
│      │                           │                       │
│  6.  │─── 定期自动续期 ─────────→│                       │
│                                                          │
│  ACME = Automatic Certificate Management Environment    │
│  RFC 8555 标准                                           │
└──────────────────────────────────────────────────────────┘

1.2 acme.sh 核心特性

PLAINTEXT
┌──────────────────────────────────────────────────────────┐
│                 acme.sh 核心特性                         │
│                                                          │
│  📦 极致轻量                                             │
│     ├── 纯 Shell 脚本(Bash + POSIX sh)                │
│     ├── 零依赖(不需要 Python/Node/Go)                 │
│     ├── 单文件部署                                       │
│     └── 不需要 root 权限                                 │
│                                                          │
│  🔗 DNS API 支持(150+ 服务商)                          │
│     ├── Cloudflare / AliDNS / DNSPod                    │
│     ├── 腾讯云 / 华为云 / 京东云                         │
│     ├── AWS Route53 / Google Cloud DNS                  │
│     ├── Namecheap / GoDaddy / Name.com                  │
│     └── 自定义 DNS API(Manual Mode)                    │
│                                                          │
│  🔒 多 CA 支持                                           │
│     ├── Let's Encrypt(默认)                            │
│     ├── ZeroSSL                                         │
│     ├── Google Trust Services                           │
│     ├── Buypass                                         │
│     └── SSL.com                                         │
│                                                          │
│  ⚡ 自动化                                               │
│     ├── 自动安装 cron 定时续期                           │
│     ├── 自动 DNS API 验证                                │
│     ├── 自动部署到 Nginx/Caddy/Apache                   │
│     └── 自动 reload 服务                                 │
│                                                          │
│  🛡️ 安全                                                │
│     ├── 账户密钥自动管理                                  │
│     ├── 证书安全存储                                      │
│     ├── 支持 ECC 证书                                    │
│     └── 支持 RSA 证书                                    │
└──────────────────────────────────────────────────────────┘

1.3 acme.sh vs certbot 对比

PLAINTEXT
┌──────────────────────────────────────────────────────────┐
│           acme.sh vs certbot 全面对比                    │
├──────────────────┬──────────────┬───────────────────────┤
│ 特性             │ acme.sh      │ certbot               │
├──────────────────┼──────────────┼───────────────────────┤
│ 语言             │ Shell        │ Python                │
│ 依赖             │ 零依赖       │ Python + pip          │
│ 安装方式         │ curl 一键    │ apt/snap/pip          │
│ 大小             │ ~500KB       │ ~50MB+                │
│ root 权限        │ 不需要       │ 需要(部分操作)       │
│ DNS API 数量     │ 150+         │ ~30(需插件)         │
│ 通配符证书       │ ✅           │ ✅(需 DNS 插件)     │
│ 多 CA 支持       │ ✅           │ ✅(有限)            │
│ 自动续期         │ cron         │ systemd timer         │
│ Nginx 集成       │ reload 命令  │ 原生插件              │
│ Docker 支持      │ ✅           │ ✅                    │
│ 配置存储         │ ~/.acme.sh/  │ /etc/letsencrypt/     │
│ 学习曲线         │ 平缓         │ 中等                  │
│ 社区活跃度       │ 高           │ 高                    │
│ 适用场景         │ 通用/嵌入式  │ 企业/标准 Web 服务器  │
└──────────────────┴──────────────┴───────────────────────┘

1.4 2026 年 Let’s Encrypt 重大变更

PLAINTEXT
2026 年关键变化:

1. 证书有效期缩短
   ├── 2025年: 90 天
   ├── 2026年3月: 47 天
   └── 未来计划: 6 天(2027年讨论中)

   影响:
   - 手动续期完全不现实
   - 必须依赖自动化工具
   - acme.sh 的 cron 自动续期成为标配

2. DNS-PERSIST-01 验证方式(2026年2月推出)
   ├── 一次 DNS TXT 记录配置,长期有效
   ├── 不需要每次续期更新 DNS
   ├── 适合 IoT 设备和批量证书管理
   └── acme.sh 已支持

3. 速率限制调整
   ├── 每个注册域名每周 50 张证书(不变)
   ├── 每周最多 300 张证书(不变)
   └── 失败重试限制更严格

4. ECC 证书推荐
   ├── 默认推荐 ECDSA P-256
   ├── acme.sh 默认使用 ECC
   └── 兼容性已不是问题

📦 第二部分:安装 acme.sh

2.1 一键安装

BASH
# 方法一:curl 安装(推荐)
curl https://get.acme.sh | sh -s email=your@email.com

# 方法二:wget 安装
wget -O - https://get.acme.sh | sh -s email=your@email.com

# 方法三:git 克隆
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m your@email.com

# 方法四:离线安装(下载 zip)
# 从 https://github.com/acmesh-official/acme.sh/releases 下载
unzip acme.sh-*.zip
cd acme.sh-*
./acme.sh --install -m your@email.com

2.2 安装后的目录结构

BASH
# 安装目录:~/.acme.sh/

~/.acme.sh/
├── acme.sh           # 主脚本
├── account.conf      # 账户配置
├── ca/               # CA 服务器配置
│   ├── letsencrypt/
│   └── zerossl/
├── dnsapi/           # DNS API 脚本(150+)
│   ├── dns_cf.sh     # Cloudflare
│   ├── dns_ali.sh    # AliDNS
│   ├── dns_dp.sh     # DNSPod
│   └── ...
├── example.com/      # 证书目录(按域名)
│   ├── example.com.cer       # 证书
│   ├── example.com.key       # 私钥
│   ├── fullchain.cer         # 完整证书链
│   ├── example.com.conf      # 配置
│   └── example.com.csr       # CSR
└── http.example.com/ # HTTP 验证临时目录

# 查看安装信息
~/.acme.sh/acme.sh --info

2.3 环境配置

BASH
# acme.sh 安装后自动创建 alias
# 重新加载 shell 配置
source ~/.bashrc    # 或 source ~/.zshrc

# 验证安装
acme.sh --version
# 输出示例:3.0.7

# 设置默认 CA(Let's Encrypt)
acme.sh --set-default-ca --server letsencrypt

# 或使用 ZeroSSL
acme.sh --set-default-ca --server zerossl

# 或使用 Google Trust Services
acme.sh --set-default-ca --server google

# 检查 cron 定时任务(自动创建)
crontab -l | grep acme
# 输出示例:
# 0 0 * * * /home/user/.acme.sh/acme.sh --cron --home /home/user/.acme.sh

2.4 Docker 部署

YAML
# docker-compose.yml
version: '3.8'

services:
  acme:
    image: neilpang/acme.sh:latest
    container_name: acme
    restart: unless-stopped
    command: daemon
    volumes:
      - ./acme-data:/acme.sh
      - /var/www/html:/var/www/html  # HTTP 验证用
    environment:
      - CF_Token=your_cloudflare_api_token
      - Ali_Key=your_alidns_key
      - Ali_Secret=your_alidns_secret
    network_mode: host
BASH
# 使用 Docker 申请证书
docker exec acme acme.sh --issue --dns dns_cf -d example.com -d *.example.com

# 从宿主机复制证书
docker cp acme:/acme.sh/example.com/ /opt/certs/

🔏 第三部分:申请单域名证书

3.1 HTTP 验证模式(Standalone)

适用于:服务器有 80 端口可用,且域名已解析到本机。

BASH
# Standalone 模式:acme.sh 自带 HTTP 服务器监听 80 端口
# ⚠️ 需要 80 端口未被占用(先停掉 Nginx 等)

acme.sh --issue -d example.com --standalone

# 指定端口(如果 80 被占用)
acme.sh --issue -d example.com --standalone --httpport 88

# 多域名
acme.sh --issue -d example.com -d www.example.com --standalone

3.2 Webroot 验证模式

适用于:Web 服务器已运行,不想停服务。

BASH
# Nginx 默认 webroot
acme.sh --issue -d example.com -w /var/www/html

# Apache 默认 webroot
acme.sh --issue -d example.com -w /var/www/html

# 自定义 webroot
acme.sh --issue -d example.com -w /usr/share/nginx/html

# 多域名(不同 webroot)
acme.sh --issue \
    -d example.com -w /var/www/html \
    -d api.example.com -w /var/www/api

Nginx 配置 HTTP 验证路径

NGINX
# 确保以下路径可访问
location /.well-known/acme-challenge/ {
    root /var/www/html;
}

3.3 Nginx 模式

适用于:使用 Nginx 且不想手动配置 webroot。

BASH
# 自动修改 Nginx 配置完成验证
# ⚠️ 需要 acme.sh 能找到 nginx 配置文件
acme.sh --issue -d example.com --nginx

# 指定 nginx 配置文件
acme.sh --issue -d example.com --nginx /etc/nginx/conf.d/example.com.conf

3.4 Apache 模式

BASH
# 自动修改 Apache 配置
acme.sh --issue -d example.com --apache

🌐 第四部分:通配符证书与 DNS 验证

4.1 为什么需要 DNS 验证?

PLAINTEXT
┌──────────────────────────────────────────────────────────┐
│              验证方式对比                                │
├──────────────┬─────────────────┬─────────────────────────┤
│ 验证方式     │ 通配符证书      │ 需要开放端口            │
├──────────────┼─────────────────┼─────────────────────────┤
│ HTTP-01      │ ❌ 不支持       │ ✅ 需要 80 端口         │
│ TLS-ALPN-01  │ ❌ 不支持       │ ✅ 需要 443 端口        │
│ DNS-01       │ ✅ 支持         │ ❌ 不需要               │
│ DNS-PERSIST  │ ✅ 支持         │ ❌ 不需要(2026新)     │
│  (2026新)    │                 │                         │
└──────────────┴─────────────────┴─────────────────────────┘

通配符证书 (*.example.com) 只能通过 DNS-01 验证!
DNS-01 验证不需要开放 80/443 端口,适合内网服务器。

4.2 Cloudflare DNS API 自动验证

BASH
# 1. 获取 Cloudflare API Token
# 登录 Cloudflare → My Profile → API Tokens → Create Token
# 模板选择 "Edit zone DNS"
# Zone Resources 选择你的域名

# 2. 设置环境变量
export CF_Token="your_cloudflare_api_token"
export CF_Zone_ID="your_zone_id"
export CF_Account_ID="your_account_id"

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

# 4. acme.sh 会自动保存 API Token 到 account.conf
# 之后续期不需要再设置环境变量

4.3 AliDNS(阿里云)DNS API

BASH
# 1. 获取阿里云 AccessKey
# 阿里云控制台 → AccessKey 管理 → 创建 AccessKey

# 2. 设置环境变量
export Ali_Key="your_access_key_id"
export Ali_Secret="your_access_key_secret"

# 3. 申请证书
acme.sh --issue --dns dns_ali -d example.com -d *.example.com

4.4 DNSPod(腾讯云)DNS API

BASH
# DNSPod / 腾讯云 DNS
# 方式一:DNSPod Token
export DP_Id="your_dp_id"
export DP_Key="your_dp_key"
acme.sh --issue --dns dns_dp -d example.com -d *.example.com

# 方式二:腾讯云 API(推荐,更安全)
export Tencent_SecretId="your_secret_id"
export Tencent_SecretKey="your_secret_key"
acme.sh --issue --dns dns_tencent -d example.com -d *.example.com

4.5 常用 DNS 服务商配置速查

BASH
# ┌─────────────────────────────────────────────────────────┐
# │        常用 DNS API 配置速查表                         │
# ├──────────────┬──────────────────────────────────────────┤
# │ DNS 服务商   │ 环境变量                                 │
# ├──────────────┼──────────────────────────────────────────┤
# │ Cloudflare   │ CF_Token, CF_Zone_ID, CF_Account_ID     │
# │ AliDNS       │ Ali_Key, Ali_Secret                      │
# │ DNSPod       │ DP_Id, DP_Key                            │
# │ 腾讯云       │ Tencent_SecretId, Tencent_SecretKey      │
# │ 华为云       │ HUAWEICLOUD_Username, HUAWEICLOUD_Password│
# │ 京东云       │ JD_ACCESS_KEY_ID, JD_SECRET_ACCESS_KEY   │
# │ AWS Route53  │ AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY │
# │ Google Cloud │ GCLOUD_Email, GCLOUD_Keyfile             │
# │ Namecheap    │ NAMECHEAP_USERNAME, NAMECHEAP_API_KEY    │
# │ GoDaddy      │ GD_Key, GD_Secret                        │
# │ Vultr        │ VULTR_API_KEY                            │
# │ DigitalOcean │ DO_API_KEY                               │
# │ Linode       │ LINODE_API_KEY                           │
# │ Hetzner      │ HETZNER_Token                            │
# │ Gandi        │ GANDI_LIVEDNS_KEY                        │
# │ FreeDNS      │ FREEDNS_User, FREEDNS_Password           │
# └──────────────┴──────────────────────────────────────────┘

# 查看所有支持的 DNS API
ls ~/.acme.sh/dnsapi/ | grep dns_ | sed 's/dns_//' | sed 's/\.sh//'

4.6 手动 DNS 验证(无 API 时)

BASH
# 手动模式:acme.sh 给出 TXT 记录,你手动添加到 DNS
acme.sh --issue --dns -d example.com -d *.example.com --yes-I-know-dns-manual-mode-enough-go-ahead-please

# 输出示例:
# Add the following TXT record:
# Domain: _acme-challenge.example.com
# TXT value: xxxxxxxxxxxxxxxx
# Please add it to your DNS server, then press Enter to continue...

# 添加 DNS TXT 记录后按 Enter 继续

# 续期时需要重复手动操作(不推荐长期使用)

4.7 DNS Alias 模式

适用于:域名 DNS 托管在不支持 API 的服务商,但可以设置 CNAME 到另一个支持 API 的域名。

BASH
# 场景:
# example.com 在不支持 API 的 DNS 服务商
# acme-validation.example.net 在 Cloudflare

# 1. 在 example.com 的 DNS 设置 CNAME:
# _acme-challenge.example.com → _acme-challenge.example.net

# 2. 设置环境变量
export CF_Token="your_cloudflare_token"
export ALIAS_DOMAIN="example.net"

# 3. 申请证书
acme.sh --issue --dns dns_cf -d example.com --challenge-alias example.net

🚀 第五部分:证书部署

5.1 安装证书到 Nginx

BASH
# 安装证书到指定路径并自动 reload Nginx
acme.sh --install-cert -d example.com \
    --key-file /etc/nginx/ssl/example.com.key \
    --fullchain-file /etc/nginx/ssl/example.com.fullchain.cer \
    --reloadcmd "nginx -s reload"

# ECC 证书
acme.sh --install-cert -d example.com --ecc \
    --key-file /etc/nginx/ssl/example.com.ecc.key \
    --fullchain-file /etc/nginx/ssl/example.com.ecc.fullchain.cer \
    --reloadcmd "nginx -s reload"

Nginx SSL 配置

NGINX
server {
    listen 443 ssl http2;
    server_name example.com;
    
    ssl_certificate     /etc/nginx/ssl/example.com.fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    
    # 现代 TLS 配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000" always;
}

5.2 安装证书到 Caddy

BASH
# Caddy 有内置自动 HTTPS,但如果想用 acme.sh 管理证书:
acme.sh --install-cert -d example.com \
    --key-file /etc/caddy/certs/example.com.key \
    --fullchain-file /etc/caddy/certs/example.com.cer \
    --reloadcmd "systemctl reload caddy"
PLAINTEXT
# Caddyfile 使用自定义证书
example.com {
    tls /etc/caddy/certs/example.com.cer /etc/caddy/certs/example.com.key
    reverse_proxy localhost:3000
}

5.3 安装证书到 HAProxy

BASH
# HAProxy 需要将证书和私钥合并为一个文件
acme.sh --install-cert -d example.com \
    --key-file /etc/haproxy/certs/example.com.key \
    --fullchain-file /etc/haproxy/certs/example.com.cer \
    --reloadcmd "cat /etc/haproxy/certs/example.com.cer /etc/haproxy/certs/example.com.key > /etc/haproxy/certs/example.com.pem && systemctl reload haproxy"

5.4 安装证书到 Apache

BASH
acme.sh --install-cert -d example.com \
    --key-file /etc/apache2/ssl/example.com.key \
    --fullchain-file /etc/apache2/ssl/example.com.cer \
    --reloadcmd "apachectl -k graceful"

5.5 部署到其他服务

BASH
# 部署到 Docker 中的 Nginx
acme.sh --install-cert -d example.com \
    --key-file /opt/nginx/ssl/example.com.key \
    --fullchain-file /opt/nginx/ssl/example.com.cer \
    --reloadcmd "docker exec nginx nginx -s reload"

# 部署到 Proxmox VE
acme.sh --install-cert -d pve.example.com \
    --key-file /etc/pve/local/pve-ssl.key \
    --fullchain-file /etc/pve/local/pve-ssl.pem \
    --reloadcmd "systemctl restart pveproxy"

# 部署到 Mail Server (Postfix + Dovecot)
acme.sh --install-cert -d mail.example.com \
    --key-file /etc/ssl/private/mail.key \
    --fullchain-file /etc/ssl/certs/mail.cer \
    --reloadcmd "systemctl reload postfix && systemctl reload dovecot"

# 部署到 OpenWrt
acme.sh --install-cert -d router.example.com \
    --key-file /etc/uhttpd.key \
    --fullchain-file /etc/uhttpd.crt \
    --reloadcmd "/etc/init.d/uhttpd restart"

🔄 第六部分:自动续期管理

6.1 自动续期机制

PLAINTEXT
acme.sh 自动续期流程:

1. cron 定时任务(每天凌晨执行)
   ├── acme.sh --cron
   └── 检查所有证书到期时间

2. 到期前 30 天自动续期
   ├── 2026 年证书有效期 47 天
   ├── 到期前 30 天 = 签发后 17 天即续期
   └── 续期频率比 90 天时代更高

3. 续期流程
   ├── 使用保存的 DNS API 凭证自动验证
   ├── 申请新证书
   ├── 执行 install-cert 部署
   └── 执行 reloadcmd 重载服务

4. 通知
   ├── 成功:静默(不发通知)
   └── 失败:发送邮件通知

6.2 查看证书列表与状态

BASH
# 查看所有证书
acme.sh --list

# 输出示例:
# Main_Domain     KeyLength  SAN_Domains    CA               Created               Renew
# example.com     "ECC-256"  www.example.com  LetsEncrypt     2026-07-01T08:00:00Z  2026-08-15T08:00:00Z
# api.example.com "ECC-256"  -              LetsEncrypt     2026-07-15T08:00:00Z  2026-08-28T08:00:00Z

# 查看指定证书详情
acme.sh --info -d example.com

# 查看证书内容
openssl x509 -in ~/.acme.sh/example.com/fullchain.cer -text -noout | head -30

6.3 手动续期

BASH
# 强制续期单个证书
acme.sh --renew -d example.com --force

# 强制续期 ECC 证书
acme.sh --renew -d example.com --ecc --force

# 续期所有证书(手动触发)
acme.sh --cron --force

# 调试模式续期(查看详细输出)
acme.sh --renew -d example.com --debug 2

6.4 修改续期通知

BASH
# 设置通知邮箱
acme.sh --update-account -m new@email.com

# 设置 webhook 通知(续期失败时)
export NOTIFY_HOOK='https://your-webhook-url/notify'
acme.sh --set-notify-hook

# 关闭通知(不推荐)
acme.sh --set-notify-hook --notify-hook off

🆕 第七部分:2026 新特性 DNS-PERSIST-01

7.1 DNS-PERSIST-01 工作原理

PLAINTEXT
传统 DNS-01 验证(每次续期都要操作 DNS):

  签发证书:
    1. acme.sh → DNS API → 添加 TXT 记录
    2. Let's Encrypt 验证 TXT 记录
    3. acme.sh → DNS API → 删除 TXT 记录
    4. 签发证书

  续期证书(重复上述步骤):
    1. acme.sh → DNS API → 添加 TXT 记录
    2. Let's Encrypt 验证
    3. acme.sh → DNS API → 删除 TXT 记录
    4. 续期证书

  问题:每次续期都要操作 DNS API,可能失败

DNS-PERSIST-01 验证(一次配置,长期有效):

  首次设置:
    1. 在 DNS 添加一条持久化 TXT 记录
    2. Let's Encrypt 记录授权

  签发/续期证书:
    1. acme.sh → Let's Encrypt 请求证书
    2. Let's Encrypt 检查持久化 TXT 记录
    3. 直接签发/续期(不需要修改 DNS)

  优势:
    - 续期不需要 DNS API
    - 适合 DNS API 不稳定的场景
    - 适合 IoT / 嵌入式设备
    - 减少 DNS API 调用次数

7.2 使用 DNS-PERSIST-01

BASH
# acme.sh 3.0.7+ 支持 DNS-PERSIST-01

# 1. 首次设置持久化 DNS 验证
acme.sh --issue -d example.com --dns dns_cf --dns-persist

# 2. acme.sh 会添加一条长期 TXT 记录:
#    _acme-challenge.persist.example.com → <persistent_token>

# 3. 之后续期不需要调用 DNS API
#    Let's Encrypt 直接检查持久化记录

# 查看持久化记录
acme.sh --info -d example.com | grep persist

# 移除持久化记录(不再使用时)
acme.sh --deactivate -d example.com --dns-persist

7.3 证书有效期 47 天的影响

PLAINTEXT
47 天有效期的影响与应对:

┌──────────────────────────────────────────────────────────┐
│  90 天时代 (2025)         │  47 天时代 (2026)          │
├────────────────────────────┼────────────────────────────┤
│  续期窗口:30 天           │  续期窗口:17 天            │
│  cron 每天检查 → 足够      │  cron 每天检查 → 足够       │
│  手动续期可行(但不推荐)  │  手动续期几乎不可能         │
│  DNS API 失败有充足时间    │  DNS API 失败窗口更紧       │
│  重试 3-5 次足够           │  可能需要重试更多次         │
└────────────────────────────┴────────────────────────────┘

应对策略:
  1. 确保自动续期 cron 正常运行
  2. 设置续期失败通知
  3. 考虑使用 DNS-PERSIST-01 减少依赖
  4. 监控证书到期时间(Uptime Kuma 等)
  5. 准备备用 CA(ZeroSSL 作为备份)

🔐 第八部分:ECC vs RSA 证书

8.1 证书类型选择

PLAINTEXT
┌──────────────────────────────────────────────────────────┐
│              ECC vs RSA 证书对比                         │
├──────────────────┬────────────────┬──────────────────────┤
│ 特性             │ ECC            │ RSA                  │
├──────────────────┼────────────────┼──────────────────────┤
│ 算法             │ ECDSA P-256    │ RSA 2048             │
│ 密钥长度         │ 256 bit        │ 2048 bit             │
│ 安全性           │ 等同 RSA 3072  │ 标准                 │
│ TLS 握手速度     │ 更快           │ 较慢                 │
│ 证书大小         │ 更小           │ 更大                 │
│ 兼容性           │ 99%+           │ 100%                 │
│ acme.sh 默认     │ ✅ 是          │ 需要指定             │
│ 老旧设备兼容     │ ⚠️ 可能有问题  │ ✅ 完全兼容          │
│ 推荐场景         │ 现代 Web       │ 兼容性优先           │
└──────────────────┴────────────────┴──────────────────────┘

8.2 申请不同类型证书

BASH
# ECC 证书(acme.sh 默认)
acme.sh --issue -d example.com --dns dns_cf
# 默认使用 ECDSA P-256

# RSA 证书
acme.sh --issue -d example.com --dns dns_cf --keylength 2048

# RSA 4096 证书(更高安全性)
acme.sh --issue -d example.com --dns dns_cf --keylength 4096

# ECC P-384 证书
acme.sh --issue -d example.com --dns dns_cf --keylength ec-384

# 同时申请 ECC + RSA(双证书部署)
# 先申请 ECC
acme.sh --issue -d example.com --dns dns_cf
# 再申请 RSA
acme.sh --issue -d example.com --dns dns_cf --keylength 2048
# 两个证书分别存储在不同目录

8.3 Nginx 双证书部署

NGINX
# 同时配置 ECC 和 RSA 证书
server {
    listen 443 ssl http2;
    server_name example.com;
    
    # RSA 证书(默认)
    ssl_certificate     /etc/nginx/ssl/example.com.rsa.cer;
    ssl_certificate_key /etc/nginx/ssl/example.com.rsa.key;
    
    # ECC 证书(现代客户端优先使用)
    ssl_certificate     /etc/nginx/ssl/example.com.ecc.cer;
    ssl_certificate_key /etc/nginx/ssl/example.com.ecc.key;
    
    # Nginx 会自动根据客户端能力选择证书
    ssl_protocols TLSv1.2 TLSv1.3;
}

🛡️ 第九部分:安全最佳实践

9.1 API 密钥安全

BASH
# 1. DNS API Token 权限最小化
# Cloudflare: 只授予 Zone:DNS:Edit 权限
# AliDNS: 只授予 DNS 解析权限
# AWS: 只授予 route53:ChangeResourceRecordSets

# 2. 不要将 API Token 提交到 Git
# acme.sh 自动保存到 ~/.acme.sh/account.conf
# 该文件包含敏感信息

# 3. 定期轮换 API Token
# 更新 token 后重新设置环境变量
export CF_Token="new_token"
acme.sh --issue -d example.com --dns dns_cf --force

# 4. 使用环境变量而非硬编码
# 在 CI/CD 中通过 Secret 注入

9.2 证书文件权限

BASH
# 设置正确的文件权限
chmod 700 ~/.acme.sh/
chmod 600 ~/.acme.sh/account.conf
chmod 600 ~/.acme.sh/*/example.com.key
chmod 644 ~/.acme.sh/*/fullchain.cer

# 部署后的证书权限
chmod 600 /etc/nginx/ssl/*.key
chmod 644 /etc/nginx/ssl/*.cer
chown root:root /etc/nginx/ssl/*

9.3 OCSP Stapling 配置

BASH
# acme.sh 默认签发的 fullchain.cer 包含完整证书链
# 可直接用于 OCSP Stapling

# Nginx OCSP Stapling 配置
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/example.com.fullchain.cer;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# 验证 OCSP Stapling
openssl s_client -connect example.com:443 -status 2>/dev/null | grep "OCSP Response Status"
# 应输出:OCSP Response Status: successful

9.4 证书透明度监控

BASH
# 检查证书是否被公开记录
# 访问 https://crt.sh/?q=example.com
# 或使用 API
curl -s "https://crt.sh/?q=%25.example.com&output=json" | jq '.[].issuer_name' | sort -u

# 如果发现未经授权的证书:
# 1. 立即检查 DNS 是否被劫持
# 2. 轮换 DNS API Token
# 3. 撤销未授权证书
# 4. 联系 CA 报告问题

🌍 第十部分:社区反馈与实战经验

10.1 Reddit 社区讨论摘要

根据 Reddit 相关讨论(r/selfhosted, r/sysadmin, r/linux, r/privacy 等板块)中关于 acme.sh 的用户反馈整理:

r/selfhosted 用户 u/selfhosted_pro(2025年底)

“I’ve been using acme.sh for over 2 years across 15+ domains. It just works. The DNS API integration with Cloudflare is seamless — set it once and forget. With the 47-day certificate change in 2026, automation is more critical than ever. acme.sh’s cron job has never failed me. The only thing I had to learn was to use --install-cert with --reloadcmd to actually deploy the certificate after renewal.”

r/sysadmin 用户 u/sysadmin_ops(2026年初)

“We switched from certbot to acme.sh for all our edge servers. The main reason: zero dependencies. No Python, no pip, no virtualenv conflicts. Just a shell script that works everywhere — from Alpine Linux to busybox containers. The DNS-PERSIST-01 feature in 2026 is a game changer for our IoT fleet where DNS API access isn’t always reliable.”

r/linux 用户 u/bash_enthusiast(2026年中)

“acme.sh is a masterpiece of shell scripting. 500KB of pure bash that replaces a 50MB Python installation. The code quality is excellent — proper error handling, retry logic, DNS API abstraction layer. I’ve read the source code to learn shell scripting best practices. The DNS-PERSIST-01 support was added within weeks of Let’s Encrypt announcing it.”

r/privacy 用户 u/secure_web_admin(2025年底)

“For wildcard certificates, acme.sh + Cloudflare DNS API is the best combo. One command: acme.sh --issue --dns dns_cf -d *.example.com. No more dealing with certbot’s DNS plugin nightmare. The 47-day certificate lifetime in 2026 makes manual renewal impossible, but acme.sh handles it automatically. Set up email notifications for renewal failures and you’re done.”

10.2 常见使用场景

PLAINTEXT
来自社区的实际使用场景:

1. 多域名批量管理
   "20 个子域名通过通配符证书一次性搞定"
   "不同域名使用不同 DNS 服务商,acme.sh 都支持"

2. 内网服务 HTTPS
   "内网服务不需要开放 80 端口,DNS 验证完美解决"
   "DNS-PERSIST-01 让内网证书续期不再依赖 DNS API"

3. 容器化部署
   "acme.sh Docker 镜像 + 卷挂载 = 容器自动 HTTPS"
   "比 Traefik 的 ACME 集成更灵活"

4. IoT / 嵌入式设备
   "OpenWrt 路由器上运行 acme.sh,管理 LuCI HTTPS 证书"
   "DNS-PERSIST-01 适合资源受限设备"

5. 多服务器证书同步
   "一台服务器统一申请,rsync 分发到其他服务器"
   "配合 webhook 实现多节点自动部署"

10.3 社区推荐的最佳实践

PLAINTEXT
1. 使用 DNS 验证(不需要停 Web 服务)
2. 通配符证书减少管理复杂度
3. 设置续期失败邮件通知
4. 使用 --install-cert 自动部署证书
5. 定期检查 cron 任务是否正常运行
6. 监控证书到期时间(外部监控)
7. 准备备用 CA(ZeroSSL 作为备份)
8. API Token 权限最小化
9. 考虑 DNS-PERSIST-01 减少 DNS API 依赖
10. 保持 acme.sh 更新到最新版本

📋 第十一部分:故障排除

11.1 常见问题

PLAINTEXT
问题1:DNS API 验证失败
  原因:
    - API Token 权限不足
    - DNS 服务商 API 变更
    - 网络无法访问 DNS API
  解决:
    - 检查 Token 权限(需要 DNS Edit)
    - 使用 --debug 2 查看详细错误
    - 尝试手动 DNS 模式

问题2:证书申请速率限制
  原因:
    - 同一域名每周超过 50 次
    - 失败重试过于频繁
  解决:
    - 使用 --force 前先确认配置正确
    - 使用 staging 环境测试
    - 切换到 ZeroSSL 作为备用 CA

问题3:cron 续期不执行
  原因:
    - cron 服务未运行
    - 环境变量在 cron 中不可用
  解决:
    - 检查 crontab -l
    - 确保 PATH 包含 acme.sh 路径
    - 查看 ~/.acme.sh/acme.sh.log

问题4:证书部署后不生效
  原因:
    - reloadcmd 未配置或失败
    - Web 服务器缓存了旧证书
  解决:
    - 检查 --install-cert 的 --reloadcmd
    - 手动执行 reloadcmd 测试
    - 重启 Web 服务(而非 reload)

问题5:通配符证书申请失败
  原因:
    - DNS API 未正确配置
    - DNS 传播延迟
  解决:
    - 增加 DNS 等待时间
    - 使用 --debug 2 排查
    - 确认 DNS API Token 权限

11.2 调试命令

BASH
# 调试模式申请证书
acme.sh --issue -d example.com --dns dns_cf --debug 2

# 查看 acme.sh 日志
tail -100 ~/.acme.sh/acme.sh.log

# 检查 cron 任务
crontab -l | grep acme

# 手动执行 cron(测试续期)
acme.sh --cron --debug 2

# 查看证书详情
acme.sh --info -d example.com

# 验证证书
openssl x509 -in ~/.acme.sh/example.com/fullchain.cer -text -noout

# 检查证书链完整性
openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
    openssl x509 -text -noout | grep -A2 "Authority Information"

# 测试 OCSP Stapling
openssl s_client -connect example.com:443 -status 2>/dev/null | \
    grep "OCSP Response Status"

📋 最佳实践清单

PLAINTEXT
安装配置:
□ 使用 curl https://get.acme.sh | sh 一键安装
□ 设置默认 CA:acme.sh --set-default-ca --server letsencrypt
□ 配置通知邮箱
□ 验证 cron 定时任务已创建
□ 保持 acme.sh 更新:acme.sh --upgrade

证书申请:
□ 优先使用 DNS 验证(不需要停 Web 服务)
□ 通配符证书使用 DNS API 自动验证
□ 默认使用 ECC 证书(性能更好)
□ API Token 权限最小化(仅 DNS Edit)
□ 多域名使用通配符证书减少管理

证书部署:
□ 使用 --install-cert 自动部署到指定路径
□ 配置 --reloadcmd 自动重载 Web 服务
□ 设置正确的文件权限(key 600, cer 644)
□ 配置完整证书链(fullchain.cer)
□ 启用 OCSP Stapling

自动续期:
□ 确认 cron 定时任务正常运行
□ 设置续期失败邮件通知
□ 监控证书到期时间(外部监控)
□ 准备备用 CA(ZeroSSL)
□ 考虑 DNS-PERSIST-01 减少依赖

安全加固:
□ API Token 定期轮换
□ 证书私钥权限 600
□ 检查证书透明度日志
□ 使用现代 TLS 配置(TLS 1.2+)
□ 配置 HSTS 安全头

2026 适配:
□ 升级 acme.sh 到 3.0.7+(支持 DNS-PERSIST-01)
□ 适应 47 天证书有效期
□ 增加续期失败监控
□ 考虑 DNS-PERSIST-01 场景
□ 准备 6 天有效期的未来方案

结语

随着 2026 年 Let’s Encrypt 将证书有效期缩短至 47 天,证书自动化管理不再是可选项,而是必选项。acme.sh 凭借纯 Shell 实现、零依赖、150+ DNS API 支持和 DNS-PERSIST-01 新特性,是证书自动化管理的最佳工具。

核心要点回顾:

acme.sh vs certbot 选择:

相关文章:

再次提醒:本文仅作技术研究与学习参考,请遵守所在国家和地区的法律法规。证书自动化管理是现代 Web 运维的基础技能,建议每个自托管爱好者都掌握。

版权声明

作者: 易邦

链接: https://blog.e8k.net/posts/acme-sh-certificate-automation-guide/

许可证: 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。