本页目录

证书操作手册

openssl

# 查看远程服务器证书
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -text -noout
# -servername: 指定 SNI (同一 IP 多个证书时必须)
# </dev/null: 立即关闭连接
# 输出含: Subject, Issuer, Validity, SAN, Public Key, Signature

# 查看本地证书文件
openssl x509 -text -noout -in cert.pem
openssl x509 -text -noout -in cert.pem | grep -E 'Not Before|Not After|DNS:'

# 检查证书是否过期
openssl x509 -checkend 86400 -noout -in cert.pem && echo "OK" || echo "EXPIRED"

# 生成私钥 (ECDSA P-256, 现代推荐)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out key.pem
# 或 RSA 2048 (兼容旧系统)
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out key.pem

# 生成 CSR (证书签名请求, 交 CA 签发)
openssl req -new -key key.pem -out csr.pem -subj "/CN=example.com"
# 含 SAN 的 CSR (现代必须, Chrome 已忽略 CN):
cat > san.cnf <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[req_distinguished_name]
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = *.example.com
EOF
openssl req -new -key key.pem -out csr.pem -config san.cnf

# 自签证书 (测试用, 不信任)
openssl req -new -x509 -days 365 -key key.pem -out cert.pem -subj "/CN=localhost"

# 验证证书链
openssl verify -CAfile ca-bundle.crt cert.pem

# 查看证书指纹 (匹配 known 证书)
openssl x509 -fingerprint -sha256 -noout -in cert.pem

acme.sh

# DNS-01 签发 (阿里云 DNS) — 可签通配符 *.example.com
export Ali_Key="xxx" Ali_Secret="yyy"
acme.sh --issue --dns dns_ali -d example.com -d '*.example.com'
# → ~/.acme.sh/example.com_ecc/ 目录下生成证书

# 安装证书到目标位置 + reload hook
acme.sh --install-cert -d example.com \
  --cert-file /etc/caddy/certs/example.crt \
  --key-file /etc/caddy/certs/example.key \
  --fullchain-file /etc/caddy/certs/example-fullchain.crt \
  --reloadcmd "systemctl reload caddy"

# 手动续期
acme.sh --renew -d example.com --force

# 自动续期 (cron)
acme.sh --cron
# → 检查所有证书, 过期前 30 天自动续, 续成功 → run reloadcmd

# 查看已签发
acme.sh --list

certbot

# DNS-01 签发 (腾讯云 DNSPod)
certbot certonly --dns-tencentcloud \
  --dns-tencentcloud-credentials /etc/letsencrypt/tencentcloud.ini \
  --dns-tencentcloud-propagation-seconds 30 \
  -d example.com

# 续期 (dry-run)
certbot renew --dry-run

# 查看已签发
certbot certificates

故障排查

# 证书过期
openssl x509 -text -noout -in cert.pem | grep "Not After"

# 证书链不完整 (curl 报 SSL error)
openssl verify -CAfile ca-bundle.crt cert.pem
# → 中间 CA 缺失 → 需要 fullchain.pem (cert + intermediates)

# Let's Encrypt rate limit
# → Failed validation limit: 5 failures per account per hostname per hour
# → 用 --dry-run 或 staging 环境测试: --server https://acme-staging-v02.api.letsencrypt.org/directory

# acme.sh 自动续期没跑
# → 检查 crontab: crontab -l | grep acme.sh
# → 或手动: acme.sh --cron --force