wGrow
menu
Field note · Migrated 2026-04-12 · 5 min

Automating Let's Encrypt for IIS in 2026: most of the C# is no longer needed.

Our 2023 piece walked through a custom C# Windows Service using Certes + Microsoft.Web.Administration to manage Let's Encrypt for IIS. In 2026 the right answer is mostly to use a maintained tool. Here is the honest update.

In 2023 we shipped a small C# Windows Service that handled the Let’s Encrypt SSL/TLS certificate lifecycle for IIS websites — using the Certes ACME library and Microsoft.Web.Administration for binding installation. We wrote it because the maintained tools at the time didn’t fit our deployment shape on a couple of client estates. We wrote up the design as Team-Notes #83.

It is 2026. We would not write that service today. Here is the honest rewrite.

What we’d actually use in 2026

For 95% of IIS estates, the right answer is one of:

  1. win-acme (wacs) — an actively-maintained, command-line ACME client for Windows that knows about IIS bindings, scheduled tasks, and most of what our custom service did. Free, open-source, well-tested.
  2. Certify the Web — a Windows GUI client built on top of the same ACME ecosystem. Useful where the operator is more comfortable with a UI.
  3. Front the IIS estate with a reverse proxy that handles certs — Cloudflare, Caddy, NGINX, or AWS ALB. The IIS host doesn’t manage public certs at all.

For most clients, option 3 (reverse proxy in front) is now the cleanest. The IIS host serves an internal cert; the public certificate lives one hop earlier and is renewed automatically by the proxy.

When the custom Windows Service is still right

We still use the design from the 2023 article in two cases:

  • Air-gapped or tightly-restricted estates where neither win-acme nor a reverse proxy is permitted, but ACME via an outbound HTTP proxy is. We have one such gov-adjacent client.
  • Estates with a quirky binding pattern — e.g. wildcard certs across multiple IIS host names with non-standard SNI handling — where the maintained tools require workarounds we can’t audit.

For both, the Certes-based Windows Service is still in production and still works.

What changed in the protocol

A few details from the 2023 article are stale and worth flagging:

ACMEv1 is gone

ACMEv1 was deprecated and is no longer accepted by Let’s Encrypt. ACMEv2 is the only protocol in 2026. If you have an old client (ours included a fallback to v1 in 2023), check its dependency versions and confirm v2.

TLS-ALPN-01 vs HTTP-01 vs DNS-01

In 2023 we used HTTP-01 challenge handling via .well-known/acme-challenge. That still works. In 2026 we more often use DNS-01 for two reasons:

  • It supports wildcard certs.
  • It doesn’t require the IIS host to be reachable from the public internet on port 80, which lets us run cleaner ingress firewall posture.

DNS-01 needs an automatable DNS provider (Route 53, Cloudflare, Azure DNS). Most of our clients have one of those.

Renewal cadence and rate limits

Let’s Encrypt rate limits have not changed dramatically. The thing that changed is operational hygiene:

  • We renew at 30 days remaining (not 14), so a failed renewal has time to retry.
  • We monitor the certificate expiry on the live binding (not just on the Windows Service’s last run), with a CloudWatch / Sentinel alarm that pages a human at 14 days remaining.
  • The renewal job logs to a centralised audit pipeline. Silent failures are the failure mode we keep seeing in client estates.

What we’d cut from the original

  • The implication that “writing your own service” is a normal first step for IIS Let’s Encrypt automation in 2026. It isn’t. It is a fallback for specific constraints.
  • The C# code samples that targeted ACMEv1 idioms. Those are misleading now.

What we’d keep

The design lessons:

  • A Windows Service is the right host shape for unattended renewal on Windows. Scheduled Tasks work and are simpler, but a service gives cleaner logging and healthcheck behaviour.
  • Service identity matters. Run the renewal under a least-privileged account, not LocalSystem.
  • Treat the renewal pipeline as a production workload. Audit logs, health alerts, paged failures. Not a setx -A cron line.

A short note on the rebrand

Migrating this article was a useful exercise. Most of our 2008–2024 Team-Notes archive contains specific code samples that are no longer the right pattern, alongside design lessons that are. The studio’s job, on a migration, is to keep the durable lesson and replace the stale specifics — not to polish the stale specifics until they look fresh.

— wGrow studio · migrated from Team-Notes #83