Comparison: Certbot vs acme.sh for Let's Encrypt automation in Docker multi-domain — pros and cons
By Kevin Marcondes · Published on · 7 min read
A comparison of Certbot vs acme.sh for automating Let's Encrypt in Docker environments with multiple domains. This guide explains when each ACME client fits best, how to integrate them behind a reverse proxy, and how to organize volumes, hooks, and renewals in Compose. Typical architectures and practical examples are included to help your technical decision.
Scenario: multiple containers and domains in Docker
Environments with several services and domains require automatic renewal, zero downtime and consistent certificate storage. The ACME client must work behind proxies, handle SAN (multiple -d) and often support wildcard issuance via DNS-01. You can centralize issuance in one container and share certificates via a volume, or issue per service depending on topology.
If you're getting started with certificates, see general concepts in How to get free SSL with Let's Encrypt.
- Typical targets: *.example.com and additional domains in SAN.
- Automatic renewal without interrupting Nginx/HAProxy/Traefik.
- Secure storage of private keys and backup of the account key.
- Compatibility with HTTP-01 behind a proxy and DNS-01 at the provider.
Automation architectures in Docker
There are two common patterns to integrate Certbot or acme.sh in Docker. The choice affects how you mount volumes, rotate certificates and reload processes. Define a single “issuance point” and a controlled reload plan to avoid TLS gaps.
- Centralized issuer: one container manages all domains, saves to a dedicated volume and other services mount the certificates read-only.
- Per-service: each app runs its own ACME client and issues its own certificates — useful for independent teams but increases credentials and failure points.
- For HTTP-01, use a webroot shared with the proxy. For DNS-01, inject DNS provider tokens into the issuer.
Side-by-side features: what differs in practice
Below is a comparative view of the criteria that matter most in Docker environments with many domains and continuous automation needs.
| Criterion | Certbot | acme.sh |
|---|---|---|
| Base and dependencies | Official client in Python; heavier, Python-based plugins | POSIX shell script; very lightweight image and footprint |
| Container distribution | Widely available and commonly used in Docker | Available as a lightweight container for CI/Docker use |
| ACME challenges | HTTP-01 and DNS-01 | HTTP-01 and DNS-01 |
| DNS plugins/integration | Provider-specific plugins; new ones via Python plugins | Broad support for many providers via environment variables |
| Automation with webserver | Has installers for Apache/Nginx (outside Docker); in Docker use webroot or standalone | No installers; uses hooks and simple commands |
| Multiple domains (SAN) | Supports multiple -d on the same certificate | Supports multiple -d on the same certificate easily |
| Wildcard (*.domain) | Supported via DNS-01 | Supported via DNS-01 (direct flow) |
| Key types | RSA and ECDSA | RSA and ECDSA (e.g., ec-256) |
| Deploy/reload hooks | --deploy-hook and --post-hook | --reloadcmd and simple shell hooks |
| Staging mode (test) | Supported (--staging) | Supported (--staging) |
Automating multiple domains and wildcards
To reduce the number of certificates, combine domains with SAN. This simplifies management but a single mistake can affect more hosts. Prefer wildcards (*.domain.com) when subdomains change frequently and you control DNS-01. In Docker, keep a dedicated volume for certificates with strict permissions.
Both Certbot and acme.sh handle SAN and wildcards well. acme.sh is often more straightforward when configuring DNS-01 with provider tokens. Certbot excels when you reuse a webroot and already have reload automations in place.
- Consolidate SAN when domain change cadence is similar across hosts.
- Wildcard reduces re-issuance when new subdomains appear.
- Separate certificates for critical domains to isolate failures.
- Centralize configuration storage and versioning.
HTTP-01 vs DNS-01 behind a reverse proxy
For HTTP-01, traffic to /.well-known/acme-challenge must reach the issuer or a shared webroot. This requires proxy configuration. For DNS-01, the challenge is validated via TXT records, ideal for wildcards and clusters without port 80 exposed.
If you use modern proxies with built-in ACME, compare approaches in Traefik vs Caddy: HTTPS Routing in Docker (/en/traefik-vs-caddy-https-docker). For an example with a traditional load balancer, see the HAProxy + Let's Encrypt tutorial (/en/haproxy-letsencrypt-docker-healthchecks-vps). And to choose a proxy, check Traefik vs Nginx as reverse proxy (/en/traefik-vs-nginx-reverse-proxy-docker).
- HTTP-01: simple with webroot, depends on correct routing in the proxy.
- DNS-01: ideal for wildcard and multi-host, requires DNS provider tokens.
- In both cases, plan reloads without interrupting service.
Ongoing operation, security and performance
Minimize the scope of credentials and mount certificates read-only. Prefer ECDSA P-256 for smaller keys and faster handshakes when client compatibility allows. Design proxy reloads (SIGHUP or reload endpoint) to avoid full restarts.
Use staging when validating automations to avoid hitting rate limits. Back up the account key and the certificate directories. Never expose DNS tokens in repositories; use secrets and environment access controls.
- Prefer Certbot when you rely on webroot/HTTP-01, already have Certbot hooks, or want the official client alignment.
- Prefer acme.sh when you need DNS-01/wildcard across many providers, lightweight images, and simple shell scripts for CI/CD integration.
Compose example: Certbot with shared webroot (HTTP-01)
Minimal layout using a webroot shared with Nginx. Certbot writes the challenge to the volume and Nginx serves it from /.well-known/acme-challenge. After issuance, certificates reside in a dedicated volume. Review permissions and plan the Nginx reload.
version: '3.8'
services:
nginx:
image: nginx:alpine
volumes:
- challenge:/var/www/certbot:ro
- certs:/etc/letsencrypt:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
ports:
- "80:80"
- "443:443"
certbot:
image: certbot/certbot
volumes:
- challenge:/var/www/certbot
- certs:/etc/letsencrypt
entrypoint: ["sh","-c"]
command: >-
"certbot certonly --webroot -w /var/www/certbot \
-d example.com -d www.example.com \
--email [email protected] --agree-tos --no-eff-email --non-interactive && \
echo 'Emissão concluída. Configure um mecanismo de reload do Nginx.'"
volumes:
challenge:
certs:
Compose example: acme.sh with DNS-01 and multiple domains
Typical flow for wildcard via DNS-01. acme.sh writes certificates to a dedicated volume. consuming services mount that volume read-only. Store DNS tokens in Docker secrets or protected variables and enable staging before production.
version: '3.8'
services:
acme:
image: your-acme-sh-image
environment:
- ACME_SERVER=letsencrypt
# Exemplo Cloudflare (use secrets na prática):
- CF_Token=${CF_TOKEN}
- CF_Zone_ID=${CF_ZONE_ID}
volumes:
- certs:/acme
entrypoint: ["sh","-c"]
command: >-
"acme.sh --issue --dns dns_cf \
-d example.com -d *.example.com \
--keylength ec-256 --server letsencrypt && \
acme.sh --install-cert -d example.com \
--fullchain-file /acme/example.com/fullchain.pem \
--key-file /acme/example.com/privkey.pem && \
echo 'Certificados prontos no volume. Programe renovações.'"
volumes:
certs:
Frequently asked questions
Which is better for multiple domains and wildcards in Docker?
Both work well. For DNS-01 and wildcards, acme.sh is often more straightforward thanks to provider integrations via environment variables. For HTTP-01 with a webroot already established in the proxy, Certbot is a solid, well-documented choice.
Can I use them with Traefik, Nginx or HAProxy behind Docker?
Yes. For HTTP-01, route /.well-known/acme-challenge to the webroot or issuer. For DNS-01, no HTTP traffic is needed—just access to the DNS API. Implement a clean proxy reload after certificate renewal.
How to avoid Let's Encrypt rate limits during tests?
Use staging mode in both clients. It lets you validate issuance and renewal workflows without consuming production limits. Switch to the production server when tests are complete and keep renewal windows with margin.
Where to store certificates and how to reload without downtime?
Store certificates in a dedicated volume mounted read-only for consuming services. Reload by signal or proxy endpoint (e.g., SIGHUP for Nginx) after renewal. Avoid unnecessary container restarts.
Is it safe to keep DNS provider tokens in environment variables?
It's common but requires care. Prefer Docker secrets or your orchestrator's secret store. Restrict scope and permissions at the DNS provider, rotate tokens periodically, and never commit secrets to the repository.
Standardize your certificate automation in Docker
Describe your multi-domain scenario and we'll evaluate challenge routes, volume layout and renewal policy for a stable operation.
Discuss my setupSee also
- ZFS vs LVM+LUKS on VPS for Databases — snapshots, performance and post-failure recovery
- Practical comparison — Nginx Unit vs PHP‑FPM vs RoadRunner for PHP monoliths in containers — latency, throughput & memory
- Flyway vs Liquibase vs Sqitch: database versioning for PHP/Laravel projects
- ZFS vs Btrfs for Snapshots, Replication and Incremental Retention on VPS with Docker — Practical Pros and Cons