Certbot
What is Certbot?
Certbot is the standard client for Let's Encrypt, issuing free, automated TLS/SSL certificates. Laradock runs it as a one-shot container that requests a certificate via the HTTP-01 "webroot" challenge, it doesn't serve traffic itself, it just proves domain ownership through your existing web server and writes out the certificate files.
Start Certbot
- Laradock CLI
- Docker Compose
./laradock start certbot
docker compose up -d certbot
Certbot needs a domain that already resolves to your server and a web server (nginx, apache2, or caddy) listening on port 80 to serve the challenge, since the webroot method requires Let's Encrypt to fetch a file over plain HTTP before it will issue a certificate.
Stop Certbot
- Laradock CLI
- Docker Compose
./laradock stop certbot
docker compose stop certbot
Certbot's run-certbot.sh runs once at container start and then the container just sleeps, so stopping it is safe at any time and doesn't affect certificates already issued.
Configuration
certbot/defaults.env is empty. The two values Certbot needs, domain and email, are hardcoded directly in certbot/compose.yml:
environment:
- CN="fake.domain.com"
Edit certbot/compose.yml and replace CN with your real domain and EMAIL with your real address, then rebuild:
- Laradock CLI
- Docker Compose
./laradock rebuild certbot
docker compose build certbot
How the certificate is issued
certbot/Dockerfile builds on phusion/baseimage:bionic-1.0.0, installs the letsencrypt apt package, and runs certbot/run-certbot.sh as its entrypoint:
letsencrypt certonly --webroot -w /var/www/letsencrypt -d "$CN" --agree-tos --email "$EMAIL" --non-interactive --text
/var/www/letsencrypt inside the container is bind-mounted from ./certbot/letsencrypt/ on your host. For the challenge to succeed, your web server must serve that same folder at http://your-domain/.well-known/acme-challenge/. Laradock's shipped nginx/sites/*.conf files already include that location block pointing at /var/www/letsencrypt/, but as of this writing nginx/compose.yml does not itself mount ./certbot/letsencrypt/ into the nginx container, so you need to add that volume mapping to nginx/compose.yml (or your apache2/caddy equivalent) yourself before Certbot's challenge can be reached.
On success, run-certbot.sh copies the issued files into ./data/certbot/certs/ on your host:
<domain>-cert1.pemchain1.pemfullchain1.pem<domain>-privkey1.pem
Point your web server's SSL config at those files.
Check whether it succeeded
Certbot's entrypoint runs run-certbot.sh once, then sleeps, it doesn't stay attached to your terminal, so check the container's logs to see whether the challenge actually succeeded or Let's Encrypt rejected it:
- Laradock CLI
- Docker Compose
./laradock logs certbot
docker compose logs --tail=100 certbot
Success shows Congratulations! from letsencrypt and the four .pem files listed above under ./data/certbot/certs/. Any other outcome means the challenge failed, see Common issues.
Test with the staging environment first
Every real request against Let's Encrypt's production endpoint counts against its per-domain rate limits, so if you're still iterating on your domain/DNS/web-server setup, point Certbot at Let's Encrypt's staging endpoint instead, it issues certificates your browser won't trust, but doesn't count against production rate limits. Add --staging to the letsencrypt certonly line in certbot/run-certbot.sh:
letsencrypt certonly --webroot -w /var/www/letsencrypt -d "$CN" --agree-tos --email "$EMAIL" --non-interactive --text --staging
Rebuild and start Certbot as above. Once the staging run succeeds, remove the --staging flag and rebuild again to get the real, browser-trusted certificate.
Renew the certificate
Let's Encrypt certificates expire after 90 days, and this container doesn't set up any renewal cron, run-certbot.sh only ever runs once, at container start. To renew, just start it again the same way you did the first time:
- Laradock CLI
- Docker Compose
./laradock restart certbot
docker compose restart certbot
For unattended renewal, schedule that same command on your host (e.g. a monthly host cron entry) well before the 90-day expiry, and confirm success afterward with Check whether it succeeded above.
Common issues
- Challenge fails / "Invalid response" from Let's Encrypt. Almost always means the web server isn't serving
./certbot/letsencrypt/at/.well-known/acme-challenge/on port 80, or the domain doesn't resolve to this server yet. Confirm the volume mapping and DNS before retrying. - Still using
fake.domain.com/[email protected]. These are placeholders incertbot/compose.yml. Certbot will fail (or issue a cert nobody can use) until you set them to real values and rebuild. - Rate limited by Let's Encrypt. Let's Encrypt caps retries per domain per week. Test with their staging environment first if you're iterating on config.
- Certificate doesn't renew automatically. See Renew the certificate,
./laradock restart certbot(or your own cron) is required, there's nothing automatic here.
Pair this with nginx or Apache2 to actually serve HTTPS traffic. New to Laradock? Start at Getting Started.