Self-hosted service
go-acme/lego avatar
go-acme/lego

go-acme/lego: An ACME Client and Go Library for Let's Encrypt Certificates

Let's Encrypt/ACME client and library written in Go

9,896 stars1,171 forksGoMIT

At a glance

What is it?
lego issues, renews and revokes certificates against ACME v2 CAs, from a single Go binary or as an importable library. It ships more than 200 DNS providers, and that breadth is both its strongest argument and its main cost.
Who is it for?
Adopt lego when you need dns-01 against a provider that certbot does not support, or when you want certificate issuance inside a Go program rather than beside it. Skip it if you only run HTTP-01 on a handful of nginx hosts, where certbot's packaging and renewal timer already do the job.
Can I use it commercially?
Yes. MIT 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 3 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 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What lego solves, and who ends up using it

Getting a certificate from Let's Encrypt means speaking ACME v2, which is RFC 8555. lego is an implementation of that protocol in Go, usable two ways: as a command line tool and as a library you import into your own program. The README describes it as an "ACME client and library for Let's Encrypt and other ACME CAs written in Go", and the documentation is hosted at go-acme.github.io/lego.

The audience splits along that line. The CLI suits operators who need certificates on a server and want a single static binary rather than a Python runtime. The library suits Go developers whose application already knows the domain names it serves and would rather request a certificate in process than shell out to a separate tool. The feature list covers the full certificate lifecycle: register with a CA, obtain certificates from scratch or from an existing CSR, renew, and revoke. SAN certificates, certificate bundling and an OCSP helper function are listed as well.

Where lego separates itself from a minimal ACME client is the DNS side. The README says it comes with more than 200 DNS providers, documented individually under the /dns path of the documentation site. That matters because dns-01 is the only challenge type that works for wildcard certificates and for hosts that are not reachable from the public internet. A client with ten providers is a client you cannot use on the registrar you happen to have.

How lego talks to a CA: challenges, solvers and the DNS provider layer

lego implements the three standard ACME challenges: HTTP (http-01), DNS (dns-01) and TLS (tls-alpn-01). The README also lists support for RFC 8737, the TLS Application-Layer Protocol Negotiation challenge extension; RFC 8738, certificates for IP addresses; and RFC 9773, the Renewal Information extension. Two drafts are listed as supported: draft-ietf-acme-profiles-00 for profiles, and draft-ietf-acme-dns-persist-01, described as a challenge for persistent DNS TXT record validation.

The mechanism is the usual ACME loop, with one layer that lego owns. For dns-01, the client must create a TXT record under _acme-challenge for the domain, wait for the CA to see it, and remove it afterwards. lego abstracts that into a provider interface, and the providers/ directory in the repository holds the implementations. The go.mod file shows what that costs: the module requires SDKs from AWS, Azure, Alibaba Cloud, Akamai, Baidu, Tencent and others, alongside smaller vendor clients. A binary built from this repository carries the dependency graph of every provider it compiles in.

CNAME support is on by default, which the README links to Let's Encrypt's own explanation of onboarding customers through CNAME delegation. Custom challenge solvers are documented as an extension point, so a provider that is not in the list can be added without forking the client. For HTTP-01 and TLS-ALPN-01 the client needs to serve something on the target host; for DNS-01 it needs API credentials for the zone. Those are different operational shapes, and picking the wrong one for your network is the most common way a first attempt fails.

Installing lego and issuing a first certificate

The README does not inline installation steps. It points to the install page of the documentation site, and the repository ships a Dockerfile, a Makefile and a goreleaser configuration, so three routes exist: the documentation's install instructions, a container image published as goacme/lego, and a build from source.

Building from source uses the Makefile target. The Makefile sets CGO_ENABLED=0 and writes the binary to dist/lego on Linux and macOS, or dist/lego.exe on Windows, with the version injected through ldflags.

bash
make build

After that, dist/lego exists and running it with no arguments prints the available commands. The Dockerfile builds the same binary in a golang:1-alpine stage and copies it into an alpine:3 image with ca-certificates and tzdata installed, with the binary as the entrypoint.

bash
docker build -t goacme/lego .
docker run --rm goacme/lego --help

For a first real issuance, the shape of the command depends on the challenge. A DNS-01 run names the provider with --dns and passes credentials through environment variables that the provider's documentation page defines, then names the domains with -d and the contact address with -m. The CLI reference lives under /obtain on the documentation site, and the provider pages under /dns give the exact variable names. There is no single credential variable that works across providers, so the provider page is the source to read before running anything.

What you should see on success is a .lego directory holding the account registration and the certificate files for each domain. The README does not document the exact file layout in the text shown here, so check the CLI documentation for the output paths your version writes.

The dependency weight of 200 DNS providers

The provider count is the feature most people arrive for, and it is also the sharpest trade-off. Because providers are compiled into the module, go.mod lists cloud SDKs for AWS, Azure, Alibaba Cloud, Akamai, Baidu, Tencent, Myra, Azion, Exoscale, DNSimple and more. A library consumer pulls that graph unless the build is arranged otherwise, and the repository layout keeps the provider code in a separate providers/ tree precisely because it is large.

