ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

Windows下win-acme自动签发与管理nginx SSL证书全攻略

Windows下win-acme自动签发与管理nginx SSL证书全攻略

简介:win-acme是一款面向Windows平台的开源免费SSL证书自动获取与部署工具,专为网站管理员、运维人员及系统集成商设计,可帮助快速完成Let's Encrypt等机构证书的申请、续期与安装,适配IIS、nginx等多类Web服务器。该版本为x64 pluggable扩展包,兼顾灵活配置与自动化脚本场景。

压缩包共28个文件,大小35.58MB,包含wacs.exe主程序、settings_default.json配置、Web_Config.xml模板,以及21个PowerShell脚本(如ImportADFS、ImportExchange、EasyDNS等)和2个批处理文件,分别用于不同服务器场景的证书导入与自动部署,dat文件用于域名列表管理,整体结构清晰。

目前已有376人学习下载,对于苦于官网下载缓慢的用户,此CSDN版本可直接获取。通过内置脚本和配置模板,读者能直接在IIS、nginx等环境实现证书签发与自动续期,并参考配套教程深入了解定时续订、多域名管理等进阶用法,是提升网站传输安全、降低运维成本的实用工具包。

1. 在 Windows 上免费给 nginx 签 SSL 证书:win-acme 是少有的省心选择

做运维的都知道,Let's Encrypt 的免费证书有效期只有 90 天,手动续期一次两次还能忍,站点一多就成了纯体力活。win-acme 这个 Windows 平台的 ACME 客户端,就是专门解决「自动申请 + 自动续期」这个问题的。它不需要装 Python 环境,不用配 WSL,下载解压就能跑,支持 HTTP、DNS、 TLS-ALPN 等多种验证方式,也能直接把签下来的证书丢给 nginx、IIS 或者其他服务用。我最近在 Windows Server 上迁移一批站点,实测下来这个工具能省掉 80% 的证书维护时间。如果你手头刚好是 Windows 环境 + nginx,这篇笔记能帮你把整个流程完整跑通,包括那些文档里没写清楚的坑。

2. 免费 SSL 证书的选型:为什么我选了 win-acme 而不是其他客户端

2.1 横向对比:Windows 平台下主流 ACME 客户端的适用边界

市面上的 ACME 客户端其实不少,但真正在 Windows 上跑得顺的没几个。我在选型时对比过几款常见的方案,各自的适用场景差异很大:

Certbot:官方推荐客户端,但 Windows 版本支持得不够到位。虽然能在 Windows 上跑,但很多插件(比如 nginx 插件)在 Windows 下不可用,需要手动改配置。更麻烦的是 Certbot 依赖 Python 环境,Windows 上装 Python 还得配路径,多一层环境变量的问题。

acme.sh:本来是 Unix 下的脚本,Windows 上要跑得装 Git Bash 或者 WSL。如果你服务器上已经装了 Git,那可以接受,但如果是一个干净的 Windows Server,为了签个证书去装一套模拟环境,代价高了。

win-acme:原生 Windows 程序,.NET 写的,直接下载 zip 解压就能跑。自带交互式配置界面和命令行两种模式,服务方式有 Scheduled Task 和 Windows Service 两种,验证方式覆盖 HTTP、DNS、TLS-ALPN。最关键的一点,它对证书安装后的事件钩子(Post-Installation Script)支持很好,可以把证书转换格式后直接丢给 nginx。

我最后选 win-acme 还有一个现实原因:它支持通配符证书(Wildcard),这在多子域名的场景下特别重要,而有些轻量级客户端对通配符支持不完整。

2.2 理解 win-acme 的运行时结构:pluggable 版本里多了什么

你手里这个包的名字是win-acme.v2.2.9.1701.x64.pluggable.zip,注意里面有个 pluggable 关键字。这是 win-acme 的扩展版本,相比精简版多了几个额外的验证插件和存储插件,包括:

  • 更多的 DNS API 插件(比如 Cloudflare、Route53 这类)
  • 额外的 Target 插件,可以从其他来源获取证书
  • 额外的存储插件,可以把证书存到更多地方

