How to Build Resilient Let's Encrypt Renewal Pipelines

The operational reality of managing public-facing infrastructure has fundamentally shifted. With Google Chrome driving the industry toward a maximum public TLS certificate validity of 90 days, the 90-...

Tim Henrich
September 21, 2026
6 min read
42 views

How to Build Resilient Let's Encrypt Renewal Pipelines

The operational reality of managing public-facing infrastructure has fundamentally shifted. With Google Chrome driving the industry toward a maximum public TLS certificate validity of 90 days, the 90-day lifecycle pioneered by Let's Encrypt is no longer just an option—it is the baseline standard for web security.

Managing 90-day certificates manually across dozens, hundreds, or thousands of endpoints is mathematically and operationally unfeasible. It guarantees eventual human error, leading to expired certificates, service outages, and broken trust. Automating certificate renewal via the Automated Certificate Management Environment (ACME) protocol is a strict requirement for modern DevOps and security teams.

However, basic automation—like throwing Certbot into a monthly cron job—often masks underlying fragility. Network hiccups, DNS propagation delays, silent server failures, and strict API rate limits can easily break naive renewal pipelines.

This post details how to architect, secure, and monitor Let's Encrypt renewal pipelines that survive edge cases, scale to enterprise environments, and prevent expiration-induced downtime.

The Modern ACME Landscape

Let's Encrypt issues certificates for over 300 million websites, and the infrastructure supporting this scale is constantly evolving. Relying on outdated assumptions about how ACME clients behave can lead to unexpected failures.

ACME Renewal Information (ARI)

Historically, ACME clients operated on a hardcoded "blind renewal" schedule, typically attempting to renew a certificate exactly 30 days before expiration (the 60-day mark of a 90-day certificate).

Let's Encrypt is currently championing the ACME Renewal Information (ARI) extension. ARI allows the Certificate Authority (CA) to dynamically signal to your ACME client exactly when it should renew a specific certificate. This is critical for incident response. If Let's Encrypt discovers a compliance bug and needs to revoke millions of certificates, ARI allows them to stagger the renewal signals. Instead of every server in the world rushing the API simultaneously when the revocation is announced, clients equipped with ARI will smoothly distribute the load, preventing global outages.

Ensure your chosen ACME client (such as recent versions of Certbot or cert-manager) supports ARI to take advantage of this dynamic scheduling.

Multi-Perspective Validation and Trust Chains

To combat BGP hijacking—where an attacker manipulates internet routing to steal a certificate for a domain they don't own—Let's Encrypt now validates domain control from multiple global network perspectives simultaneously. If your firewall rules strictly geo-block traffic, HTTP-01 challenges will fail. Your ACME challenge endpoints must be globally accessible.

Furthermore, Let's Encrypt has retired its long-standing cross-signatures (like the DST Root CA X3 workaround for older Android devices). Modern automation must rely purely on the ISRG Root X1 chain. If you are hardcoding trust stores in legacy applications, you must update them to trust ISRG Root X1 directly.

Selecting the Right Challenge Type

Let's Encrypt verifies domain ownership through ACME challenges. Selecting the correct challenge type dictates how your automation will be structured.

HTTP-01: The Standard Choice

The HTTP-01 challenge requires your web server to serve a specific token at http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>.

When to use it: Standard, public-facing web servers and reverse proxies.
Advantages: Simple to set up, requires no DNS API credentials, and works seamlessly behind load balancers.
Disadvantages: Cannot issue wildcard certificates (*.example.com). Requires port 80 to be open to the internet.

DNS-01: The Secure and Internal Choice

The DNS-01 challenge requires you to provision a specific DNS TXT record under _acme-challenge.<YOUR_DOMAIN>.

When to use it: Issuing wildcard certificates, securing internal/private network services that Let's Encrypt cannot reach via HTTP, or operating in strict environments where opening port 80 is prohibited.
Advantages: Does not require a public web server. Allows you to secure internal microservices (facilitating Zero Trust Architecture) without running an internal CA.
Disadvantages: Requires programmatic access to your DNS provider's API. Prone to propagation delays.

Solving Real-World Automation Bottlenecks

Even with the right challenge type, automation pipelines often break in production due to environmental constraints. Here is how to architect around the most common failure points.

1. Surviving API Rate Limits in CI/CD

Let's Encrypt enforces strict rate limits, most notably the limit of 50 certificates per registered domain per week. If your CI/CD pipeline requests a new certificate every time it spins up a test environment, you will exhaust this limit and block production deployments.

The Solution: Always configure non-production environments to use the Let's Encrypt Staging Environment. The staging environment has significantly higher rate limits and produces untrusted certificates perfectly suited for verifying that your ACME pipeline works.

For example, when using acme.sh, append the --test flag during development:

acme.sh --issue -d test.example.com --dns dns_aws --test

The staging API endpoint is https://acme-staging-v02.api.letsencrypt.org/directory. Only point your production clients to the production directory.

2. Mitigating DNS-01 Propagation Delays

When using the DNS-01 challenge, your ACME client writes a TXT record via your DNS provider's API and immediately tells Let's Encrypt to verify it. If your DNS provider relies on global anycast networks, it might take several minutes for that TXT record to propagate. If Let's Encrypt checks a nameserver that hasn't synced yet, the challenge fails.

The Solution: Implement polling or wait hooks. Most robust ACME clients allow you to define a sleep period or actively poll authoritative nameservers before signaling Let's Encrypt.

In acme.sh, you can force a wait time using --dnssleep:

acme.sh --issue -d "*.example.com" --dns dns_cf --dnssleep 120

3. Securing DNS APIs via CNAME Delegation

A major security flaw in many DNS-01 implementations is violating the Principle of Least Privilege. To automate TXT record creation, administrators often hand their web servers an API token with full read/write access to their primary DNS zone (e.g., Route53 or Cloudflare). If the web server is compromised, the attacker can hijack the entire domain's DNS.

The Solution: Use CNAME delegation (often called Alias Mode). You can delegate the _acme-challenge subdomain to a completely separate, isolated DNS zone used only for validation.

  1. Create a new DNS zone: acme-auth.example.net.
  2. In your primary zone (example.com), create a CNAME record:
    _acme-challenge.example.com CNAME _acme-challenge.acme-auth.example.net
  3. Issue an API token that only has write access to acme-auth.example.net.

When Let's Encrypt looks up the TXT record for example.com, it will follow the CNAME and find the token in the isolated zone. Your primary DNS zone remains safe from compromised web servers.

Technical Implementation Strategies

How you implement ACME depends heavily on your infrastructure architecture.

Kubernetes with cert-manager

In cloud-native environments, cert-manager is the industry standard. It runs as a Kubernetes controller, seamlessly integrating with the Gateway API and Ingress controllers.

To automate Let's Encrypt in Kubernetes, you define a ClusterIssuer:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: security@example.com
    privateKeySecretRef:
      name: letsencrypt-prod-account-key
    solvers:
    - http01:
        ingress:
          class: nginx

Once the issuer is configured, you simply annotate your Ingress resources. cert-manager automatically provisions the Certificate resource, handles the HTTP-01 challenge, and mounts the resulting TLS secret directly to the Ingress controller:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-app-ingress
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - app.example.com
    secretName: app-example-com-tls
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80

Cloud-Native Reverse Proxies

For environments not running Kubernetes, modern reverse proxies like Caddy and Traefik have ACME clients built directly into their binaries.

Caddy, for example, requires zero configuration for HTTPS. If you define a public domain in your Caddyfile, it

Share This Insight

Related Posts