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