如果你只需要基础的 HTTP 验证 + 本地文件存储,非 pluggable 版也够用。但考虑到 DNS 验证在很多场景下是刚需(比如服务器 80 端口被占用),我建议直接用 pluggable 版,省得后面缺插件再换。

win-acme 的结构不复杂,核心就是三个环节:Target(目标)决定给哪个域名签证书,Validation(验证)决定怎么证明你拥有这个域名,Store(存储)决定证书签下来往哪放。理解了这个三元组,后面配置就顺了。

2.3 环境准备:跑起来前必须确认的四件事

不要急着解压就开干,我踩过几次坑之后总结出这套前置检查,每一步都有血的教训:

第一,确认系统版本和 .NET 环境。win-acme v2 要求 Windows 7 以上,但实际生产环境建议 Windows Server 2016 以后。.NET Framework 4.7.2 以上是硬性要求,因为工具本身跑在 .NET 上。检查方法很简单,PowerShell 里跑(Get-Item "HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full").GetValue("Release"),如果返回的值大于 461808 就说明 4.7.2 没问题。

第二,确认 80 端口和 443 端口的情况。HTTP 验证方式需要 80 端口能访问,TLS-ALPN 验证需要 443 端口。如果你的服务器上已经跑了 IIS 或者 nginx 占用了这些端口,就要选对验证方式。最常见的坑是 IIS 和 nginx 同时存在,两个服务抢 80 端口,导致验证失败。

第三,确认 DNS 解析记录。确保你要签证书的域名已经解析到这台服务器,不只是本机 hosts 文件,是公网 DNS 的 A 记录。Let's Encrypt 服务器是从公网发起验证请求的,你本机解析到哪它不管。

第四,确认防火墙规则。Windows 防火墙默认会拦掉外部对 80 和 443 端口的访问。别忘了在防火墙里放行这两个端口,不然验证请求根本到不了你的服务器。

做完这四件事,解压 win-acme 包到一个固定路径,比如C:\win-acme,路径里不要带空格,后面配计划任务和脚本会省很多事。

3. 首次申请证书:交互式配置与命令行完全拆解

3.1 交互式界面:五分钟跑通第一张证书

解压后运行wacs.exe,会进入交互式配置界面。这个界面长得很像旧式的控制台程序,新手第一次看到可能有点懵,但其实逻辑很清晰。

启动后,主菜单会列出一堆选项。第一次使用选N(Create certificate (default))就行。接下来会问你用哪个 Target,这里选1(IIS)或者2(Manual)。如果你的站点跑在 IIS 上就选 1,跑在 nginx 或其他服务就选 2。

选 Manual 之后会让你输入域名列表,多个域名用逗号分隔。比如要签example.com和www.example.com两个域名的证书,就输example.com,www.example.com。这里有个细节:第一个输入的域名会被当作证书的主名称(Common Name),后面的作为 SAN(Subject Alternative Name)加进去。所以把主域名放在最前面。

接下来选验证方式,这里是最关键的一步:

  • HTTP:需要在网站根目录放一个验证文件,win-acme 会帮你自动创建和删除。如果你的 nginx 站点根目录是C:\wwwroot\example,选这个方式就会自动在那个目录下创建.well-known\acme-challenge目录来响应验证。前提是 nginx 的配置允许访问这个路径。
  • TLS-ALPN:需要在 443 端口上临时跑一个 HTTPS 服务来响应验证。如果 443 被 nginx 占用了,win-acme 会尝试用 SNI 方式绕过,但成功率看运气。
  • DNS:通过修改 DNS 的 TXT 记录来验证。需要你的 DNS 服务商提供 API 密钥,比如 Cloudflare 的 API Token。这个方式最稳,不受端口和目录限制。

