Library / SDK
caddyserver/certmagic avatar
caddyserver/certmagic

CertMagic: automatic HTTPS for Go programs that are not Caddy

Automatic HTTPS for any Go program: fully-managed TLS certificate issuance and renewal

5,605 stars354 forksGoApache-2.0

At a glance

What is it?
CertMagic is the ACME client behind the Caddy web server, packaged as a Go library. It handles certificate issuance, renewal, OCSP stapling and the three standard ACME challenges, at the cost of a persistent storage directory and a public DNS name.
Who is it for?
Adopt CertMagic when your Go service already terminates TLS itself, your domain points at the host, and you can give it a writable storage directory; the one-line certmagic.HTTPS call covers the common case. Do not adopt it if you cannot open port 80 or 443 and have no DNS provider integration, if you need certificates for internal names that no public CA will sign, or if your TLS already terminates at a load balancer that does its own certificate management.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The certificate chore CertMagic removes from a Go binary

A Go service that wants HTTPS normally has three unglamorous jobs: obtain a certificate, renew it before expiry, and reload it without dropping connections. CertMagic exists to delete all three. It is the ACME client that the Caddy web server uses, extracted so that any Go program can call it directly.

The intended audience is narrow but real. You write a Go server, you own a public domain name, and you do not want a sidecar, a cron job or a config file full of certificate paths. The README's pitch is a before-and-after pair: http.ListenAndServe(":80", mux) becomes certmagic.HTTPS([]string{"example.com"}, mux). One call serves the router over HTTPS, adds HTTP to HTTPS redirects, obtains and renews the certificate, and staples OCSP responses.

What it is not: a Kubernetes controller, a standalone daemon, or a tool you run from a shell. It is a library you import. If your deployment model has no Go code in it, CertMagic is the wrong shape entirely.

How issuance, storage and challenges fit together

The architecture is a Config object plus pluggable backends. The README describes a Config type with defaults, a certificate authority setting, an optional email address for the ACME account, and a rate limiter. Underneath, the actual ACME protocol work is delegated to ACMEz, and DNS provider integrations come through libdns, so any libdns provider works without CertMagic-specific code.

Storage is the piece that surprises people. The default backend is the file system, and the repository has a filestorage.go alongside a storage.go interface, so certificates, account keys and OCSP staples persist between restarts. The requirements section lists persistent storage as a hard requirement, not a suggestion. In a container, that means a mounted volume; without it, every restart re-requests certificates and you will meet the CA's rate limits.

Challenge solving is where the deployment constraints come from. CertMagic supports the three common ACME challenges. HTTP requires port 80, TLS-ALPN requires port 443, and DNS requires a provider integration but no inbound reachability at all. The README is explicit that the port requirement comes from the ACME protocol rather than the library, which is a fair point: no ACME client can validate a domain it cannot reach.

For fleets, the README describes distributed challenge solving with active locking and smart queueing, plus coordination so that multiple instances behind a load balancer do not fight over the same certificate. On-demand TLS is the other unusual feature: certificates issued during the TLS handshake, with custom decision functions to throttle which names are allowed. That is powerful and also the easiest way to get yourself rate limited if the decision function is permissive.

Installing CertMagic and serving a first HTTPS handler

The README gives one installation command. It requires Go 1.21 or newer according to the requirements section, though the go.mod in the repository declares go 1.25.0, so a recent toolchain is the safe choice.

bash
go get github.com/caddyserver/certmagic

That adds the module to your go.mod. The README's first example is the whole integration: pass a domain and an existing http.Handler to certmagic.HTTPS, and the library takes over TLS.

go
certmagic.HTTPS([]string{"example.com"}, mux)

Before that call can succeed, the README states plainly that your domain's A/AAAA records must point at the server. Run the program on a host that can bind ports 80 and 443, with a writable storage directory for the default file system backend. On success, the process listens on 443 with a certificate it obtained itself, and requests to port 80 are redirected to HTTPS. The README notes that OCSP responses are stapled automatically.

For anything beyond the one-liner, the documented path is to configure a certmagic.Config and call ManageSync or ManageAsync on your names, which is what the README's "advanced use" examples cover. ManageSync blocks until certificates are loaded, which is usually what you want in main before you start serving.

Where CertMagic is the wrong tool

The first failure mode is environmental. If you cannot bind port 80 or 443 and you have no DNS provider that libdns supports, there is no challenge left to solve and no certificate to obtain. The README lists the DNS challenge as the way to waive the reachability requirement, which means the DNS path is the escape hatch, not a fallback that appears automatically.

