DEV Community

Cover image for Setup HTTPS with NGINX and Certbot
Quartz Technology
Quartz Technology

Posted on

Setup HTTPS with NGINX and Certbot

Table of content

During the deployment of a new application, it is common to make the application accessible through a domain name.

This is a simple step, really satisfying, but I used to struggle a bit when I started to do it for my first client.

Project architecture are usually the same, you got a proxy like NGINX that will take care of the redirection to your application(s).
As security measure you setup a firewall and open port 80 and 443 to allow traffic on HTTP and HTTPS.

Basic application deployment on a VPS using NGINX as proxy exposing port 80 and 443

And then it comes to set up HTTPS, and questions like "should I expose my application before enabling HTTPS?", "how do I just do that?", "wait, where do I store those configuration files?".

This article targets beginners who want a simple and fast way to set HTTPS on any application deployed on a VPS.

Why set up HTTPS?

A bit of theory before starting, why is it important to set up HTTPS on your application?

Basically, HTTPS adds a security layer around HTTP protocol thanks to TLS encryption.
When a request is sent with HTTPS, it hides the content of the request, so it cannot be intercepted and used by an attacker.

Here is a great article from CloudFlare for the most curious.

Set up VPS environment

For this guide, I'll use a basic VPS with Ubuntu as operating system and the domain name example.vasek.technology.

To begin, we need to install Nginx and Certbot.

Nginx is a powerful tool for web serving. We will use it to catch requests sent to the domain name and redirect them to the application.
Certbot is a simple CLI to set HTTPS on a server.

You do not need to set up your application to enable HTTPS, you can do that later.

Let's install Nginx.

# Update apt dependencies
sudo apt update

# Install Nginx
sudo apt install nginx -y
Enter fullscreen mode Exit fullscreen mode

This will automatically set up Nginx as a service in your VPS so it will be automatically restart if you shut down your VPS and start it later.

You can verify that Nginx is correctly configured with sudo systemctl status nginx.

sudo systemctl status nginx result showing running status

You should also see a new folder in etc/nginx containing a lot of files and folders.
Let's not pay attention to them for now.

conf.d          koi-utf     modules-available  proxy_params     sites-enabled  win-utf
fastcgi.conf    koi-win     modules-enabled    scgi_params      snippets
fastcgi_params  mime.types  nginx.conf         sites-available  uwsgi_params
Enter fullscreen mode Exit fullscreen mode

If you go to your IP address on your web browser, you should also see the default Nginx welcome page.

Nginx welcome page

Let's now install Certbot, to do so we will need Python.

# Install python3
sudo apt install python3 python3-venv libaugeas0

# Set up a virtual environment to not conflict with our local one
sudo python3 -m venv /opt/certbot/

# Install pip in this environment
sudo /opt/certbot/bin/pip install --upgrade pip

# Install Certbot with nginx plugin
sudo /opt/certbot/bin/pip install certbot certbot-nginx

# Create a symbolic link to access use certbot from anywhere
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot

# Verify certbot is installed
certbot --version
# certbot 2.3.0
Enter fullscreen mode Exit fullscreen mode

Link domain name to VPS IP

It is time to link your domain name to the VPS IP, so you can access the page from it.

I personally use Google Domain but any domain name manager works. Let's create a A record that points to your VPS IP.

Domain name A record creation example on Google Domain

After few minutes, you should be able to access your website on this domain name.

Nginx welcome page accessed through domain name

But as you see, it is still written as not secure. Let's fix that!

Set up basic Nginx configuration

Create a new file nginx.conf anywhere in your VPS and add the most basic configuration that will simply serve the welcome page.
We will set up a symbolic link later to let Nginx use it.

server {
    # Listen on HTTP port (80)
    listen 80;

    # Serve Nginx welcome page
    root /var/www/html;

    # Set domain name to serve.
    server_name example.vasek.technology www.example.vasek.technology;
}
Enter fullscreen mode Exit fullscreen mode

Now we need two last thing.

First, the default index.html page in /var/www/html may not be named properly. By default, Nginx will look for index.html.

In my case, it is always named index.nginx-debian.html, let's rename it
to index.html

# Check for files in /var/www/html
ls /var/www/html
# index.nginx-debian.html

# Rename it to index.html
mv /var/www/html/index.nginx-debian.html /var/www/html/index.html
Enter fullscreen mode Exit fullscreen mode

Secondly, Nginx will process every config files located in /etc/nginx/sites-enabled.
I usually prefer to create a symbolic link to that location, so I can maintain it from my git repository. So others can review it and if it is simpler if I want to change my VPS.

# Create a symbolic link. Make sure to use an absolute path to your nginx config
# file using $PWD variable
ln -s "$PWD/nginx.conf" /etc/nginx/sites-enabled/nginx.conf 

# Show the file to verify the symbolic link has been correctly done.
cat /etc/nginx/sites-enabled/nginx.conf 
server {
    # Listen on HTTP port (80)
    listen 80;
    listen [::]:80;

    # Serve Nginx welcome page
    root /var/www/html;

    # Set domain name to serve.
    server_name example.vasek.technology www.example.vasek.technology;
}
Enter fullscreen mode Exit fullscreen mode

You can also remove the default configure

rm /etc/nginx/sites-enabled/default
Enter fullscreen mode Exit fullscreen mode

Let's verify that our config is correct.

nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
Enter fullscreen mode Exit fullscreen mode

It is normal if you do not see your file in the log, the main config is in /etc/nginx/nginx.conf and includes any files in /etc/nginx/sites-enabled

Now we can reload nginx to apply new configuration.

nginx -s reload
Enter fullscreen mode Exit fullscreen mode

Let's verify if the Nginx is still serving the welcome page on our domain name.

Nginx welcome page accessed through domain name

Use Certbot to enable HTTPS

It is time set up HTTPS on our domain name. Let's run Certbot.

# Generate SSL certificate using certbot.
certbot --nginx -d example.vasek.technology --email tom@quartz.technology
Enter fullscreen mode Exit fullscreen mode

Note that the --email is an important option, you should provide a valid address email that will stay in time. This email is used as proof of ownership and is used by site like Whois to record all domain names and their owner.

If you take a look at your nginx.conf, you will see a lot of changes.

server {    
    # Serve Nginx welcome page
    root /var/www/html;

    # Set domain name to serve.
    server_name example.vasek.technology www.example.vasek.technology;

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.vasek.technology-0001/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.vasek.technology-0001/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    # Redirect HTTP to HTTPS
    if ($host = example.vasek.technology) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    listen [::]:80;
    server_name example.vasek.technology www.example.vasek.technology;
    return 404; # managed by Certbot
}
Enter fullscreen mode Exit fullscreen mode

The file has been updated by Certbot to serve HTTPS on your domain name and also redirect HTTP traffic to HTTPS.
It may be a bit messy so clean extra spaces and reorder tabs if necessary.

You can go back on your domain name and see that HTTPS is now enable.

Nginx welcome page accessed through domain name with HTTPS

Congratulation! You can now update your configuration to serve your application after deploying it on your VPS.

For example

    # Serve Nginx welcome page
    # Replaced by location
    # root /var/www/html;


    # Redirect request to application listening on
    # port 3000 in the VPS.
    location / {
        proxy_pass http://localhost:3000;
    }
Enter fullscreen mode Exit fullscreen mode

I hope this article was useful to you! I remember my first time struggling to add HTTPS on my first application with 10 different tabs opened about Nginx and its obscure configuration.

Feel free to reach me out or comment if you have any question 🚀

Written by Vasek - Tom C. for Quartz.

Top comments (0)