选好验证方式后,选存储方式。默认是PEM files,也就是把证书和私钥以 PEM 格式存到文件夹里,这正好是 nginx 需要的格式。如果想装到 Windows 证书库,就选Certificate store。nginx 场景下直接选 PEM 文件就完事了。

最后会让你确认是否设置自动续期。选Y,win-acme 会在 Windows 计划任务里创建一个每天运行的任务来检查证书有效期,剩余天数少于阈值就自动续期。

完成这些步骤后,win-acme 会立即开始验证并签发证书。签下来的文件会放在C:\win-acme\certs\<域名>目录下,主要文件是cert.pem(证书链)、key.pem(私钥)、chain.pem(中间证书),还有一个fullchain.pem(证书链和中间证书合并)。nginx 配置里经常用到的就是fullchain.pem和key.pem,不用自己手动拼接。

3.2 命令行模式:一次性跑通且可重复执行

交互式界面适合第一次配置,但真要自动化,还是得用命令行模式。win-acme 的命令行参数设计得很规整,核心就是--target、--validation、--store三个参数,分别对应前面说的三元组。

比如我要给example.com和www.example.com签证书,用 HTTP 验证,PEM 存储,命令就是:

wacs.exe --target manual --host example.com,www.example.com --validation http --webroot C:\wwwroot\example --store pemfiles --pemfilespath C:\win-acme\certs

各参数的含义拆开说:

  • --target manual:指定使用手动目标,即不用 IIS 站点发现逻辑
  • --host example.com,www.example.com:要签的域名列表,逗号分隔
  • --validation http:使用 HTTP 验证方式
  • --webroot C:\wwwroot\example:HTTP 验证文件的存放目录,就是网站的根目录。这个参数只对 HTTP 验证有效
  • --store pemfiles:指定证书存储为 PEM 文件
  • --pemfilespath C:\win-acme\certs:PEM 文件的输出目录

如果你是第一次跑,不想交互式一步步回答,可以再加上--accepttos参数(自动接受服务条款)和--email your@email.com(注册 ACME 账号用的邮箱):

wacs.exe --target manual --host example.com,www.example.com --validation http --webroot C:\wwwroot\example --store pemfiles --pemfilespath C:\win-acme\certs --accepttos --email admin@example.com

注意--email这个参数,它只会影响新注册的 ACME 账号。如果之前交互式模式注册过了,命令行再指定邮箱不会改变账号,而且会报错或忽略。建议一开始就确定邮箱,后面不要变。

3.3 配置文件持久化:settings.json 的作用域

交互式运行过一次之后,win-acme 会在安装目录下生成settings.json(早期版本叫settings_default.json)。这个文件记录了你的偏好设置,比如 ACME 服务器地址、邮箱、默认存储类型等。

等命令行跑过一次证书申请后,还会生成challenge-settings.json和renewal-settings.json。其中renewal-settings.json记录了每张证书的续期配置,包括域名列表、验证方式、存储方式这些信息。自动续期任务就是靠读这个文件来执行的。

如果你想通过命令行批量签多张证书,最干净的方式是直接编辑renewal-settings.json,把新证书的配置按相同结构追加进去,然后跑一次wacs.exe --renew,它会自动读配置并补齐缺失的证书。这个逻辑很像 CI/CD 里的声明式配置,写好后基本不用管。

4. 自动续期与 nginx 集成:证书换新后如何不打断服务

4.1 计划任务与 Windows 服务的二选一

win-acme 在交互式配置中设了自动续期后,会在计划任务里创建一个名为win-acme renew(默认)的每日任务。它做的是检查所有已注册证书的有效期,如果剩余天数小于阈值(默认 0 天,也就是过期当天才续),就自动续期并执行后续脚本。

但这里有个需要改的默认值:如果把续期阈值设为 0 天,意味着证书刚好在过期那天才换,中间只要验证失败一次,就有一段无证书的空白期。我一般会把阈值改为 7 天,也就是剩余 7 天时就开始尝试续期,留出容错空间。这个设置不在 plan 任务里控制,而是在settings.json里调整,也可以直接用命令行参数:

wacs.exe --renew --renewal-threshold 7

如果你不想用计划任务,也可以注册为 Windows 服务。把 win-acme 注册成服务后,它会常驻后台,按固定间隔自动检查。服务模式的优点是启动快、不依赖用户登录状态;缺点是占内存(大概几十 MB),而且如果程序崩了不会像计划任务那样每次重新拉起。

生产环境我推荐用计划任务 + 服务方式都别碰,原因很简单:计划任务出错有日志可查,服务出错排起来麻烦。而且计划任务可以设置「错过启动时间尽快运行」,就算服务器刚好在计划时间点关机,重启后也会补跑。

4.2 nginx 证书加载与热更新:不需要重启服务的秘密

nginx 里配置 SSL 证书非常直接,server 块里指定证书路径即可:

server { listen 443 ssl; server_name example.com; ssl_certificate C:/win-acme/certs/example.com/fullchain.pem; ssl_certificate_key C:/win-acme/certs/example.com/key.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; }

几个参数的作用说明一下:ssl_certificate指向完整证书链文件,nginx 要求证书和中间证书都包含在这个文件里,所以用fullchain.pem最省事;ssl_certificate_key是私钥文件;ssl_session_cache和ssl_session_timeout是 SSL 会话复用的优化参数,减少重复握手开销。

证书自动续期后,nginx 里的文件会被替换成新证书,但 nginx 在启动时只加载一次证书,运行中不会主动重新读取。所以必须在续期后执行nginx -s reload让新证书生效。

reload和restart的差别在于:reload是平滑重载,不会断开现有连接,nginx 会先让旧 worker 进程处理完已建立的连接再退出,新连接走新配置;restart则会瞬间中断所有连接。SSL 证书切换用reload完全没问题,不需要重启。

我推荐在 win-acme 的续期后钩子里直接执行 reload 命令:

wacs.exe --renew --post-script "C:\nginx\nginx.exe -s reload" --post-script-params "--param1"

--post-script参数指定续期成功后要执行的脚本,在这里就是 nginx 的 reload。--post-script-params是传给脚本的参数,如果你把 reload 写成了一个 .bat 文件来统一处理多条命令,就需要用到这个参数。

4.3 跨服务器证书同步:证书文件分发的一个可行思路

单机场景下,证书续期和 nginx reload 都在同一台服务器,上面这套配置就够了。但如果你的 nginx 跑在另一台服务器(比如证书在 Windows 上签发,nginx 在 Linux 上),就得做证书同步。

我的做法是:win-acme 续期后用--post-script执行一个脚本,把 PEM 文件拷贝到网络共享目录,或者直接推送到目标服务器。比如用scp或者robocopy把文件传过去,然后通过 ssh 远程执行 nginx reload。这个逻辑可以封装成一个 .bat 脚本:

@echo off REM 拷贝证书到 Linux 服务器 scp C:\win-acme\certs\example.com\*.pem user@192.168.1.100:/etc/nginx/ssl/ REM 远程重载 nginx ssh user@192.168.1.100 "nginx -s reload"

这个脚本的问题在于 scp 需要输密码,没法非交互运行。解决办法是用 ssh key 认证,在 Windows 上生成密钥对后把公钥拷到 Linux 的authorized_keys文件里。Windows OpenSSH 客户端默认支持这个流程,不需要额外装东西。

如果不想搞 ssh key,简单的方案是用robocopy拷贝到本机的共享目录,然后 Linux 那边用 inotify 监控目录变化自动 reload。这个思路更绕,但避免了 SSH 密钥管理。实际选哪种取决于你的网络架构——只要保证证书文件的更新和 nginx reload 是串行的,不会出现证书文件和私钥版本不一致的情况就行。

5. 避坑与排查:win-acme 在 Windows + nginx 下的十个常见翻车点

5.1 问题一:验证文件被 nginx 的 location 重写规则吃掉了

