Windows
How to use win-acme to get Let's Encrypt certificates for IIS
win-acme (wacs.exe) reads the IIS bindings, obtains a Let's Encrypt certificate for the site, adds or updates its HTTPS binding, and creates a scheduled task that renews the certificate automatically.
The steps apply to win-acme 2.2.x (2.2.9.1 is the version offered on the project site as of November 2026; check win-acme.com for the current release) on Windows Server 2019, 2022 and 2025 with IIS 10.
Prerequisites
win-acme runs on the IIS server itself with administrator rights.
- Windows Server with IIS and a site that has an HTTP binding with host name
example.com(andwww.example.comif needed). - DNS
A/AAAArecords for those names pointing at the server, for example203.0.113.10. - Inbound TCP 80 and 443 open in Windows Firewall and any network firewall, unless you use DNS validation.
- Outbound HTTPS to
acme-v02.api.letsencrypt.org.
Step 1: Download win-acme
Download the x64 "trimmed" zip from win-acme.com (or the pluggable build if you need DNS plugins), and extract it to a permanent folder, because the scheduled task points there:
New-Item -ItemType Directory -Force C:\Tools\win-acme
Expand-Archive -Path $HOME\Downloads\win-acme.v2.2.9.1.x64.trimmed.zip -DestinationPath C:\Tools\win-acme
Adjust the zip file name to the version you downloaded.
Step 2: Create the certificate interactively
Start an elevated PowerShell and run:
cd C:\Tools\win-acme
.\wacs.exe
Choose N: Create certificate (default settings), pick the IIS site, select the bindings (host names) to include, accept the Let's Encrypt terms, and optionally enter an email address. win-acme validates each name over HTTP, stores the certificate, adds an HTTPS binding on port 443 with SNI for each host name, and creates the scheduled task.
Step 3 (alternative): Unattended setup
For scripted deployments use the same plugins from the command line:
.\wacs.exe --source iis --siteid 1 --host example.com,www.example.com `
--installation iis --accepttos --emailaddress admin@example.com
Find the site ID with Get-Website | Select-Object ID, Name. For a wildcard or a server without inbound port 80, add a DNS validation plugin, for example --validation cloudflare --cloudflareapitoken <token> with the pluggable build; see the win-acme command-line reference for other providers.
Step 4: Redirect HTTP to HTTPS
win-acme does not add a redirect. Use the URL Rewrite rule from installing an SSL certificate on IIS, and keep the HTTP binding in place so the redirect and future HTTP-01 validations keep working.
Verify
The public site should present the Let's Encrypt certificate, and the server should list the renewal, the HTTPS binding and the win-acme scheduled task. Check the public site with the SSL checker, or from any terminal:
curl ssl.sh/example.com
On the server:
.\wacs.exe --list
Get-WebBinding -Name "Default Web Site" -Protocol https
Get-ScheduledTask | Where-Object TaskName -like "win-acme*"
Automatic renewal
The scheduled task runs wacs.exe --renew every day at 9:00 by default. A certificate is renewed 55 days after issuance (RenewalDays), earlier if Let's Encrypt's ARI response suggests it (unless RenewalDisableServerSchedule is set), and in any case when fewer than 7 days of validity remain. After renewal win-acme updates the IIS bindings to the new certificate.
Test the whole path without waiting:
.\wacs.exe --renew --force --test
--force spends a real certificate order, so use it sparingly and not in a loop. Settings live in settings.json next to wacs.exe. Add the site to ssl.sh monitoring (in development), since Let's Encrypt no longer emails expiry warnings.
Troubleshooting
- Validation fails with a timeout or connection error: port 80 is blocked, DNS points elsewhere, or a redirect sends the challenge to another host; the causes match certbot timeout during connect.
- Unauthorized (403) on the challenge URL: another IIS feature (authentication, URL rewrite to HTTPS on a different host) intercepts
/.well-known/acme-challenge/; exclude that path. - CAA record prevents issuance: see CAA record prevents issuance.
- Renewal task never runs: the task was created under a user that lost permissions, or the win-acme folder moved; recreate it from the main menu (More options → Manage scheduled task) and check Task Scheduler history.
- Too many failed validations: you retried too quickly; see Let's Encrypt rate limits and test with
--testagainst staging.
FAQ
Does win-acme need port 80 open?
For the default HTTP-01 validation, yes: Let's Encrypt connects to http://example.com/.well-known/acme-challenge/... on port 80. If port 80 is closed or you need a wildcard, choose a DNS validation plugin instead.
Will 55-day renewal still work when certificates get shorter?
Only with ARI enabled and RenewalDays reviewed. The fixed default was chosen for 90-day certificates. win-acme also honours ARI suggestions and renews when fewer than 7 days remain, but before Let's Encrypt's 64-day default arrives on February 10, 2027, review RenewalDays in settings.json and keep ARI enabled. Check the win-acme release notes for changes to these defaults.
Can win-acme use a CA other than Let's Encrypt?
Yes. Pass the CA's ACME directory with --baseuri (and External Account Binding credentials if the CA requires them). Make sure your CAA records allow that CA.