The second is storage. Certificates and account keys live in persistent storage by default on the local file system. A container with an ephemeral filesystem will re-issue on every deploy. The README's own requirements section treats this as a precondition, and it is the single most common way a working development setup breaks in production.

On-demand TLS deserves its own warning. Issuing during a handshake means an attacker who can trigger handshakes for arbitrary names can trigger issuance for arbitrary names. CertMagic provides custom decision functions to regulate and throttle this, and the README frames them as part of the feature rather than an optional extra. Treat a permissive decision function as a bug.

Finally, CertMagic is not a certificate manager in the Kubernetes sense. It has no CRDs, no reconcile loop over cluster objects, and no notion of a Secret. If your platform already terminates TLS at an ingress controller, adding CertMagic inside the pod duplicates work rather than replacing it.

CertMagic compared with certbot and cert-manager

The practical alternative most people weigh is certbot, a command-line tool that writes certificates to disk and relies on a scheduled task for renewal. The difference is where the certificate lives. Certbot hands you files and a reload hook; CertMagic keeps the certificate in memory and renews it from inside the process. For a Go service, that removes the reload step entirely, but it also means the certificate is not visible to anything else on the box.

Against cert-manager, the split is architectural. Cert-manager runs as a controller inside Kubernetes and expresses certificates as cluster resources, so the certificate is shared infrastructure. CertMagic is per-process and has no cluster concept beyond the distributed locking the README describes for challenge solving. If you run Kubernetes, cert-manager fits the platform's idioms; CertMagic fits a Go binary that owns its own listener.

One design choice worth noting is that CertMagic generates a new private key for each certificate by default. The README says this is deliberate, to discourage pinning and reduce the scope of a key compromise. The trade-off is that anything pinning the key will break on renewal, which is exactly the intent, but it is a compatibility decision you should make consciously.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-09-10, so it is receiving changes. The most recent tagged release listed is v0.25.3 from 2026-05-11, with v0.25.2 in February 2026 and v0.25.0 in September 2025. The gap between the last tag and the last push suggests work continues on master between releases, which is normal for this project.

The version number is the upgrade signal. CertMagic is still on 0.x, so the maintainers have not promised API stability, and the jump from v0.25.0 to v0.25.2 to v0.25.3 within a year is a reminder to read release notes before bumping. The dependency list in go.mod is small but not trivial: ACMEz, libdns, miekg/dns, zap, blake3, and golang.org/x/crypto among others. A major version bump of ACMEz, which is already at v3, is the kind of change that can ripple through your build.

Licensing is Apache-2.0, a permissive licence that allows commercial use and modification with the usual conditions around notices and patent grants. That is a summary, not legal advice; if you redistribute a modified CertMagic, read the licence text in LICENSE.txt yourself.

Editorial conclusion

Adopt CertMagic when your Go service already terminates TLS itself, your domain points at the host, and you can give it a writable storage directory; the one-line certmagic.HTTPS call covers the common case. Do not adopt it if you cannot open port 80 or 443 and have no DNS provider integration, if you need certificates for internal names that no public CA will sign, or if your TLS already terminates at a load balancer that does its own certificate management. Before shipping, verify three things: that your domain's A/AAAA records resolve to the server, that the storage path survives restarts and redeploys, and that a staging run against LetsEncryptStagingCA succeeds so you do not burn production rate limits while testing.

Frequently asked questions

Why do I need a certificate manager?

CertMagic takes over the recurring work of obtaining a TLS certificate and renewing it before expiry, which the README lists as its first feature. Without something doing that, you are tracking expiry dates by hand or writing your own renewal job.

How do I get a TLS certificate with CertMagic?

It acts as an ACME client, using Let's Encrypt by default or any CA that conforms to the ACME specification, and solves the HTTP, TLS-ALPN or DNS challenge. The README states that your domain's A/AAAA records must point at your server unless you use the DNS challenge.

What are the differences between cert-manager and certbot?

Certbot is a command-line tool that writes certificates to disk and relies on a scheduled task for renewal, while cert-manager runs as a controller inside Kubernetes and treats certificates as cluster resources. CertMagic sits in neither camp: it is a Go library that renews from inside your process.

What does SSL/TLS stand for?

SSL stands for Secure Sockets Layer and TLS for Transport Layer Security, the protocol that encrypts connections. CertMagic's job is to obtain and renew the TLS certificates that make those connections trusted.

Official sources

  1. caddyserver/certmagic on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/caddyserver-certmagic.svg)](https://hysenlabs.com/projects/caddyserver-certmagic)