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
exit

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 127.0.0.1:3000;
 }
server {
listen 80;

server_name myapp.com;

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 myapp.com

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/myapp.com/fullchain.pem > /home/myapp/app/fullchain.pem && chown myapp:myapp /home/myapp/app/fullchain.pem

cp /etc/letsencrypt/live/myapp.com/privkey.pem > /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
  2.       
          x x x x x /usr/bin/certbot renew --quiet
          x x x x x cp /etc/letsencrypt/live/myapp.com/fullchain.pem > /home/myapp/app/fullchain.pem && chown myapp:myapp /home/myapp/app/fullchain.pem
          x x x x x cp /etc/letsencrypt/live/myapp.com/privkey.pem > /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:

[Service]                                                                                                                                                                                           
    WorkingDirectory=/home/myapp/app                                                                                                                                                         
    ExecStart=/usr/local/bin/node app.js                                                                                                                                                                
    Restart=always                                                                                                                                                                                      
    StandardOutput=syslog                                                                                                                                                                               
    StandardError=syslog                                                                                                                                                                                
    SyslogIdentifier=myapp                                                                                                                                                                             
    User=myapp                                                                                                                                                                              
    Group=myapp                                                                                                                                                                            
    Environment=NODE_ENV=production                                                                                                                                                                     

    [Install]                                                                                                                                                                                           
    WantedBy=multi-user.target

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')
 };

 app.disable('x-powered-by');


 // Routes will be inserted here


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