现象:win-acme 报告 HTTP 验证失败,错误信息类似The client could not verify the domain,但手工访问http://example.com/.well-known/acme-challenge/xxx能看到文件内容。

原因:很多 nginx 站点配置里会写一个通用的location /块做反向代理或重写,比如try_files $uri $uri/ /index.php?$query_string这种。验证路径.well-known也被匹配到了这个规则,请求被转发到后端应用而不是直接读文件。win-acme 把验证文件写进了 webroot,但 nginx 没按静态文件返回。

解决:在 nginx 配置中加一条精确匹配规则,让验证路径绕过所有其他规则:

location ^~ /.well-known/acme-challenge/ { root C:/wwwroot/example; try_files $uri =404; }

^~前缀表明确认匹配这个路径后就不再查找其他 location,root指到网站根目录,try_files直接返回文件。注意root的路径要和 win-acme 的--webroot参数完全一致。

5.2 问题二:HTTP 验证时 80 端口被 IIS 抢了

现象:服务器上同时装了 IIS 和 nginx,IIS 占用了 80 端口,win-acme 验证请求到达服务器后,响应来自 IIS 而不是预期目录。

原因:Windows 下多个 HTTP 服务抢 80 端口很常见,特别是默认装了 IIS 的 Windows Server。IIS 的默认站点监听 80 端口,它的请求处理逻辑(比如 URL 重写)可能会把验证路径重写掉,或者 IIS 返回 404。

解决:最简单的方案是别用 HTTP 验证,改用 DNS 验证。在交互式界面或命令行中把--validation http换成--validation dns --dnsserver cloudflare(具体参数因 DNS 服务商而异)。DNS 验证不依赖本地端口和站点目录,只要你的 DNS API 能改 TXT 记录就能验证。如果必须用 HTTP 验证,就先把 IIS 默认站点的 80 端口绑顶解掉,保证 nginx 独占 80。

5.3 问题三:证书续期成功后,nginx 仍在用旧证书

现象:续期日志一切正常,证书文件也换了新的,但浏览器访问网站还是显示旧证书。

原因:nginx 的主进程在启动时加载证书,运行期间不会自动重新读取磁盘上的证书文件。哪怕 pem 文件内容变了,nginx 还保留着内存中的旧证书。

解决:必须在续期后执行nginx -s reload。如果你没有在 win-acme 的--post-script里配 reload,就手动跑一次。这里有个验证技巧:reload 后用openssl s_client -connect example.com:443 -servername example.com命令看返回的证书有效期,确认是否已换新。Windows 上如果没有 openssl,可以用 PowerShell 的Test-NetConnection配合证书面板查看,但不太直观。

5.4 问题四:renewal-settings.json 里找不到新加的域名

现象:手动编辑renewal-settings.json新增了一个域名的配置,跑wacs.exe --renew却没有任何反应。

原因:win-acme 的--renew命令只会处理已经登记过的证书。直接改renewal-settings.json虽然能让续期任务看到新条目,但必须有对应的 ACME 账户和 Target 配置,而新增时如果不走--target参数重跑一遍申请流程,工具不会自动识别为「需要续期的证书」。

解决:新增域名时不要想着直接改配置文件,老老实实跑一次交互式申请或命令行申请:

wacs.exe --target manual --host newdomain.com --validation dns --store pemfiles --pemfilespath C:\win-acme\certs

跑完这张证书的申请后,它会被自动登记到续期列表中。之后再手动编辑renewal-settings.json调参数才不会掉链子。我一般会先把新域名通过命令行签下来,再去配置文件里改验证阈值这些细节。

5.5 问题五:计划任务运行成功但证书没换

现象:Windows 计划任务显示上次运行结果为「成功」,但证书文件日期没变。

原因:计划任务里运行的wacs.exe没有以管理员权限执行,导致它定位不到配置文件和证书目录。win-acme 的续期过程需要写配置、读证书、改文件,这些操作在非管理员权限下可能被拒绝,但程序会吞掉部分异常,直接跳过了续期动作。

