Containers and platforms

Heroku Automated Certificate Management (ACM) guide

By · Last verified

Heroku Automated Certificate Management (ACM) gets and renews Let's Encrypt certificates for your app's custom domains. Add each domain, point DNS at the herokudns.com target Heroku gives you, and ACM issues the certificate, usually within 45 to 60 minutes.

ACM is free for all apps, and certificates renew one month before they expire. Uploading your own certificate switches ACM off for that app. Steps follow the Heroku Dev Center as of November 2026, with example-app and example.com as examples.

At a glance

Question Heroku
CA for automatic certificates Let's Encrypt (via ACM)
Price Included for all applications
Subdomain (www.example.com) CNAME to its <haiku>.herokudns.com DNS target
Root (example.com) ALIAS/ANAME/flattened CNAME to its DNS target; A records are not supported
CAA must allow letsencrypt.org
Wildcard via ACM Not in the Common Runtime docs; Private Space rules below
Upload your own certificate Yes, heroku certs:add (disables ACM)
Renewal Automatic, one month before expiry
TLS versions TLS 1.2 and TLS 1.3 only

Step 1: Add the domains

Add the root and www names separately; Heroku requires root domains to be added in addition to any subdomains:

heroku domains:add www.example.com -a example-app
heroku domains:add example.com -a example-app
heroku domains -a example-app

Each domain gets its own DNS target, for example whispering-willow-5678.herokudns.com. Your Heroku account must be verified to add domains, and adding domains costs nothing.

Step 2: Point DNS at the targets

Point each name at its own herokudns.com target: a CNAME for www, and an ALIAS, ANAME or flattened CNAME for the root.

Name Record Value
www.example.com CNAME whispering-willow-5678.herokudns.com
example.com ALIAS, ANAME or flattened CNAME hidden-sierra-7936.herokudns.com

Heroku is explicit that A records are not enough for root domains, because Heroku's IP addresses are dynamic. Providers with ALIAS or ANAME include DNSimple, DNS Made Easy, easyDNS, Namecheap and DreamHost, and Cloudflare flattens a CNAME at the root. If your provider only offers A records at the root, move DNS to one that supports these record types.

Older apps sometimes point at example-app.herokuapp.com or *.herokussl.com. ACM cannot verify those; switch to the herokudns.com target. Also leave out AAAA records, which ACM does not support.

Step 3: Check CAA records

If the domain publishes CAA records, add one that allows Let's Encrypt:

example.com.  3600  IN  CAA  0 issue "letsencrypt.org"

Otherwise ACM fails with CAA record prevents issuance, CAA record does not match issuer. If your DNS provider does not support CAA at all, ACM can fail with DNS provider doesn't support CAA. Test with the CAA checker.

Step 4: Enable ACM and watch the status

Enable ACM once DNS points at Heroku, then check the status:

heroku certs:auto:enable -a example-app
heroku certs:auto -a example-app

Generating a certificate usually takes 45 to 60 minutes. The statuses are:

Status Meaning
Cert Issued A certificate has been issued for the domain.
In Progress Heroku is verifying the domain's DNS.
DNS Verified DNS is verified; the certificate is being generated. Not finished yet.
Waiting Heroku is waiting to process the certificate.
Failing Heroku cannot verify DNS and will keep trying for up to an hour.
Failed Heroku cannot verify DNS and has stopped trying.

Wildcards and your own certificate

Wildcard domains can be added to an app with a CNAME from * to the wildcard's DNS target. Heroku's ACM article does not describe ACM issuing wildcard certificates in the Common Runtime. For Private Spaces it says you must upload your own wildcard certificate, that Cedar-generation Private Space apps using ACM cannot have wildcard domains, and that a newer generation of Private Space apps can use ACM with wildcard domains.

To use an EV certificate, another CA or a wildcard certificate, upload it:

heroku certs:add server.crt server.key -a example-app
heroku certs -a example-app

Include the intermediate certificates in server.crt. Uploading a certificate disables ACM; run heroku certs:auto:enable to return to ACM later. Heroku does not let you extract private keys, so keep your own copy. For automatic renewal of a wildcard on a Private Space app, Heroku points to add-ons such as SSL FastTrack or ExpeditedSSL.

