第09章 - 高级功能与技巧
本章介绍 acme.sh 的高级功能,包括 ECC 证书、通配符证书、多域名证书、DNS 别名模式、证书格式转换、调试技巧等,帮助你充分发挥 acme.sh 的潜力。
9.1 ECC 证书(椭圆曲线密码)
9.1.1 ECC 证书的优势
| 对比项 | RSA-2048 | ECC-256 |
|---|---|---|
| 安全级别 | 约等同于 3072 位 ECC | 等同于 RSA-3072 |
| 密钥大小 | 2048 位 | 256 位 |
| TLS 握手速度 | 较慢 | 更快(CPU 占用更低) |
| 证书文件大小 | 较大 | 更小 |
| 兼容性 | 所有系统和设备 | 不支持 Windows XP 及极老旧浏览器 |
对于现代服务器(2024 年+),推荐使用 EC-256(prime256v1)或 EC-384(secp384r1)。
9.1.2 申请 ECC 证书
# EC-256(推荐,性能最佳)
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--keylength ec-256
# EC-384(更高安全级别)
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--keylength ec-384
# RSA-4096(极高安全要求场景)
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--keylength 4096
# 默认(RSA-2048)
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com
9.1.3 安装 ECC 证书
申请 ECC 证书后,安装时需要加 --ecc 参数:
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/nginx/ssl/ec/privkey.pem \
--fullchain-file /etc/nginx/ssl/ec/fullchain.pem \
--reloadcmd "systemctl reload nginx"
9.1.4 同域名 RSA + ECC 双证书部署
对于高并发、对性能要求较高的网站,可以同时申请 RSA 和 ECC 两套证书,现代客户端会自动选择 ECC(旧版浏览器降级使用 RSA):
# 申请 RSA 证书(默认路径)
acme.sh --issue --dns dns_cf -d example.com -d *.example.com
# 申请 ECC 证书(存储在 example.com_ecc 目录下)
acme.sh --issue --dns dns_cf -d example.com -d *.example.com --keylength ec-256
# 安装 RSA 证书
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/rsa/privkey.pem \
--fullchain-file /etc/nginx/ssl/rsa/fullchain.pem \
--reloadcmd "systemctl reload nginx"
# 安装 ECC 证书
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/nginx/ssl/ecc/privkey.pem \
--fullchain-file /etc/nginx/ssl/ecc/fullchain.pem \
--reloadcmd "systemctl reload nginx"
Nginx 双证书配置(Nginx 1.11.0+):
server {
listen 443 ssl http2;
server_name example.com;
# RSA 证书(兼容旧版客户端)
ssl_certificate /etc/nginx/ssl/rsa/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/rsa/privkey.pem;
# ECC 证书(现代客户端优先使用)
ssl_certificate /etc/nginx/ssl/ecc/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/ecc/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
}
9.2 通配符证书
9.2.1 通配符证书的特点
通配符证书(Wildcard Certificate)*.example.com 的特点:
- 覆盖
example.com的所有直接子域:www.example.com、api.example.com、mail.example.com等 - 不覆盖根域名
example.com本身(需要单独加-d example.com) - 不覆盖多级通配符:
sub.api.example.com不被*.example.com覆盖 - 必须使用 DNS-01 验证(HTTP-01 无法验证通配符)
9.2.2 申请通配符证书
# 同时覆盖根域名和所有直接子域
acme.sh --issue --dns dns_cf \
-d example.com \
-d *.example.com
# 仅通配符(不含根域名)
acme.sh --issue --dns dns_cf \
-d *.example.com
9.2.3 多级通配符
如果需要同时覆盖多个层级,需要申请多个通配符:
# 覆盖 example.com、*.example.com 和 *.api.example.com
acme.sh --issue --dns dns_cf \
-d example.com \
-d *.example.com \
-d *.api.example.com
9.3 多域名 SAN 证书
9.3.1 SAN 证书说明
SAN(Subject Alternative Names)证书允许一张证书覆盖多个不相关的域名,非常适合在一台服务器上托管多个网站的场景。
Let’s Encrypt/ZeroSSL 每张证书最多支持 100 个 SAN 域名。
9.3.2 申请多域名 SAN 证书
# 在同一个 DNS 服务商管理的多个域名
export CF_Token="your_cf_token"
export CF_Account_ID="your_account_id"
acme.sh --issue --dns dns_cf \
-d example.com \
-d www.example.com \
-d api.example.com \
-d *.example.com \
-d another-domain.com \
-d *.another-domain.com
9.3.3 混合 DNS 服务商 SAN 证书
如果多个域名分布在不同的 DNS 服务商,需要为每个域名单独指定 DNS API:
acme.sh --issue \
-d example.com --dns dns_cf \
-d another-domain.com --dns dns_ali \
-d third-domain.com -w /var/www/html
9.4 DNS 别名模式深度解析
9.4.1 应用场景
DNS 别名模式(DNS Alias Mode)解决了以下几个痛点:
场景一:主域名 DNS 无 API
主域名 example.com 的 DNS 托管在不支持 API 的服务商(如部分国内小型 DNS 服务商),但希望自动续期。
场景二:安全隔离
不希望将主域名的 DNS 操作权限(API Key)存放在 Web 服务器上(避免服务器被入侵后 DNS 被劫持)。
场景三:集中化验证
多台服务器的多个域名,都通过一个统一的 DNS API 账户(如 Cloudflare)进行验证,简化管理。
9.4.2 完整配置步骤
前提:准备一个辅助域名 challenge-dns.io,托管在 Cloudflare。
第一步:在主域名的 DNS 控制台,为每个需要申请证书的域名添加 CNAME(一次性操作):
_acme-challenge.example.com CNAME _acme-challenge.challenge-dns.io
_acme-challenge.api.example.com CNAME _acme-challenge.challenge-dns.io
第二步:申请证书时使用 --challenge-alias 参数:
export CF_Token="your_cf_token_for_challenge_dns_io"
export CF_Account_ID="your_cf_account_id"
# 申请 example.com 证书
acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--challenge-alias challenge-dns.io
# 申请 api.example.com 证书
acme.sh --issue --dns dns_cf \
-d api.example.com \
--challenge-alias challenge-dns.io
acme.sh 会将 TXT 记录写入 _acme-challenge.challenge-dns.io,而主域名通过 CNAME 指向该记录,CA 验证时会跟随 CNAME 找到正确的 TXT 值。
9.5 Standalone 独立服务器模式进阶
9.5.1 在 Docker 容器中运行 Standalone
如果在 Docker 容器内运行 acme.sh,使用 Standalone 模式时需要映射端口:
docker run --rm \
-v /docker/acme.sh:/acme.sh \
-p 80:80 \
neilpang/acme.sh --issue \
--standalone \
-d example.com
9.5.2 反向代理后的 Standalone 模式
在使用 Nginx 作为反向代理的环境中,将 ACME 验证路径转发到 acme.sh 的 Standalone 服务:
server {
listen 80;
server_name example.com;
# 将 ACME 验证请求转发给本地 8888 端口
location /.well-known/acme-challenge/ {
proxy_pass http://127.0.0.1:8888;
}
# 其他请求正常处理或重定向
location / {
return 301 https://$host$request_uri;
}
}
# 使用 8888 端口申请证书
acme.sh --issue -d example.com --standalone --httpport 8888
9.6 调试与诊断
9.6.1 启用调试输出
# 基础调试(级别 1)
acme.sh --issue --dns dns_cf -d example.com --debug
# 详细调试(级别 2,输出所有 API 请求和响应)
acme.sh --issue --dns dns_cf -d example.com --debug 2
# 最详细调试(级别 3)
acme.sh --issue --dns dns_cf -d example.com --debug 3
9.6.2 使用测试 CA 验证配置
在生产环境申请之前,先用测试 CA 验证整个流程是否正常:
# 使用 Let's Encrypt 测试服务器(颁发的证书不受信任,但不消耗配额)
acme.sh --issue --dns dns_cf -d example.com -d *.example.com \
--server letsencrypt_test
# 或使用 --test 参数
acme.sh --issue --dns dns_cf -d example.com \
--test
9.6.3 常见诊断命令
# 检查证书文件完整性
openssl x509 -in ~/.acme.sh/example.com/fullchain.cer -noout -text
# 验证私钥与证书匹配
# 两个命令输出的 MD5 值应相同
openssl x509 -noout -modulus -in ~/.acme.sh/example.com/example.com.cer | openssl md5
openssl rsa -noout -modulus -in ~/.acme.sh/example.com/example.com.key | openssl md5
# 检查已安装证书的 SSL 握手
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | openssl x509 -noout -dates
# 检查证书链完整性
openssl verify -CAfile ~/.acme.sh/example.com/ca.cer ~/.acme.sh/example.com/example.com.cer
# 用 curl 测试 HTTPS
curl -vI https://example.com 2>&1 | grep -E "SSL|expire|issuer"
9.6.4 DNS TXT 记录验证
在 DNS API 模式出现问题时,手动验证 DNS 记录:
# 检查 TXT 记录(使用 Google DNS)
dig @8.8.8.8 _acme-challenge.example.com TXT
# 检查 TXT 记录(使用阿里 DNS)
dig @223.5.5.5 _acme-challenge.example.com TXT
# 检查 CNAME(DNS 别名模式)
dig _acme-challenge.example.com CNAME
# 使用 nslookup
nslookup -type=TXT _acme-challenge.example.com 8.8.8.8
9.7 证书格式与转换
9.7.1 PEM 到 PKCS12(PFX)
# 生成 PFX(Windows IIS、Java 应用服务器)
acme.sh --toPkcs -d example.com --password "your_password"
# 生成的文件位置:~/.acme.sh/example.com/example.com.pfx
# ECC 证书转 PFX
acme.sh --toPkcs -d example.com --ecc --password "your_password"
9.7.2 PEM 到 PKCS8(Java 应用)
# 将私钥转换为 PKCS8 格式(某些 Java 应用需要)
openssl pkcs8 -topk8 -inform PEM -outform PEM \
-in ~/.acme.sh/example.com/example.com.key \
-out /path/to/privkey-pkcs8.pem \
-nocrypt
9.7.3 手动 PEM 转 PFX(不使用 acme.sh 命令)
openssl pkcs12 -export \
-in ~/.acme.sh/example.com/fullchain.cer \
-inkey ~/.acme.sh/example.com/example.com.key \
-out /path/to/example.com.pfx \
-passout pass:"your_password"
9.8 IPv6 服务器支持
对于仅有 IPv6 地址的服务器(IPv6 only):
# Standalone 模式(IPv6)
acme.sh --issue -d example.com --standalone --listen-v6
# 确保服务器有 IPv6 可达性
ping6 acme-v02.api.letsencrypt.org
9.9 证书透明度日志(CT Logs)
acme.sh 申请的证书会自动记录到证书透明度日志(CT Logs)中。这是 CA 颁发证书时的要求,无法关闭。可以通过以下网站查询你域名的所有历史证书:
9.10 非 root 用户运行 acme.sh
acme.sh 设计为无需 root 权限即可运行,这是它的重要安全特性之一。
# 以普通用户安装
su - myuser
curl https://get.acme.sh | sh -s email=myuser@email.com
source ~/.bashrc
# 以普通用户申请证书(使用 DNS API,无需 80 端口权限)
acme.sh --issue --dns dns_cf -d example.com
# 如果需要安装到系统目录,使用 sudo 执行 reloadcmd
acme.sh --install-cert -d example.com \
--key-file /home/myuser/ssl/privkey.pem \
--fullchain-file /home/myuser/ssl/fullchain.pem \
--reloadcmd "sudo systemctl reload nginx"
配置 sudoers 允许无密码执行:
# /etc/sudoers.d/acme-nginx
myuser ALL=(ALL) NOPASSWD: /usr/bin/systemctl reload nginx
9.11 使用自定义 CSR 申请证书
在某些特殊场景(如需要指定 CSR 中的特定字段),可以使用预先生成的 CSR:
# 生成私钥和 CSR
openssl req -new -newkey rsa:2048 -nodes \
-keyout /path/to/my.key \
-out /path/to/my.csr \
-subj "/CN=example.com"
# 使用自定义 CSR 申请证书
acme.sh --signcsr --csr /path/to/my.csr --dns dns_cf
9.12 批量操作技巧
9.12.1 批量申请多个域名的证书
#!/bin/bash
# batch_issue.sh - 批量申请证书
export CF_Token="your_cf_token"
export CF_Account_ID="your_account_id"
DOMAINS=(
"site1.com *.site1.com"
"site2.com *.site2.com"
"site3.com www.site3.com api.site3.com"
)
for domain_group in "${DOMAINS[@]}"; do
primary=$(echo $domain_group | awk '{print $1}')
echo "Issuing certificate for: $domain_group"
# 构建 acme.sh 命令
CMD="acme.sh --issue --dns dns_cf"
for domain in $domain_group; do
CMD="$CMD -d $domain"
done
eval "$CMD"
echo "Done: $primary"
echo "---"
done
9.12.2 批量更新已有证书的安装路径
#!/bin/bash
# 如果服务器迁移,批量更新证书安装配置
acme.sh --list | tail -n +2 | awk '{print $1}' | while read domain; do
echo "Reinstalling cert for: $domain"
acme.sh --install-cert -d "$domain" \
--key-file "/etc/nginx/ssl/$domain/privkey.pem" \
--fullchain-file "/etc/nginx/ssl/$domain/fullchain.pem" \
--reloadcmd "systemctl reload nginx"
done
9.13 小结
本章介绍了 acme.sh 的高级功能:
- ECC 证书:
--keylength ec-256或ec-384,性能更好,推荐现代环境 - 通配符证书:必须用 DNS-01 验证,使用
-d *.example.com - 多域名 SAN:一张证书最多 100 个域名
- DNS 别名模式:主域名 CNAME 到辅助域名,集中管理验证
- 调试模式:
--debug或--debug 2获取详细日志 - 格式转换:
--toPkcs生成 PFX,支持 Windows/Java 环境 - 非 root 运行:使用 DNS API 模式完全无需 root 权限
下一章将介绍常见问题的诊断和解决方案。