Creating a Website with NodeJS and Nginx on DigitalOcean with automatic deployments using Git.

nodejsIntroduction


Just writing down the steps I usually take to deploy a website with NodeJS on Digital Ocean. We start off by creating a simple website, then we purchase a domain name from Enom.com, continue by spinning up a Ubuntu instance on DO, configure NodeJS and git, then we are free to go live.

Creating the Website
Hosting with Digital Ocean
Setup of NodeJS and Git
Source control
Acquiring a domain name
Configuring Nginx
Conclusion


Creating the Website

Let’s create a simple helloWorld website. Nothing fancy in NodeJS. If you don’t already have NodeJS installed do so. With most operating systems just head over to NodeJS.org and download the installation file. On Ubuntu just execute apt-get install nodejs . Then create a directory called ‘simple’ and this will be our starting point.

% npm init   // just enter through and leave everything at default
% npm install express  --save       

Create a file called index.js containing

var express = require('express')
  , http = require('http')
  , config = require('configuration');

var app = express();
var server = app.listen(config.port);
console.log("Express server listening on port "+ config.port);

app.get('/',index);

function index(req,res){
   res.send('Hello ' + config.say);
}

Also let’s create a configuration file, called configuration.js

module.exports.port=3000;
module.exports.say="World";

Now we can execute the application using

% node index.js
Express server listening on port 3000

Navigating to http://localhost:3000 we find the service running.

running the NodeJS service

Now with a website ready to go we need a a server to put it on and a domain name.

Hosting with Digital Ocean


For hosting there’s a plutera of new options out there, ranging from Amazon Web Services to Google Compute. However the one I found easiest to use is Digital Ocean. If you are a student you can get $100 free from the Github Student Development Pack to use towards Digital Ocean.

$100 Promo Code

So create an account, login, and let’s create our first droplet!
For most of the applications we’ll be fine with just a basic $5/month box.
BasicBox
Scrolling farther down the page we find the Select Image section, just pick a basic Ubuntu box. We could go Applications and find node, but it makes things a little more complicated (ironically).

Select Ubuntu

This would be the time to provide your SSH keys which can be found using:

