nginx-certbot icon indicating copy to clipboard operation
nginx-certbot copied to clipboard

Multiple domains don't really work well!

Open masikh opened this issue 2 years ago • 5 comments

My proposed fix is below:

Main difference: Use each item from the array of domains...

#!/bin/bash

domains=(www.domain.com cdn.domain.com api_domain.com registry.domain.com www-registry.domain.com)
rsa_key_size=4096
data_path="./data/certbot"
email="[email protected]"              # Adding a valid address is strongly recommended
staging=1                             # Set to 1 if you're testing your setup to avoid hitting request limits

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

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
    exit
  fi
fi


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
fi

for domain in "${domains[@]}"
do
    echo "### Creating dummy certificate for ${domain} ..."
    path="/etc/letsencrypt/live/$domain"
    mkdir -p "$data_path/conf/live/$domain"
    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
done

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

for domain in "${domains[@]}"
do
    echo "### Deleting dummy certificate for ${domain} ..."
    docker-compose run --rm --entrypoint "\
      rm -Rf /etc/letsencrypt/live/$domain && \
      rm -Rf /etc/letsencrypt/archive/$domain && \
      rm -Rf /etc/letsencrypt/renewal/$domain.conf" certbot
    echo
done

for domain in "${domains[@]}"; do
    echo "### Requesting Let's Encrypt certificate for ${domain} ..."
    # Select appropriate email arg
    case "$email" in
      "") email_arg="--register-unsafely-without-email" ;;
      *) email_arg="--email $email" ;;
    esac

    # 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 \
        -d $domain \
        --rsa-key-size $rsa_key_size \
        --agree-tos \
        --force-renewal" certbot
    echo
done

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

masikh avatar May 17 '23 15:05 masikh

Worked like a charm, thanks @masikh !

dontic avatar Aug 11 '23 10:08 dontic

I disagree, the original script works very well for multiple domains.

When I first read the script, I was also a bit surprised by this mkdir statement:

domains=(example.org www.example.org)
rsa_key_size=4096
data_path="./data/certbot"
# ...
mkdir -p "$data_path/conf/live/$domains"

But this is actually fine, domains is a Bash array, and using $domains will give you the first element of the array.

Try this:

echo "The value of domains is: $domains"

It will print The value of domains is: example.org, without mentioning the second domain www.example.org. So the mkdir command is fine.

Now as far as the actual certbot command is concerned, the original script is IMHO much better than @masikh's version above, because it only creates one certificate, which is valid for all the given domains. The above version on the other hand creates a separate certificate for every domain.

https://eff-certbot.readthedocs.io/en/stable/using.html#certbot-command-line-options says:

-d DOMAIN, --domains DOMAIN, --domain DOMAIN
                        Domain names to include. For multiple domains you can
                        use multiple -d flags or enter a comma separated list
                        of domains as a parameter. All domains will be
                        included as Subject Alternative Names on the
                        certificate. The first domain will be used as the
                        certificate name, unless otherwise specified or if you
                        already have a certificate with the same name. In the
                        case of a name conflict, a number like -0001 will be
                        appended to the certificate name. (default: Ask)

dietmar avatar Sep 20 '23 10:09 dietmar

The problem seem to be that what @dietmar is saying works only for bash. In bash I get the same result that you got executing:

echo "The value of domains is: $domains"

But when executing the same 2 commands (including the same variable assignment) in zsh I got:

The value of domains is: example.org www.example.org

hguilla avatar Sep 24 '23 13:09 hguilla

Met the same issue today on Ubuntu 20.0.4. I defined 2 domains in array, but all commands were completed for first domain only. I like the solution by masich more, because it's more intuitive, it's easier to read the code with explicitly defined cycles, and ofk it's more convinient to debug it.

kzkvv avatar Jan 21 '24 14:01 kzkvv

Each has its own advantages, @masich is solution allows ssl for multiple different primary domains,@dietmar can only be configured for multiple second-level domain names under a single primary domain name

ip520011 avatar Jul 11 '24 03:07 ip520011