Skip to content
Go back

Managing multiple SSL certificates for staging web server

Updated: 

Table of Contents

Open Table of Contents

Issuing certificates

Most straightforward and easy way to issue a certificate for a Nginx server is with certbot. Apart from native support for Nginx and Apache, you can pretty much use it with most popular Unix-based OS like Debian or Ubuntu.

Issuing a certificate is as easy as

certbot certonly -d '${BRANCH}.staging.com'\
    -d 'subdomain1.${BRANCH}.staging.com'\
    -d 'subdomain2.${BRANCH}.staging.com'\
    --webroot --webroot-path /var/www/subdomains/$BRANCH/public\
    --non-interactive;

This will issue a single certificate with the shortest name ('${branch}.staging.com' for given example) for all specified domains (-d $domain).

Including all subdomains into one certificate is magnitudes faster than issuing one for each subdomain. Also, you get one files, which is easy to manage in web server configs.

If you have a lot of different deployments on one server, it is probably better to set up everything one time. Hence, the certonly command, which will not tweak our web server configuration.

webroot plugin allows to not stop web server for each deployment and change content on the fly, like updating deployment on branch update.

Since we’re automating everything, use --non-interactive won’t ask for any prompts.

Configuring nginx .conf file for webroot plugin

With webroot plugin certbot performs HTTP challenge for files placed in $webroot/.well-known/acme-challenge/, so we need a separate piece of code to allow access to those files. You can’t serve content via HTTPS without a certificate, so we need to allow access to challenges via HTTP.

server {
    listen 80;
    server_name staging.com ~^(subdomain1\.|subdomain2\.|)((?<branch>.+)\.|)staging\.com$;

    set $dir "test";
    if ($branch != "") {
        set $dir branches/${branch};
    }
 
    location /.well-known/ {
        autoindex on;
        alias /var/www/$dir/public/.well-known/;
    }

    location / {
        return 403;
    }
}

This will allow access to content from .well-known folder via HTTP, and return 403 for any other locations.

To use issued certificate, you can just copy configuration from nginx plugin into your configuration file. Make sure to properly setup dynamic certificate names for different domains.

server {
    #...
    # ssl
    ssl_certificate /etc/letsencrypt/live/$certname/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$certname/privkey.pem;

    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
    ssl_ecdh_curve secp384r1;

    ssl_stapling on;
    ssl_stapling_verify on;
    #...
}

Testing configuration

Before issuing a real certificates, you want to perform dry runs testing command without any system writes. Before running into rate limit issue, I didn’t know letsencrypt has one. Just pass --staging or --test-cert flags to test your configuration.

certbot certonly\
    -d 'staging.com'\
    -d 'subdomain1.staging.com'\
    -d 'subdomain2.staging.com'\
    --webroot --webroot-path /var/www/test/public\
    --staging --non-interactive;

Don’t forget to revoke and delete issued certificate after success (notice how we still pass --staging flag).

certbot revoke\
    --cert-name staging.com\
    --delete-after-revoke\
    --staging\
    --non-interactive;

Renewing certificates

As with issuing certificates, you should dry run renewal process.

certbot renew\
    --cert-name "${BRANCH}.staging.com"\
    --dry-run\
    --non-interactive;

If this succeeds, then your certificate is valid and you can successfully use it for HTTPS connections. Run following commands to add a cronjob.

SLEEPTIME=$(awk 'BEGIN{srand(); print int(rand()*(3600+1))}'); echo "0 0,12 * * * root sleep $SLEEPTIME && certbot renew -q" | sudo tee -a /etc/crontab > /dev/null

Since lifetime of a staging deployment is much shorter than certificate’s lifetime, I don’t usualy do it.

Deleting certificates

As outlined in testing section, you can delete your certificates with the following script (don’t forget to revoke it!).

certbot revoke\
    --cert-name "${BRANCH}.staging.com"\
    --delete-after-revoke\
    --non-interactive;

Please be careful and don’t omit dry runs and tests of your configuration before shipping to production. You can also read official user guide of certbot.


Share this post on:

Previous article
Optimizing Web Assets, Part 1, General Ideas
Next article
Guide to HTML dark mode responsive images