Node.js: how to set up an app on Ubuntu Server with nginx and Let's Encrypt

In this article we're going to explain how to set up a Node.js app with nginx and Let's Encrypt on Ubuntu Server 16.04.

First, we need to create the web space for the app and the associated user account:

sudo -i # Get root privileges
adduser myapp
su - myapp
mkdir app www

After getting root privileges, we can create a new set of nginx's rules (sudo -i and then nano /etc/nginx/sites-available/myapp):

upstream myapp {
server {
listen 80;


root /home/myapp/www;
index index.html;

client_max_body_size 8m;

location / {
  try_files $uri @myapp;

location @myapp {
  proxy_pass https://myapp;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";                                                                                                                                                          

Now we can enable the new rules:

ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp

Then we need to add the official repository used by the Let's Encrypt command line tool:

add-apt-repository ppa:certbot/certbot

Just refresh now the package list:

apt-get update

Now let's install Certbot:

apt-get install python-certbot-nginx

Let's get an SSL certificate for our app:

certbot --nginx -d

After obtaining the certificate, we can choose Option #2 to allow Certbot to add the SSL rules to our nginx's configuration file.

Now let's copy the certificate files to our app directory:

cp /etc/letsencrypt/live/ > /home/myapp/app/fullchain.pem && chown myapp:myapp /home/myapp/app/fullchain.pem

cp /etc/letsencrypt/live/ > /home/myapp/app/privkey.pem && chown myapp:myapp /home/myapp/app/privkey.pem

The code seen above can also be used to create a cronjob in order to renew the certificate before it expires:

  1. export VISUAL=nano; crontab -e
          x x x x x /usr/bin/certbot renew --quiet
          x x x x x cp /etc/letsencrypt/live/ > /home/myapp/app/fullchain.pem && chown myapp:myapp /home/myapp/app/fullchain.pem
          x x x x x cp /etc/letsencrypt/live/ > /home/myapp/app/privkey.pem && chown myapp:myapp /home/myapp/app/privkey.pem
  3. systemctl restart cron

Replace the x characters with the appropriate cron's time values.

We need to create a systemd service by typing nano /etc/systemd/system/myapp.service and inserting the following contents:

    ExecStart=/usr/local/bin/node app.js                                                                                                                                                                


Enable the service:

systemctl enable myapp

Let's start the service:

systemctl start myapp

We need to test the nginx configuration before restarting it:

nginx -t

If everything is correct, we can restart it:

systemctl restart nginx

The basic structure of our Node.js app (/home/myapp/app/app.js) will be as follows:

'use strict';

const express = require('express');
const fs = require('fs');
const https = require('https');
const port = process.env.PORT || 3000;
const app = express();
const sslOptions = {
  key: fs.readFileSync('privkey.pem'),
  cert: fs.readFileSync('fullchain.pem')


 // Routes will be inserted here

 https.createServer(sslOptions, app).listen(port);
Prev Articles Next