Secure an IIS website on a Windows Server VPS at no cost with Let's Encrypt and win-acme. This process was tested on Windows Server 2022 and IIS 10.


For Ubuntu, see our Certbot guide.


Before you start

  • A Windows Server VPS with IIS and an HTTP site for your domain.
  • Administrator access.
  • An A record pointing the domain at the VPS public IP.
  • TCP 80 and 443 open in the BinaryLane External Firewall and Windows Firewall.

Let's Encrypt uses HTTP validation on port 80. Keep it available for issuance and renewal.


1. Check the IIS site


Ensure the intended IIS site has an HTTP binding on port 80 with the correct hostname. List its ID in elevated PowerShell:

Import-Module WebAdministration
Get-Website | Select-Object Name, Id, State, PhysicalPath

2. Install win-acme


Download the current 64-bit pluggable ZIP from the official releases page, then extract it to a permanent location such as C:\Tools\win-acme.

C:\Tools\win-acme\wacs.exe --version

3. Request the certificate


From an elevated Command Prompt, replace the site ID and email address:

C:\Tools\win-acme\wacs.exe --target iis --siteid 2 --validation filesystem --validationsiteid 2 --installation iis --installationsiteid 2 --accepttos --emailaddress you@example.com --closeonfinish

win-acme writes the challenge into the selected IIS site, installs the certificate in the Windows WebHosting store, creates the IIS HTTPS binding, and creates a win-acme renew scheduled task.


4. Verify renewal

Get-ScheduledTask | Where-Object { $_.TaskName -like 'win-acme*' } | Select-Object TaskName, State
C:\Tools\win-acme\wacs.exe --renew --closeonfinish

Let's Encrypt certificates last 90 days. The renewal task needs the IIS HTTP binding and port 80 to remain available.


Optional: redirect HTTP to HTTPS


Only add this after HTTPS works. Replace the site name and hostname:

Import-Module WebAdministration
$site = 'Default Web Site'
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $site -Filter 'system.webServer/httpRedirect' -Name 'enabled' -Value $true
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $site -Filter 'system.webServer/httpRedirect' -Name 'destination' -Value 'https://www.example.com'
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $site -Filter 'system.webServer/httpRedirect' -Name 'httpResponseStatus' -Value 'Permanent'
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Location $site -Filter 'system.webServer/httpRedirect' -Name 'exactDestination' -Value $false

Use the base HTTPS URL. Do not add {R:0}; IIS preserves the path when exactDestination is $false.


Troubleshooting

  • Timeout: port 80 is blocked.
  • 404: the IIS hostname binding or web root is wrong.
  • DNS failure: the A record is missing, incorrect, or not propagated.