Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@AfroThundr3007730
Last active March 30, 2024 23:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save AfroThundr3007730/d23f64f72d6fba9272586f0d3adf8442 to your computer and use it in GitHub Desktop.
Save AfroThundr3007730/d23f64f72d6fba9272586f0d3adf8442 to your computer and use it in GitHub Desktop.
Renews my LetsEncrypt certificates if they expire in less than 3 days.

This gist includes a certificate renewal script, which I use to renew both of my LetsEncrypt certificates, as well as the systemd unit files necessary to automate it. It's currently set to run every 12 hours, and renews the certificates if they expire in less than 3 days. The certbot tool is required in order to use this script. Note that I generated my keys and CSR manually because I needed to add specific extensions to my certificates. That process is not covered here.

Filename Description
01-getcert.sh The certificate renewal script.
02-cli.ini Example Certbot configuration.
03-getcert.timer The systemd timer unit file.
04-getcert.service The systemd service unit file.
05-openssl.conf Example openssl.conf for the CSR
06-getcert-ddns.sh DDNS version of the renewal script.
#!/bin/bash
# Certbot automated renewal script by AfroThundr
# Uses the tls-alpn-01 challenge for renewal
# This runs twice since I use two certificates (RSA and ECDSA)
# Version 1.2.3 updated 20240304
# SPDX-License-Identifier: GPL-3.0-or-later
# Declare some variables...
dom=example.com
cfg=/etc/letsencrypt/cli.ini
dirs=(/etc/ssl/private/letsencrypt{1,2})
service=apache2
cbot="certbot certonly --standalone --preferred-challenges tls-alpn-01 \
--config $cfg --keep-until-expiring --agree-tos --expand"
for dir in "${dirs[@]}"; do
# Check if cert is close to expiring first
printf 'Checking for certificate expiration...\n'
now=$(date -ud "now" +%s)
exp=$(date -ud "$(openssl x509 -in "$dir"/"$dom".crt -enddate -noout |
cut -d= -f 2)" +%s)
days_exp=$(bc <<<"( $exp - $now ) / 86400")
# Begin renewal process only if cert is expiring soon
if [[ $days_exp -le ${days_min:=3} ]]; then
printf 'Certificate expiring soon, proceeding with renewal.\n'
# Stop web server if running, then leave flag
[[ $RENEW == true ]] || {
systemctl stop $service
RENEW=true
}
# Backup existing files, then renew cert
if [[ -f "$dir"/"$dom".crt ]]; then
mv "$dir"/"$dom".crt{,.bak}
mv "$dir"/ca-chain.pem{,.bak}
mv "$dir"/"$dom".pem{,.bak}
fi
printf 'Running renewal on %s\n' "$dir"/"$dom".crt
$cbot --csr "$dir"/"$dom".csr --cert-path "$dir"/"$dom".crt \
--chain-path "$dir"/ca-chain.pem --fullchain-path "$dir"/"$dom".pem
# If successful, remove backups; if not, revert
if [[ -f "$dir"/"$dom".crt ]]; then
rm -f "$dir"/*.bak
chmod 0600 "$dir"/*
else
mv "$dir"/"$dom".crt{.bak,}
mv "$dir"/ca-chain.pem{.bak,}
mv "$dir"/"$dom".pem{.bak,}
fi
printf 'Certificate renewal complete.\n'
fi
# Start web server, if stopped by us
[[ $RENEW == true ]] && systemctl start $service
done
# Nothing to do, time to go.
printf 'Certificates are up to date, exiting.\n'
exit 0
# This is an example of the kind of things you can do in a configuration file.
# All flags used by the client can be configured here. Run Certbot with
# "--help" to learn more about the available options.
# Use a 4096 bit RSA key instead of 2048
rsa-key-size = 4096
# Uncomment and update to register with the specified e-mail address
email = root@example.com
# Uncomment and update to generate certificates for the specified domains.
domains = example.com, www.example.com, foo.example.com
# Uncomment to use a text interface instead of ncurses
text = True
# Uncomment to use the standalone authenticator on port 443
# authenticator = standalone
# standalone-supported-challenges = tls-alpn-01
# Uncomment to use the webroot authenticator. Replace webroot-path with the
# path to the public_html / webroot folder being served by your web server.
# authenticator = webroot
# webroot-path = /var/www/html
[Unit]
Description=LetsEncrypt certificate renewal timer
[Timer]
OnCalendar=0/12:15
RandomizedDelaySec=1800
Persistent=1
[Install]
WantedBy=timers.target
[Unit]
Description=LetsEncrypt certificate renewal service
[Service]
Type=simple
ExecStart=/usr/local/sbin/getcert
PrivateTmp=true
StandardOutput=syslog
[ req ]
default_bits = 3072
encrypt_key = yes
distinguished_name = req_dn
string_mask = utf8only
default_md = sha384
x509_extensions = server_cert
req_extensions = server_cert
[ req_dn]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address
countryName_default = US
stateOrProvinceName_default = MD
localityName_default =
0.organizationName_default = My Orginazation
organizationalUnitName_default =
emailAddress_default =
[ server_cert ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
keyUsage = critical, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = email:move
subjectAltName = @san_ext
# Following not needed unless you want mandatory OSCP stapling.
tlsfeature = status_request
[ san_ext ]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = foo.example.com
#!/bin/bash
# Certbot automated renewal script by AfroThundr
# Alternate version using Dynamic DNS (RFC 2136)
# See https://certbot-dns-rfc2136.readthedocs.io
# Version 1.2.3 updated 20240304
# SPDX-License-Identifier: GPL-3.0-or-later
# Declare some variables...
dom=example.com
cfg=/etc/letsencrypt/cli.ini
dns=/etc/letsencrypt/dns.ini
dirs=(/etc/ssl/private/letsencrypt)
service=nginx
cbot="certbot certonly --dns-rfc2136 --dns-rfc2136-credentials $dns \
--config $cfg --keep-until-expiring --agree-tos --expand"
for dir in "${dirs[@]}"; do
# Check if cert is close to expiring first
printf 'Checking for certificate expiration...\n'
now=$(date -ud "now" +%s)
exp=$(date -ud "$(openssl x509 -in "$dir"/"$dom".crt -enddate -noout |
cut -d= -f 2)" +%s)
days_exp=$(bc <<<"( $exp - $now ) / 86400")
# Begin renewal process only if cert is expiring soon
if [[ $days_exp -le ${days_min:=3} ]]; then
printf 'Certificate expiring soon, proceeding with renewal.\n'
# Leave flag if renewing certificate
${RENEW:=true}
# Backup existing files, then renew cert
if [[ -f "$dir"/"$dom".crt ]]; then
mv "$dir"/"$dom".crt{,.bak}
mv "$dir"/ca-chain.pem{,.bak}
mv "$dir"/"$dom".pem{,.bak}
fi
printf 'Running renewal on %s\n' "$dir"/"$dom".crt
$cbot --csr "$dir"/"$dom".csr --cert-path "$dir"/"$dom".crt \
--chain-path "$dir"/ca-chain.pem --fullchain-path "$dir"/"$dom".pem
# If successful, remove backups; if not, revert
if [[ -f "$dir"/"$dom".crt ]]; then
rm -f "$dir"/*.bak
chmod 0600 "$dir"/*
else
mv "$dir"/"$dom".crt{.bak,}
mv "$dir"/ca-chain.pem{.bak,}
mv "$dir"/"$dom".pem{.bak,}
fi
printf 'Certificate renewal complete.\n'
fi
# Restart dependent service, if certificate renewed
[[ $RENEW == true ]] && systemctl restart $service
done
# Nothing to do, time to go.
printf 'Certificates are up to date, exiting.\n'
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment