If you run a Node.js application on your own VPS, you’ll need a solution for obtaining SSL certificates. In this tutorial, we will guide you on how to set up HTTPS using the popular free solution Let’s Encrypt and Certbot.

These are the steps we’ll follow:

  1. Install Certbot
  2. Generate the SSL certificate using Certbot
  3. Allow Express to serve static files
  4. Confirm the domain
  5. Obtain the certificate
  6. Setup the renewal

Install Certbot

To install Certbot on a Linux distribution that uses apt-get to manage packages, run the following commands:

sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

For testing purposes on a Mac (requires Homebrew), you can install Certbot with the following command:

brew install certbot

Please note that you will need to link Certbot to a real domain name for it to be useful.

Generate the SSL certificate using Certbot

Once Certbot is installed, you can generate the SSL certificate by running the following command as root:

certbot certonly --manual

Alternatively, you can use sudo from a non-root user:

sudo certbot certonly --manual

During the process, Certbot will prompt you to provide the domain of your website, your email address, and to accept the Terms of Service. You will also be asked for permission to share your email address with the Electronic Frontier Foundation (EFF).

Finally, you can enter the domain where you want to use the SSL certificate.

After completing these steps, Certbot will provide instructions for verifying the domain ownership. This involves creating a file with a unique name in the .well-known/acme-challenge/ folder of your website.

Allow Express to serve static files

To serve the verification file from Express, you need to enable serving static files. You can do this by creating a static folder and adding the .well-known subfolder to it. Then, configure Express to serve the static files:

const express = require('express')
const app = express()

//...

app.use(express.static(__dirname + '/static', { dotfiles: 'allow' }))

//...

Make sure to include the dotfiles option, as it is required for the visibility of the .well-known folder.

Confirm the domain

After configuring Express to serve static files, run your application and make sure the verification file is reachable from the public internet. Go back to Certbot, which should still be running, and press ENTER to continue with the script.

Obtain the certificate

If everything went well, Certbot will create the SSL certificate and the private key. It will also provide you with the paths to these files.

To start using the generated SSL certificate and key in your Express application, copy and paste the paths into your code:

const fs = require('fs')
const https = require('https')
const app = express()

app.get('/', (req, res) => {
    res.send('Hello HTTPS!')
})

https
    .createServer(
    {
        key: fs.readFileSync('/etc/letsencrypt/path/to/key.pem'),
        cert: fs.readFileSync('/etc/letsencrypt/path/to/cert.pem'),
        ca: fs.readFileSync('/etc/letsencrypt/path/to/chain.pem'),
    },
    app
    )
    .listen(443, () => {
        console.log('Listening...')
    })

Note that the above code makes the server listen on port 443, which requires root permissions.

Setup the renewal

The SSL certificate is only valid for 90 days, so it’s important to set up an automated system for renewing it. This can be done using a cron job.

To configure a cron job, find the absolute path of certbot on your system. Then, create a cron job entry to run the renewal script twice per day:

0 */12 * * * root /usr/local/bin/certbot renew >/dev/null 2>&1

This will run the renewal script at 00:00 and 12:00 every day.

To add the cron job to the system’s crontab, use the following command:

env EDITOR=pico crontab -e

Replace pico with your preferred editor. Enter the new script, save, and the cron job will be installed.

You can view the list of active cron jobs by running:

crontab -l

That’s it! You have successfully set up Let’s Encrypt and Certbot for your Express application and enabled HTTPS.