Skip to main content

TLS and Certbot

Certbot / Let's Encrypt

Tested on Ubuntu 20.04. Not supported on Ubuntu 14.04.

Install

sudo snap install core && sudo snap refresh core
sudo apt remove certbot # remove any apt-packaged version first
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo ufw allow 443

The old ppa:certbot/certbot PPA is deprecated; the snap is the supported route.

Everyday commands

certbot --version
sudo certbot certificates # list installed certificates
sudo certbot renew # renew everything near expiry
sudo certbot renew --dry-run # test renewal without touching anything
sudo systemctl status certbot.timer # the automatic-renewal timer
sudo certbot delete --cert-name www.domain.net

Issue a certificate

Standalone (Certbot runs its own temporary web server on port 80/443):

sudo certbot certonly --standalone -d your_domain1 -d your_domain2
sudo ls /etc/letsencrypt/live/your_domain

Webroot (your web server keeps running; Certbot writes the challenge into its document root):

sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
# nginx:
# location ^~ /.well-known/acme-challenge/ {
# default_type "text/plain";
# root /var/www/letsencrypt;
# }

certbot certonly --webroot \
--webroot-path /var/www/letsencrypt \
--agree-tos --email [email protected] \
-d example.com -d sub1.example.com

Add names to an existing certificate — list all names, including the ones already covered:

sudo certbot certonly --agree-tos --email [email protected] \
--expand -d example.com -d www.example.com

Key options

OptionMeaning
--apache / --nginxUse the web-server plugin for auth and install
--standaloneRun a temporary standalone server for the challenge
--webrootServe the challenge from an existing web root
--manualInteractive or hook-driven issuance (e.g. DNS)
--agree-tosAccept the ACME subscriber agreement
--expandReissue an existing cert with additional names
--force-renewalRenew even if not near expiry

If port 80 is not reachable from the internet, you must use DNS validation instead of HTTP validation.

Nginx snippet

Certbot writes these into the server block when the nginx plugin is used:

listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

Automatic renewal

The Debian/Ubuntu packages install two renewal mechanisms — a cron job and a systemd timer:

/etc/cron.d/certbot
/lib/systemd/system/certbot.timer -> certbot.service

Modern Certbot prefers deploy hooks in a directory over the deprecated renew_hook line. Reload the web server after a successful renewal:

# /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx
#!/bin/sh
set -e
systemctl reload nginx
chmod +x /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx

Hooks in renewal-hooks/pre, .../deploy and .../post run at those three phases. If you renew in standalone mode while a web server occupies port 80/443, stop it in a pre hook and restart it in a post hook — but note this interrupts service during renewal:

# renewal-hooks/pre/01-stop-nginx -> systemctl stop nginx
# renewal-hooks/post/01-restart-nginx -> systemctl start nginx

Pin a certificate to standalone validation in /etc/letsencrypt/renewal/DOMAIN.conf:

authenticator = standalone
# installer = nginx

Troubleshooting

too many failed authorizations recently — remove the stale account state and retry (rate limits still apply):

rm -rf /etc/letsencrypt/accounts

Java keytool

Manage a Java truststore/keystore. Do not rename the .jks file after creating it — the alias and store are referenced by path elsewhere.

keytool -import -trustcacerts -alias root -file root.crt -keystore server.keystore
keytool -import -trustcacerts -alias cross -file 1_cross_Intermediate.crt -keystore server.keystore
keytool -import -trustcacerts -alias intermediate -file 2_issuer_Intermediate.crt -keystore server.keystore
keytool -import -trustcacerts -alias tomcat -file 3_user_domain.crt -keystore server.keystore

keytool -list -v -keystore server.keystore

Import the chain in order — root first, then each intermediate, then the leaf — so each certificate can be validated against the one above it as it is added.