Effective + Simple Way to Manage & Obtain Multiple Let’s Encrypt Certificate for Different Domains Using a Small Shell Script

Published by Philipp Schuster on

Yesterday I faced the problem that I need a convenient way to manage multiple domains on the same host/IP. I have “main” domains with potentially further sub-domains. How can one optimize the retrieval of certificates without writing all the shell commands manually or look ’em up in the shell history? I asked myself this question and came up with this solution, not sure if my solution is ideal but it is effective and works.

What if one wants certificates for domains sub1.example.com, example.com, sub1.example.org, sub2.example.org, and example.info? We could obtain one big certificate using

$ sudo certbot --standalone --preferred-challenges http -d sub1.example.com, example.com, sub1.example.org,sub2.example.org,example.info

but this is not cool. We could use three individual commands for each main domain and its subdomains. But what if we want to add a sub domain in the future and want to reuse the command, without searching long for it in the history? I automatized this process.

Let there be a directory structure as seen below:

domains
├── domain_com.example
├── domain_org.example
└── domain_info.example

Suppose each file with prefix “__domain” has content that is structured as follows:

# add all sub domains here; comments are ignored
# MAIN domain must be first entry
# all domains that belong to this certificate

example.org
sub1.example.org
gitlab.example.org

My shell script domains.sh would create three certificates at /etc/letsencrypt/live/example.{com,org,info}/ out of the directory structure in this example. If you want to add more subdomains in the future, you edit the domain txt file (shown above) and rerun domains.sh. Hence, the certificate in the lets encrypt path will be updated automatically. Note that you have to execute the script with bash or zsh but not sh.

#!/bin/zsh
echo "aquires let's encrypt for all domains specified in domains.txt in standalone mode"

# dir with text files that contains the primary domain plus all sub domains
# this way we have disjunct certificates for all sub domains and not one single BFR
DOMAINS_DIR="./domains"
for DOMAIN_FILE in $DOMAINS_DIR/domain_*
do
	# construct the command/domain string for a main domain and all its sub domains
	# and obtains a certificate

	DOMAINS_CMD_STR=""
	while read DOMAIN; do
		# reading each line

		# ignore all comment lines AND empty lines
	    if (echo "$DOMAIN" | grep -q --invert-match '#') && (echo "$DOMAIN" | grep .); then
	    	# main domain must come first, because this is the name where
	    	# the certificates are located in /etc/letsencrypt
	        DOMAINS_CMD_STR="$DOMAINS_CMD_STR,$DOMAIN"
	    fi
	done < $DOMAIN_FILE

	# remove beginning/trailing comma
	DOMAINS_CMD_STR=$(echo $DOMAINS_CMD_STR | sed 's/,//')

	# e.g. "domain1.tld,domain2.tld,...,domainN.tld"
	# echo "$COMMANDS_STRING"

    sudo certbot certonly --standalone --preferred-challenges http -d $DOMAINS_CMD_STR
done

Philipp Schuster

Hi, I'm Philipp and interested in Computer Science. I especially like low level development, making ugly things nice, and de-mystify "low level magic".

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *