Serving a node app with nginx

I’m using Ubuntu 14.04 and Node 0.12.5. (A convenient digital ocean droplet!)

SSH into our machine….

Setup Nginx

Nginx is a web server. It routes and manages incoming connections. It serves the same purpose as Apache.

Install

1
2
sudo apt-get update
sudo apt-get install nginx

The main commands:

It will be started after install. These are for reference. You don’t need to do any of them right now.

1
2
3
sudo service nginx start
sudo service nginx stop
sudo service nginx restart

Getting familiar with nginx

Where is nginx?

1
cd /etc/nginx

If we looks at the directory listing (ls), we see all the goodies. At this point, all I really care about are two folders: sites-enabled and sites-available.

We need to put a record of our site in sites-available. Then, we’ll put a symbolic link to that file in sites-enabled. The records in sites-enabled are what nginx looks for when mapping incoming requests to the files to execute (our app!).

Make a record for our app in sites-available

I like to start by making a copy of the default record.

1
2
cd /etc/nginx/sites-available
cp default your.site.com

Tell nginx what we want to happen when we get a request to that URL

We do that by creaing a vhost file. You can use any shell text editor you want. I like pico because it tells me what to do. If you’re a cool person you’ll probably use vim.

1
pico your.site.com

You’ll see there’s a ton of comments. (# = comment). If you study this file it will explain a lot of great things. Otherwise, I just delete everything (Ctrl+K cuts a line at a time. I’m too lazy to learn the correct way to delete thing). So what was the purpose of copying? Yeah, I really just think it’s worthing looking at the possible options to get familiar with nginx.

So here’s what your file should look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
listen 80;
server_name your.site.com;
location / {
proxy_pass http://127.0.0.1:3009;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}

Two things you’ll need to change…. the server name on line 4. And the port at the end of line 61. Well, you don’t need to change the port, but it will need to match whatever port your launch your node app on.

So what’s going on here? Basically, this is known as a reverse proxy. When you run node on development on your computer you get a local address with a port. You visit that local address on that port and you see your site. This is the same thing. Nginx just acts as a gobetween from external users to the localhost on your server.

Enable the site

We enable the site by placing the same record we created in sites-available in sites-enabled. The best way to do this is with a symbolic link so that changes in one place are reflected in both locations.

1
2
cd /etc/nginx/sites-enabled
ln -s ../sites-available/your.site.com your.site.com

Now that everything is setup, we need to restart Nginx

1
sudo service nginx restart

Run our app with PM2

You could start your app like you normally woul with the node command, adjusting the port as you normally would, but if you have one error, your app will crash.

PM2 is a service that automatically restarts your node app if it crashes. It does some other cool things too that make it better for production that something like nodemon.

I chose PM2 over Passenger because I couldn’t get Passenger to work. PM2 just works with very little config.

Install PM2

1
sudo npm install pm2 -g

Here is my go-to pm2 command:

1
pm2 list

That gives an overview of your processes.

Note: PM2 works on a per-user basis. I use PM2 from my deployer user since the deployer user has restricted permissions and needs to restart the app whenever there’s an update. I know I haven’t mentioned a deployer user yet. I’ll explain in another blog post

Configure PM2 to run our app

We can configure PM2 with a json file. This isn’t the only way, but I like it since I can set my environment to be production and do other cool things.

I’ve created a file called pm2-config.json in my app file home: /var/www/your.site.com. It doesn’t matter too much where you put the file.

Let’s create our config file:

1
2
cd /var/www/your.site.com
pico pm2-config.json

Here’s what my file looks like:

1
2
3
4
5
6
7
8
{
"name" : "myprocessname",
"script" : "current/bin/www",
"port" : 3009,
"env": {
"NODE_ENV": "production"
}
}

It’s pretty simple. You just need to change the valuse to match your needs. Script is the entry point of your app. I’m using the express framework, so the entry point to your app may look different.

Important Make sure the port setting matches what you said the port would be when you were configuring Nginx. It doesn’t matter if you have a different port setting in your script file. PM2 will override it.

Note: Why do I have “myprocessname” instead of “your.site.com”. Many of my apps use two processes. One to access the app in a traditional manner, and another to listen for messages from a message queue. I can restart these processes independently from eachother.

Start the app

1
pm2 start pm2-config.json

We’re good to go!

avatar

Dev Blog