解决:打开计划任务,找到 win-acme 相关的任务,在「常规」选项卡里勾选「使用最高权限运行」。同时确认任务的「起始于」目录正确,也就是指向C:\win-acme。如果不勾管理员权限,win-acme 在续期时连 ACME 账户私钥都读不到。

5.6 问题六:续期时提示主机名重复或冲突

现象:同一个域名在renewal-settings.json里出现两次,续期时提示Host name already exists。

原因:原来的证书是用交互式界面创建的,后面你又用命令行跑了一次相同域名的申请。两条路径都往renewal-settings.json里写了一条记录,但使用的 Target 类型不一样,win-acme 无法合并。

解决:打开renewal-settings.json,到renewals节点下找到重复的域名条目,删掉那个 Target 类型和现在的环境不匹配的旧条目,保留一个就行。删完记得备份一份再动手。

5.7 问题七:证书签下来了但私钥和证书不匹配

现象:nginx 启动时报cannot load certificate key,或者浏览器报ERR_SSL_VERSION_OR_CIPHER_MISMATCH。

原因:PEM 文件里的证书和私钥不是一对。常见原因是cert.pem来自旧证书,key.pem来自新证书,两个文件不是同一批签发出来的。

解决:确认cert.pem和key.pem的生成时间是不是同一次签发的。可以通过对比两者的公钥指纹来判断:

openssl x509 -in cert.pem -noout -modulus | openssl md5 openssl rsa -in key.pem -noout -modulus | openssl md5

两个命令输出的 MD5 值一致就说明是一对。Windows 下没装 openssl 的话,用下载的证书管理器看证书的公钥信息,和私钥文件做对比。不一致的话删掉证书目录,重新签一次,别偷懒手动拼接。

5.8 问题八:DNS 验证时 API 权限不足

现象:DNS 验证报错,提示类似403 Forbidden或Authentication failed。

原因:DNS 服务商的 API Token 没有给足权限。很多服务商的最小权限原则下,只给 Zone Read 权限没法创建 TXT 记录,验证必然失败。

解决:去 DNS 服务商的控制台检查 Token 的权限范围,确保包含「编辑 DNS 记录」或「Zone Write」权限。如果服务商支持按域名粒度授权,只给当前域名的权限就行。注意不要给子域名的只读权限。

5.9 问题九:续期后 webroot 目录下残留.well-known文件夹

现象:网站根目录下出现.well-known/acme-challenge文件夹,里面是空的或残留历史验证文件。

原因:win-acme 在验证完成后一般会清理验证文件,但如果中途崩溃或验证方式切换(比如从 HTTP 换成了 DNS),清理逻辑可能没跑到。

解决:不影响运行,但如果你的 nginx 站点根目录有严格的目录权限控制,多出来的目录可能触发安全扫描的误报。手动删掉即可,不影响后续续期。如果你用的是 DNS 验证,这个目录根本不会被用到。

5.10 问题十:内网服务器无法从 Let's Encrypt 拉取证书

现象:日志显示连接 ACME 服务器超时,或报Could not connect to the ACME server。

原因:Let's Encrypt 的 ACME 服务需要公网访问能力。内网服务器的出站防火墙可能拦了 443 端口的 HTTPS 请求,或者服务器只能通过 HTTP 代理上网。

解决:先确认出站 443 是否通:Test-NetConnection acme-v02.api.letsencrypt.org -Port 443。如果被拦,在settings.json里配置代理:

"proxy": "http://your-proxy-server:3128"

如果企业网络有自己的 CA 体系,不建议用 Let's Encrypt,直接用内网 CA 更省事——win-acme 里也可以配置自定义 ACME 服务器地址来对接内网 CA。

6. 验证与进阶:从证书签发到站点安全性的全链路检查

证书签完、nginx 配好、自动续期跑通以后,别急着收工,还有一些检查和进阶调优值得做。先说验证环节,我每次换证书后都会跑一遍这套操作,大概五分钟:

