Hosting & Deploying NodeJS Apps on Ubuntu

Doing local development with Node is simple. All you have to do is node app.js in the folder where your source code is and your application is working.

Where things get complicated is when you want to put your app in production, on a web server for the whole world to admire it.

If you are coming from PHP or Ruby on Rails you might be used to having a very simple way of hosting & deploying your application. All you have to do is put your code into a specific folder. Every time you have an update, just replace the code. It just works.

Let’s look at how you can host and deploy a production ready NodeJs application.

For this purpose we will need SSH access to a freshly installed server. For this tutorial we will look at doing this on Ubuntu, but all steps are easily reproducible on CentOS or any other flavor of Linux.

Your server can be running in AWS, Rackspace or even in your local VirtualBox. It doesn’t really matter, the steps are always the same.

Getting your hands dirty

I know that you are impatient to learn what your setup will be, so let’s get this out of the way.

First, we will use the Nginx web server to handle all requests from the web.

Requests for static content will be handled directly by Nginx. If we need to support SSL, this will also be handled by Nginx. All other web requests will be handled again by Nginx but forwarded to our Node application code.

Second, to ensure that our node application is always on, even when the application crashes or the server is restarted, we will use upstart or systemd tasks depending on what is available on your system of choice.

Last, we will launch as many instances of our application as cores and cpus has our server machine. The purpose of this is to use the maximum of the available resources. Each instance will listen for requests on a separate port and Nginx will forward the appropriate requests.

If you don’t understand this setup or you’ve never heard some of its components. Don’t worry, everything will be explained in details below.

On the other hand if all of this is very clear to you, you can skip the next few paragraphs and go directly to the actual commands and files that we will use to make it all work.

What does it mean to host an app?

Just like on your development machine you can run node app.js on your server and your code will be executed perfectly.

However, this is far from ideal and there are many problems with it. Let’s look at just a few of them.

Serving static files, like JavaScript, images & CSS, can be done with node but it is not very efficient. It may use too much memory and it might not cache frequently accessed files.

Establishing secure SSL connection is not simple, yet most web applications require it. There are certificate files to handle as well as other small details. Moreover, your application code does not care whether the connection is secure or not, as this will only add unnecessary complication to your logic.

Limiting file uploads is critical for any app which allows file uploading. Otherwise, unintentionally or intentionally a user may try to upload a 10GB (or much bigger) file and crash your server. Implementing this efficiently in Node is hard.

These are just few of the reasons, and there are many more, why you should have something else in front of your node application which will handle user requests.

It should serve static files, establish secure connections, as well as other things and decide when a request should be handled by your application code and when not.

Nginx is one of the most widely used web servers. It can do all of the above and lot more. In addition, it is very easy to setup. That is why we are going to use it.

Use all available resources

Node is famous for being a single threaded process. What this means is that no two things happen at the same time. If your server has multiple cores or processors it will only use one of them.

This is not very efficient. If you can use all of the cores you will be able to handle higher load with the same server and as a result save some money.

One solution is to write some additional code. Node ships with a cluster module which can handle the situation described above.

However, I believe it is better to keep in Node only your application logic, and handling multiple processes is not part of that.

Instead all you have to do on your server is run node app.js multiple times, each time providing a different predefined port the app to listen to. Then Nginx can forward requests to each of these ports.

Always On

The next problem that you will face is to keep your app always on. It may crash or your server may restart or something else could happen. You need to ensure that no matter what, your app is always running.

Moreover, this should happen automatically. You don’t want to wake up in the middle of the night, just because your server restarted due to temporarily power outage (this happens even on Amazon or Rackspace servers).

Fortunately, all Linux instances come with what is called an init system. This are robust systems which can monitor the status of your application, restart it when certain conditions are met and start it when the server itself is started.

In the past, using the init system required writing complicated scripts and everybody hated it.

These days, most modern Linux distributions come with a modern init system called “systemd” which is very easy to use. The only exception until recently was Ubuntu, which up to version 14.10 came with “upstart”, which is also easy to use. Beginning with version 15.04 Ubuntu also uses “systemd”.

Deploying

Now that you know how your are going to run your code, the next question is how you are going to put your code on your server.

We are going to use Git. It has many great features but we are going to use just a few of them, mainly it’s ability to push changes between computers.

Now that you know how it should work in theory, let’s look how it is done in practice.

Install

First, you will need to install all necessary packages on your server.

The start on line ensures that your app will start when the server starts
and the file system and network are loaded. The respawn ensures that if your
app instance dies for whatever, then it will be launched again.

Put this in /etc/init/node-app-1.conf. Then take the same file, replace
env PORT=5000 with env PORT=5001 and save it as /etc/init/node-app-2.conf.

Now you have two upstart jobs node-app-1 and node-app-2. Each can look
after one instance of your application. You need to create as many as processor
cores you have on your server. For example, if you have two cpus, each with the
cores, then you need 4. For the purpose of this article we will imagine that we
have 1 CPU with 2 cores.

You can run your app instances with

$ sudo start node-app-1
$ sudo start node-app-2

Your app will handle requests at the ports 5000 & 5001. If one of them crashes
or the server is restarted, they will be also restarted. Your application is now
really always on.

Systemd

Since Ubuntu 15.04 and Debian 8, systemd is the default init system. Systemd has
services. Each service describe how an application is running.

This configuration will make available all static files from /opt/app/public/ at the /public/ path. It will forward all other requests to the two instances of our app listening at the ports 5000 and 5001. Basically, Nginx is both a web server and load balancer.

To use this configuration save it in /etc/nginx/sites-available/node-app and then do the following:

Did you like this article?

Please share it

Enter your email and get our NPM Cheat Sheet for NodeJS Developers and
the links to our 5 most popular articles which have helped thousands of
developers build faster, more reliable and easier to maintain Node applications.