ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

win-acme 实战:Windows 下 ACME 证书自动续签与部署指南

win-acme 实战:Windows 下 ACME 证书自动续签与部署指南

简介:win-acme.v2.1.18-x64 是一款面向 Windows 平台网站运维者与个人站长的免费 SSL 证书申请与管理工具,基于 ACME 协议对接 Let's Encrypt,可自动完成域名所有权验证、证书签发、IIS 等服务器安装及到期续订,并支持通配符证书与多域名统一管理,帮助预算有限的个人或小型项目零成本启用 HTTPS。资源包共 27 个文件,以 15 个 ps1 脚本和 4 个 dll 运行库为主,辅以 json 配置、bat 批处理、xml 与 dat 数据文件及 wacs-x64.exe 主程序,压缩包约 29.58MB,解压即可按需调用图形或命令行方式操作。目前已有 336 人学习下载。借助其中的脚本与默认配置模板,读者可快速搭建自动化证书申请流程,理解 HTTP 与 DNS 两种验证方式的差异,并掌握续订计划与日志排查思路,适合希望低成本提升站点安全性的初、中级用户参考实践。

1. 证书到期前三天才想起来续签,win-acme 能救你一次

凌晨两点收到监控告警,站点证书还有 72 小时过期,浏览器已经开始给访客弹红色警告。这种场景下,手动去 CA 后台重新签发、下载、转换格式、上传、改 Nginx 配置、reload,一套流程走完天都亮了。win-acme 就是干这件事的:一个跑在 Windows 上的 ACME 客户端,把域名验证、证书签发、格式转换、部署、定时续签串成一条流水线。它解决的不是“怎么申请免费域名”——域名本身该买还得买——而是“怎么让免费 DV 证书在 Windows 环境里自动续命”。适合谁?手上管着 IIS 或 Nginx 站点、服务器是 Windows、又不想为一张 DV 证书掏钱或写一堆脚本的运维和全栈。下面按我实际拆包和跑通的顺序讲,参数怎么填、坑在哪,一并说清。

2. 拆开 win-acme 的包:它到底替你做了哪些事

2.1 ACME 协议在 Windows 上的落地路径

win-acme 的本质是一个 ACME 协议客户端。ACME 的核心流程分三步:账户注册、订单创建与域名验证、证书签发与下载。Let's Encrypt 这类 CA 通过 ACME 接口暴露这些能力,win-acme 负责把 HTTP 请求、密钥对生成、CSR 构造、挑战响应这些底层动作封装成可配置的步骤。

域名验证是整条链路里最容易翻车的一环。win-acme 支持两种主流挑战方式:HTTP-01 和 DNS-01。HTTP-01 要求 CA 能通过 80 端口访问到/.well-known/acme-challenge/下的验证文件,win-acme 会在本地起一个临时监听或者把文件写到你指定的 web 根目录;DNS-01 则要求在域名 DNS 里添加一条 TXT 记录,适合没有公网 80 端口、或者需要泛域名证书的场景。选哪种不是拍脑袋:有公网 IP 且 80 端口没被占,HTTP-01 最省事;走 CDN、内网穿透、或者要*.example.com泛域名,只能上 DNS-01,而且得看你的 DNS 服务商有没有对应的 API 插件。

我一般会先确认三件事再动手:域名解析是否已经指向这台机器、80 端口是否被 IIS 或其他服务独占、当前账户是否有写 IIS 站点配置或目标目录的权限。这三条任何一条不满足,后面都会以“验证失败”的形式还回来,而且报错信息往往不直白。

2.2 交互式向导与命令行两条入口

win-acme 解压后目录里有两个可执行文件:wacs.exe是交互式向导,wacs.exe带参数就是命令行模式。新手建议先走向导,它会用菜单把“新建证书 / 续签 / 导入”这些动作列出来,每一步都有默认值,回车即可。熟手直接上命令行,方便写进计划任务和 CI。