The practical consequences are build time and binary size, not correctness. It also means the project's release surface is wide: a change in a vendor SDK can force a dependency bump that touches one provider and nothing else. The Makefile's generate target regenerates documentation and a version file, and validate-doc fails the build when the generated documentation is stale, which is a sign of how much of the repository is generated rather than hand-written. If you are integrating lego as a library, decide early whether you need the full provider set or a narrow build, because that decision is easier to make before your own dependency graph grows around it.

Where lego is the wrong tool

lego does not terminate TLS and does not configure a web server. It obtains and renews certificate files. Everything after that, loading them into nginx, reloading the process, and scheduling the renewal, is outside its scope. The README lists an OCSP helper function but says nothing about a web server integration or a systemd timer, so a deployment that needs the certificate picked up automatically needs a hook or a wrapper you write yourself.

HTTP-01 issuance also assumes the host is reachable from the CA on port 80, which rules it out for internal services, wildcard certificates and anything behind a firewall. Those cases push you to dns-01, which pushes you back to the provider list: if your DNS host is not among the more than 200 providers, you are writing a custom challenge solver rather than running a command.

The library route has its own cost. Importing lego means carrying its dependency graph into your program and tracking its release cadence. For a small Go service that needs one certificate, that may be more machinery than the problem deserves. The README does not describe a lightweight build mode, so the assumption should be that you get the module as published.

lego against certbot: two different centres of gravity

Certbot is the reference client most people meet first, and the comparison is real rather than rhetorical. Certbot is a Python application built around server configuration: it knows about nginx and Apache, can install a certificate into a virtual host, and ships an installer that edits configuration files. lego does none of that. It is a Go binary and a library that produces certificate files, and it leaves installation to you.

That difference decides the choice more than any feature list. If your environment is a conventional Linux host running nginx with a package manager, certbot's installer and renewal timer cover the whole job, and lego would mean writing the reload step yourself. If your environment is a container, a Go service, or a DNS setup where the certificate must be issued for a wildcard or an unreachable host, lego's single binary and its dns-01 provider coverage fit better. The related searches around lego versus certbot are asking this exact question, and the honest answer is that they overlap only on the issuance step.

Licence, releases and what upgrades cost

lego is MIT licensed. That is permissive: you can use it commercially, modify it and redistribute it, provided the copyright notice and permission notice are retained. The LICENSE file at the repository root carries the exact terms, and nothing here is legal advice; read that file if the distinction matters to your organisation.

The release cadence is visible in the tags. v5.5.0 and v5.5.1 both landed on 2026-09-17, with v5.4.1 on 2026-08-31, and the last push to the default branch was on 2026-09-17. The module path is github.com/go-acme/lego/v5, so the major version is part of the import path and a v6 would be a deliberate, breaking move rather than a surprise. Patch releases arriving on the same day as a minor release is a normal pattern for a project with a wide provider surface, and it argues for pinning a version rather than tracking the default branch.

Upgrade cost is dominated by the provider SDKs in go.mod, not by lego's own API. A bump that moves an AWS or Azure SDK can change behaviour in one provider while leaving the rest untouched, so a scheduled upgrade is worth testing against the specific provider you use rather than the whole suite. The Makefile's test target runs go test -v -cover ./..., and the e2e target runs the end-to-end suite under ./e2e with LEGO_E2E_TESTS=local set. Those are the commands the project itself uses to check a change.

Editorial conclusion

Adopt lego when you need dns-01 against a provider that certbot does not support, or when you want certificate issuance inside a Go program rather than beside it. Skip it if you only run HTTP-01 on a handful of nginx hosts, where certbot's packaging and renewal timer already do the job. Before committing, confirm that your DNS provider appears in the provider list, that your credentials are read from the environment as that provider's documentation requires, and that the certificate files land where your web server expects them.

Frequently asked questions

What is the ACME certificate protocol that lego implements?

ACME is the protocol defined in RFC 8555 for issuing certificates automatically, and it is what Let's Encrypt and other CAs speak. lego implements ACME v2, including the RFC 8737 TLS-ALPN challenge extension, RFC 8738 for IP address certificates and RFC 9773 for renewal information.

How do I run lego with Docker?

The repository includes a Dockerfile that builds the binary in a golang:1-alpine stage and copies it into an alpine:3 image with ca-certificates and tzdata, using the lego binary as the entrypoint. The project also publishes an image under the name goacme/lego, which the README links to on Docker Hub.

Which DNS providers does lego support for dns-01?

The README states that lego comes with more than 200 DNS providers, each documented on its own page under the /dns section of the documentation site. If your provider is missing, the README points to an issue template for requesting a new one, and custom challenge solvers are documented as an extension point.

Is lego a replacement for certbot?

Only for the issuance step. lego obtains, renews and revokes certificates and writes the files, but it does not edit web server configuration or install certificates into a virtual host the way certbot's installers do. You handle the reload and the scheduling yourself.

Can I use lego as a Go library instead of the CLI?

Yes. The README lists both a CLI and a library usage path, with the library documented under the /library section of the documentation site. The module path is github.com/go-acme/lego/v5, so the major version is part of the import path.

Official sources

  1. go-acme/lego on GitHub
  2. License: MIT
  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/go-acme-lego.svg)](https://hysenlabs.com/projects/go-acme-lego)