A beginner's guide to automated SSL certificate renewal with Let's Encrypt and Certbot on Nginx using Docker

This blog provides a step-by-step guide on automating the SSL certificate renewal process using Let's Encrypt and Certbot on an Nginx web server within a Docker container. It explains the importance of SSL certificates for website security, introduces Let's Encrypt as a cost-effective solution, and emphasizes the need for automating certificate renewal due to Let's Encrypt's 90-day validity period.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

A beginner's guide to automated SSL certificate renewal with Let's Encrypt and Certbot on Nginx using Docker

SSL certificates are an essential component of website security. They provide a secure connection between a website and its visitors, ensuring that sensitive information, such as login credentials and payment details, is encrypted and protected from cyber threats.

Let’s Encrypt as Solution:

Let’s Encrypt is a trusted SSL certificate authority provider that offers free trusted SSL certificates for one domain. By using Let's Encrypt, you can secure your website with a trusted SSL certificate without paying any fees. This makes it an excellent choice for small businesses and personal websites that want to provide a secure browsing experience for their visitors. Get started with Let's Encrypt today and enjoy the benefits of a secure website!

The Need for Automating SSL Certificate Renewal:

Automating the SSL certificate renewal process is crucial for maintaining the security and trustworthiness of your website. Let's Encrypt free SSL certificates expire every 90 days, which means you need to renew them regularly to ensure uninterrupted service. Manually renewing SSL certificates can be a time-consuming and error-prone process, especially if you have multiple domains or subdomains. That's why automating the SSL certificate renewal process is essential. By automating the process, you can ensure that your SSL certificates are always up-to-date and that your website remains Safe.

Self-signed SSL certificates

Self-signed SSL certificates are created by the domain owner to support HTTPS and SSL handshakes before establishing a connection between the client and server. However, these certificates are not verified by a trusted certificate authority, making them insecure. When visitors connect to a website with a self-signed certificate, their browser fails to verify the domain's identity, making it easier for attackers to perform man-in-the-middle attacks and intercept sensitive information. 

SSL trusted by Certificate Authority Provider

To verify the identity of a domain, web browsers rely on trusted third-party SSL certificate providers. By using a trusted certificate authority (CA), visitors to a website can ensure that their information transmitted over networks is encrypted and the connection is secure. This is why businesses and organizations opt for SSL certificates provided by trusted CAs. 

Type of SSL Certificate

There are 3 types of certificates that can be procured using the let’s encrypt.

  • Wild-Card Trusted SSL CA
    Wild-Card Trusted SSL CA covers all sub-domains of a domain with a single certificate
  • Multiple sub-domain Trusted SSL CA
    Multiple sub-domain Trusted SSL CA covers several specific sub-domains with a single certificate
  • Single sub-domain Trusted SSL CA
    Single sub-domain Trusted SSL CA covers only one specific sub-domain with a single certificate.

In this, article we will use the example of a single sub-domain trusted SSL CA provided for free by Let’s Encrypt SSL CA Provider. However, the third-party providers require verification that the person or entity who is requesting for trusted SSL certificate can actually authorized to manage and control the DNS.
There are various types of verification challenges such as email verification and DNS Record entry or SMS-based OTP verification though these types of processes require some level of human intervention. This is the reason for most business entities fail to automate this process. 
Let’s Encrypt also provides CLI and supports one more verification process named acme-challenge. ACME is a protocol used by the third party to ensure the DNS belongs to the person or the entity requesting the Trusted SSL CA. In the below example, we will understand how to procure the trusted SSL Certificate automatically.

Version: '3'

    image: nginx
      environment: ${ENVIRONMENT}
      - ./configs/${NGINX_CONFIG}:/etc/nginx/nginx.conf:ro
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
      - 80:80
      - 443:443
    restart: always
    command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

    image: certbot/certbot
      - ./data/certbot/conf:/etc/letsencrypt
      - ./data/certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 89d & wait $${!}; done;'"

In the above, example we have created 2 services one for Nginx and Certbot. Both services share the same volumes as the certbot will procure the Trusted SSL certificate and re-news it once expires. Once, the SSL certificate is created the Nginx service will consume it.

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;

http {
    server {
        listen 80;
        listen [::]:80;
        server_name <DNS>;

        location ~ /.well-known/acme-challenge {
            allow all;
            root /var/www/certbot;

Note: To automate the whole process it relies upon the HTTP (80) Port. So, make sure that the inbound ports are exposed publicly.

In the above Nginx configuration, we have exposed an end-point that will be consumed by the third party to complete the acme-challenge


By using the above end-points let’s encrypt ensures via the public and private key-based authentication.


if ! [ -x "$(command -v docker-compose)" ]; then
  echo 'Error: docker-compose is not installed.' >&2
  exit 1

email="<DNS-OWNER-EMAIL>" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits

if [ -d "$data_path" ]; then
  read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
  if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then

if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
  echo "### Downloading recommended TLS parameters ..."
  mkdir -p "$data_path/conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
  curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"

echo "### Creating dummy certificate for $domains ..."
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
  openssl req -x509 -nodes -newkey rsa:$rsa_key_size -days 1\
    -keyout '$path/privkey.pem' \
    -out '$path/fullchain.pem' \
    -subj '/CN=localhost'" certbot

echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx

echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
  rm -Rf /etc/letsencrypt/live/$domains && \
  rm -Rf /etc/letsencrypt/archive/$domains && \
  rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot

echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
for domain in "${domains[@]}"; do
  domain_args="$domain_args -d $domain"

# Select appropriate email arg
case "$email" in
  "") email_arg="--register-unsafely-without-email" ;;
  *) email_arg="--email $email" ;;

# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi

docker-compose run --rm --entrypoint "\
  certbot certonly --webroot -w /var/www/certbot \
    $staging_arg \
    $email_arg \
    $domain_args \
    --rsa-key-size $rsa_key_size \
    --agree-tos \
    --force-renewal" certbot

echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload

Above, script will procure the SSL certificate trusted by third party CA Provider and the validity of the certificate will be 90 days. So, run the script on your machine to procure the certificate for the first time. But, what happens if after 90 days and certificate expires?
Well, we already have set up the entry-point command of the certbot container in docker-compose.yaml to run after 89 days. However, we will have to keep running the cert docker container. 
However, if you do not want to keep it running then let’s set up a cron job that will run the script for us at the interval of 89 days. Or you can set the interval according to your needs. For instance, a day before the SSL certificate expires. i.e. 89 days.

0 0 */89 0 0 docker run --rm -it --name certbot -v 
"/docker-volumes/data/letsencrypt:/data/letsencrypt" -v 
"/docker-volumes/etc/letsencrypt:/etc/letsencrypt" -v 
"/docker-volumes/var/lib/letsencrypt:/var/lib/letsencrypt" -v 
"/docker-volumes/var/log/letsencrypt:/var/log/letsencrypt" certbot/certbot renew --webroot -w 
/data/letsencrypt --quiet && docker kill --signal=HUP production-nginx-container


As a trusted SSL certificate authority provider, Let's Encrypt offers free SSL certificates for 90 days. By automating the SSL certificate procurement process, small business owners who require a single domain can save money while still ensuring their website is secure and encrypted with sensitive information.
No matter which web server you are using or the type of SSL certificate. Using the above process you can still automate the process of renewing trusted SSL certificate CA by let’s encrypt.!

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.