先看目录结构,解压后大致是这样:

win-acme/ ├── wacs.exe ├── settings.json ├── validation/ ├── web/ └── cache/

settings.json存全局配置,validation/放 HTTP-01 的验证文件,web/是内置的简易 web 服务根目录,cache/缓存账户密钥和订单状态。第一次运行会在同目录生成这些内容,所以别把它塞进Program Files这种需要管理员权限才能写的路径,放C:\tools\win-acme这类目录最省心。

命令行创建一个 HTTP-01 证书的典型写法:

wacs.exe --target manual ^ --host example.com ^ --validation selfhosting ^ --store pemfiles ^ --pemfilespath C:\certs\example ^ --accepttos ^ --emailaddress ops@example.com

逐段说明:--target manual表示手动指定域名而不是从 IIS 站点里自动发现;--host后面跟要签的域名,多个域名用逗号分隔;--validation selfhosting让 win-acme 自己起临时监听完成 HTTP-01 验证,前提是 80 端口空闲;--store pemfiles指定输出 PEM 格式,配合--pemfilespath落到指定目录,方便 Nginx 或其它服务读取;--accepttos接受服务条款,非交互场景必须带;--emailaddress用于到期提醒和账户找回。如果站点跑在 IIS 上,把--target manual换成--target iis,win-acme 会自动枚举站点、绑定并直接写入 IIS 的证书存储,省掉手动部署。

提示:--validation selfhosting依赖 80 端口。如果 IIS 已经占了 80,改用--validation filesystem --webroot C:\inetpub\wwwroot,让 win-acme 把验证文件写进现有站点根目录,由 IIS 直接对外提供。

2.3 证书存储格式与部署目标的选择

win-acme 支持多种存储后端:Windows 证书存储(--store certificatestore)、PEM 文件(--store pemfiles)、PFX 文件(--store pfxfile),以及直接部署到 IIS、Exchange 等目标。选错存储格式是新手最常见的返工点。

跑 IIS 的机器,用certificatestore最顺,证书直接进LocalMachine\My,IIS 绑定里能直接选到。跑 Nginx、Apache 或者自研服务的,用pemfiles,因为这类服务读的是fullchain.pem和privkey.pem两个文件。需要把证书分发给多台机器或导入其它系统的,用pfxfile并设一个导出密码。

一个 PEM 输出的完整参数示例:

wacs.exe --target manual ^ --host example.com,www.example.com ^ --validation filesystem ^ --webroot C:\inetpub\wwwroot ^ --store pemfiles ^ --pemfilespath C:\certs\example ^ --pfxpassword Str0ngP@ss ^ --installation none ^ --accepttos ^ --emailaddress ops@example.com

--installation none表示只签发不自动部署,适合证书由外部配置管理工具统一分发的场景。--pfxpassword在同时需要 PFX 输出时使用,纯 PEM 场景可以不带。多个域名写在一起时,第一个域名会成为证书的 Common Name,其余进 SAN 列表,顺序别随意调。

3. 把自动续签跑起来:计划任务、DNS-01 与验证

3.1 用计划任务托管续签,而不是手动重跑

证书签下来只是开始,Let's Encrypt 的 DV 证书有效期 90 天,靠人记着续签迟早出事。win-acme 在首次签发时会问你要不要创建计划任务,选是的话它会在 Windows 任务计划程序里注册一个每日运行的任务,命令大致是wacs.exe --renew --baseuri https://acme-v02.api.letsencrypt.org/。这个任务每天跑一次,win-acme 自己判断哪些证书临近到期(默认剩余 30 天内)才真正发起续签,没到期的直接跳过,不会频繁打扰 CA。

手动补建计划任务的命令:

schtasks /create /tn "win-acme renew" ^ /tr "C:\tools\win-acme\wacs.exe --renew --baseuri https://acme-v02.api.letsencrypt.org/" ^ /sc daily /st 03:30 /ru SYSTEM /rl HIGHEST

/ru SYSTEM让任务以系统账户运行,避免用户注销后任务不执行;/rl HIGHEST给最高权限,因为写 IIS 证书存储和重启站点需要管理员权限。/st 03:30是执行时间,挑业务低峰。这里有个容易忽略的点:任务的工作目录默认是System32,而 win-acme 的settings.json和cache/是相对路径解析的,所以要么在/tr里写全路径,要么在任务属性里显式设置“起始于”为 win-acme 所在目录,否则会出现“任务跑了但读不到配置”的玄学问题。

3.2 DNS-01 挑战:泛域名与无公网端口的解法

要签*.example.com,HTTP-01 无能为力,必须走 DNS-01。win-acme 的 DNS 验证依赖插件,插件放在plugins/目录下,按 DNS 服务商区分。配置时需要在settings.json或命令行里提供 API 凭据,win-acme 调用服务商 API 自动添加_acme-challenge的 TXT 记录,等待传播后触发 CA 校验,校验完再删掉记录。

以命令行方式指定 DNS 验证的骨架:

wacs.exe --target manual ^ --host *.example.com,example.com ^ --validation dns ^ --dnsscript "C:\tools\win-acme\plugins\your-dns-plugin.exe" ^ --dnsscriptparameters "apikey=YOUR_KEY;zone=example.com" ^ --store pemfiles ^ --pemfilespath C:\certs\wildcard ^ --accepttos ^ --emailaddress ops@example.com

--validation dns切到 DNS 模式,--dnsscript指向具体插件可执行文件,--dnsscriptparameters是传给插件的键值对,不同插件参数名不一样,得对着插件说明填。泛域名和裸域要一起签时,--host里两个都写上,因为*.example.com不覆盖example.com本身。

DNS 传播延迟是这条链路的主要不确定性。常见做法是在插件参数里把等待时间调大,或者先用nslookup -type=TXT _acme-challenge.example.com手动确认记录已生效再让 win-acme 继续。我一般会把首次 DNS-01 签发放在白天做,盯着传播过程,跑通一次之后再交给计划任务。

3.3 验证签发结果与文件权限

签发完成后别急着收工,先验证产物。PEM 目录下应该出现example.com-chain.pem、example.com-key.pem、example.com-crt.pem这类文件。用 OpenSSL 检查证书链和有效期:

openssl x509 -in C:\certs\example\example.com-crt.pem -noout -subject -dates -ext subjectAltName

输出里Not After应该是 90 天左右之后,subjectAltName要包含你申请的所有域名。再用openssl verify -CAfile chain.pem crt.pem确认链完整,缺中间证书是 Nginx 部署后浏览器仍报不受信任的常见原因。

文件权限同样要管。计划任务以 SYSTEM 运行,写出来的 PEM 文件属主是 SYSTEM,如果 Nginx 以低权限账户运行,读不到privkey.pem就会启动失败。稳妥做法是在--installation阶段挂一个后置脚本,把文件 ACL 改成目标服务账户可读,或者干脆让 Nginx 以有读权限的账户运行。这一步不做,续签成功但服务起不来,等于白续。

4. 避坑与排查:五个真实翻车现场

4.1 80 端口被占导致 HTTP-01 验证失败

现象:日志里出现Challenge failed或Connection refused,CA 访问/.well-known/acme-challenge/返回 404 或超时。原因:--validation selfhosting需要独占 80 端口,而 IIS 的 Default Web Site 或其它服务已经监听 80,win-acme 起不来临时监听。解决:改用--validation filesystem --webroot <站点根目录>,让验证文件走现有 web 服务;或者临时停掉占用 80 的服务再签。我倾向前者,因为续签是长期行为,不能每次都停服务。

4.2 计划任务“成功”但证书没更新

