The short answer
On Linux a renewal writes a file and reloads a service. On Windows there is a third step in between: every listener references the certificate by its SHA-1 thumbprint, and a renewed certificate always has a new one. An ACME client such as win-acme handles the request, the import into the machine store and the IIS binding, and a scheduled task repeats it. Remote Desktop, Exchange, SQL Server and any binding made directly through http.sys do not update themselves — they keep serving the old certificate, silently, until someone re-points them.
On this page
- Why a Windows renewal has three steps
- Picking a renewal client
- The scheduled task, and who it runs as
- The private key ACL problem
- Everything on the box that is not IIS
- Farms and the Centralized Certificate Store
- Automating a paid OV or EV certificate
- What shorter lifetimes do to the arithmetic
- Proving the first unattended renewal
- FAQ
Why a Windows renewal has three steps
A Linux renewal is two operations. New files land at a path, and the service that reads that path is told to read it again. The path is stable, so nothing else has to know a renewal happened. Windows breaks that assumption. A certificate is not a file on disk, it is an object in the machine store, and every consumer addresses it by a forty-character SHA-1 thumbprint that changes on every issuance.
That single design difference is where most Windows automation goes wrong, and it goes wrong quietly. The client reports success. The certificate really is in LocalMachine\My, really is valid, really does have the right names on it. It is simply not the object your listeners are pointing at, and nothing in Windows raises a flag about that, because from each listener's point of view nothing changed at all.
There is a second, less obvious consequence. The private key is not part of the certificate object. It lives in its own key container with its own access control list, which means a permission granted to an application pool identity applies to one key and not to its replacement. Both problems have the same shape: something outside the certificate holds a reference to it, and the renewal replaces the thing being referred to.
Picking a renewal client
Three clients cover almost every Windows deployment. win-acme is the command-line default and the one most guides assume: it requests the certificate, imports it, rewrites the IIS binding and registers the scheduled task in one pass. Certify The Web wraps the same job in a GUI and adds deployment tasks for non-IIS targets. Posh-ACME is a PowerShell module for people who would rather write the deployment themselves.
| Client | Fits when | Handles the rebinding? |
|---|---|---|
| win-acme | IIS is the only consumer, or you are comfortable adding a post-renewal script | IIS bindings automatically; anything else through a script hook |
| Certify The Web | Several certificates on one box, or a team that wants a console rather than a config file | IIS plus configurable deployment tasks for other targets |
| Posh-ACME | No IIS at all, or the deployment is genuinely bespoke | Nothing by default; you write the deployment step |
The choice matters less than the honest question underneath it: what else on this server presents a certificate? If the answer is only IIS, win-acme on its own is enough and you can stop reading after the next two sections. If the answer includes Remote Desktop or a mail role, the client is only doing part of the job whichever one you pick.
One practical note on DNS validation. Wildcard names require DNS-01, and on Windows that means storing an API credential for your DNS provider somewhere a background task can read it months from now. That credential is a renewal dependency exactly like the certificate itself, and expired API keys are a common cause of renewals that ran perfectly for a year and then stopped. Which challenge your setup can realistically use is worth settling before the client is installed rather than after, and the constraints behind each challenge type is the shorter route to that decision.
The scheduled task, and who it runs as
Windows has no cron, so renewal runs from Task Scheduler. win-acme registers that task for you on first use and it fires daily, doing nothing on most days and renewing when a certificate crosses the threshold. The task normally runs as SYSTEM, which is the detail that decides whether the second cycle works, because you created the certificate as an elevated administrator and SYSTEM is not you.
Everything the interactive run had, the scheduled run needs again. Write access to the machine certificate store. Rights to administer IIS. Read access to the client's configuration folder. Outbound HTTPS from the server itself, which is not the same as outbound HTTPS from your workstation. On a domain-joined server that also has to reach a DNS API or a file share, a dedicated service account with the Log on as a batch job right is usually easier to reason about than SYSTEM, because you can grant it what it needs and see what you granted.
There is also a subtlety with no interactive session: anything that would prompt does not fail, it hangs. A client waiting for confirmation at three in the morning leaves a task in the running state and a certificate that quietly does not renew. Run the client once with whatever unattended flag it offers before you trust the schedule.
Check the renewal threshold while you are in there. win-acme has long defaulted to renewing at 55 days before expiry, which is sensible on a 398-day certificate and increasingly odd as the maximum lifetime falls. On a 47-day certificate, a threshold of 55 days is reached before the certificate exists. Any client that expresses its window as a fixed number of days rather than a proportion of lifetime has to be revisited each time the cap drops, so read the value your version actually uses rather than assuming the default still makes sense.
The private key ACL problem
A certificate in the Windows store is two objects, not one. The certificate itself is public and readable by anyone on the machine. The private key sits in a separate container with its own access control list, and a service can only use the certificate if its identity appears in that list. Renewal creates a new key, so it creates a new list, and every grant made against the old key ceases to exist.
This is why so many Windows setups work for exactly one cycle. An administrator installs the certificate, notices that the application pool cannot read the key, opens certlm.msc, right-clicks the certificate and grants the pool identity read access through Manage Private Keys. It works. Nobody writes it down, because it felt like a one-time fix. Five months later the renewal succeeds, the binding updates, and the site returns an error nobody can trace to a certificate at all.
win-acme addresses part of this by granting the local Administrators group full control over the private key of certificates it imports, precisely so that the identity which created the certificate interactively and the SYSTEM account that renews it later are not working against different permissions. That helps the client. It does nothing for an application pool running as a custom identity, or for a service account used by SQL Server, which still needs its own grant on every new key.
There are two durable fixes and one that only looks durable. The durable ones are to have the renewal client re-apply the ACL as part of its deployment step, or to run the consuming service under an identity that is already covered by the grant the client makes. The one that only looks durable is granting the permission by hand and assuming it persists, which is the default behaviour of almost every Windows certificate deployment that has not been tested through a renewal.
Everything on the box that is not IIS
IIS updates its own bindings, and that is the part of Windows certificate automation that generally works. Every other listener on the server stores the thumbprint in its own place and reads it from there. None of them watch the certificate store, so none of them notice a renewal, and none of them log anything when the certificate they are pinned to expires underneath them.
Start with an inventory rather than a guess. netsh http show sslcert lists every certificate binding registered with http.sys, including the ones IIS did not create and does not know about, each with its IP and port, certificate hash and application GUID. Anything in that output that IIS did not put there is yours to re-point after every renewal.
| Listener | Where the thumbprint lives | How to re-point it |
|---|---|---|
| IIS sites | IIS configuration, surfaced through http.sys | The ACME client does it |
| Non-IIS http.sys bindings | IP, port, certificate hash and application GUID | netsh http delete sslcert then add sslcert with the new hash |
| Remote Desktop | WMI: Win32_TSGeneralSetting in Root\CimV2\TerminalServices | Set SSLCertificateSHA1Hash from PowerShell |
| Exchange Server | Per-service attachment inside Exchange | Enable-ExchangeCertificate -Thumbprint with the services listed |
| SQL Server, WinRM, ADFS, agents | Registry or per-product configuration | Product-specific; each needs its own step in the script |
Remote Desktop is worth calling out because the format catches people. The value has to be exactly forty hexadecimal characters with no spaces, and a thumbprint copied out of the certificate MMC arrives with invisible spacing that Windows accepts into the field and then refuses to use. Strip it in the script rather than trusting the clipboard.
Exchange has its own trap. Attaching a renewed certificate to the SMTP service prompts about replacing the default transport certificate, which is fine interactively and unhelpful in a scheduled task. That is one more reason the post-renewal script should be written and run once by hand before anything depends on it.
None of these produce a helpful error. What you get instead is a user reporting that the mail client warns, or that RDP throws a name mismatch box, weeks after the website stopped having a problem. If your servers present certificates on more than one port, the shape of that problem is covered in more depth in which Remote Desktop role needs which certificate.
Farms and the Centralized Certificate Store
Running the same renewal on eight web servers means eight ACME accounts, eight scheduled tasks and eight opportunities for one of them to fail unnoticed. IIS has a better answer for farms. The Centralized Certificate Store keeps certificates as PFX files on a file share, loads them on demand using the name from the client's TLS handshake, and lets every node in the farm read from the same place.
The mechanics are simple enough to be worth knowing before you commit to it. IIS matches a request to a file by name: a site at www.contoso.com is served from www.contoso.com.pfx, and a wildcard covering it is stored as _.contoso.com.pfx. Every PFX in the store is encrypted with the same password, which IIS holds as an encrypted value in its own configuration. Renewal then becomes one operation instead of eight: overwrite the file on the share.
Two consequences follow from that design. The shared password is genuinely shared, so rotating it is a change to every server in the farm rather than to the store. And the naming convention is load-bearing: a certificate whose subject does not match the host name IIS is looking for will sit in the share being ignored, with no error beyond a failed handshake. Both are manageable. Neither is obvious from the setup wizard.
Automating a paid OV or EV certificate
The assumption that automation means Let's Encrypt is a habit from a few years ago, when commercial certificate authorities had no ACME endpoint. Most now do. You get an account key and an HMAC key from your account panel, pass them to the client as External Account Binding credentials, and point it at the CA's ACME directory instead of the public one. The Windows side of the job is byte-for-byte the same.
Certum, the certificate authority behind the certificates we resell, publishes ACME support for its Commercial SSL line, covering single-domain, multi-domain and wildcard certificates, with HTTP-01 for hostnames and DNS-01 where a wildcard makes it necessary. If you are choosing a certificate for a Windows estate and automation is a requirement rather than a preference, that capability is worth confirming before you buy; the certificate types available and what each one validates is the shortest route to that comparison.
What automation cannot remove for OV and EV is the organization check. A certificate authority has to confirm the legal entity behind the name, and no protocol makes that instant. It can, however, be front-loaded. Once the organization is validated, reissue against that validation runs over ACME like any other request, and the certificate keeps coming back without anyone touching it.
The number that changed recently is the reuse period. Ballot SC-081v3 cut the time a certificate authority may reuse vetted organization data from 825 days to 398 days as of March 15, 2026, so the organization check now recurs at least once a year rather than once every two. That is a calendar entry rather than an engineering problem, and it is the whole of what stays manual when you run organization-validated certificates on an automated estate.
This is also becoming less of a choice. The Chrome Root Program requires a certificate authority applying to the Chrome Root Store to support at least one automated issuance and renewal solution for every certificate policy it issues under, which removes "our CA has no API" as a reason to renew by hand. What that obligation covers and when it bites is set out in the automation requirement landing in 2027.
What shorter lifetimes do to the arithmetic
The CA/Browser Forum approved a schedule in April 2025 that takes the maximum public certificate lifetime from 398 days down to 47 in three steps: 200 days from March 15, 2026, 100 days from March 15, 2027, and 47 days from March 15, 2029. Most certificate authorities issue 199 days today to stay comfortably inside the current cap. Domain validation reuse falls on the same schedule, reaching 10 days in 2029.
For a Windows estate the interesting number is not how often the certificate is issued. It is how many rebinding operations that implies. Ten servers with three listeners each produce thirty re-point operations per cycle, which is about thirty a year now and roughly two hundred and forty a year once 47-day certificates arrive. Issuance scales with hosts. Rebinding scales with listeners, and that is the one that stops being survivable by hand first.
It also changes what a failed renewal costs. On a 398-day certificate a client that renews at 55 days leaves nearly two months to notice a problem. On a 47-day certificate there is no comparable buffer at all, and a renewal that fails twice in a row is an outage rather than an inconvenience. The practical conclusion is that the alerting matters as much as the automation, and it has to run somewhere other than the server it is watching, which is the subject of what to watch on a certificate and where to watch it from.
Proving the first unattended renewal
The gap between installing an ACME client and finding out whether it works is months, and that gap is where Windows automation fails. Close it on the day you install by forcing one renewal under the scheduled task's own identity, then checking the things that would have broken. It takes about ten minutes and it replaces a hope with a fact.
| Check | What proves it |
|---|---|
| The task actually ran as its own identity | Last run result of 0 in Task Scheduler, not a manual run from your console |
| A new certificate exists | Get-ChildItem Cert:\LocalMachine\My shows a new thumbprint and a later expiry |
| Every listener moved | netsh http show sslcert shows the new hash on every port, not just 443 |
| The consuming identity can still read the key | The application pool or service starts and serves without a manual permission grant |
| The old certificate is gone from the path | What the server presents from outside, checked from a machine that is not the server |
The last row is the one people skip, and it is the only one that reflects what a visitor sees. Everything above it describes the server's opinion of itself. A quick external check against each hostname and port closes that loop, and running it on a schedule is what turns a working automation into one you can stop thinking about.
Keep the post-renewal script in source control with the rest of the server configuration rather than in a folder next to the client. It is the piece that encodes which listeners exist on that host, it changes when a role is added, and it is the first thing anyone will need when the person who set this up has moved on.