Skip to content

Instantly share code, notes, and snippets.

@alanorth
Last active August 16, 2016 06:48
Show Gist options
  • Save alanorth/51acd476891c67dfe27725848cf5ace1 to your computer and use it in GitHub Desktop.
Save alanorth/51acd476891c67dfe27725848cf5ace1 to your computer and use it in GitHub Desktop.
Proxying a NodeJS app with nginx on Ubuntu 16.04

Proxying a NodeJS App with nginx

An example of a simple NodeJS application running via systemd that is accessed via an nginx proxy.

Pre-requisites

NodeJS app will be running as the tomcat7 system user, and there are a few assumptions that must be met to allow the installation of NodeJS:

  • The tomcat7 user must be able to write to its home folder — /usr/share/tomcat7 — so it can create the ~/.nvm, ~/.npm and other directories during installation
  • The ~tomcat7/.profile file must exist and be writable before installing nvm, as this is the default config file for login shells, ie sudo su - tomcat7. The nvm installer will append lines to those files to setup their environments on login.

Node Version Manager (NVM)

The easiest way to get NodeJS without relying on the system's package manager is to use Node Version Manager (NVM). Also, this lets you install whatever version of NodeJS you want, and doesn't require root because it installs in the user's shell.

I'll use NodeJS v4 because it's the current long-term support version:

$ wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.31.4/install.sh | bash

After the intstallation is finished, close and re-open your shell to activate NVM. Then install NodeJS v4 (LTS) and use npm to install the DSpace dependencies:

$ nvm install v4
$ nvm alias default v4

Initiate a sample project and [install ExpressJS](https://expressjs.com/en/starter/installing.html:

  $ nvm use v4
  $ mkdir hello && cd hello
  $ npm init
  $ npm install express --save
  $ npm install express

Create the entry point for the NodeJS app, index.js:

var express = require('express');
var app = express();

// only allow localhost
app.set('trust proxy', 'loopback') // specify a single subnet

app.get('/api', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Try running the app:

$ node index.js

Configure nginx Reverse Proxy

Add a location block to default virtual host in nginx:

location /api {
  proxy_pass http://127.0.0.1:3000;
}

I use /api because I had used the same path in the NodeJS index.js above.

Make The NodeJS App Persistent

Create a systemd service file for the application, /etc/systemd/system/nodejs-hello.service:

[Unit]
Description=CGSpace DSpace API
After=network.target

[Service]
User=tomcat7
WorkingDirectory=/usr/share/tomcat7/src/git/hello
ExecStart=/usr/share/tomcat7/.nvm/versions/node/v4.4.7/bin/node index.js
Restart=always
RestartSec=10s
StartLimitInterval=0

[Install]
WantedBy=multi-user.target

Now load, enable, and start the app using systemctl:

$ sudo systemctl enable nodejs-hello
$ sudo systemctl start nodejs-hello
$ systemctl status nodejs-hello
● nodejs-hello.service - CGSpace DSpace API
   Loaded: loaded (/etc/systemd/system/nodejs-hello.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2016-08-15 09:37:08 EEST; 8s ago
 Main PID: 5092 (node)
    Tasks: 5
   Memory: 18.7M
      CPU: 217ms
   CGroup: /system.slice/nodejs-hello.service
           └─5092 /usr/share/tomcat7/.nvm/versions/node/v4.4.7/bin/node index.js

Aug 15 09:37:08 dspace systemd[1]: Started CGSpace DSpace API.
Aug 15 09:37:08 dspace node[5092]: Example app listening on port 3000!

Now you can access the application via whatever hostname you're using in the nginx vhost. If you kill the node process systemd will restart the app!

Testing

$ http --print Hhb https://localhost:9443/api --verify no
GET /api HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:9443
User-Agent: HTTPie/0.9.6

HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 12
Content-Type: text/html; charset=utf-8
Date: Mon, 15 Aug 2016 08:13:22 GMT
ETag: W/"c-7Qdih1MuhjZehB6Sv8UNjA"
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Robots-Tag: none
X-XSS-Protection: 1; mode=block

Hello World!

And Bob's your uncle!

@oguya
Copy link

oguya commented Aug 16, 2016

I can see how awesome this will be on ansible ;)

something like...

tasks/nodejs
    - install node
    - clone node app from git
    - copy node service template & start the service

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment