使用acme.sh来实现自动化申请和续订TLS证书

缘由

写这篇文章的原因是本人的博客收到了证书过期错误, 在Egde Beta浏览器无法访问, 故写了此篇文章来记录

介绍

由AI生成, 本人验证

使用 acme.sh 这类 ACME 客户端(特别是对接 Let's Encrypt 等免费 CA)来实现自动化申请和续订 TLS 证书,相比传统的到商业证书运营商(如 DigiCert, Sectigo, GlobalSign 等)手动申请证书,具有显著的优势,尤其是在自动化、成本和效率方面。

以下是详细的对比和优点分析:


✅ 1. 完全自动化(核心优势)

传统方式 使用 acme.sh
需要手动登录运营商网站,填写信息,选择域名,选择验证方式(文件验证、DNS验证、邮箱验证等),下载证书文件,再手动上传部署。 一行命令即可完成申请和部署,支持自动续期(默认每60天检查一次)。
续期也需要在证书到期前手动操作,容易忘记导致证书过期。 acme.sh 安装时会自动创建 cron 定时任务,到期自动续期,无需人工干预。
高风险:一旦忘记续期,网站 HTTPS 会中断,影响用户体验和 SEO。 零风险:自动化流程确保证书永远有效。

🌟 优点总结省时、省力、避免人为失误,实现真正的"设置一次,永久有效"


✅ 2. 成本极低(通常是免费)

传统方式 使用 acme.sh
商业证书价格较高,尤其是 EV 证书或多域名证书,每年需要支付几百到上千元不等。 对接 Let's Encrypt 是完全免费的,不限制申请数量。
即使是便宜的 DV 证书,长期累积也是一笔开销。 0 成本,特别适合个人博客、开发测试、中小项目、微服务等场景。

💰 优点总结大幅降低 HTTPS 部署成本,推动全网加密普及


✅ 3. 快速部署,即时生效

传统方式 使用 acme.sh
验证、审核、签发可能需要几分钟到几小时(尤其是 EV 证书)。 从申请到签发通常在 10-30 秒内完成,特别适合 CI/CD、容器化、Serverless 等动态环境。
无法满足快速上线需求。 可集成到自动化部署脚本中,新服务上线即拥有 HTTPS。

优点总结极速响应,适合现代 DevOps 流程


✅ 4. 支持现代验证方式(尤其是 DNS-01)

传统方式 使用 acme.sh
多数依赖 HTTP-01(需开放 80 端口)或邮箱验证。 支持多种验证方式,尤其是 DNS-01 API 自动化验证
通配符证书申请复杂,价格昂贵。 使用 --dns dns_dp 等参数,一键申请通配符证书(*.example.com ,且免费。
在内网、无公网 IP、或 80/443 端口被占用的场景下难以部署。 只要能调用 DNS API,即可完成验证,不受网络拓扑限制。

🌐 优点总结灵活性强,适用场景更广


✅ 5. 易于集成和管理

传统方式 使用 acme.sh
每个证书独立管理,容易混乱。 所有证书集中管理在 ~/.acme.sh/ 目录下,结构清晰。
需要手动配置 Web 服务器(Nginx/Apache)指向新证书。 使用 --install-cert 可自动复制证书到指定路径,并通过 --reloadcmd 自动重载服务(如 systemctl reload nginx)。
难以批量管理多个域名。 支持批量脚本化管理多个域名的证书。

🔧 优点总结标准化、可编程、易于运维


⚠️ 传统商业证书的优势(acme.sh 的不足)

虽然 acme.sh 优势明显,但传统商业证书在某些场景下仍有价值:

场景 传统商业证书优势
企业信任度要求高 EV 证书会在浏览器地址栏显示公司名称,增强用户信任(Let's Encrypt 不提供 EV)。
需要更长有效期 商业证书可购买 1-2 年有效期;Let's Encrypt 证书最长 90 天acme.sh 自动续期弥补了这一点)。
需要保险和 SLA 保障 商业 CA 通常提供证书保险(如签发错误导致损失可赔偿)和更高 SLA。
私有 CA 或内部 PKI 企业内网可能使用私有 CA,不依赖公共 ACME 服务。

✅ 总结:何时选择 acme.sh

使用场景 推荐方案
个人网站、博客、开发测试环境 ✅ 强烈推荐 acme.sh + Let's Encrypt
中小型企业官网、API 服务、微服务架构 ✅ 推荐 acme.sh,成本低、自动化强
需要通配符证书的项目 ✅ 首选 acme.sh(免费 + 自动化)
对品牌信任要求极高(如银行、支付) ⚠️ 考虑商业 EV 证书
内网或私有 CA 环境 ⚠️ 使用企业内部 PKI 方案

🔚 结论

对于绝大多数现代 Web 应用和服务,使用 acme.sh 实现自动化申请和续订 TLS 证书,相比传统手动申请方式,具有压倒性的优势

自动化 + 免费 + 快速 + 灵活 = 更高效、更安全、更现代的 HTTPS 管理方式。

它已经成为 DevOps 和云原生环境中事实上的标准工具之一。除非有特殊的企业信任或合规需求,否则 acme.sh 是部署 HTTPS 的首选方案。

安装

通常情况下, 网站,应用都在服务器里部署,服务器环境一般都使用Linux系统, 所以要求Linux发行版有Git软件,多数的发行版都内置, 直接运行以下脚本即可, 或者在宿主机pull下来, 然后传递给服务器

bash 复制代码
git clone https://github.com/acmesh-official/acme.sh.git
cd ./acme.sh
cp ./acme.sh /usr/local/bin

使用

根据你的域名所在的运营商, 例如腾讯云的DNSPod, 阿里云, cloudflare等,不同的运营商, 脚本有区别,这里以DNSPod来演示

使用DNSPod方式生成证书

  1. 访问DNSPod
  2. 创建密钥并填写到下方的DP_IdDP_Key变量中

填写对应的变量, 然后在服务器执行该脚本, 等待执行完毕之后留意结果, 它会告诉你TLS证书文件的位置.

证书文件通常是 fullchain.cer强烈推荐使用 fullchain 文件 ,因为它不仅包含你的域名证书,还包含了必要的中间证书(Intermediate CA Certificates),这能确保大多数客户端(浏览器、手机等)都能完整地验证证书链,避免出现安全警告。当客户端(如浏览器)连接到你的 Nginx 服务器时,Nginx 会将这个文件里的证书发送给客户端。客户端会验证这个证书是否由可信的 CA 签发、是否在有效期内、域名是否匹配等。验证通过后,客户端会使用证书里的公钥来加密后续通信的密钥。
该脚本适用于第一次安装的情况, 如果后续需要重新生成证书, 重新运行上面的脚本失败时, 那么只需要在脚本末尾添加 --force参数

该脚本为申请一个主域 + 通配符多域名(SAN)证书:

bash 复制代码
export DP_Id=<你的DNSPod id>
export DP_Key=<你的DNSPod key>
Daomain=<你的网站域名>
acme.sh --issue --dns dns_dp -d $Daomain -d *.$Daomain --keylength ec-256 --debug

参数说明:

  • --issue 是触发证书申请流程
  • --dns dns_dp: 使用 DNS 挑战(DNS-01) 方式验证域名所有权,acme.sh会自动调用 DNSPod 的 API,在你的域名下添加一条 _acme-challenge 的 TXT 记录来完成验证, 验证完成后, 会自动删除该 TXT 记录(临时添加), 它支持申请通配符证书(*.example.com),无需开放 80/443 端口
  • -d--domain: 指定你要为哪些域名申请证书
  • --keylength ec-256: 指定生成的私钥类型和长度。ec-256 表示使用 椭圆曲线加密(ECC) ,具体是 prime256v1(NIST P-256) 曲线, 相比传统的 RSA 2048,ECC 提供了更高的安全性和更小的密钥体积,性能更好。可选值还包括:ec-384, ec-521, 2048, 3072, 4096 等。
  • --debug: 开启调试模式,输出详细的日志信息

之后就可以复制证书文件到其他位置来使用了 例如:

bash 复制代码
dir=/root/.acme.sh/example.com_ecc/
daomain=example.com
cp $dir/fullchain.cer /home/docker/nginx/ssl/nginx.crt
cp $dir/$daomain.key /home/docker/nginx/ssl/nginx.key

在Docker的nginx里使用TLS证书

示例nginx.conf:

ini 复制代码
server {
    listen 80;
    server_name ${DOMAIN};
    return 301 https://$host$request_uri;
}

server {
    server_name ${DOMAIN} www.${DOMAIN};

    # HTTP/3 with QUIC
    listen 443 quic reuseport;

    # HTTP/2 and HTTP/1.1
    listen 443 ssl;
    http2 on;

    # Security headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always;
    add_header X-XSS-Protection          "1; mode=block" always;
    add_header X-Frame-Options           SAMEORIGIN always;
    add_header X-Content-Type-Options    nosniff always;
    add_header Alt-Svc                   'h3=":443"; ma=86400; h3-29=":443"; ma=86400';

    # SSL/TLS configuration
    ssl_protocols               TLSv1.3 TLSv1.2;
    ssl_ecdh_curve              X25519:P-256:P-384;

    # 通用兼容性密码套件
    ssl_ciphers                 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256";

    ssl_prefer_server_ciphers   on;

    # 显式声明 TLS 1.3 密码(需要 OpenSSL 1.1.1+)
    ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;

    # SSL certificates
    ssl_certificate     /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    location / {
        root   /etc/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}

方式1: 将证书文件(.crt或.pem或.cer后缀文件)和私钥文件(.key后缀文件)复制到nginx容器里

xml 复制代码
docker cp <证书文件> <容器名称>:<nginx的ssl_certificate参数指定的文件路径>
docker cp <私钥文件> <容器名称>:<nginx的ssl_certificate_key参数指定的文件路径>

例如:

bash 复制代码
docker cp "*.example.com_ecc/fullchain.cer" blog:/etc/nginx/ssl/nginx.cer

docker cp "*.example.com.key" blog:/etc/nginx/ssl/nginx.key

方式2: 将证书路径挂载到容器里

yml 复制代码
services:
  blog:
    image: example/blog # 这里需要替换成你的镜像
    container_name: blog # 镜像名称
    build:
      context: .
      dockerfile: .
      target: final
    ports:
      - '80:80'
      - '443:443'
      - '443:443/udp'
    # 环境变量
    environment:
      DOMAIN: example.com # 这里需要替换成你的域名
    restart: on-failure:4 # 重启策略,最多重启n次
    volumes:
      - /home/docker/blog/conf:/etc/nginx/conf.d # nginx.conf目录路径
      - /home/docker/nginx/ssl:/etc/nginx/ssl:ro # tls证书文件目录路径

续订证书

一般情况下, acme.sh60天自动更新一次证书过期时间, 如果没有自动更新, 可以使用以下脚本来手动更新: 强制续订证书,默认是每60天自动更新:

bash 复制代码
export DP_Id=<你的DNSPod id>
export DP_Key=<你的DNSPod key>
Daomain=<你的网站域名>

acme.sh --renew -d $Daomain --force

常见问题

Q: nginx无法读取文件, 缺少read权限: 2025/08/27 14:18:43 [emerg] 1#1: cannot load certificate key "/etc/nginx/ssl/nginx.key": BIO_new_file() failed (SSL: error:8000000D:system library::Permission denied:calling fopen(/etc/nginx/ssl/nginx.key, r) error:10080002:BIO routines::system lib)

bash 复制代码
ls -l

out:

diff 复制代码
-rw-r--r-- 1 root root 4116 Aug 27 22:17 nginx.crt
-rw-r----- 1 root root  227 Aug 27 22:17 nginx.key

A: 给对应的文件添加read权限:

bash 复制代码
chmod +r nginx.key

Q: 查看证书是否过期: A:

  1. 方式1: 直接查看你的网站的锁图标的详细信息
  1. 方式2: 使用openssl工具:
bash 复制代码
openssl x509 -in <证书文件> -noout -dates

参考

  1. github.com/acmesh-offi...
相关推荐
孤岛与风9 分钟前
CentOS扩容非LVM分区
linux·运维·centos
BIBI20499 分钟前
如何使用 Xshell 8 连接到一台 CentOS 7 电脑(服务器)
linux·服务器·centos
卑微的小李15 分钟前
Qt在Linux下编译发布 -- linuxdeployqt的使用
linux·c++·qt
小猪写代码27 分钟前
Ubuntu 的磁盘管理
linux·ubuntu
再吃一根胡萝卜41 分钟前
如何查看本地所有 Podman 镜像
docker
用户51681661458413 小时前
[VMware 无法检测此光盘中映像中的操作系统] VMware创建虚拟机无法检测操作系统iso镜像文件
linux·前端
MacroZheng3 小时前
斩获 7.8K star!一款堪称开源监控新标杆的项目,牛皮!
java·linux·后端
sjd_积跬步至千里3 小时前
Nginx-正则匹配
nginx
为了摸鱼而战3 小时前
Docker-compose知识点梳理,你要懂的都在这
docker·容器
博语小屋3 小时前
程序(进程)地址空间(1)
linux