How to run NodeJS in Production using NGINX with Ubuntu 18.04

NodeJS with NGINX on Ubuntu 18.04

The following tutorial will show you how to safely run NodeJS in production using NGINX. We assume some safe defaults that will satisfy most requirements.

You may be asking yourself, why would anyone want to put a NodeJS app behind NGINX, since you can use Express, for example, to host your app directly. Like nearly all web servers built for a particular language, there are usually a number of downfalls that potential increase risk in production environments.

Why Bother with NGINX?

Security

To run NodeJS as a web server requires root privileges. This becomes a serious security issue, since a vulnerability in NodeJS or your application could mean an attacker would have full, unfettered access to your server.  NGINX, on the other hand, runs with a less privileged account, thus limiting your damage if an attacker gained control of it.

TLS

Nearly all NodeJS libraries for TLS/SSL perform poorly or have a number of serious vulnerabilities associated with them. NGINX has been optimized for TLS traffic, handling more efficiently and with much fewer vulnerabilities than a random NPM module.

Headers and Simple Routing

Most routing should be done by your application, no doubt. However, there are several scenarios where traffic should be routed before it even touches your application. This ensures your application is only routing relevant traffic and ignoring everything else.

Same idea with headers. Not all headers should be set by your application. Having a layer above your application is useful for a number of scenarios that we won’t go into detail.

Install NodeJS

The version of NodeJS available for Ubuntu 18.04 is v8.10. The version of NPM is 3.5.2. If this is suitable for your application you can simply install them using APT. Otherwise, you will need to use a separate method.

Installing the Ubuntu’s Repository

The following command will install the latest version of NodeJS available from Ubuntu’s repositories.

sudo apt install nodejs

Installing NodeJS from the Official Repository

NodeJS currently offers two repositories to install from. You can either use the v8 repository or the v10 repository. Both instructions are listed below.

Adding NodeJS v8 Repository

Run the following script to prepare your server for NodeJS’s official repository for v8. This will download their public key and add the repository to APT.

curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -

Adding NodeJS v10 Repository

If you require something a little more recent, you can run the following script to prepare your server for NodeJS v10.

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -

Installing NodeJS

sudo apt install nodejs

Optional Build Essentials
Some modules have libraries that require being compiled on your server before they can be used. This is typical of those written in C, for example.

sudo apt-get install -y build-essential

Running Your NodeJS App as a Service

Running an application should require minimal effort. Let’s configure our NodeJS application as a service that we can easily start and stop. We’ll also want to ensure it starts automatically after every boot.

  1. Create an account your service will run as.
    sudo useradd -s myapp
  2. Ensure your service account has enough privileges to run your app.
  3. Create a new SystemD configuration file for your app.
    sudo vi /etc/systemd/system/myapp.service
  4. Add the following lines to it.
    [Unit]
    Description=My NodeJS APP - It's pretty awesome
    Documentation=https://docs.myapp.com
    After=network.target
    
    [Service]
    Environment=PORT=3000
    Type=simple
    User=myapp
    ExecStart=/usr/bin/node /path/to/app/server.js
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target

    After=network.target tells SystemD that this service depends on the network stack being online before it can start.

    Environment=PORT=3000
     is setting an environment variable our app will use to set the listening port. In this example, port 3000.

    Type=simple tells SystemD to not allow our process to be forked.

  5. Register your changes.
    sudo systemctl daemon-reload
  6. Start your application.
    sudo systemctl start myapp
  7. Enable your service to allow it to start automatically after a system boot.
    sudo systemctl enable myapp

Installing  NGINX

Nearly all recent distributions support and provide NGINX through their official software repositories. This simplifies our effort since we won’t have to worry too much about building, installing, and patching.

The drawback, of course, you are unlikely to be running any bleeding edge version of NGINX. Even worse, such is the case with Debian, Red Hat and CentOS, you could be several major version behind. But unless you require those bleeding edge features, which most won’t, you should be fine using what’s available out of the box.

sudo apt install nginx

Configuring NGINX

With NGINX installed we can proceed with configuring it for our backend NodeJS application. We will host our app over the default port 80, though you could pick any at your own discretion.

  1. Create a new NGINX site configuration file
  2. Add the following lines.
  3. Save your changes and exit the text editor
  4. Apply your changes.