How to add wildcard HTTPS on digitalocean using certbot (ubuntu 20 + NGINX)

How to add wildcard HTTPS on digitalocean using certbot (ubuntu 20 + NGINX)

A detailed guide how to setup SSL using certbot for subdomains on digitalocean | ubuntu | nginx

Why?

  • I want my web applications secure (SSL)
  • I want to deploy multiple web applications (wildcard), *.mydomain.com
  • I want a more detailed step by step because the official one is way to short

DISCLAIMER: The base for these command is the official letsencrypt+certbot documentaion with extra details for digital ocean and Nginx. All links are at the end.

1 - Create a server

Create a new ubuntu 20.04 (LTS) Droplet at your digitalocean account Add your SSH key where you can ssh to it) Copy its Public IP address

2 - Server basic bootstrap

Access it, using the following command:

ssh root@PUBLIC_IP

Run the following commands

export PATH=$PATH:/usr/bin

sudo apt-get update
sudo apt-get install -y vim htop build-essential \
    libssl-dev libffi-dev net-tools \
    python3-dev python3-pip python-setuptools

# snap to install the certbot
sudo snap install core; sudo snap refresh core

3 - Non root user

Creates a non root user for better security and use it for SSH instead of root

export NEW_USER=ubuntu

# Creates a new user (as sudor)
adduser $NEW_USER
usermod -aG sudo $NEW_USER

# Copy the SSH Key to it (you can ssh using it instead of root)
mkdir /home/$NEW_USER/.ssh
chmod 700 /home/$NEW_USER/.ssh
sudo cp /root/.ssh/authorized_keys /home/$NEW_USER/.ssh/authorized_keys
sudo chown -R $NEW_USER:$NEW_USER /home/$NEW_USER/.ssh
sudo chmod 600 /home/$NEW_USER/.ssh/authorized_keys

# Change to the new user (or you can open a new ssh terminal)
su - $NEW_USER

4 - Install NGINX and firewall

sudo apt-get install -y nginx

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'
sudo ufw enable

5 - Install certbot and its digitalocean plugin

sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap set certbot trust-plugin-with-root=ok

# Digital ocean plugin
sudo snap install certbot-dns-digitalocean

# Add the credentials for digital ocean (see tips below)
mkdir -p ~/.secrets/certbot/
export DO_TOKEN=00001111229aaaabbbbccccddddeeeeffff...

echo "dns_digitalocean_token = $DO_TOKEN" > ~/.secrets/certbot/digitalocean.ini
chmod 600 ~/.secrets/certbot/digitalocean.ini

TIP: Logged in you DO account, inside de API area, it's possible to create a new token and export it as DO_TOKEN

6 - Create an initial page and make NGINX redirect to it

systemctl status nginx

sudo mkdir -p /var/www/billcode.com.br/html
sudo chown -R $USER:$USER /var/www/billcode.com.br/html
sudo chmod -R 755 /var/www/billcode.com.br

# Add the content bellow to the following file:
vim /var/www/billcode.com.br/html/index.html

<html>
  <head>
    <title>Welcome to my secure site!</title>
  </head>
  <body>
    <h1>Success! ๐Ÿ˜Š</h1>
  </body>
</html>

# Add the content bellow to the following file:
sudo vim /etc/nginx/sites-available/billcode.com.br

server {
    listen 80;
    listen [::]:80;
    server_name billcode.com.br;

    root /var/www/billcode.com.br/html;
    index index.html index.htm index.nginx-debian.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

# Enable it
sudo ln -s /etc/nginx/sites-available/billcode.com.br /etc/nginx/sites-enabled/

# Enable the bucket size on nginx.conf
sudo vim /etc/nginx/nginx.conf

# remove the comment for
server_names_hash_bucket_size 64;

# Check if all the nginx files are correct
sudo nginx -t

# Apply the changes
sudo systemctl restart nginx

At this point, you can access your URL (yourdomain.com) and check the HTML (Success!)

7 - Generate the certificate using wildcard

sudo certbot certonly \
--cert-name billcode.com.br \
--dns-digitalocean \
--dns-digitalocean-credentials ~/.secrets/certbot/digitalocean.ini \
--server https://acme-v02.api.letsencrypt.org/directory \
-d "*.billcode.com.br" \
-d billcode.com.br \
-i nginx

Make sure the the nginx file has the following content. NOTE: If the above command didn't add automatically the content bellow, you must add it manually.

sudo vim /etc/nginx/sites-available/billcode.com.br
# /etc/nginx/sites-available/billcode.com.br

server {
    listen 80;
    listen [::]:80;
    server_name *.billcode.com.br;

    return 301 https://$host$request_uri;
}

server {

    listen 443 ssl;
    server_name *.billcode.com.br;

    ssl_certificate /etc/letsencrypt/live/billcode.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/billcode.com.br/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    error_log  /var/log/nginx/billcode-error.log warn;

    client_max_body_size 20m;

    location / {
        root /var/www/billcode.com.br/html;
        try_files $uri $uri/ /index.html;
        index index.html;
    }
}

Check the nginx again and apply the changes:

sudo nginx -t
sudo systemctl restart nginx

At this point your domain should display the page (html) using HTTPS

8 - Wildcard

Because we created a wildcard certificate, we can deploy multiple applications using subdomains, for example, to server a second app or site:

A) Make sure your digitalocean domain settings has a CNAME using the wildcand:

DNS records
Type                  Hostname
CNAME             *.billcode.com.br

B) Add a second nginx config file point to another application

# /etc/nginx/sites-available/app2.billcode.com.br

server {
    listen 80;
    listen [::]:80;
    server_name app2.billcode.com.br;

    return 301 https://$host$request_uri;
}

server {

    listen 443 ssl;
    server_name app2.billcode.com.br;

    ssl_certificate /etc/letsencrypt/live/billcode.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/billcode.com.br/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    error_log  /var/log/nginx/app2.billcode-error.log warn;

    client_max_body_size 20m;

    location / {
        root /home/ubuntu/repos/app2;
        try_files $uri $uri/ /index.html;
        index index.html;
    }
}

9 - Renew the certificate

The certificate will last only 3 months, follow the official documentation and make sure the crontab has the command to renew it.

The way I did it and I'm not sure it's the best one: First, I ran the command in DRY mode to check if it's working:

sudo certbot renew --dry-run

Then I've the command in my crontab, since my certificated was first created on 27/May, so I've used the following crontab entry:

##### min
#
#  #### hour
#  #
#  #  #### day
#  #  #
#  #  #  #### month
#  #  #  #
#  #  #  #               #### day of week
#  #  #  #               #
#  #  #  #               # ##### script
#  #  #  #               # #
1  0  27 May,Aug,Nov,Feb * certbot renew

In this way, it will run on the first minute of 27 of May, Aug, Nov and Feb. If you have a better way to do it, please, let me know!

Use the crontab as sudo to add the entry above for the root user:


sudo crontab -e

I hope this post help you, otherwise, let me know what's missing! Cheers

References

ย