第一步,验证证书链的完整性。在浏览器里访问站点,点开锁形图标看证书详情,确认有效期和签发机构。命令行下用openssl s_client更直观:

openssl s_client -connect example.com:443 -servername example.com -showcerts

看输出里的Certificate chain部分,应该包含服务器证书和中间证书,且没有多余证书。verify return code显示ok才算完整。如果显示unable to get local issuer certificate,说明中间证书没配全,nginx 里应该换成fullchain.pem。

第二步,检查证书的 SAN 覆盖范围。如果你签的是example.com,www.example.com,浏览器访问两个域名都应该显示信任的证书标识。漏了哪个 SAN,哪个域名就会报证书错误。用openssl x509 -in cert.pem -text -noout | grep "Subject Alternative Name"确认。

第三步,测试自动续期任务是否真的可用。不要等到 90 天后才验证,有个技巧是调低续期阈值强行触发一次:

wacs.exe --renew --renewal-threshold 999

这个命令会让系统认为所有证书都已过期,强制走一次完整的续期流程。如果这次能成功,说明你的计划任务、验证方式、post-script 都没问题。跑完记得改回正常阈值。

做完验证,再说两个进阶方向。

进阶一:通配符证书的签法。如果你有多个子域名,签一张*.example.com的通配符证书比签一堆单域名证书省心多了。win-acme 支持通配符,但有个硬性限制:通配符证书不能用 HTTP 验证,只能用 DNS 验证。因为 Let's Encrypt 的 HTTP 验证不能证明你拥有整个域,只有 DNS 的 TXT 记录可以。命令如下:

wacs.exe --target manual --host *.example.com --validation dns --dnsserver cloudflare --store pemfiles --pemfilespath C:\win-acme\certs

注意--host参数要写成*.example.com的形式,win-acme 会识别为通配符请求。签下来后 nginx 的配置不变,server_name example.com *.example.com都能用这张证书。

进阶二:证书到期监控。除了 win-acme 自己的日志,我习惯加一个独立的监控脚本,每天检查证书剩余天数,低于阈值就发邮件或写入事件日志。写一个 PowerShell 脚本挂在计划任务里:

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import("C:\win-acme\certs\example.com\cert.pem") $daysLeft = ($cert.NotAfter - (Get-Date)).Days if ($daysLeft -lt 14) { Write-EventLog -LogName Application -Source "SSLMonitor" -EventId 1001 -EntryType Warning -Message "SSL cert expires in $daysLeft days" }

这个脚本的意义在于:win-acme 的自动续期是「到期前触发」,如果它因为各种原因没跑成功,你自己得有个兜底机制。监控的阈值设为 14 天,留出足够的时间去手动处理。

另外还有一个小习惯建议从第一天就养成:每次升级 win-acme 版本前,先备份整个安装目录。这个工具升级文档里说的「直接覆盖解压」确实可行,但配置文件和证书文件夹都在同一目录下,覆盖过程中万一出问题,证书还在但配置丢了,续期任务直接罢工。我都是先复制整个目录到win-acme-backup,再升级,跑一遍--renew确认没问题再删备份。

最后说一个我自己的判断标准:免费证书并不等于免费的运维。Let's Encrypt 证书 90 天的有效期是设计如此,不是 bug。如果你觉得 90 天太短、续期太频繁,可以考虑用收费证书或内部 CA,但 win-acme 这套自动续期机制已经把这 90 天的成本摊得很薄了。真正决定证书能不能稳定在线的,不是签发工具,而是你围绕它搭的这套「申请 → 验证 → 存储 → reload → 监控」的闭环。把这套闭环跑通了,后面再加域名、换服务器,都是复制粘贴的事。

希望这篇拆解能帮你在 Windows 上用 win-acme 把免费证书这件事一次搞定,少走我当年踩过的那些弯路。

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

RELATED READING

延伸阅读

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