I’ve started to move on to the next phase of learning about Node.js. I have a few sites created and for the most part IISNode has done a good job allowing me to run within IIS. Enabling output and kernel level caching gives a nice boost to performance as well. While this is all well and good, it’s not how Node.js is generally run in production scenarios. I decided it was time to learn about hosting Node.js sites on Linux behind nginx.
Here’s what I want to accomplish.
- Get a Linux VM setup; Ubuntu 13.04 x64
- Install Node.js & nginx
- Configure nginx to proxy my site with caching enabled for static files
- Setup my site to start when the server boots
There’s not much exciting here. Just a vanilla Ubuntu server install. I made sure I had OpenSSH installed so I could manage it remotely. I’ve done this part before.
Important! I am not an experienced Linux administrator. I can get around and do some basics, but Linux is undiscovered country for me. The steps below are what I’ve been able to scrape together off the internet. It worked for me. If there’s something I did wrong or there’s a better way, I’d love to hear about it!
Installing Node.js & nginx
Doing a little of the Google magic points out that while Ubuntu has a Node.js package, its not maintained or up to date. The Node repo has a nice Github wiki page covering the steps you need to do to add a reference to the up to date package.
sudo apt-get update sudo apt-get install python-software-properties python g++ make sudo add-apt-repository ppa:chris-lea/node.js sudo apt-get update sudo apt-get install nodejs
This worked like a charm. Now I have Node v0.10.13 running.
I followed a similar process with nginx. They have straightforward documentation for each of the main Linux distros.
The first step is to install the nginx public key. I downloaded it the server then ran this command:
sudo apt-key add nginx_signing.key
Next I added these two lines to the end of
deb http://nginx.org/packages/ubuntu/ raring nginx deb-src http://nginx.org/packages/ubuntu/ raring nginx
Now I’m ready to install.
apt-get update apt-get install nginx
Success! nginx installed.
This is where things got fun. So I found a good post on StackOverflow with an answer that looked like what I needed! So I started at the top and went to create a new file in
/etc/nginx/sites-available. Only, I didn’t have a
sites-available directory. Did I miss a step?
Again, StackOverflow to the rescue! It turns out that the
sites-enabled setup is part of the Ubuntu maintained package, not the main package from the nginx folks. I like the concept of the
sites-enabled setup, so I decide to implement it. I create the directories, edit the
/etc/nginx/nginx.conf file, restart nginx (
sudo service nginx restart), and now I can go back to getting the site setup.
I used an article from the ARG! Team Blog I found on Hardening Node.js For Production. Looked like what I wanted! Instead of putting the server configuration directly in the
nginx.conf, I put mine in the
sites-available directory and created a symbolic link to it in the
sites-enabled directory. For those that want to see the command:
cd /etc/nginx/sites-enabled sudo ln -s /etc/nginx/sites-available/test.conf test.conf
The article from the ARG! Team Blog goes into detail about what’s going on in this file. Here are the highlights:
Lines 1-3: This defines where my Node.js site is at. In my case, its on the same machine on port 3500. This can be another server, or multiple servers to round-robin against.
This defines where the static content is that nginx should serve instead of Node.js. Notice that it points to my
public directory inside my site.
Lines 15-23: This defines the root of the site that nginx should proxy for. We add a bunch of headers to tell Node.js/Express that there’s a proxy in front of it.
Line 21: The url here isn’t the url used to access the site. Instead it is referring to Line 1 as the backend servers to send requests to.
Time to test it!
After I got all this setup, I started up my site. I opened it up in the browser and…
Not quite what I was expecting. At least I know nginx is running. But what went wrong? I rechecked everything and I thought it looked right. Then I remembered the instructions for enabling the
sites-enabled. I had added this line as directed:
What I missed was to remove the line that was already there:
I commented it out by putting a
# in front of it and restart nginx again. When I tested this time, success!
Here’s my final nginx.conf after adding the rest of the parts from the ARG! Team blog:
Ok, time for the last step.
Start the site when the server boots
I’m used to Windows services which are compiled programs. Ubuntu has Upstart which is a nicer script driven system. It looks like that’s the modern approach for what I want to do.
Important I’m not running a module to restart Node if it goes down! This is just a test. When I move a real production site behind nginx I will use a module like Forever.
I started with this StackOverflow post and couldn’t get it to work. I did more searching and ran across the Upstart Cookbook which helped to explain what I was even trying to do, and then I found this post about Node.js and the Forever module. The example they gave was much simpler.
To create an Upstart script create a file in
/etc/init. I called mine
test.conf for simplicity. Here’s what I ended up with in the file:
#!upstart description "Test Node.js Site" env FULL_PATH="/home/joe/testsite" env FILE_NAME="app.js" start on startup stop on shutdown script exec node $FULL_PATH/$FILE_NAME > /home/joe/testsite/test.log end script
I start it up with:
sudo start test
And the site is live!
I reboot the server and… the site is down. Hmm. Back to the Google.
This time it’s AskUbuntu (a StackExchange Network Site) which has a perfectly named post: Why isn’t my upstart service starting on system boot? It led me to try changing my start event from
on startup on line 8 to:
start on net-device-up IFACE=eth0
I reboot once again… and the site is up!
Now that I have a basic site setup I want to play around with moving a few other sites onto this server and off of IIS. Since I still do have sites that I want to keep on IIS, I’m also planning on having nginx proxy for those as well. If things go well I’ll probably also move this site as well.