This guide explains how to install a Let's Encrypt TLS certificate on an IIS site hosted on a Windows Server VPS. The main procedure uses simple-acme. It covers HTTP-01 validation, wildcard certificates through DNS-01, IIS bindings with SNI, scheduled renewal, HSTS, monitoring and the most common errors.
The expected result is as follows:
http://example.comanswers on port 80 and redirects to HTTPS;https://example.comandhttps://www.example.compresent a valid certificate;- the certificate carries the right DNS names in its SANs;
- IIS uses the correct binding on port 443;
- a scheduled task checks daily whether a renewal is needed;
- the next renewal can succeed without human intervention.
Method, scope and limits of this guide
The information was cross-checked on 29 August 2026 against the official documentation of Let's Encrypt, Microsoft IIS and simple-acme. The commands were compared with the PowerShell and IIS references published by Microsoft.
Versions, issuance limits and validity periods change regularly. Before applying this procedure in production, reproduce it on a staging VPS with a real subdomain, and check the figures in this article against the official pages linked throughout the text.
This guide covers a public IIS site tied to a DNS name. It does not cover domain controller certificates, LDAPS or AD CS, nor Exchange, RDS Gateway or SQL Server, nor an internal PKI, nor an IIS cluster without centralised certificate deployment, nor a proxy that terminates TLS on another machine. In those cases the certificate can still come from an ACME authority, but the installation and renewal method must be adapted to the service.
Let's Encrypt, ACME, IIS and simple-acme: who does what?
| Component | Function |
|---|---|
| Let's Encrypt | public certificate authority that validates control of the name and signs the certificate |
| ACME v2 | protocol automating validation, issuance, renewal and revocation |
| simple-acme | third-party ACME client that talks to Let's Encrypt and drives IIS |
| Windows certificate store | holds the certificate and its private key on the server |
| IIS and HTTP.sys | bind the certificate to an address, a port and a host name |
| Windows scheduled task | runs simple-acme regularly to check for renewals |
Let's Encrypt issues Domain Validation certificates. They prove technical control of the requested names and encrypt the connection. They do not certify a company's legal identity and they fix neither a vulnerable application nor a compromised server. Let's Encrypt does not offer OV or EV certificates, as stated in its official FAQ.
Public certificates are also recorded in Certificate Transparency logs. The DNS names in a certificate must therefore not be treated as secret. Let's Encrypt explains this in its documentation on CT logs.
simple-acme or win-acme: which one to pick?
win-acme remains the best-known client in the IIS ecosystem. simple-acme presents itself on its own site as a backwards-compatible replacement, built by the same person. As of 29 August 2026, simple-acme publishes version 2.4.0 while win-acme still distributes its own 2.2.9.1: both projects are available, and moving from one to the other is a choice, not an obligation.
This guide uses simple-acme because it is the more recently updated branch. If you already run win-acme and it renews your certificates correctly, nothing forces you to migrate in a hurry.
The getting started documentation confirms that the tool detects IIS bindings, uses Let's Encrypt by default, performs HTTP validation, installs the certificate in the Windows store, creates or updates the HTTPS bindings and creates a renewal scheduled task.
simple-acme is not a Microsoft product nor an "official Let's Encrypt client". It is third-party open source software. Download it only from the simple-acme site or its linked GitHub repository, then verify the file's integrity.
If you already use win-acme
Do not blindly delete win-acme or its %ProgramData% folder. Start with an inventory:
Get-ScheduledTask |
Where-Object TaskName -Match "win-acme|simple-acme" |
Select-Object TaskName, State, TaskPath Then inventory the renewals and where their configuration lives. simple-acme is announced as a compatible replacement, but a server or DPAPI context migration requires checking secrets, paths, plugins and certificates. Follow the simple-acme migration procedure and keep a backup before making any change.
Understanding HTTP-01, DNS-01 and TLS-ALPN-01
Let's Encrypt must verify that you control every requested name.
| Method | Validation | Required port or service | Wildcard | Recommended use |
|---|---|---|---|---|
| HTTP-01 | a resource under /.well-known/acme-challenge/ | public TCP 80 | no | a public IIS site on a single server |
| DNS-01 | a TXT record under _acme-challenge | public DNS API | yes | wildcard, cluster, port 80 unavailable |
| TLS-ALPN-01 | a special TLS response | public TCP 443 | no | advanced TLS infrastructures |
For HTTP-01, Let's Encrypt requests a resource of the form:
http://example.com/.well-known/acme-challenge/<TOKEN> Validation always arrives on port 80. Let's Encrypt can follow up to ten redirects, but only to HTTP or HTTPS and only to ports 80 or 443. HTTP-01 cannot obtain *.example.com. These rules are described on the official Challenge Types page.
For DNS-01, the client publishes a TXT record under:
_acme-challenge.example.com DNS-01 supports wildcards and works without a public web server. To stay automatable it does require a DNS API, or delegating _acme-challenge to a zone that can be automated. Use API credentials with reduced privileges: giving the web server a key that can modify all your DNS zones greatly increases the impact of a compromise.
Prerequisites
You need an up-to-date Windows Server VPS, administrator access over RDP or console, IIS installed with a site that already answers over HTTP, a public domain or subdomain you control, a correct A record and, if it exists, a correct AAAA record, TCP ports 80 and 443 open in both the Windows firewall and the network firewall, outbound HTTPS connectivity to the ACME API, a monitored operations email address, and a backup of the IIS configuration before making changes.
Our Windows VPS provide a manageable Windows environment with full administrator access. Since versions, resources and options can change, check the product page at deployment time.
1. Audit Windows Server and IIS
Open Windows PowerShell as administrator:
Get-ComputerInfo |
Select-Object WindowsProductName, WindowsVersion, OsBuildNumber
Get-WindowsFeature Web-Server
Get-Service W3SVC
Get-NetFirewallProfile |
Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction The Web-Server role must be installed and the W3SVC service must be running. If IIS is not installed yet:
Install-WindowsFeature Web-Server -IncludeManagementTools Install-WindowsFeature requires an elevated console and -IncludeManagementTools installs the management tools, as per the Windows Server 2025 reference. If you are starting from a fresh server, our guide on getting started with a Windows VPS covers the initial connection and updates.
Inventory the sites and their bindings:
Import-Module WebAdministration
Get-Website |
Select-Object Name, Id, State, PhysicalPath
Get-WebBinding |
Select-Object protocol, bindingInformation, sslFlags Note the name and the ID of the site to secure. The examples below use:
| Parameter | Example |
|---|---|
| IIS site | MySite |
| IIS ID | 2 |
| Main domain | example.com |
| Alias | www.example.com |
| Public IPv4 | 203.0.113.10, a documentation value to replace |
The ranges 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24 are reserved for documentation. Do not copy them into a real configuration.
Add the missing HTTP bindings
simple-acme can derive names from IIS bindings. Every requested name must therefore be explicit and genuinely point at this server.
New-WebBinding `
-Name "MySite" `
-Protocol "http" `
-IPAddress "*" `
-Port 80 `
-HostHeader "example.com"
New-WebBinding `
-Name "MySite" `
-Protocol "http" `
-IPAddress "*" `
-Port 80 `
-HostHeader "www.example.com" Only run these commands if the bindings do not already exist. Microsoft documents New-WebBinding and its parameters in the WebAdministration reference.
Check the result:
Get-WebBinding -Name "MySite" -Protocol http |
Select-Object bindingInformation An empty binding such as *:80: accepts every name not captured by another site. It can mask a configuration error and cause the wrong content to be validated. On a multi-site server, use precise host names.
2. Check public DNS, including IPv6
From the VPS:
Resolve-DnsName example.com -Type A
Resolve-DnsName www.example.com -Type A
Resolve-DnsName example.com -Type AAAA -ErrorAction SilentlyContinue
Resolve-DnsName www.example.com -Type AAAA -ErrorAction SilentlyContinue The A answers must match the public IPv4 address serving IIS. If an AAAA record exists, the site must work over that IPv6 address too.
Let's Encrypt prefers IPv6 on its first attempt when an AAAA record is published. An IPv6 server that answers with the wrong content can fail validation without falling back to IPv4. The fix is to point AAAA at the right server and serve the same site, or to remove AAAA if IPv6 is not in use. There is no option to ask Let's Encrypt to prefer IPv4. See the IPv6 Support documentation.
Also check any CAA records:
Resolve-DnsName example.com -Type CAA -ErrorAction SilentlyContinue The absence of CAA does not prevent issuance. If a CAA policy is present, it must authorise Let's Encrypt, for example:
example.com. CAA 0 issue "letsencrypt.org" For separate control of wildcards, the issuewild tag can be used. Let's Encrypt's CAA identifying domain is letsencrypt.org, as stated in its CAA documentation. A SERVFAIL error may indicate a broken DNSSEC chain or a failing DNS server.
3. Open only the necessary ports
Create inbound rules for HTTP and HTTPS:
New-NetFirewallRule `
-DisplayName "IIS HTTP - TCP 80" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 80 `
-Action Allow `
-Profile Any
New-NetFirewallRule `
-DisplayName "IIS HTTPS - TCP 443" `
-Direction Inbound `
-Protocol TCP `
-LocalPort 443 `
-Action Allow `
-Profile Any If these rules already exist, audit them instead of creating duplicates:
Get-NetFirewallRule -DisplayName "IIS HTTP - TCP 80","IIS HTTPS - TCP 443" |
Get-NetFirewallPortFilter The Windows firewall and the host's network firewall are two separate layers. A correct local rule is not enough if upstream filtering refuses the port. Our guide on configuring the Windows Server firewall on a VPS details that separation.
For HTTP-01, port 80 must be reachable from the Internet. Let's Encrypt does not publish a stable range of validation addresses to allow: restricting access to a few arbitrary IP addresses will eventually cause a failure.
Check local listening:
Get-NetTCPConnection -State Listen |
Where-Object LocalPort -In 80,443 |
Select-Object LocalAddress, LocalPort, OwningProcess Then test from a connection outside the VPS:
Test-NetConnection example.com -Port 80
Test-NetConnection example.com -Port 443 A test run from the server itself does not always prove public reachability, particularly where NAT, a proxy or geographic filtering is involved.
4. Back up the IIS configuration
Before changing the bindings:
$appcmd = "$env:windir\System32\inetsrv\appcmd.exe"
& $appcmd add backup "Before-LetsEncrypt"
& $appcmd list backup This backup protects the IIS configuration, not the site content, the database or the application's secrets. Also keep a system backup according to your policy. Our guide on backing up a Windows VPS presents several approaches.
5. Download and verify simple-acme
Recommended method on Windows Server 2019 and 2022: the official archive
Download the Windows x64 build from the official simple-acme page. Choose:
- the trimmed build for HTTP-01 and a simple IIS setup: it is smaller but does not support plugins;
- the full build if you need external plugins, in particular for a DNS provider.
Extract the archive to a permanent location:
C:\Program Files\simple-acme Do not leave wacs.exe in Downloads or in a temporary folder. The scheduled task depends on the executable's path.
Compute the archive's SHA-256 before extracting:
Get-FileHash `
-Path "C:\Users\Administrator\Downloads\simple-acme.zip" `
-Algorithm SHA256 Compare the value character by character with the hash published on the download page. As of 29 August 2026 the official page lists version 2.4.0, build 2.4.0.2350. Do not freeze that hash into a long-lived procedure: it changes with every release.
Windows Server 2025 method: WinGet
The simple-acme documentation states that WinGet is available on Windows Server 2025:
winget install simple-acme Then check the path actually installed:
Get-Command wacs.exe -ErrorAction SilentlyContinue On Server 2019 or 2022, prefer the official archive unless WinGet has been explicitly installed and managed in your image.
Verify the executable
Set-Location "C:\Program Files\simple-acme"
.\wacs.exe --version Always run the first configuration from an administrator console. The simple-acme installation documentation notes that elevated privileges are required to manage IIS, create the scheduled task and listen for validation requests.
6. Test in staging before production
Let's Encrypt recommends its staging environment for trials. Its certificates are not trusted by browsers, but the limits are far better suited to troubleshooting. The ACME v2 test URL is published in the staging documentation.
From the simple-acme folder:
.\wacs.exe --test --verbose Pick the same site and the same names as for production. A staging certificate will trigger a trust warning in the browser: that is expected.
After the test:
- open
Manage renewalsin simple-acme; - identify the renewal tied to the staging server;
- cancel it if you no longer need it;
- then run the production procedure;
- check that a production task and the correct IIS binding are active.
Avoid using --nocache and --force repeatedly. As of 29 August 2026, Let's Encrypt documents in particular 50 new certificates per registered domain per 7 days, 5 certificates per exact set of identifiers per 7 days, and 5 authorization failures per identifier per account per hour. Renewals coordinated through ARI are exempt from these limits. Always check the Rate Limits page when troubleshooting, as these values change.
7. Issue the certificate with the interactive wizard
Run:
Set-Location "C:\Program Files\simple-acme"
.\wacs.exe For a standard IIS site:
- choose
N: Create certificate (default settings); - select the IIS site
MySite; - select only
example.comandwww.example.com; - check that no internal name, old alias or test environment is included;
- accept the ACME terms of service;
- provide an operations email address;
- keep HTTP-01 and the default self-hosting module;
- keep installation in the Windows store and the IIS bindings.
Letters and labels may change slightly between versions. Rely on the meaning of each choice and on the documentation for the version you installed, not on an old screenshot.
The simple-acme self-hosting plugin briefly starts an in-memory listener. It can share port 80 with IIS and HTTP.sys. The port is still required from outside. See the Self-hosting documentation.
At the end, simple-acme should validate each name, request the certificate from Let's Encrypt, place the certificate and its key in the Windows store, create or update the matching HTTPS bindings, save the renewal settings and create the daily scheduled task.
8. Fully automated command-line variant
Start by confirming the IIS ID:
Get-Website -Name "MySite" |
Select-Object Name, Id Then adapt this command:
.\wacs.exe `
--source iis `
--siteid 2 `
--host example.com,www.example.com `
--validation selfhosting `
--installation iis `
--emailaddress [email protected] `
--accepttos --source iis triggers unattended mode. --siteid restricts the source to the right site and --host filters the bindings precisely. These parameters are documented in the simple-acme IIS source and the CLI reference.
Before wiring this command into a deployment tool, replace every example value, run it first with --test --verbose, do not pass a DNS secret in clear text through PowerShell history, keep a log output, and use option L in the renewal manager to obtain the command line equivalent to a manually created configuration.
The command line creates a new renewal. To modify an existing renewal, use the interactive manager; adding new parameters to --renew does not reconfigure the existing object.
9. Verify the certificate and the IIS bindings
Check the bindings
Get-WebBinding -Name "MySite" |
Select-Object protocol, bindingInformation, sslFlags,
certificateHash, certificateStoreName You should find one HTTPS binding per name:
*:443:example.com
*:443:www.example.com On a VPS hosting several sites on the same IPv4 address and the same port 443, the bindings must use SNI. In New-WebBinding, the value SslFlags = 1 denotes an SNI binding; Microsoft documents values 0 to 3 in the New-WebBinding reference.
Check the certificate in the Windows stores
$domain = "example.com"
$stores = @(
"Cert:\LocalMachine\WebHosting",
"Cert:\LocalMachine\My"
)
Get-ChildItem $stores -ErrorAction SilentlyContinue |
Where-Object {
($_.DnsNameList | ForEach-Object Unicode) -contains $domain
} |
Sort-Object NotAfter -Descending |
Select-Object Subject, Issuer, Thumbprint,
NotBefore, NotAfter, HasPrivateKey Check that Issuer matches the expected Let's Encrypt chain, that HasPrivateKey is True, that NotAfter is in the future, that DnsNameList contains every name in use, and that the thumbprint matches the HTTPS binding.
Some modern profiles may leave the Common Name empty. The decisive field for names is the Subject Alternative Name, so do not base your audit on Subject alone.
Check HTTP.sys
netsh http show sslcert Microsoft recommends comparing the binding in ApplicationHost.config with the HTTP.sys SSL store during an incident. See How to Set Up SSL on IIS and the netsh http reference.
Check from outside
From another network:
curl.exe -I http://example.com/
curl.exe -I https://example.com/
curl.exe -I https://www.example.com/ Once the redirect is configured, the first call should return a 301 or 308 to HTTPS. The HTTPS calls should answer with no name or chain error.
Also test a browser with no previous session, a phone on 4G or 5G, IPv4 and IPv6 if AAAA exists, a reputable external TLS analyser, and pages containing images, scripts and stylesheets in order to spot mixed HTTP content.
10. Configure the HTTP to HTTPS redirect
Only enable the redirect once you have validated the certificate on every name.
IIS 10 version 1709 and later include a native site-level HSTS mechanism with HTTP to HTTPS redirection. Microsoft notes that the destination uses standard port 443. Run:
$appcmd = "$env:windir\System32\inetsrv\appcmd.exe"
& $appcmd set config `
-section:system.applicationHost/sites `
"/[name='MySite'].hsts.enabled:True" `
/commit:apphost
& $appcmd set config `
-section:system.applicationHost/sites `
"/[name='MySite'].hsts.max-age:300" `
/commit:apphost
& $appcmd set config `
-section:system.applicationHost/sites `
"/[name='MySite'].hsts.includeSubDomains:False" `
/commit:apphost
& $appcmd set config `
-section:system.applicationHost/sites `
"/[name='MySite'].hsts.redirectHttpToHttps:True" `
/commit:apphost The attributes and this appcmd syntax are published in the Microsoft reference HSTS settings for a Web Site.
Start with max-age=300 during functional validation. Once HTTPS and renewal have been observed, move to 60 days, that is 5184000 seconds, watch for certificate errors and subdomains, then raise it to a year, 31536000, if your organisation's policy allows.
To change the duration:
& $appcmd set config `
-section:system.applicationHost/sites `
"/[name='MySite'].hsts.max-age:5184000" `
/commit:apphost Only enable includeSubDomains if every subdomain works over HTTPS on a lasting basis. Do not enable HSTS preloading merely to improve a score: joining the preload list is a separate commitment and is hard to undo quickly.
HSTS turns certificate errors into failures that cannot be bypassed by browsers which have memorised the policy. Let's Encrypt recommends a cautious rollout and warns about this risk in its Integration Guide.
Should port 80 stay open after the redirect?
Yes if renewal uses HTTP-01. Port 80 may only serve the redirect and /.well-known/acme-challenge/, but it must remain publicly reachable for future validations. Let's Encrypt can follow a valid redirect to 443, and the simple-acme self-hosting listener can share the port with IIS.
If your policy requires port 80 to be closed permanently, first reconfigure renewal to DNS-01 or another compatible method. Do not close the port and wait until expiry to discover that renewal is broken.
11. Verify and monitor automatic renewal
simple-acme creates a scheduled task after the first successful certificate. By default it runs daily under the SYSTEM account, at a time picked at random between 9 am and 11 am to spread the load. It only renews when a condition calls for it, in particular the certificate's remaining lifetime, a change of names, a revocation, an incomplete installation or an ARI recommendation. See Automatic renewal.
List the task:
Get-ScheduledTask |
Where-Object TaskName -Match "simple-acme|win-acme" |
Select-Object TaskName, State, TaskPath Display its state:
$task = Get-ScheduledTask |
Where-Object TaskName -Match "simple-acme" |
Select-Object -First 1
if ($task) {
Get-ScheduledTaskInfo `
-TaskName $task.TaskName `
-TaskPath $task.TaskPath
} Check LastTaskResult, LastRunTime and NextRunTime. The task must stay enabled and point at the permanent simple-acme folder.
Testing without triggering repeated issuance
A normal check does not force a new certificate:
.\wacs.exe --renew --verbose This command only renews objects that have entered their window. For a one-off test of the whole process, the documentation offers:
.\wacs.exe --renew --force --verbose Do not run --force in a loop and do not add --nocache without reason. Use staging for repeated troubleshooting. The cache offers partial protection against the limits, but it is no substitute for a diagnostic method.
Reading the logs
The logs are normally found under:
%ProgramData%\simple-acme\<acme-server>\Log To find the recent files:
Get-ChildItem "$env:ProgramData\simple-acme" -Recurse -File |
Where-Object Extension -In ".log",".txt" |
Sort-Object LastWriteTime -Descending |
Select-Object -First 20 FullName, LastWriteTime, Length Also check the Windows Event Viewer. simple-acme keeps its logs for 120 days by default and can send notifications if an SMTP server is configured.
Alerting on imminent expiry
This local check can be wired into your monitoring:
$warningDate = (Get-Date).AddDays(21)
$expiring = Get-ChildItem `
"Cert:\LocalMachine\WebHosting",
"Cert:\LocalMachine\My" `
-ErrorAction SilentlyContinue |
Where-Object {
$_.HasPrivateKey -and
$_.NotAfter -lt $warningDate -and
$_.NotAfter -gt (Get-Date)
} |
Sort-Object NotAfter |
Select-Object Subject, Thumbprint, NotAfter
$expiring Monitor the date presented to the remote client, not only the certificates stored locally. An old certificate can still be served if the IIS binding or the proxy was not updated.
As of 29 August 2026, Let's Encrypt certificates are valid for 90 days by default and the vast majority of those it issues use that lifetime. A short profile of about 6 days is optionally available to all subscribers. Let's Encrypt also plans to reduce its maximum certificate lifetime to 45 days by February 2028, with industry rules capping lifetimes at 47 days from 15 March 2029. The official page on certificate lifetimes shows why monitored automation is essential.
12. Wildcard certificate with DNS-01
For *.example.com, HTTP-01 does not work. Run simple-acme again and choose M: full options:
- source: IIS bindings or manually entered names;
- names:
example.comand*.example.comif both are needed; - validation: DNS-01;
- plugin: the one for your DNS provider;
- key: RSA or EC depending on your policy and your clients;
- storage: Windows certificate store;
- installation: IIS bindings.
The wildcard *.example.com covers www.example.com or app.example.com, but not the bare domain example.com and not a.b.example.com. Request the bare domain explicitly if it must be covered.
The full build of simple-acme is required to load external plugins, as the trimmed build does not support them. Plugins are installed under %ProgramData%\simple-acme\plugins. The current list is in the DNS validation documentation.
Securing DNS credentials
- create a token dedicated to ACME validation;
- restrict it to the strictly necessary zones and actions;
- use the simple-acme secret vault rather than a clear-text argument;
- protect the
%ProgramData%\simple-acmefolder; - plan for token rotation and revocation;
- do not use a global account key if a limited token exists.
If your DNS provider offers no suitable API, delegate _acme-challenge.example.com by CNAME or NS to an automatable validation zone. This sometimes avoids giving the web server access to your whole main zone.
13. Harden TLS without breaking Windows
The certificate does not by itself choose TLS versions and cipher suites. IIS relies on Schannel, so the configuration is largely defined at system level.
Inventory the suites:
Get-TlsCipherSuite |
Select-Object Name, Cipher, Hash, Exchange Microsoft advises applications to use the system defaults rather than arbitrarily imposing their own protocol versions. The TLS registry settings documentation also points out that a Schannel change affects services beyond the IIS site.
Checkpoints: install Windows updates, keep TLS 1.2 for compatibility, note that TLS 1.3 is supported from Windows Server 2022, disable legacy protocols only after inventorying your clients, test the application, the APIs, the monitoring agents and the older clients, back up the settings before any change, and avoid copying an unversioned registry script from a blog.
The support matrix is published in Protocols in TLS/SSL (Schannel SSP). An overly strict policy can also stop the ACME client from reaching the API.
14. Troubleshooting: symptoms, causes and actions
| Symptom | Likely cause | Check | Fix |
|---|---|---|---|
connection timed out on HTTP-01 | port 80 filtered upstream | external TCP 80 test | open the Windows firewall and the network firewall |
unauthorized with a 404 | wrong server or wrong binding | DNS, IIS logs, bindings | fix A/AAAA and the host header |
| validation tries the wrong IPv6 | stale or inconsistent AAAA | Resolve-DnsName -Type AAAA | fix or remove AAAA |
CAA forbids issuance | CAA does not authorise Let's Encrypt | Resolve-DnsName -Type CAA | authorise letsencrypt.org if policy allows |
DNS SERVFAIL | broken DNSSEC or authoritative DNS | queries against each NS | fix DNSSEC or the DNS server |
| self-hosting listener cannot start | URL reservation or incompatible software | netsh http show urlacl | fix the reservation or use filesystem/DNS-01 |
| wrong certificate served | incorrect SNI binding or thumbprint | Get-WebBinding, netsh http show sslcert | fix the host header, SNI and the certificate |
| browser reports mixed content | resources still loaded over HTTP | developer console | convert resource URLs to HTTPS |
| renewal missing | task deleted or path moved | Task Scheduler | recreate the task from simple-acme |
| renewal succeeds but the old certificate is served | IIS step not installed, or an intermediate proxy | IIS binding and remote test | reconfigure the installation, update the TLS terminator |
| too many requests | tests carried out in production | ACME log and the Retry-After header | wait, honour Retry-After and use staging |
Testing the HTTP-01 path
Default validation is handled in memory while simple-acme runs. To diagnose a route or a proxy you can nonetheless check that no rule blocks the prefix:
curl.exe -I http://example.com/.well-known/acme-challenge/test A 404 outside validation is normal; a network refusal, mandatory authentication, a WAF block or a redirect to an unusual port is not. During a real validation with --test --verbose, watch the detailed response and the logs.
Identifying the process bound to port 80
$connection = Get-NetTCPConnection -LocalPort 80 -State Listen |
Select-Object -First 1
if ($connection) {
Get-Process -Id $connection.OwningProcess
}
netsh http show urlacl The System process is common with HTTP.sys and IIS; it does not automatically mean malware is occupying the port.
Diagnosing a wrong SNI certificate
Display the HTTPS bindings:
Get-WebBinding -Protocol https |
Select-Object ItemXPath, bindingInformation, sslFlags,
certificateHash, certificateStoreName Where several sites share *:443, each name must have its own binding and SNI must be active. The empty binding *:443: can become the default for clients without SNI and serve an unexpected certificate.
15. Maintenance, updates and incident response
Updating simple-acme
On Windows Server 2025 with WinGet:
winget upgrade simple-acme For a manual installation, download the new official archive, verify the hash, back up the folder and replace the program files. Renewals are stored separately under %ProgramData% and must be preserved. After updating:
.\wacs.exe --version
.\wacs.exe --list
.\wacs.exe --renew --verbose Always read the release notes before a major branch change.
If a private key leaks
- isolate and analyse the compromised server;
- revoke the certificate;
- fix the cause of the leak;
- generate a new key and a new certificate;
- replace every affected binding;
- look for other exposed certificates or secrets;
- document the incident.
In simple-acme, revocation is available under Manage renewals > Revoke certificate or through --revoke with the renewal's identifier. Let's Encrypt states that revocation is required when a private key is compromised and describes the accepted reasons in Revoking Certificates.
Cancelling a renewal is not the same as revoking a certificate. Cancelling stops future management; revocation signals that an already-issued certificate must no longer be trusted.
Go-live checklist
- Windows Server and IIS are up to date.
- The IIS site has explicit host headers.
Apoints to the correct public IPv4 address.- Any published
AAAAcorrectly serves the same site. - Ports 80 and 443 are reachable from outside.
- The IIS configuration has been backed up.
- simple-acme comes from the official source and its hash was verified.
- Staging was used for the initial troubleshooting.
- The certificate contains every expected SAN.
- HTTPS bindings use SNI if the IP address is shared.
- HTTP redirects to HTTPS without a loop.
- HSTS was rolled out gradually.
- The scheduled task exists, is enabled and has already succeeded.
- Logs and expiry are monitored.
- The validation method will still be available at the next renewal.
- A revocation and recovery procedure exists.
Frequently asked questions
Is Let's Encrypt really free on IIS?
Yes. Let's Encrypt does not charge for issuing its DV certificates. The Windows VPS, the domain name, the administration work and any DNS services remain payable to their own providers.
Is the certificate valid for 90 days?
As of 29 August 2026 the standard profile is still valid for 90 days by default. A short profile of about 6 days is optionally available, and Let's Encrypt plans to bring its maximum lifetime down to 45 days by February 2028. Never build an operation around a manual quarterly renewal.
Is port 80 mandatory?
It is mandatory for HTTP-01, even if the internal listener uses another port behind a redirect or NAT. It is not needed for DNS-01. TLS-ALPN-01 uses 443 but suits advanced infrastructures above all.
Can port 80 be closed after installation?
Not if renewal stays on HTTP-01. Keep it reachable for the redirect and for validations, or move renewal to DNS-01 before closing it.
How do I obtain a *.example.com wildcard?
Use DNS-01 with an automated API plugin, available in the full build of simple-acme. Also add example.com to the certificate if the bare domain must be covered.
Does a wildcard certificate cover every level?
No. *.example.com covers a single level such as www.example.com, but neither example.com nor a.b.example.com.
Should I choose RSA or ECDSA?
RSA offers very broad compatibility. ECDSA provides more compact keys and signatures, but must be checked against your oldest clients. For a first general-purpose IIS deployment, the tool's default is usually the safest choice.
Is HTTPS enough to secure the site?
No. HTTPS encrypts transport and authenticates the name presented. It does not replace updates, access control, backups, application security, secret protection and monitoring.
What about a Linux VPS?
The approach is the same, but the tool changes: on Nginx or Apache you would normally use Certbot. See our guide on installing a Let's Encrypt SSL certificate with Certbot on Nginx or Apache.
Conclusion
On IIS, getting a Let's Encrypt certificate takes a few minutes with simple-acme. What deserves attention is everything that follows: the correct HTTPS binding on each name, a redirect without a loop, HSTS rolled out gradually, and above all a renewal that will still work in three months without you.
Remember the three most common traps: an AAAA record pointing elsewhere and failing validation, a port 80 closed after the move to HTTPS even though renewal depends on it, and an IIS binding that was never updated and keeps serving the old certificate. Check those three points and the automation will hold.
Main technical sources
Let's Encrypt
- Challenge Types: HTTP-01, DNS-01 and TLS-ALPN-01
- IPv6 Support
- Certificate Authority Authorization (CAA)
- Staging Environment
- Rate Limits
- Certificate Lifetimes
- Integration Guide and ARI renewal
- Revoking Certificates
simple-acme
- Downloads and SHA-256 checksums
- Installation
- Getting started with IIS
- Automatic renewal
- IIS source
- Installing and updating IIS bindings
- HTTP self-hosting validation
- DNS validation
- Command-line reference