% cat ~/.ssh/id_rsa.pub
ssh-rsa aspdjapsdklasjdlkadj12312o3j1d09jasdad0[1j2i123120131u30j 

Just copy and paste the printed key.

Now we are ready to deploy the droplet! Click Create Droplet!
Now creating the droplet

Once DigitalOcean finishes creating the droplet you will be taken to the status page where all of the administration and password recovery will be done.
Status page

Ready to connect to our server and configure it!

Setup of NodeJS and Git


With the machine running in the cloud we can ssh into it. Grab the IP address from the Status page above. In my case it was 104.236.53.5.

% ssh root@104.236.53.5
 The authenticity of host '104.236.53.5 (104.236.53.5)' can't be established. (yes/no) yes
 Warning: Permanently added '104.236.53.5' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 15.04 (GNU/Linux 3.19.0-15-generic x86_64)
 * Documentation:  https://help.ubuntu.com/

Now we are ready to install NodeJS.

% sudo apt-get update
% sudo apt-get install nodejs -y
% sudo apt-get install npm -y
% sudo apt-get install build-essential -y
% sudo npm install forever --global // We'll need this later .... 

We can test out our installation of NodeJS by executing

% nodejs
> console.log("HelloWorld");
Hello World
undefined

Quit by pressing CTRL+C twice.

However npm and other applications will be looking for the node executable, and not necessarily nodejs. We’ll have to create a symlink pointing from node to nodejs.

% which nodejs
/usr/bin/nodejs
% ln -s /usr/bin/nodejs /usr/bin/node

No we are going to configure a Remote Git Server. This will allow us to automatically deploy applications, to both Github and the server. By doing this we can easily deploy without having to ssh into the server and have to do any additional configuration.

Installing git is straight forward using

sudo apt-get install git -y

Find out where you are located and let’s configure a git server.

% pwd
/root
% ls -l 
total 0

% mkdir -p git/simple.git
% mkdir -p node/simple
% mkdir node/config

% cd git/simple
% git init --bare

Use your favorite editor to create the post-receive file in the hooks directory.

% vim hooks/post-receive

#!/bin/sh
forever stop index.js
git --work-tree=/root/node/simple --git-dir=/root/git/simple.git checkout -f
cp /root/node/config/simple_configuration.js /root/node/simple/configuration.js
cd /root/node/simple
npm install
forever start  -o logfile.out -e logerror.out index.js

:wq //write and quit

make it executable

chmod +x hooks/post-receive

After any push this script will clone a new copy of the repo and overwrite everything in the /root/git/simple directory. It will then copy the configuration.js file from the config directory into the /root/node/simple directory, this way we can preserve our production configuration files. Afterwards it’ll cd into the /root/node/simple directory and perform an npm install to install any dependencies and finally run forever with the index.js script.

Before we continue let’s create the production configuration script called simple_configuration.js

% vim /root/node/config/simple_configuration.js

module.exports.port=8000;
module.exports.say="World Wide Web";

:wq  //write and quit

Source control


We’ll be keeping our website on Github, so create an account and a repo called simple.
simple repo.

First we need to create a .gitignore file so our configuration.js does not commit. We might be storing some sensitive information, like user accounts and database information.

simple/.gitignore
    configuration.js    
    node_modules/

If you already 'git add'ed files and they are being commited even thought they should be ignored, you can reset the git repo using __git rm -r --cached .__

Let’s make our initial commit, by going back to the terminal.

simple/

    % git init
    % git add remote origin git@github.com:marek5050/simple.git
    % git add .
    % git commit -m "Initial Commit"
    % git push --set-upstream origin master

**COOL! ** so we have uploaded something onto Github. But let’s do something better! Let’s upload it to our server too!

edit simple/.git/config and add the following lines

[remote "live"]
    url = ssh://root@104.131.140.201:1024/root/git/simple.git
    fetch = +refs/heads/*:refs/remotes/origin/*

We should now have 2 remotes, one will be the origin (Github) and the second will be our server. Let’s try pushing again..

% git add .
% git commit -m "Pushing to server" 
% git push 
 ...
remote: express@4.12.4 node_modules/express
 ...
remote: info:    Forever processing file: index.js
To ssh://root@104.131.140.201/root/git/simple.git
9ce91b6..d40a423  master -> master

Awesome let’s go check the server!!

    % ssh root@104.131.140.201
    % forever list 
     info:    Forever processes running
     data:        uid  command         script   forever pid   logfile                 uptime        
     data:    [0] UBf5 /usr/bin/nodejs index.js 14311   14316 /root/.forever/UBf5.log 0:0:1:47.978

    % cd node/simple
    % ls -l 
    -rw-r--r-- 1 root root   68 Jun  5 16:00 configuration.j
    -rw-r--r-- 1 root root  319 Jun  5 16:00 index.js
    -rw-r--r-- 1 root root  588 Jun  5 16:11 logerror.out
    -rw-r--r-- 1 root root   38 Jun  5 16:11 logfile.out
    drwxr-xr-x 3 root root 4096 Jun  5 16:00 node_modules
    -rw-r--r-- 1 root root  314 Jun  5 15:56 package.json
% cat  node/simple/logerror.out
% cat node/simple/logfile.out
Express server listening on port 8000

The server is now running. We can now visit the website in our browser.
Public server running

Now we want the website to be accessible via the default http port 80. So that when we direct the browser to http://104.131.140.201/ we’ll access it. We could just tell NodeJS to serve the page on port 80, but that limits the number of web sites we can host on a single machine. For this we can use a web proxy server such as Nginx or Apache. They are both identically configured, so we’ll go with Nginx. But before all of this can happen we’ll need to configure a domain. We can buy cheap .com or nowadays even .whatever for about $10. Part of the student pack is a free domain name with Namecheap.

Acquiring a domain name

We can buy domain names from a variety of hosting services such as Hostgator and Bluehost. But I’ve been using Enom for quite a while so I’ll show you how to that up instead.

First search for an available domain that we can acquire.
search simplewebsite enom

Select an available Top Level Domain (tld,ie .ninja, .net, .com), for us it would be simplewebsite.rocks and click “add” and “checkout.”

click checkout to purchase domain

Once the account is created and domain purchased, go and sign into your Digital Ocean. On the top menu click DNS. Type in the name of the DNS you purchased and in the dropdown select the virtual machine spun up in the previous section.
DNS Configuration

The next screen will give you a bunch of information, from here we’ll just need the NS addresses. Usually they are ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com.

Detailed information about DNS

Go back to Enom and once logged in there’s a little box called Domains click on Registered. Find and select the domain and click on DNS Server Settings.
Configure the Name Servers to the information we found a few seconds ago. Probably ns1.digitalocean.com, ns2.digitalocean.com, ns3.digitalocean.com.

DNS Server Settings

Click save, you’ll get a message that the propagation usually takes about 24 hours. Yet, from experience it usually takes 15 seconds, so we can go on to configure Nginx.

Configuring Nginx


Okay I ended up buying a different domain name I want to test out, crossfit.social.
The installation is straight forward with a simple:

% sudo apt-get install nginx

Now we need to configure it, the quickest way will be by creating a file crossfit.social.conf.

%vim /etc/nginx/conf.d/crossfit.social.conf
server {
  listen 80; 
  server_name crossfit.social;
  
  location / {
    proxy_pass http://localhost:8000;
    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;
  }
}

Nginx should be already running and will need to be reloaded with

% service nginx reload

The configuration file tells nginx whenever it receives a request for crossfit.social it should redirect it to localhost:8000, which is the port our NodeJS server is running on.

DNS Configured.. We can access the page

Conclusion

With forever configured our server will run almost forever and restart whenever it encounters a problem. The only thing we need to worry about now is, what happens when the virtual machine restarts? We need to create a script in the /etc/init.d/ directory. The script will automatically run forever start /root/node/simple/index.js upon restart. This way we cover most of our corner cases. I’ll paste the script here in a week or so since school is finally starting again!

Advertisements

8 thoughts on “Creating a Website with NodeJS and Nginx on DigitalOcean with automatic deployments using Git.”

  1. Look into PM2 instead of forever. It is a much better process manager than forever. Can handle clustering AND auto generate init.d scripts as well as has its own fancy deployment system. That way you won’t have to come back in a week…

  2. Hi, I did exactly the same but if I call my website I am getting the default site of my domain provider.

    1. I created a droplet with Node.js, Mongodb and Nginx
    2. I created a sample index.js with port 3000 which is working locally and on server with curl localhost:3000

    // Load the http module to create an http server.
    var http = require(‘http’);

    // Configure our HTTP server to respond with Hello World to all requests.
    var server = http.createServer(function (request, response) {
    response.writeHead(200, {“Content-Type”: “text/plain”});
    response.end(“Hello World\n”);
    });

    // Listen on port 3000
    server.listen(3000);

    // Put a friendly message on the terminal
    console.log(“Server running at http://localhost:3000/“);

    3. I changed the nameserver ns1.digitalocean .. nsn.. and I got a confirm about it. I also checked it with whois IP – Address
    4. On nano /etc/nginx/sites-available/default
    I added the following like your example configuraton:

    server {
    listen 80;

    server_name my_domain.com;

    location / {
    proxy_pass http://localhost:3000;
    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;
    }
    }
    5. I linked with site-enabled
    sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
    Before I deleted the default file in sites-enabled.

    6. I restart nginx
    7. If I call my IP or Hostname(my_domain.com or http://www.my_domain.com) I will redirect to default site of my domain provider.

    Now what the hell I am doing wrong? 🙂

    Many thanks in advance.

    Machu

    1. You also need to add the domain to your digitalocean account. There’s a DNS menu where you have to register domains you are redirecting to digitalocean.

      This way digitalocean knows to which droplet to route your domain.

      Thanks for the detailed description!

  3. Hi Marke, you’re welcome!

    You explained above about adding Domains. Do you mean this?

    I added just :

    A @ 107170138202

    Nothing more. Can you please give me an example?

    Many thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s