ACME clients: how to choose one by class, not by name
An ACME client is the software that gets certificates for you: it places an order with the certificate authority, proves control of each name and downloads the certificate [1]. Every client implements the same ACME protocol, defined in RFC 8555, so the authority runs the same checks whichever one asks [1]. What differs is where the client runs, whether it can put the certificate into your server, and what it does when something fails. Those three should decide the choice, and the clients named below are examples of each class.
- Protocol
- RFC 8555, the same for every client [1]
- Classes
- built into the server, a program run on a schedule, a library inside your application, a platform
- Challenges
- HTTP-01, DNS-01 and TLS-ALPN-01; which of them each client supports is in the table below
- Wildcards
- at Let's Encrypt only through DNS validation, so a record in your DNS has to change: by the client through your provider's API, or by hand [2]
- Default key in our runs
- ECDSA P-256 from Certbot 5.8.0, lego 5.5.2 and acme.sh 3.1.6 [7]
The four classes
Built into the server. The software that terminates connections obtains certificates itself, so the program that gets a certificate is the one that serves it. Caddy works this way: its documentation describes certificates provisioned for all your sites and kept renewed [5].
A separate program run on a schedule. A tool runs periodically, renews what is due, writes the files and reloads the server. It works with any server and has the most moving parts. Certbot and acme.sh are examples [2][3].
A library inside your own application. The application manages its own certificates, which suits software you distribute or services that create hostnames on the fly. lego is published as both an ACME client and an ACME library written in Go [4].
A platform that does it for you. Certificates are a property of the hosting or delivery layer, and nothing runs on your side. Bridge CDN works this way: Bridge SSL is the certificate layer of Bridge CDN, and certificates are issued and renewed automatically where your site is served. There is no file to install and no date to remember.
Clients compared
Within a class, clients differ in the challenges they support and in how the certificate reaches the server. The marker on each client's name is the source for its row; [7] marks what our runs showed.
| Client | Class | Challenges | How the certificate reaches the server | Default authority | License |
|---|---|---|---|---|---|
| Caddy [5] | built into the server | HTTP-01 and TLS-ALPN-01 on by default; DNS-01 with DNS provider credentials and a plugin | Caddy is the web server and serves it | Let's Encrypt, then a second ACME authority if that fails | Apache 2.0 |
| Certbot [2] | program on a schedule | HTTP-01; DNS-01 through DNS plugins or the manual plugin | the Apache and nginx plugins edit the server's configuration; certonly only saves the files | Let's Encrypt | Apache 2.0 |
| acme.sh [3] | program on a schedule | HTTP-01 [7]; TLS-ALPN-01 with --alpn; DNS-01 through DNS APIs, aliases or by hand | --install-cert copies key and chain to your paths and runs --reloadcmd [7]; its Apache and nginx modes do not edit your configuration | an authority other than Let's Encrypt; --server picks another | GPLv3 |
| lego [4] | library and command-line client | HTTP-01, DNS-01, TLS-ALPN-01 | writes files under .lego/certificates; --deploy-hook runs a command after each successful issue or renewal [7] | Let's Encrypt [7] | MIT |
| cert-manager [6] | controller in a Kubernetes cluster | HTTP01 and DNS01 | keeps the key and certificate in a Kubernetes Secret used by a Pod or an Ingress controller | none: each Issuer names its ACME server | Apache 2.0 |
Certbot or acme.sh
Both run on the server as a scheduled program. They differ in how the certificate gets into the server. Certbot's Apache and nginx plugins change the server's configuration to use the certificate, and its guide asks you to point the server at the files in /etc/letsencrypt/live/ instead of copying them [2]. acme.sh does not edit the server's configuration: it copies the key and chain to the paths you name, and its README says the files in its own folder are for internal use only [3]. Certbot is most useful with root privileges, which let it configure Apache and nginx; acme.sh is a shell script that does not require root [2][3]. Check the authority too: the acme.sh README marks one other than Let's Encrypt as its default [3].
Whichever client you pick, it registers and keeps the ACME account, which is a protocol object of its own.
What each client left on disk
We issued one certificate for example.com and www.example.com with each command-line client, against Pebble, a local test authority, over HTTP-01 [7].
| Aspect | Certbot 5.8.0 | lego 5.5.2 | acme.sh 3.1.6 |
|---|---|---|---|
| Files | live/example.com/: cert.pem, chain.pem, fullchain.pem, privkey.pem, each a link into archive/ | certificates/: example.com.crt, example.com.issuer.crt, example.com.key, example.com.json | example.com_ecc/: example.com.cer, ca.cer, fullchain.cer, example.com.key, the CSR and two .conf files |
| Certificate with its chain | fullchain.pem, 2 certificates | example.com.crt, 2 certificates | fullchain.cer, 2 certificates |
| Key | ECDSA P-256, file mode 600 | ECDSA P-256 | ECDSA P-256 |
| What the server should read | the live/ files themselves [2] | example.com.crt and example.com.key [4] | the copies --install-cert made [3] |
A server given cert.pem alone sends no intermediate. Certbot's guide says that a server using cert.pem must also be given chain.pem, or some browsers will show errors [2].
Certbot: how it gets and installs a certificate
Certbot is the ACME client from EFF, the Electronic Frontier Foundation: it fetches a certificate from Let's Encrypt and can deploy it to a web server. It is meant to run on the web server itself and is most useful with root privileges, which let it configure Apache and nginx. For installation the documentation recommends the snap on Linux distributions that use systemd; the Docker image can obtain certificates but cannot install them into your web server, and pip is supported on a best-effort basis inside a virtual environment [2]. Running Certbot on your own server is one of the two routes to a Let's Encrypt certificate.
If a client you already use is Certbot and your server runs Windows, the page on Certbot on Windows sets out what its team has published about that platform.
Authenticators and installers
Certbot does its work through plugins. An authenticator proves control of the names and is always required; an installer edits the web server's configuration to use the certificate and is needed only if you want Certbot to do that:
--nginxand--apacheauthenticate over HTTP-01 and install [2].--webrootwrites the challenge file into the directory a running web server already serves [2].--standaloneruns its own HTTP server on port 80, so you may need to stop a web server that holds that port [2].DNS plugins answer DNS-01 through your provider's API and are installed separately. DNS validation, by these plugins or the manual plugin, is the only way Certbot gets a wildcard certificate from Let's Encrypt [2].
Our pip-installed Certbot 5.8.0 listed two plugins, standalone and webroot, both authenticators, and no installer [7].
Obtain and install, or obtain only
Warning. Back up the nginx configuration before certbot --nginx: Certbot's guide recommends it, and certbot --nginx rollback reverts the plugin's changes [2].
$ sudo certbot --nginx -d example.com -d www.example.com
$ sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.comThe first command uses the nginx plugin to obtain the certificate and install it; certbot on its own does the same as certbot run. The second only saves the files, and pointing the web server at them is yours. Files go to /etc/letsencrypt/live/<name>/, where the name is the one given to --cert-name or else the first domain [2]. Renewal timers, deploy hooks and dry runs are part of automating certificate renewal.
The questions that decide
Five questions decide between clients, in the order that removes options fastest.
What terminates your connections? If that software obtains certificates itself, as Caddy does [5], it is the first candidate, because nothing is left to deploy. If a platform terminates TLS, the question is already settled.
Can the client deploy the result? Obtaining a certificate is the easy half. Something must place the files and reload the service, and a client that cannot do it leaves you writing the missing step yourself. Certbot's installers and acme.sh's
--install-certdo it in different ways [2][3].Which challenge do you need? A wildcard needs DNS validation, so for unattended renewal the client must change your DNS through your provider's API. Check your provider against the client's list before you choose [2][3][4].
What happens when it fails? Whether failures are visible, whether they are retried, and whether anything reports them. A client that fails silently is no better than none until the certificate expires.
Who maintains it? Anything running unattended for years needs to keep receiving updates. This matters more than a feature comparison, and the project's release history answers it.
What the class decides for you
Each class has a characteristic failure and a characteristic strength.
A client built into the server cannot fail to deploy, because there is nothing to deploy. The cost is coupling: certificate behaviour is whatever that software implements, and changing servers means revisiting it.
A separate program works with anything, and pays for it in joints: the schedule, the challenge, the files and the reload can each stop on their own.
A library keeps certificates with the application, and makes their failures your code's responsibility.
On a platform none of that is yours, which is both the point and the limit: where it does something you need differently, there may be no setting to change.
Where the client should run
Where the client runs is easy to leave at the default, the server in front of you.
On the server that terminates connections is the obvious choice, and the right one when that server is long-lived and managed directly. The certificate is obtained where it will be used, and nothing has to travel.
On the machine that builds or deploys suits infrastructure rebuilt from images, where anything written onto a running server is lost at the next deployment. Here the certificate belongs in the deployment pipeline, not on the instance.
Somewhere central suits fleets: one place obtains certificates and distributes them, so the credentials for validation sit in one place instead of on every instance. In Kubernetes, cert-manager plays this role inside the cluster: it creates certificates for workloads and renews them before they expire [6].
What decides is what happens to the server. If it is replaced regularly, a client running on it is replaced too, and whatever it obtained goes with it. That mismatch gives you automation that worked once and then stopped.
What not to choose on
Three criteria look relevant to choosing a client and are not.
Feature counts. The protocol is the same. Long feature lists include integrations with particular DNS and hosting providers, such as Certbot's third-party plugins, the acme.sh DNS APIs and lego's DNS providers [2][3][4], and each of those matters only if you use that provider.
Popularity. How widely a client is used tells you nothing about whether it fits the way your connections are terminated, and that is the question that decides.
Speed of issuance. A renewal runs while the old certificate is still valid, so how long one issuance takes never reaches a visitor.
The one thing to verify before committing
Whether it can deploy to your setup, end to end, unattended.
Obtain a certificate with it, let it place the files and reload, then confirm from outside that the new certificate is the one being served. That single test separates a client that will work for years from one that needs a person at every renewal.
If the sequence needs a script you write to bridge a gap, that script is now part of your certificate infrastructure: keep it under version control, make its failures visible and make sure someone knows it exists.
FAQ
Does the choice of client affect the certificate?
What is the most important criterion?
Whether the client can install the result into your setup without a person present. Every client obtains certificates; placing the files and reloading the service at every renewal is where they differ.
Should I use the client built into my server?
Yes, where one exists and supports the challenge you need. A server that obtains its own certificates removes deployment as a separate step, and a step that does not exist cannot fail silently.
Do I need a specific client for wildcards?
You need one that can change your DNS records unattended, because Let's Encrypt validates a wildcard only through DNS. That narrows the field to clients that support your DNS provider's API, and makes that API part of your certificate infrastructure. [2]
What is Certbot?
EFF's ACME client. It fetches a certificate from Let's Encrypt and can deploy it to a web server: its Apache and nginx plugins edit the server's configuration, and certbot certonly only saves the files. [2]
Does Certbot run on Windows?
Certbot's documentation lists Windows among its systems, with Administrator access required, but its changelog for version 2.10.0 says the beta Windows installer is no longer published. [2]
Sources
RFC 8555, Automatic Certificate Management Environment (ACME): sections 4 and 7.
Certbot documentation: Introduction, Get Certbot, User Guide (plugins, Where are my certificates?); Certbot changelog; LICENSE.txt.
acme.sh README: supported CAs, modes, installing the certificate; LICENSE.md.
lego documentation and README: features, obtaining certificates; LICENSE.
Caddy documentation, Automatic HTTPS; Caddy README and LICENSE.
cert-manager documentation: overview and the ACME issuer; LICENSE.
Our runs: Certbot 5.8.0, lego 5.5.2 and acme.sh 3.1.6 against the Pebble 2.10.1 test authority on one machine, over HTTP-01; the files listed, the key types, Certbot's plugin list and the defaults printed by
--help.