Switching from an uploaded certificate to ACM

ACM uses the same DNS configuration as Heroku SSL (SNI), and enabling it on a Private Space app needs no DNS change. While ACM verifies DNS, the app keeps serving the existing certificate. For Private Space apps Heroku documents this order:

  1. Find the uploaded certificate's name with heroku certs.
  2. Run heroku certs:auto:enable.
  3. Wait with watch heroku certs:auto until the new certificate is issued. Skipping the wait can cause downtime.
  4. Remove the old certificate with heroku certs:remove --name <name>.

Verify

Once ACM shows the certificate as issued, each domain presents a Let's Encrypt certificate. Check it with the SSL checker, or:

curl ssl.sh/example.com

Then inspect the certificate:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -issuer -subject -ext subjectAltName -dates

On macOS, avoid curl -k for this check: Heroku notes that on many macOS versions curl with -k does not send SNI.

Renewal

ACM renews certificates one month before they expire and creates a new certificate whenever you add or remove a custom domain. If ACM cannot create a certificate, Heroku sends a notification after three days of attempts. Uploaded certificates are never renewed by Heroku; replace them with heroku certs:update. Let's Encrypt itself stopped sending expiry emails on June 4, 2025, and its default lifetime becomes 64 days on February 10, 2027, so add critical domains to ssl.sh monitoring (in development).

Troubleshooting

Do not turn ACM off and on to speed things up; that can trigger a Let's Encrypt rate limit. Fix the cause, then run:

heroku certs:auto:refresh -a example-app

Heroku documents these failure reasons:

  • CN exceeding 64 character limit: the domain name is longer than 64 characters.
  • Incorrect DNS settings: the record is wrong, the domain fails DNSSEC validation, or a Private Space app has no running web dyno.
  • Unable to resolve DNS for domain: the name has not propagated; ACM checks Google Public DNS (8.8.8.8).
  • CDN not returning HTTP challenge: the domain points at a CDN such as CloudFront that returns 404 for the challenge file.
  • DNS redirect not forwarding path: the DNS provider's forwarding drops the challenge path.
  • Incorrect CNAME target: the CNAME points at <app-name>-<random-identifier>.herokuapp.com instead of the DNS target.
  • Rate limited: too many certificate requests for the domains in 7 days; wait, then refresh. See Let's Encrypt rate limits.
  • DNS provider timed out: refresh to retry.
  • Strict TLS in CDN not supported: Cloudflare is in front but misconfigured; Heroku recommends not combining ACM with Cloudflare and disabling ACM there.
  • DNS provider doesn't support CAA and CAA record prevents issuance, CAA record does not match issuer: see Step 3 and CAA record prevents issuance.
  • Domain record does not exist: Let's Encrypt got NXDOMAIN; check the spelling and the CNAME.
  • Domain considered unsafe: Google Safe Browsing flags the domain.
  • Let's Encrypt domain blocklist: ask on the Let's Encrypt community forum.

FAQ

Does Heroku ACM cost extra?

No. Heroku's documentation says all applications include ACM for free. It uses Let's Encrypt certificates and renews them one month before they expire.

Why can't I use an A record for my root domain on Heroku?

Heroku uses dynamic IP addresses, so an A record pointing at a fixed IP will break. Use an ALIAS, ANAME or flattened CNAME record that points the root domain at the herokudns.com DNS target shown by heroku domains.

Does ACM issue wildcard certificates?

Heroku's ACM article tells Private Space apps to upload their own wildcard certificate and says Cedar-generation Private Space apps using ACM cannot have wildcard domains, while a newer generation can. For wildcard HTTPS in other cases, plan to upload your own wildcard certificate, which turns ACM off for that app.

Should I turn ACM off and on again to fix a stuck certificate?

No. Heroku warns that toggling ACM can hit a Let's Encrypt rate limit, which Heroku support cannot bypass. Fix DNS, then run heroku certs:auto:refresh.

Sources

  1. Heroku Dev Center: Automated Certificate Management
  2. Heroku Dev Center: Custom Domain Names for Apps
  3. Heroku Dev Center: Heroku SSL
  4. Let's Encrypt: Certificate Authority Authorization (CAA)