现象:任务计划程序里显示上次运行结果0x0,但证书文件修改时间没变。原因:任务的工作目录不是 win-acme 目录,settings.json和cache/按相对路径找不到,win-acme 以空配置启动,认为没有需要续签的证书就正常退出。解决:在任务属性里把“起始于”设为 win-acme 所在目录,或者在/tr里用cd /d C:\tools\win-acme && wacs.exe --renew包一层。排查时直接手动在目标目录跑一次wacs.exe --renew --verbose,看它枚举到几张证书。

4.3 DNS-01 记录未传播就触发校验

现象:DNS 模式签发间歇性失败,报DNS problem: NXDOMAIN或unauthorized。原因:插件添加 TXT 记录后立即通知 CA 校验,而权威 DNS 还没同步到所有递归解析器。解决:在插件参数里加大等待时间,或改用支持“轮询确认”的插件版本;首次配置时手动nslookup确认记录可见再继续。泛域名证书尤其容易踩这个,因为_acme-challenge的记录名和普通记录不同,容易配错主机头。

4.4 证书链不完整导致浏览器仍报警

现象:证书签发成功,Nginx 配置也 reload 了,但部分浏览器仍提示不受信任。原因:只部署了站点证书,没把中间证书拼进fullchain.pem,或者 Nginx 的ssl_certificate指向了crt.pem而非chain.pem。解决:确认--store pemfiles产出的-chain.pem包含完整链,Nginx 的ssl_certificate指向 chain 文件,ssl_certificate_key指向 key 文件。用openssl s_client -connect example.com:443 -showcerts从外部验证实际下发的链。

4.5 权限不足写不进 IIS 证书存储

现象:--target iis时报Access denied,或证书签了但 IIS 绑定没更新。原因:运行账户不是管理员,或者 UAC 提权不完整,写LocalMachine\My和改站点绑定都需要高权限。解决:以管理员身份运行,计划任务用/rl HIGHEST;如果走的是服务账户,确认该账户在证书私钥的 ACL 里有读权限。改完权限后重新跑一次--renew --force强制刷新,别等自然到期。

5. 进阶:把续签做成可观测的流水线

跑通自动续签只是及格线,真正省心的是让续签过程可观测、可回滚。我现在的习惯是给 win-acme 的每次运行留痕:在计划任务命令后面追加日志重定向,把 stdout 和 stderr 落到按日期滚动的文件里,再用一个轻量脚本每天扫一遍日志里的Error和Renewal关键字,有异常就发通知。这样证书哪天没续上,不用等浏览器报警才发现。

一个带日志和失败告警的包装脚本思路:

@echo off set LOGDIR=C:\tools\win-acme\logs set STAMP=%date:~0,4%%date:~5,2%%date:~8,2% cd /d C:\tools\win-acme wacs.exe --renew --baseuri https://acme-v02.api.letsencrypt.org/ >> "%LOGDIR%\renew-%STAMP%.log" 2>&1 if errorlevel 1 ( echo win-acme renew failed on %date% %time% >> "%LOGDIR%\alert.log" )

errorlevel 1判断的是 win-acme 的退出码,非零即异常,写进单独的告警文件,后续接邮件或 webhook 都行。日志按日期分文件,排查时直接定位到某一天,不用在几百兆的单文件里翻。

验证环节我固定做两件事:一是用openssl x509 -noout -enddate读实际部署的证书到期时间,确认和预期一致;二是从外部用curl -vI https://example.com看 TLS 握手用的证书序列号和本地文件是否对得上。这两步能覆盖“文件更新了但服务没加载”“加载了但不是新证书”这两类隐蔽故障。

还有一个容易被忽略的边界:win-acme 的续签判断基于本地缓存里的到期时间,如果cache/被误删或迁移目录时没带上,它会认为没有证书可续,静默跳过。所以迁移或备份时,settings.json和cache/要一起带走。从那以后我每次调整 win-acme 的部署目录,都强制先跑一次--renew --verbose确认它枚举到的证书数量和到期时间符合预期,再交给计划任务。希望这套流程帮到你,少在证书过期这件事上熬夜。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进