ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

使用acme.sh自动化部署Let‘s Encrypt免费SSL证书实战指南

使用acme.sh自动化部署Let‘s Encrypt免费SSL证书实战指南 1. 项目概述为什么我们需要免费的SSL证书在今天的互联网上那个小小的挂锁图标几乎成了网站可信赖的代名词。这个挂锁的背后就是SSL/TLS证书在起作用。它就像网站和访客之间的一把加密锁确保数据在传输过程中不被窃听或篡改。几年前获取这把“锁”要么需要繁琐的流程要么需要不菲的费用这让很多个人开发者、小型项目或预算有限的团队望而却步。Let‘s Encrypt的出现彻底改变了这个局面。它是一家由非营利组织互联网安全研究小组ISRG运营的证书颁发机构CA其核心使命就是让每一个网站都能轻松、免费地启用HTTPS加密。我最初接触Let‘s Encrypt时还在为一个业余项目寻找免费的SSL解决方案。当时市面上要么是自签名证书浏览器会显示吓人的不安全警告要么是昂贵的商业证书。Let‘s Encrypt的自动化、免费模式让我眼前一亮。它通过一个名为ACME的协议允许我们通过脚本自动完成证书的申请、验证和续期整个过程完全免费。这对于需要管理多个域名、子域名或者证书需要频繁更新的场景来说简直是福音。今天要聊的acme.sh就是目前社区最流行、最强大的ACME协议客户端之一它用Shell脚本写成几乎可以在任何Unix-like系统上运行功能强大且配置灵活。这篇文章就是为你准备的从零到一的实战指南。无论你是在自己的云服务器上搭建博客还是为公司测试环境配置HTTPS亦或是管理着成百上千个需要证书的服务通过acme.sh配合Let‘s Encrypt你都能以极低的成本和极高的自动化程度搞定SSL证书。我们会深入原理但更聚焦于实操把每一步为什么这么做、可能会遇到什么坑都讲清楚。准备好了吗让我们开始吧。2. 核心原理与工具选型ACME协议与acme.sh在动手之前理解背后的工作原理能让你在遇到问题时游刃有余。Let‘s Encrypt的自动化核心是ACME协议。简单来说这个协议定义了一套标准流程让你的服务器通过ACME客户端如acme.sh能够自动向证书颁发机构CA即Let‘s Encrypt证明“我确实控制着example.com这个域名请把证书发给我。”2.1 ACME协议的工作流程解析这个过程主要分为三步账户注册、域名所有权验证、证书签发与续期。账户注册你的ACME客户端acme.sh会首先在Let‘s Encrypt服务器上创建一个账户。这个账户通常关联一个邮箱用于接收证书到期提醒等重要通知。acme.sh会自动处理这一步。域名所有权验证这是最关键的一步。CA必须确认你申请的证书对应的域名确实归你控制。ACME协议主要支持两种验证方式HTTP-01挑战CA会给出一个随机的令牌token和一个密钥认证key authorization。你的ACME客户端需要将这个密钥认证放置在你域名根目录下一个特定的URL路径/.well-known/acme-challenge/中。随后CA的服务器会尝试通过HTTP访问这个URL。如果能成功获取到正确的密钥认证就证明你拥有对该网站目录的控制权从而间接证明你拥有该域名。这种方式最常见但要求你的80端口能被公网访问。DNS-01挑战这种方式更灵活尤其适合那些80/443端口不对外开放的服务器比如某些内网穿透、或防火墙策略严格的场景。CA会给出一个令牌你的ACME客户端需要用它计算出一个特定的TXT记录值然后你需要将这个TXT记录添加到你的域名DNS解析中。CA通过查询DNS的TXT记录来验证你是否拥有该域名的解析管理权。acme.sh的强大之处在于它支持通过API自动操作几十家主流DNS服务商如阿里云、Cloudflare、GoDaddy等的DNS记录实现全自动验证。证书签发与续期验证通过后CA就会签发证书。Let‘s Encrypt签发的证书有效期是90天。这比传统商业证书的1-2年短很多设计初衷就是为了鼓励自动化。你不需要手动续期acme.sh会在证书到期前自动帮你续期默认是到期前30天并自动重启或重载相关的Web服务如Nginx、Apache实现真正的“永久免费”。2.2 为什么选择acme.shACME客户端有很多比如官方的Certbot、Caddy服务器内置的等。我选择acme.sh并在生产环境中稳定使用了多年主要基于以下几点考量零依赖与纯净acme.sh就是一个纯粹的Shell脚本。它安装时除了系统自带的curl等基础工具几乎不依赖任何额外的软件包。它不会修改你的系统全局配置所有文件都存放在用户主目录下的.acme.sh/文件夹里非常干净。卸载也只需要删除这个目录即可不会在系统里留下任何垃圾。强大的自动化能力它对DNS-01挑战模式的支持是顶级的。通过预置的API模块你可以轻松配置阿里云、腾讯云DNSPod、Cloudflare等的API密钥之后acme.sh就能自动完成DNS记录的添加和删除全程无需人工干预。这对于证书管理来说是质的飞跃。灵活的输出格式它不仅能生成Let‘s Encrypt标准的证书文件fullchain.cer和私钥.key还能根据你的需要一键生成Nginx、Apache所需的配置片段甚至能生成PFX格式证书用于Windows服务器或Java应用、或为HAProxy合成PEM文件。出色的稳定性与社区支持项目在GitHub上非常活跃作者响应迅速遇到问题很容易在Issues里找到解决方案或得到帮助。经过多年迭代其稳定性和可靠性已经过无数用户验证。注意虽然我们常说“永久免费”但本质是“自动续期的免费”。只要Let‘s Encrypt服务存在且你的自动续期脚本正常运行你的证书就永远不会过期。你需要确保的是自动续期任务的持续运行。3. 实战准备环境与依赖检查理论清楚了我们开始动手。首先你需要一个Linux服务器CentOS、Ubuntu、Debian等均可和至少一个你已经拥有并可以配置DNS解析的域名。3.1 基础环境要求操作系统绝大多数Linux发行版都可以。本文将以CentOS 7.9和Ubuntu 20.04 LTS为例进行说明命令会有细微差别我会明确指出。权限你需要有sudo权限或者直接是root用户。域名与DNS准备一个或多个你要申请证书的域名例如example.com,www.example.com,api.example.com。你需要能管理该域名的DNS记录如果打算用DNS-01验证方式还需要知道你的DNS服务商是否被acme.sh支持几乎都支持。网络服务器需要能正常访问互联网。如果使用HTTP-01验证服务器的80端口必须能被公网访问如果使用DNS-01验证则无此要求。3.2 安装必要工具首先更新系统包管理器并安装最基础的依赖curl和cron。curl用于下载脚本cron是Linux系统的计划任务服务acme.sh依赖它来设置自动续期任务。对于CentOS/RHEL系列sudo yum update -y sudo yum install -y curl cronie sudo systemctl enable crond sudo systemctl start crond对于Ubuntu/Debian系列sudo apt update -y sudo apt install -y curl cron sudo systemctl enable cron sudo systemctl start cron安装完成后可以检查一下cron服务状态sudo systemctl status cron(Ubuntu) 或sudo systemctl status crond(CentOS)。看到active (running)就说明没问题。4. 安装与配置acme.sh安装acme.sh非常简单官方推荐的方式是通过curl下载脚本并安装。4.1 一键安装执行以下命令。它会从GitHub下载安装脚本并自动安装到你的用户主目录下~/.acme.sh/。同时它会在你的~/.bashrc或~/.zshrc等shell配置文件中添加一个别名alias让你可以直接在命令行使用acme.sh命令。curl https://get.acme.sh | sh -s emailmyexample.com请务必将myexample.com替换为你自己的邮箱地址。这个邮箱用于接收Let‘s Encrypt关于账户和证书的重要通知如证书即将过期的提醒。安装完成后你需要重新加载一下shell配置或者新开一个终端窗口让别名生效。source ~/.bashrc # 如果你用的是bash # 或者 source ~/.zshrc # 如果你用的是zsh现在你可以输入acme.sh --version来验证是否安装成功。如果看到版本号输出恭喜你第一步完成了。4.2 切换默认CA机构可选但推荐acme.sh默认使用的CA是Let‘s Encrypt的v2版本API这完全没问题。但Let‘s Encrypt还有一个名为Buypass的免费CA合作伙伴以及一个名为ZeroSSL的CA需要注册账户。有些用户在某些网络环境下可能遇到连接Let‘s Encrypt不稳定的情况这时可以尝试切换CA。切换到Let‘s Encrypt v2确保是acme.sh --set-default-ca --server letsencrypt切换到ZeroSSL需要先注册acme.sh可自动处理acme.sh --register-account -m myexample.com --server zerossl acme.sh --set-default-ca --server zerossl实操心得在绝大多数情况下直接使用默认的Let‘s Encrypt即可稳定性非常好。我只有在为一些对证书链有特殊要求的旧系统如某些嵌入式设备时才会考虑测试其他CA。对于通用Web服务Let‘s Encrypt是首选。5. 申请证书两种验证方式详解这是最核心的环节。我们将分别详细讲解HTTP-01和DNS-01两种方式并给出完整的命令示例。5.1 方式一HTTP-01验证适用于有公网IP和开放80端口的服务器这种方式要求你的服务器80端口能被公网访问并且Web服务如Nginx/Apache正在运行或者acme.sh能临时占用80端口。场景你的服务器上已经运行了Nginx或Apache并且通过它来提供网站服务。步骤确保Web服务运行确保你的Nginx或Apache正在运行并且配置好了对应域名的虚拟主机server block。设置Web根目录你需要知道你的网站文件存放在服务器的哪个目录。例如Nginx的常见根目录是/usr/share/nginx/html或/var/www/html。执行申请命令使用--webroot参数指定你的网站根目录。acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html/-d: 指定域名可以跟多个-d来申请包含多个域名的证书SAN证书。--webroot: 指定Web根目录路径。acme.sh会在这个目录下创建/.well-known/acme-challenge/临时文件夹并放入验证文件。命令执行后发生了什么acme.sh与CA通信获取挑战令牌和密钥。它在你指定的Web根目录下创建临时文件。CA的验证服务器通过HTTP访问http://example.com/.well-known/acme-challenge/令牌。验证通过CA签发证书。acme.sh将证书文件保存到~/.acme.sh/example.com/目录下并清理临时文件。注意事项如果你的Web服务器如Nginx配置了禁止访问以点开头的隐藏目录/.well-known/可能会导致验证失败。你需要确保该目录可被外部访问。通常现代Web服务器的默认配置是允许的。5.2 方式二DNS-01验证最通用、最推荐的方式这种方式不依赖服务器端口只要求你能操作域名的DNS解析。acme.sh支持通过API自动操作DNS记录这是实现全自动化的关键。场景服务器没有公网IP如内网穿透、80/443端口被防火墙封锁、或者你想为裸域名如example.com申请通配符证书*.example.com。HTTP-01方式无法申请通配符证书只有DNS-01可以。准备工作以阿里云为例你需要获取API密钥。登录阿里云控制台进入“AccessKey管理”。创建一对AccessKey ID和AccessKey Secret。请妥善保存Secret它只会显示一次。在服务器上设置环境变量让acme.sh能读取到。export Ali_Key你的AccessKey ID export Ali_Secret你的AccessKey Secret为了安全建议将这两行添加到你的用户配置文件~/.bashrc中然后source ~/.bashrc执行申请命令申请单域名证书acme.sh --issue --dns dns_ali -d example.com申请通配符证书acme.sh --issue --dns dns_ali -d example.com -d *.example.com--dns dns_ali: 指定使用阿里云的DNS API进行验证。其他服务商对应不同的参数如腾讯云DNSPod是dns_dpCloudflare是dns_cf。对于通配符证书域名参数需要用单引号括起来防止shell解析通配符。命令执行后发生了什么acme.sh与CA通信获取挑战所需的TXT记录名和值。它调用阿里云的API在你的域名_acme-challenge.example.com下添加一条TXT记录。等待DNS记录在全球生效通常几十秒到几分钟acme.sh会自动检测。CA的验证服务器查询该TXT记录。验证通过CA签发证书。acme.sh保存证书并调用API删除刚才添加的TXT记录避免留下无用记录。实操心得DNS-01方式是生产环境的首选。它不受网络架构限制能申请通配符证书且通过API实现全自动。务必保管好你的DNS服务商API密钥它的权限很大。建议在DNS服务商处创建权限仅限于“修改指定域名的TXT记录”的子账户Key以遵循最小权限原则。6. 证书的安装与Web服务器配置证书申请成功后它们被保存在~/.acme.sh/your_domain/目录下。但不要直接使用这个目录下的证书文件因为acme.sh未来续期时会更新这个目录下的文件如果你服务的配置文件指向这里续期后可能不会自动生效。正确的做法是使用acme.sh的--install-cert命令或--installcert将证书复制到一个固定的位置并可以触发重载服务。6.1 为Nginx安装证书假设你想把证书安装到/etc/nginx/ssl/example.com/目录。首先创建目录sudo mkdir -p /etc/nginx/ssl/example.com然后使用安装命令acme.sh --install-cert -d example.com \ --key-file /etc/nginx/ssl/example.com/key.pem \ --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \ --reloadcmd sudo systemctl reload nginx--key-file: 指定私钥文件的存放路径。--fullchain-file: 指定完整证书链文件的存放路径。这个文件包含了你的站点证书和所有中间CA证书Nginx配置ssl_certificate指令时应该用这个文件。--reloadcmd: 指定证书更新后要执行的命令。这里设置为重载Nginx配置使新证书立即生效。acme.sh会在每次成功续期后自动执行此命令。配置Nginx 编辑你的Nginx站点配置文件如/etc/nginx/conf.d/example.com.conf添加或修改SSL相关部分server { listen 443 ssl http2; server_name example.com www.example.com; ssl_certificate /etc/nginx/ssl/example.com/fullchain.pem; ssl_certificate_key /etc/nginx/ssl/example.com/key.pem; # 强化的SSL配置可选但推荐 ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # ... 你的其他配置如root, index, location等... } # 将HTTP流量重定向到HTTPS server { listen 80; server_name example.com www.example.com; return 301 https://$server_name$request_uri; }检查配置并重载Nginxsudo nginx -t # 测试配置语法 sudo systemctl reload nginx # 重载配置6.2 为Apache安装证书Apache的配置类似。安装证书acme.sh --install-cert -d example.com \ --key-file /etc/httpd/ssl/example.com/key.pem \ --fullchain-file /etc/httpd/ssl/example.com/fullchain.pem \ --reloadcmd sudo systemctl reload httpd配置Apache 启用SSL模块并编辑虚拟主机配置如/etc/httpd/conf.d/example.com.confVirtualHost *:443 ServerName example.com ServerAlias www.example.com SSLEngine on SSLCertificateFile /etc/httpd/ssl/example.com/fullchain.pem SSLCertificateKeyFile /etc/httpd/ssl/example.com/key.pem # ... 你的其他配置 ... /VirtualHost # 重定向HTTP到HTTPS VirtualHost *:80 ServerName example.com ServerAlias www.example.com Redirect permanent / https://example.com/ /VirtualHost重启Apachesudo systemctl restart httpd6.3 其他格式证书的生成有时其他服务需要特定格式的证书acme.sh也能轻松转换。生成PKCS#12格式证书.p12/.pfx 常用于Windows服务器、Java应用或某些客户端。acme.sh --toPkcs -d example.com --password your_pfx_password生成的.p12文件也会在证书目录下。生成适用于HAProxy的PEM文件 HAProxy需要将证书和私钥合并到一个PEM文件中。acme.sh --install-cert -d example.com \ --key-file /etc/haproxy/ssl/example.com/key.pem \ --fullchain-file /etc/haproxy/ssl/example.com/fullchain.pem \ --reloadcmd sudo systemctl reload haproxy # 然后手动合并或写脚本自动合并 sudo cat /etc/haproxy/ssl/example.com/fullchain.pem /etc/haproxy/ssl/example.com/key.pem /etc/haproxy/ssl/example.com/combined.pem在HAProxy配置中bind行引用这个combined.pem文件即可。7. 自动化续期与状态管理acme.sh安装时已经自动为你创建了一个cron定时任务。你可以通过crontab -l命令查看。通常它看起来像这样0 0 * * * /home/username/.acme.sh/acme.sh --cron --home /home/username/.acme.sh /dev/null这个任务每天午夜检查所有已签发证书如果证书剩余有效期小于30天就会自动续期。续期成功后会执行你之前用--install-cert设置的--reloadcmd命令如sudo systemctl reload nginx从而实现无缝更新。7.1 手动测试续期你不必等到第60天。可以手动运行cron任务来测试续期流程是否正常acme.sh --cron如果看到类似“Cert is ok, skip”或“Renew success”的信息说明一切正常。7.2 常用管理命令列出所有证书acme.sh --list查看证书信息acme.sh --info -d example.com手动强制续期一个证书acme.sh --renew -d example.com --force即使未到期也续期用于测试或更换密钥撤销证书acme.sh --revoke -d example.com如果域名已不再使用或私钥泄露删除证书本地acme.sh --remove -d example.com仅从acme.sh管理中删除不会撤销在CA的证书升级acme.shacme.sh --upgrade定期升级以获得新功能和修复8. 常见问题与故障排查实录在实际操作中你可能会遇到一些问题。这里我整理了几个最常见的情况和解决方法。8.1 验证失败连接超时或拒绝症状执行acme.sh --issue命令时卡在“Verifying...”很久最后报错“Connect timed out”或“Connection refused”。排查思路检查服务器网络ping一下外网地址curl -v https://acme-v02.api.letsencrypt.org看看是否能连通Let‘s Encrypt的API。检查防火墙/安全组如果使用HTTP-01确保服务器的80端口对公网开放。使用sudo netstat -tunlp | grep :80查看是否有程序监听。如果使用云服务器请检查云服务商安全组规则。检查Web服务器配置确保Nginx/Apache正在运行并且对/.well-known/acme-challenge/路径的访问没有被屏蔽。可以手动在网站根目录下创建一个测试文件然后通过公网IP或域名访问看是否能打开。DNS问题如果使用DNS-01确保你添加的TXT记录值完全正确并且已经全球生效。可以使用在线DNS查询工具如dig命令或nslookup -typeTXT _acme-challenge.example.com来检查。8.2 证书已签发但浏览器提示“不安全”症状配置好Nginx/Apache后用HTTPS访问网站浏览器显示红色警告如“无效证书”、“证书不匹配”。排查思路证书与域名不匹配确保证书包含你访问的域名。用openssl x509 -in /path/to/fullchain.pem -text -noout | grep DNS命令查看证书包含哪些域名。证书链不完整这是最常见的原因。你必须使用fullchain.pem文件包含站点证书和中间证书而不是单独的cert.pem只有站点证书。检查Nginx配置中的ssl_certificate指令指向的是否是fullchain.pem。服务器时间不正确如果服务器系统时间偏差太大快或慢几个小时会导致浏览器认为证书未生效或已过期。使用date命令检查并用ntpdate或timedatectl同步时间。浏览器缓存了旧的错误状态尝试使用浏览器的“无痕模式”访问或者清除SSL状态缓存。8.3 自动续期失败症状证书过期了但网站没有自动更新。排查思路检查cron服务sudo systemctl status cron确保cron服务在运行。检查cron日志查看/var/log/cron日志看acme.sh --cron任务是否有执行以及执行结果是否有错误。检查--reloadcmd命令权限这是最容易出问题的地方。cron任务通常以普通用户身份运行但--reloadcmd里我们写了sudo systemctl reload nginx。这需要该用户拥有无需密码执行该sudo命令的权限。解决方案编辑sudoers文件sudo visudo在文件末尾添加一行将username替换为你的实际用户名username ALL(ALL) NOPASSWD: /bin/systemctl reload nginx这样该用户执行sudo systemctl reload nginx时就不需要输入密码了。磁盘空间不足acme.sh运行需要临时空间。检查磁盘使用情况df -h。手动运行测试手动执行acme.sh --cron观察详细输出能定位到具体错误。8.4 申请证书时遇到“Rate limit exceeded”错误Let‘s Encrypt有严格的频率限制主要是为了保护其服务不被滥用。每个注册域名每周最多签发50张证书对于example.com及其所有子域名一周内最多成功申请50次。这通常足够除非你在频繁测试或脚本出错循环申请。每个账户每小时最多创建300个新订单对于普通用户几乎不可能触发。重复证书限制对完全相同的域名集合SAN列表一周内最多重复签发5次。如果触限了怎么办等待。大部分限制是按周重置的。检查你的脚本或流程避免不必要的重复申请。对于测试可以使用Let‘s Encrypt的测试环境Staging Environment它没有频率限制。使用acme.sh --staging参数。但注意测试环境签发的证书不被浏览器信任仅用于测试流程。8.5 为多个域名或通配符域名申请证书多域名证书SAN证书在一条命令中列出所有-d参数即可。acme.sh --issue --dns dns_ali -d example.com -d www.example.com -d api.example.com -d blog.example.com这样你会得到一张包含所有四个域名的证书。通配符证书如前所述使用DNS-01验证。acme.sh --issue --dns dns_ali -d example.com -d *.example.com这张证书将覆盖example.com和所有它的子域名如a.example.com,b.example.com但不包含二级子域名如x.y.example.com。如果需要必须单独指定。踩坑记录我曾经在一个自动化脚本里因为路径变量设置错误导致--reloadcmd命令执行失败。证书在后台成功续期了但Nginx加载的仍然是旧证书直到某天网站突然无法访问才被发现。教训是部署后一定要在证书到期前几周手动执行一次acme.sh --cron并检查服务日志确认整个“续期-安装-重载”流程完全畅通。最好能设置一个监控定期检查服务器上证书的实际过期时间。
返回列表