戰(zhàn):Windows 免費(fèi) HTTPS 證書自動(dòng)簽發(fā)與續(xù)期)
簡(jiǎn)介win-acme.v2.1.18-x64 是一款面向 Windows 站點(diǎn)管理員、個(gè)人站長(zhǎng)與小型項(xiàng)目運(yùn)維者的免費(fèi) SSL 證書自動(dòng)化工具重點(diǎn)解決 Lets Encrypt 證書申請(qǐng)、安裝與續(xù)訂流程繁瑣的問(wèn)題。壓縮包共 27 個(gè)文件、約 29.58MB包含 15 個(gè) ps1 腳本、4 個(gè) dll 運(yùn)行庫(kù)、2 個(gè) json 配置文件、2 個(gè) bat 批處理文件以及 exe 主程序、xml 配置模板、dat 公共后綴列表和 txt 版本說(shuō)明等兼顧圖形化操作與命令行腳本自動(dòng)化。工具可自動(dòng)完成域名所有權(quán)驗(yàn)證、證書簽發(fā)、IIS 等 Web 服務(wù)器部署及到期續(xù)訂并支持多域名與通配符證書管理配合日志與報(bào)告便于排查驗(yàn)證失敗、續(xù)訂異常等問(wèn)題對(duì) HTTP-01 與 DNS-01 驗(yàn)證、證書計(jì)劃任務(wù)和狀態(tài)檢查也有相應(yīng)支持。已有 334 人學(xué)習(xí)下載適合希望以較低成本為站點(diǎn)啟用 HTTPS、減少手工維護(hù)證書負(fù)擔(dān)并借助腳本與配置樣例搭建自動(dòng)化續(xù)期流程的讀者參考使用。1. 免費(fèi)域名搜進(jìn)來(lái)先說(shuō)清楚 win-acme 到底給什么搜「免費(fèi)域名」的人多半會(huì)被 win-acme 這個(gè)名字帶偏它不發(fā)域名發(fā)的是 90 天一輪的免費(fèi) TLS 證書把 HTTPS 那筆每年幾千塊的開(kāi)銷直接抹掉。v2.1.18 的 x64 自包含包解開(kāi)就是一個(gè)wacs.exe不需要預(yù)裝 .NET 運(yùn)行時(shí)Windows Server 2012 R2 以上丟上去雙擊就能跑。它管的是證書從簽發(fā)、驗(yàn)證、部署到續(xù)期的整條鏈路對(duì)接 ACME 協(xié)議、跑 HTTP-01 或 DNS-01 驗(yàn)證、把結(jié)果寫進(jìn) IIS 或 PEM/PFX 文件、再自己掛一個(gè)計(jì)劃任務(wù)做無(wú)人值守續(xù)期。適合自己維護(hù)一兩臺(tái) Windows 機(jī)器的運(yùn)維、給內(nèi)網(wǎng)測(cè)試站配證書的后端以及不想天天敲 OpenSSL 的人。它不管域名本身也不替你做解析這兩件事必須先自己搞定。2. 裝到簽發(fā)第一張證書x64 自包含包的啟動(dòng)姿勢(shì)與向?qū)в成?.1 解壓后的目錄結(jié)構(gòu)為什么優(yōu)先選自包含包這個(gè)包最大的價(jià)值是「零依賴啟動(dòng)」。解壓出來(lái)你會(huì)看到wacs.exe加一批 dll、一個(gè)web子目錄和若干插件目錄全部自包含機(jī)器上沒(méi)裝 .NET 運(yùn)行時(shí)也能直接跑。同一版本系列里還有依賴框架的變體體積小一些但換來(lái)的代價(jià)是每臺(tái)目標(biāo)機(jī)器都得先補(bǔ)運(yùn)行時(shí)一旦版本對(duì)不上雙擊就是一句「缺少運(yùn)行時(shí)」的彈窗連菜單都進(jìn)不去。生產(chǎn)環(huán)境里我一般無(wú)條件選自包含版硬盤多占幾十兆換的是排障時(shí)少一個(gè)變量。解壓路徑也有講究別放桌面或者帶中文的目錄放到C:\tools\win-acme這類純英文短路徑下因?yàn)楹竺嬗?jì)劃任務(wù)的工作目錄會(huì)引用這個(gè)位置路徑里帶空格或者中文很容易在任務(wù)計(jì)劃里被截?cái)唷5谝淮芜\(yùn)行必須以管理員身份開(kāi)命令行不是雙擊 exe——雙擊雖然也能進(jìn)交互菜單但后續(xù)寫證書存儲(chǔ)、改 IIS 綁定都需要提權(quán)中途失敗會(huì)讓你以為證書簽發(fā)失敗其實(shí)是權(quán)限不夠。先做一件事確認(rèn)這版支持哪些參數(shù)別照抄三年前的教程。# 管理員身份打開(kāi) cmd進(jìn)到解壓目錄 cd /d C:\tools\win-acme # 打印完整參數(shù)列表重點(diǎn)看 target / validation / store / installation 四段 wacs.exe --help--help的輸出很長(zhǎng)但只需要盯四組參數(shù)--target決定主機(jī)名從哪來(lái)手動(dòng)輸入還是掃 IIS--validation決定用哪種驗(yàn)證方式--store決定證書存成什么格式--installation決定要不要順手裝進(jìn) IIS。這四個(gè)決定了后面所有命令的形狀。不同小版本之間參數(shù)名會(huì)有微調(diào)比如早期版本某些開(kāi)關(guān)叫法不一樣抄舊命令最常見(jiàn)的報(bào)錯(cuò)就是「未知參數(shù)」而這條命令能在三十秒內(nèi)告訴你正確答案。養(yǎng)成習(xí)慣換一臺(tái)機(jī)器、換一個(gè)版本先跑一次--help比出問(wèn)題再回頭查強(qiáng)得多。2.2 交互向?qū)ё咭槐閺闹鞑藛蔚阶C書落地第一次用建議走交互模式把流程在腦子里建立一遍映像之后再用命令行固化。運(yùn)行wacs.exe管理員 cmd 里主菜單是幾個(gè)字母鍵新建證書、續(xù)期、管理續(xù)期、列出已有續(xù)期。選新建之后向?qū)?huì)依次問(wèn)你五件事這五件事和后面命令行的參數(shù)是一一對(duì)應(yīng)的理解了這層映射參數(shù)就不用背了。第一步問(wèn)主機(jī)名輸入www.example.com多個(gè)域名用逗號(hào)分隔注意這里填的必須是能通過(guò)公網(wǎng)解析到本機(jī)的域名填錯(cuò)后面驗(yàn)證必然失敗。第二步問(wèn)驗(yàn)證方式列表里會(huì)同時(shí)出現(xiàn)文件系統(tǒng)驗(yàn)證、自托管驗(yàn)證、DNS 手動(dòng)驗(yàn)證、DNS 腳本驗(yàn)證等選項(xiàng)每一項(xiàng)前面標(biāo)著[http-01]、[dns-01]或[tls-alpn-01]這就是協(xié)議類型。第三步問(wèn)證書存到哪可選 PEM 文件、PFX 歸檔、Windows 證書存儲(chǔ)選完還會(huì)追問(wèn)具體路徑或存儲(chǔ)位置。第四步問(wèn)要不要安裝到 IIS如果這臺(tái)機(jī)器上有 IIS 站點(diǎn)選安裝會(huì)自動(dòng)更新綁定。第五步是接受協(xié)議條款和填郵箱郵箱必須真實(shí)可用證書快到期時(shí) CA 會(huì)往這個(gè)地址發(fā)提醒很多「證書突然過(guò)期」的事故就是當(dāng)初隨手填了個(gè)不存在的郵箱。向?qū)芡昶聊簧蠒?huì)打印一段匯總包含證書路徑、指紋、到期時(shí)間和下次續(xù)期時(shí)間。這一段務(wù)必截圖或者復(fù)制到記事本因?yàn)樗呛竺鎸懩_本、核對(duì)綁定關(guān)系的依據(jù)。整個(gè)過(guò)程中最容易出錯(cuò)的是第二步和第三步的路徑驗(yàn)證路徑填的必須是網(wǎng)站真實(shí)根目錄證書輸出路徑必須是空目錄或者你有寫權(quán)限的目錄兩者填反了會(huì)得到兩種完全不同的報(bào)錯(cuò)前者是驗(yàn)證 403后者是寫文件失敗。2.3 用命令行把向?qū)Ч袒粭l能重復(fù)執(zhí)行的簽發(fā)命令交互模式適合第一次第二次開(kāi)始就該上命令行了。命令行最大的好處是可復(fù)現(xiàn)換機(jī)器、換域名改幾個(gè)變量就能重跑而且能直接塞進(jìn)自動(dòng)化腳本里。下面這條是我常用的最小可用組合做的是「手動(dòng)指定域名 文件系統(tǒng)驗(yàn)證 輸出 PEM」wacs.exe ^ --target manual ^ --host www.example.com ^ --validation filesystem ^ --webroot C:\inetpub\wwwroot ^ --store pemfiles ^ --pemfilespath C:\certs\www.example.com ^ --accepttos ^ --emailaddress opsexample.com ^ --verbose逐段說(shuō)明這幾個(gè)參數(shù)在干什么以及改哪里參數(shù)作用改動(dòng)時(shí)的注意點(diǎn)--target manual域名從參數(shù)里讀不掃 IIS想讓它自動(dòng)發(fā)現(xiàn) IIS 站點(diǎn)改成--target iis--host要簽的域名逗號(hào)分隔多個(gè)通配符寫*.example.com且必須配 DNS 驗(yàn)證--validation filesystem把驗(yàn)證文件寫進(jìn)網(wǎng)站根目錄需要--webroot配套路徑必須是站點(diǎn)真實(shí)根--webroot驗(yàn)證文件的落地目錄寫錯(cuò)就是 403用瀏覽器能訪問(wèn)到該目錄再繼續(xù)--store pemfiles輸出 PEM 格式證書需要--pemfilespath目錄不存在會(huì)自動(dòng)建--pemfilespathPEM 輸出目錄建議一域名一目錄便于腳本按目錄 reload--accepttos自動(dòng)接受 CA 條款不加會(huì)卡在交互確認(rèn)自動(dòng)化場(chǎng)景必加--emailaddress到期提醒郵箱別填 noreply 之類的假地址--verbose打印詳細(xì)過(guò)程首次簽發(fā)必開(kāi)出問(wèn)題就看它這條命令跑完最快十幾秒就能出結(jié)果。如果第一次就失敗把--verbose的輸出從頭看到尾它會(huì)明確告訴你卡在哪一步是 DNS 解析不到、是 80 端口連不上、還是文件寫不進(jìn)去。這比在瀏覽器里反復(fù)刷新猜原因高效得多。還有一點(diǎn)調(diào)試階段不要拿生產(chǎn)環(huán)境反復(fù)試ACME 服務(wù)端對(duì)同一組域名有每周簽發(fā)次數(shù)限制反復(fù)失敗重試很容易把自己鎖住正確做法是把 baseuri 指向 CA 提供的測(cè)試目錄先跑通再切回來(lái)。測(cè)試證書瀏覽器不認(rèn)這是正常的它只用來(lái)驗(yàn)證流程通不通。3. 驗(yàn)證方式怎么選HTTP-01、DNS-01 與產(chǎn)物落地位置3.1 文件系統(tǒng)驗(yàn)證和自托管驗(yàn)證差在一個(gè) 80 端口兩種方式都屬于 HTTP-01本質(zhì)都是讓 CA 通過(guò)http://域名/.well-known/acme-challenge/隨機(jī)串訪問(wèn)到一個(gè)指定內(nèi)容。差別在于誰(shuí)來(lái)提供這個(gè) HTTP 服務(wù)。文件系統(tǒng)驗(yàn)證是「借」你已有的 web 服務(wù)器win-acme 把驗(yàn)證文件寫進(jìn)網(wǎng)站根目錄的.well-known/acme-challenge/下然后由你現(xiàn)有的 IIS 或 nginx 把它吐出去。這條路適合已經(jīng)有站點(diǎn)在跑、80 端口本來(lái)就被占用的機(jī)器缺點(diǎn)是對(duì) web 服務(wù)器的路由配置有依賴最常見(jiàn)的失敗原因是站點(diǎn)做了全站 301 跳 HTTPS或者 nginx 里寫了try_files把所有請(qǐng)求都轉(zhuǎn)給后端應(yīng)用導(dǎo)致.well-known這個(gè)路徑根本落不到真實(shí)文件上。自托管驗(yàn)證是 win-acme 自己臨時(shí)起一個(gè)極簡(jiǎn) web 服務(wù)器搶占 80 端口驗(yàn)完就關(guān)。它適合這臺(tái)機(jī)器上根本沒(méi)有 web 服務(wù)、或者 web 服務(wù)不在這臺(tái)機(jī)器上的場(chǎng)景。代價(jià)是運(yùn)行期間 80 端口必須是空閑的如果 IIS 正在跑就會(huì)直接報(bào)端口占用。判斷方法很簡(jiǎn)單netstat -ano | findstr :80看有沒(méi)有進(jìn)程在監(jiān)聽(tīng)有就說(shuō)明自托管模式走不通乖乖用文件系統(tǒng)模式或者先停服務(wù)再簽。下面這段是 nginx 環(huán)境下最容易踩的配置坑放行規(guī)則要寫在跳轉(zhuǎn)規(guī)則之前server { listen 80; server_name www.example.com; # 驗(yàn)證路徑必須優(yōu)先匹配且不能跳轉(zhuǎn)、不能交給后端 location ^~ /.well-known/acme-challenge/ { root /var/www/html; default_type text/plain; try_files $uri 404; } # 其余請(qǐng)求才走 HTTPS 跳轉(zhuǎn) location / { return 301 https://$host$request_uri; } }^~前綴匹配的優(yōu)先級(jí)高于正則能保證驗(yàn)證請(qǐng)求不被后面的 rewrite 規(guī)則截走try_files $uri 404是為了在文件真的不存在時(shí)返回 404 而不是被兜底到首頁(yè)這樣出問(wèn)題時(shí)你能立刻從狀態(tài)碼判斷是「文件沒(méi)寫進(jìn)來(lái)」還是「路由被攔了」。改完 nginx 一定要nginx -t再 reload配置語(yǔ)法錯(cuò)誤會(huì)導(dǎo)致整個(gè)站點(diǎn)掛掉那時(shí)候你面對(duì)的就是雙重故障。IIS 那邊同理檢查 URL 重寫模塊里有沒(méi)有全站規(guī)則有的話給.well-known加一條排除。3.2 DNS-01 與通配符手動(dòng)模式和腳本鉤子的邊界通配符證書*.example.com只能走 DNS-01這是硬約束因?yàn)?HTTP-01 無(wú)法證明你控制所有子域。DNS-01 的原理是 CA 讓你在_acme-challenge.example.com加一條指定內(nèi)容的 TXT 記錄它去權(quán)威 DNS 查詢這條記錄查到就算通過(guò)。手動(dòng)模式下win-acme 會(huì)把該加的記錄名和記錄值打印在屏幕上你復(fù)制到 DNS 控制臺(tái)等生效后回車?yán)^續(xù)簽完再手動(dòng)刪掉。這條路適合一年只簽一次、域名數(shù)量個(gè)位數(shù)的場(chǎng)景雖然笨但絕不會(huì)因?yàn)?API 權(quán)限出問(wèn)題而失敗。腳本模式是把「加記錄 / 刪記錄」兩個(gè)動(dòng)作交給腳本win-acme 在驗(yàn)證前后各調(diào)一次。真正的坑不在腳本本身而在 DNS 傳播延遲記錄提交成功不代表權(quán)威 DNS 立刻對(duì)外可見(jiàn)客戶端如果查得太早會(huì)拿到 NXDOMAIN 直接判失敗。穩(wěn)妥做法是在腳本里加主動(dòng)探測(cè)用公共 DNS 反復(fù)查這條 TXT 直到查到為止再返回給 win-acme而不是靠固定 sleep 硬等。另一個(gè)坑是 TXT 記錄同名多條同一主域下同時(shí)簽*.example.com和example.com時(shí)兩條驗(yàn)證會(huì)往同一個(gè)記錄名寫不同值如果腳本是「覆蓋寫」而不是「追加寫」第二條必然覆蓋第一條導(dǎo)致驗(yàn)證失敗。腳本里必須實(shí)現(xiàn)「讀現(xiàn)有值 → 追加 → 驗(yàn)證完刪掉自己那條」的邏輯。提示腳本模式的參數(shù)名在不同小版本間有過(guò)調(diào)整寫腳本之前先跑wacs.exe --help找到 validation 段的實(shí)際寫法別直接套網(wǎng)上的舊示例。3.3 產(chǎn)物清單PEM、PFX、證書存儲(chǔ)分別喂給誰(shuí)同一個(gè)證書不同消費(fèi)者要不同格式這一步選錯(cuò)后面會(huì)得到「證書明明簽下來(lái)了服務(wù)就是不認(rèn)」的玄學(xué)現(xiàn)象。下面這張表是我這幾年反復(fù)對(duì)照過(guò)的對(duì)應(yīng)關(guān)系存儲(chǔ)類型落地產(chǎn)物典型消費(fèi)者備注PEM 文件fullchain.pem、privkey.pem、chain.pemnginx、Apache、Go 服務(wù)私鑰權(quán)限要收緊Linux 側(cè) 600PFX 歸檔.pfx單文件IIS 導(dǎo)入、Tomcat、Java keystore需要設(shè)密碼密碼要能傳給部署腳本W(wǎng)indows 證書存儲(chǔ)本機(jī)「?jìng)€(gè)人」或「Web 托管」存儲(chǔ)IIS 綁定、SMTP、遠(yuǎn)程桌面私鑰 ACL 丟了會(huì)報(bào)密鑰集不存在IIS 安裝中央證書存儲(chǔ) 站點(diǎn)綁定直接對(duì)外的 IIS 站點(diǎn)會(huì)自動(dòng)改綁定簽之前先備份配置PEM 那一行要特別說(shuō)一句fullchain.pem是「站點(diǎn)證書 中間證書」拼起來(lái)的完整鏈chain.pem只有中間證書privkey.pem是私鑰。nginx 的ssl_certificate要指向 fullchain 而不是單獨(dú)的站點(diǎn)證書只配站點(diǎn)證書會(huì)出現(xiàn)在部分客戶端上「證書鏈不完整」的警告桌面瀏覽器因?yàn)闀?huì)自動(dòng)補(bǔ)鏈所以看不出來(lái)手機(jī)和部分 API 客戶端就直接報(bào)錯(cuò)了。這個(gè)問(wèn)題藏得很深屬于典型的「本機(jī)測(cè)試一切正常、上線被投訴」類型。證書存儲(chǔ)那條路的坑在私鑰權(quán)限。證書導(dǎo)進(jìn)「Web 托管」存儲(chǔ)后IIS 應(yīng)用池賬戶需要能讀到私鑰如果這臺(tái)機(jī)器是從別的機(jī)器遷移過(guò)來(lái)的、或者你手工用 certutil 導(dǎo)入過(guò)私鑰 ACL 很容易丟癥狀是綁定站點(diǎn)時(shí)報(bào)0x80070520。遇到這個(gè)別急著刪證書重來(lái)先用certutil -store WebHosting看證書是否在、私鑰是否標(biāo)記為可導(dǎo)出再檢查私鑰文件的 ACL。4. 自動(dòng)續(xù)期閉環(huán)計(jì)劃任務(wù)、鉤子腳本與日志三件套4.1 續(xù)期任務(wù)是怎么被寫進(jìn)任務(wù)計(jì)劃的證書只有 90 天能不能自動(dòng)續(xù)上決定了這套方案是省事還是添亂。win-acme 在創(chuàng)建續(xù)期條目時(shí)默認(rèn)會(huì)往 Windows 任務(wù)計(jì)劃里注冊(cè)一個(gè)名字帶win-acme renew的任務(wù)觸發(fā)器設(shè)成每天跑一次實(shí)際執(zhí)行時(shí)它自己判斷「離到期還有多久」沒(méi)到續(xù)期窗口就直接退出所以天天跑并不會(huì)真的天天簽發(fā)。這個(gè)設(shè)計(jì)比「算好日期定一個(gè) 60 天后的單次任務(wù)」穩(wěn)得多因?yàn)闄C(jī)器可能關(guān)機(jī)、可能休眠、可能臨時(shí)沒(méi)網(wǎng)單次任務(wù)錯(cuò)過(guò)就是錯(cuò)過(guò)每日輪詢則有很多次補(bǔ)救機(jī)會(huì)。注冊(cè)任務(wù)時(shí)會(huì)問(wèn)你用哪個(gè)賬戶運(yùn)行這一步別隨手選當(dāng)前登錄用戶。選當(dāng)前用戶意味著任務(wù)依賴這個(gè)賬戶的密碼密碼一改、賬戶一禁用任務(wù)就靜默失敗而且失敗得很安靜——任務(wù)計(jì)劃里只顯示一個(gè)錯(cuò)誤碼沒(méi)有任何彈窗。我一般選 SYSTEM它不受登錄狀態(tài)和密碼策略影響缺點(diǎn)是腳本里如果用到了用戶級(jí)的環(huán)境變量或者映射網(wǎng)絡(luò)驅(qū)動(dòng)器會(huì)讀不到。如果確實(shí)需要訪問(wèn)網(wǎng)絡(luò)路徑就用一個(gè)有固定密碼的服務(wù)賬戶并且把「不管用戶是否登錄都運(yùn)行」勾上。:: 列出當(dāng)前所有續(xù)期條目看下一次到期時(shí)間和上次執(zhí)行結(jié)果 wacs.exe --list :: 強(qiáng)制立刻走一次續(xù)期流程用于驗(yàn)證鉤子腳本是否生效 wacs.exe --renew --force :: 測(cè)試階段不想讓它自動(dòng)注冊(cè)計(jì)劃任務(wù)加上這個(gè)開(kāi)關(guān) wacs.exe --renew --notaskscheduler--list這條命令的價(jià)值被嚴(yán)重低估。它輸出的不只是域名還有每條續(xù)期的 ID、綁定的驗(yàn)證方式、證書路徑和下次續(xù)期時(shí)間出問(wèn)題時(shí)先跑它能立刻區(qū)分是「續(xù)期條目壓根沒(méi)建」還是「條目在但執(zhí)行失敗」。--renew --force是調(diào)試?yán)鞯鼤?huì)真的去 CA 申請(qǐng)新證書所以在生產(chǎn)域名上別連著跑——一周內(nèi)重復(fù)簽發(fā)同一組域名是有次數(shù)上限的超了就得等窗口重置。想反復(fù)測(cè)流程就把 baseuri 指到測(cè)試目錄隨便折騰。注意--force繞過(guò)的是「是否在續(xù)期窗口內(nèi)」的判斷不是繞過(guò) CA 的限制。調(diào)試和生產(chǎn)的邊界要在這里劃清楚。4.2 續(xù)期后的鉤子導(dǎo)出 PEM 并讓服務(wù)熱加載證書續(xù)下來(lái)只是第一步讓正在跑的服務(wù)用上新證書才是閉環(huán)。win-acme 支持在續(xù)期成功后執(zhí)行一個(gè)腳本把續(xù)期 ID、證書指紋之類的信息作為參數(shù)傳進(jìn)去腳本里根據(jù)這些信息做后續(xù)動(dòng)作。典型場(chǎng)景是win-acme 只負(fù)責(zé)把新 PEM 寫到固定目錄腳本負(fù)責(zé)把文件同步到 nginx 目錄并 reload。# reload-nginx.ps1 # 由 win-acme 在續(xù)期成功后調(diào)用參數(shù)由 --scriptparameters 傳入 param( [string]$RenewalId, [string]$Thumbprint ) $log C:\tools\win-acme\hooks\reload.log $(Get-Date -Format s) renewal$RenewalId thumbprint$Thumbprint | Out-File $log -Append # 先做語(yǔ)法檢查檢查不過(guò)就不 reload避免把站點(diǎn)搞掛 C:\nginx\nginx.exe -t if ($LASTEXITCODE -ne 0) { nginx config test failed, skip reload | Out-File $log -Append exit 1 } # 平滑重載不中斷現(xiàn)有連接 C:\nginx\nginx.exe -s reload reload done, exit$LASTEXITCODE | Out-File $log -Append這段腳本的關(guān)鍵設(shè)計(jì)有三點(diǎn)。第一它自己寫日志因?yàn)?win-acme 的日志只記錄到「腳本已執(zhí)行」腳本內(nèi)部的成敗它看不到?jīng)]有獨(dú)立日志你就只能靠猜。第二reload 之前先nginx -t配置有問(wèn)題時(shí)寧可繼續(xù)用舊證書也不要讓服務(wù)起不來(lái)這個(gè)順序反了就是血淚經(jīng)驗(yàn)。第三用-s reload而不是重啟服務(wù)reload 是平滑的重啟會(huì)掐斷正在處理的請(qǐng)求。參數(shù)$RenewalId和$Thumbprint來(lái)自 win-acme 的占位符替換具體可用哪些占位符以--help里 script 段的說(shuō)明為準(zhǔn)不同版本支持的不完全一樣寫之前對(duì)一遍別想當(dāng)然。4.3 用日志和狀態(tài)文件判斷這次續(xù)期到底成沒(méi)成續(xù)期失敗最怕的是「靜默」計(jì)劃任務(wù)照常跑日志里沒(méi)有明顯紅色報(bào)錯(cuò)等到某天瀏覽器彈證書過(guò)期才發(fā)現(xiàn)已經(jīng)斷了兩個(gè)月。所以要有固定的巡檢動(dòng)作。日志落在程序數(shù)據(jù)目錄下路徑形如C:\ProgramData\win-acme\acme-v02.api.letsencrypt.org\Log文件名按日期組織一次續(xù)期一個(gè)文件。判斷成敗不要只看最后一行要看有沒(méi)有出現(xiàn)明確的成功字樣和證書指紋中間出現(xiàn)的重試記錄不算失敗只有最終沒(méi)有拿到新證書才算。除了日志續(xù)期條目的配置文件也值得看一眼。每個(gè)續(xù)期條目在Renewals子目錄下有一份自己的配置文件記錄了域名、驗(yàn)證方式、存儲(chǔ)路徑、上次執(zhí)行時(shí)間。這份文件是「當(dāng)前生效配置」的唯一真相改了它等于改了續(xù)期行為所以我一般先備份再動(dòng)。有些場(chǎng)景下你會(huì)需要手工改它比如換了 webroot 路徑、換了輸出目錄與其刪掉重建不如直接改配置里的路徑字段保留原來(lái)的續(xù)期 ID 和計(jì)劃任務(wù)關(guān)聯(lián)。巡檢腳本可以很簡(jiǎn)單每天讀一次最新日志找關(guān)鍵字沒(méi)有成功標(biāo)記就發(fā)告警。真正麻煩的不是寫腳本而是堅(jiān)持看。我見(jiàn)過(guò)太多「配好就不管」的案例包括我自己早期配完三個(gè)月后證書過(guò)期排查半天才發(fā)現(xiàn)是某次系統(tǒng)更新后計(jì)劃任務(wù)的運(yùn)行賬戶被改成了需要交互登錄。從那以后我給自己定了規(guī)矩任何自動(dòng)續(xù)期上線后第二周必須人為跑一次--list確認(rèn)狀態(tài)之后再按月抽查。5. 五個(gè)翻車現(xiàn)場(chǎng)從 403 到 0x80070520 的排查順序5.1 驗(yàn)證返回 403 或 Invalid response現(xiàn)象命令跑完報(bào)驗(yàn)證失敗提示從http://域名/.well-known/acme-challenge/xxx取文件失敗返回 403 或 404。原因基本只有三類webroot 路徑填的不是站點(diǎn)真實(shí)根目錄站點(diǎn)有全站跳轉(zhuǎn)或重寫規(guī)則把.well-known攔截了文件寫進(jìn)去了但 web 服務(wù)器進(jìn)程沒(méi)有讀權(quán)限。解決順序是先用瀏覽器或curl -I直接訪問(wèn)那個(gè)路徑看返回什么狀態(tài)碼403 就是權(quán)限或規(guī)則問(wèn)題404 就是路徑問(wèn)題。確認(rèn)路徑無(wú)誤后檢查 nginx 的location順序和 IIS 的 URL 重寫規(guī)則把.well-known的放行規(guī)則提到跳轉(zhuǎn)規(guī)則之前。5.2 自托管模式報(bào)端口占用現(xiàn)象選自托管驗(yàn)證后立刻失敗日志里出現(xiàn)地址已被占用的字樣。原因很直接80 端口上已經(jīng)有別的進(jìn)程在監(jiān)聽(tīng)最常見(jiàn)的是 IIS 的默認(rèn)站點(diǎn)其次是某些系統(tǒng)服務(wù)。排查用netstat -ano | findstr :80拿到 PID再tasklist | findstr PID對(duì)上是哪個(gè)進(jìn)程。解決方式不是硬停服務(wù)而是換驗(yàn)證方式——既然 80 端口已經(jīng)被 web 服務(wù)器占著直接改用文件系統(tǒng)驗(yàn)證把驗(yàn)證文件寫進(jìn)那個(gè)站點(diǎn)的根目錄反而更省事。硬停 IIS 再簽簽完還得啟回來(lái)中間站點(diǎn)是斷的。5.3 IIS 綁定更新了但瀏覽器還是舊證書現(xiàn)象證書續(xù)期成功路徑里的文件時(shí)間也是新的但瀏覽器訪問(wèn)還是顯示舊證書或者證書鏈不完整。原因通常是 IIS 站點(diǎn)綁定還指向舊證書的指紋或者用了中央證書存儲(chǔ)但站點(diǎn)沒(méi)有正確引用。先用netsh http show sslcert看 443 端口當(dāng)前綁定的指紋和--list輸出的新指紋比對(duì)不一致就是綁定沒(méi)更新。再檢查 IIS 站點(diǎn)綁定的 SNI 設(shè)置多站點(diǎn)共用 443 時(shí)靠 SNI 區(qū)分SNI 沒(méi)開(kāi)會(huì)導(dǎo)致所有域名都拿到同一個(gè)證書。改完綁定記得iisreset或者回收應(yīng)用池某些情況下 IIS 會(huì)緩存證書句柄。5.4 計(jì)劃任務(wù)天天跑但證書始終不續(xù)現(xiàn)象任務(wù)計(jì)劃里能看到任務(wù)上次運(yùn)行結(jié)果是一個(gè)非零的錯(cuò)誤碼證書到期時(shí)間紋絲不動(dòng)。原因有三個(gè)高頻項(xiàng)任務(wù)運(yùn)行賬戶的密碼過(guò)期或被改任務(wù)被設(shè)成「僅在用戶登錄時(shí)運(yùn)行」而服務(wù)器沒(méi)人登錄機(jī)器在續(xù)期窗口期長(zhǎng)期斷網(wǎng)。排查先看任務(wù)的「上次運(yùn)行結(jié)果」和「歷史記錄」再手動(dòng)用同一賬戶執(zhí)行一次--renew看報(bào)錯(cuò)。解決方式是把運(yùn)行賬戶改成 SYSTEM勾選「不管用戶是否登錄都運(yùn)行」并在腳本里加網(wǎng)絡(luò)可達(dá)性檢查不通時(shí)提前退出并寫日志而不是等到驗(yàn)證階段才失敗。5.5 報(bào) too many certificates 被限流現(xiàn)象調(diào)試階段反復(fù)重試突然所有簽發(fā)都失敗提示同一組域名的證書簽發(fā)次數(shù)超限。原因是公共 CA 對(duì)「同一組域名集合」的單位時(shí)間簽發(fā)數(shù)量有上限--force反復(fù)跑正好踩中。這個(gè)坑沒(méi)有后悔藥只能等窗口重置通常是一周。正確的應(yīng)對(duì)是提前把調(diào)試流量導(dǎo)到測(cè)試目錄簽發(fā)命令里把 baseuri 指向 CA 提供的測(cè)試入口測(cè)試證書不被瀏覽器信任但流程完全一致等流程確認(rèn)無(wú)誤再切回生產(chǎn)目錄跑一次。這個(gè)習(xí)慣我從第一次被限流之后就固定下來(lái)了此后再?zèng)]在生產(chǎn)目錄上做過(guò)任何調(diào)試。6. 多站點(diǎn)批量把續(xù)期配置當(dāng)代碼管起來(lái)機(jī)器上站點(diǎn)一多一條條敲命令就不現(xiàn)實(shí)了。批量模式的核心思路是先用一條命令把多個(gè)域名塞進(jìn)同一個(gè)證書再用--list和續(xù)期配置文件統(tǒng)一管理而不是為每個(gè)域名建一個(gè)計(jì)劃任務(wù)。6.1 多域名合并與配置復(fù)用同一個(gè)站點(diǎn)的主域、www、幾個(gè)子域完全可以簽進(jìn)同一張證書--host支持逗號(hào)分隔多個(gè)域名驗(yàn)證只需做一次續(xù)期窗口也只有一個(gè)管理成本直接降一個(gè)量級(jí)。但要注意證書里的域名數(shù)量不是越多越好一個(gè)域名驗(yàn)證失敗會(huì)導(dǎo)致整張證書簽發(fā)失敗所以「按業(yè)務(wù)分組、每組一張證書」比「全站一張大證書」更穩(wěn)。:: 三個(gè)域名合并一張證書輸出到按主域命名的目錄 wacs.exe ^ --target manual ^ --host example.com,www.example.com,api.example.com ^ --validation filesystem ^ --webroot C:\inetpub\wwwroot ^ --store pemfiles ^ --pemfilespath C:\certs\example.com ^ --accepttos ^ --emailaddress opsexample.com這條命令生成的續(xù)期條目會(huì)作為一個(gè)整體存在續(xù)期時(shí)三個(gè)域名一起驗(yàn)、一起簽、一起更新文件。改配置時(shí)改的也是這一個(gè)條目不用滿機(jī)器找散落的計(jì)劃任務(wù)。如果確實(shí)需要通配符把--host換成*.example.com,example.com同時(shí)把驗(yàn)證方式換成 DNS-01因?yàn)橥ㄅ浞恢С?HTTP 驗(yàn)證。6.2 用一條命令驗(yàn)收證書鏈簽完之后別只信日志直接驗(yàn)證證書本身。Windows 上可以用 OpenSSL也可以用 PowerShell 的Get-PfxCertificate但我更習(xí)慣用 OpenSSL 看完整的鏈和有效期信息最全# 連上目標(biāo)站點(diǎn)打印證書鏈和有效期 openssl s_client -connect www.example.com:443 -servername www.example.com /dev/null 2/dev/null \ | openssl x509 -noout -subject -issuer -dates -fingerprint -sha256輸出里重點(diǎn)看三項(xiàng)subject里的域名是否和預(yù)期一致、dates的到期時(shí)間是否是剛續(xù)期后的新日期、issuer是否是中間證書而不是根證書。如果s_client輸出里出現(xiàn)verify error: unable to get local issuer certificate說(shuō)明服務(wù)端沒(méi)把中間證書一起發(fā)出來(lái)回到 3.3 節(jié)檢查是不是只配了站點(diǎn)證書沒(méi)配 fullchain。這條命令我一般放在續(xù)期腳本的最后一步自動(dòng)跑一遍輸出寫進(jìn)日志比事后靠用戶投訴發(fā)現(xiàn)要早得多。證書這東西配好那天是最可靠的之后可靠性只會(huì)一路下降。我現(xiàn)在的習(xí)慣是每次動(dòng)過(guò) web 服務(wù)器配置、改過(guò)防火墻、換過(guò) DNS 服務(wù)商都強(qiáng)制跑一遍--list加一次 openssl 驗(yàn)證確認(rèn)鏈完整、日期正確、續(xù)期條目還在。多花三分鐘省掉的是某天早上被電話叫醒。這份 x64 自包含包解壓即用配置、日志、續(xù)期條目全部落在 ProgramData 下按照第 2 章的向?qū)ё咭槐榫湍艹龅谝粡堊C書先把單域名的閉環(huán)跑通再往上疊批量和鉤子希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取