How to Host a Node.js App on Digital Ocean

Ganga Chris

Digital Ocean is a cloud computing platform that offers developers a Solid State Drive (SSD) to do whatever they want with. Sounds fun.

DigitalOcean is a simple and robust cloud computing platform, designed for developers.

Once you have this SSD, you have access to a rich API's to access the droplet, networking for your droplet, and Storage to attach to your droplet.

They also provide you with a couple of Server Operating Systems, which you use to start up your drople.

This approach has led to the development of some pre-built images or apps, such as Wordpress and the Ghost blogging platform, that can be installed in one click.

Hosting Approach

We'll look at two ways of Hosting a NodeJS app to Digital Ocean.

  1. We'll first write our app locally, push to GitHub, then pull it from within our Digital Ocean Droplet.
  2. We'll dockerize our nodejs application and deploy it to Digital Ocean using Docker-Machine.

Sample Node App

Since we are looking at deployment, we'll keep things simple. We'll just have a simple express server telling us where the magic happens.

If you already know how node apps work, especially with express, you can skip this part, and just head to the Setting Up Digital Ocean part, since we'll clone the node app from a git repo.

Create a directory called DO-node, and inside initialize npm, then create a file, index.js

$ mkdir DO-node
$ cd DO-node
$ npm init -y
$ npm install --save express
$ touch index.js

The package.json file created should look something similar to this.

{
  "name": "node-do",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.14.0"
  }
}

Write a simple express server that tells us where the magic happens. I pulled this one directly from the express documentation.

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

app.get('/', function (req, res) {
  res.send('Hello Digital Ocean!')
})

app.listen(3000, function () {
  console.log('Magic is happening on port 3000!')
})

If we run

$ npm start

We should see the terminal with Magic is happening on port 3000! and opening the browser http://localhost:3000 should display the message Hello Digital Ocean!.

Next, you can create a github repository and push this code, or just move on with the one I've created.

If you chose to create your own repo, copy the github url, then run this.

$ git init
$ git remote add <put_your _github_repo_here>
$ echo "node_modules/" > .gitignore
$ git add .
$ git commit -m "initial commit"
$ git push origin master

Here we create a git repo, then create a .gitignore file and add in node_modules so that it's ignored. We then add everything with git add . and push it to the github repo.

Setting up Digital Ocean

First of all you need a Digital Ocean account. Head over to Digital Ocean and Sign up for an account.

Once you enter your details, you will receive a confirmation email, that will help you complete the sign up process.

You need at least $5 to be able to complete the Signing Up process. You can either add your Credit Card, or use Paypal.

At the time I'm writing this, if you are a student, you can get the Github Student Pack, which has a $50 worth credit for Digital Ocean to get you started with hosting in Digital Ocean.

Once you've signed up, and have $5 or above in your account, we should be good to go.

Creating a Droplet.

There are two ways to create a Droplet in Digital Ocean. You can do it with the Digital Ocean Control Panel, or using the Digital Ocean API. We'll cover the latter one on the second deployment with Docker Machine.

When you log in to your Digital Ocean account you should see a Create Droplet button.

To see how much credit you have, you can click on the arrow next to your avatar on the far right, then click on settings, and click on the billing section on the left.

Once you are good to go, Click on the Create Droplet Button. You will be taken this page

You'll see we have three tabs

  1. Distributions refers to linux distros which we can install into the new droplet we are about to create. In this case we see Ubuntu, FreeBSD, Fedora, Debian, CoreOs and CentOS. Note that all these are the Server Versions of these distros.
  2. One-click apps refers to images already built with support for some common softwares. If you click on the tab, you'll see common application platforms such as Django, MEAN, Wordpress, Drupal and even Docker. This installs all the dependencies required to run these apps, unlike the first distributions where we'll have to install everything manually.
  3. Snapshots refers to droplet images we've built before, and we'd like to create another droplet based off of them.

So click on the One-click apps section, and select the NodeJS 6.9.2 on 16.04 which means nodejs on Ubuntu 16.04.

Head to the next section. To choose a size. Choose the $5/mo ($5 per month) option on the Standard Tab. This options has 512 MB ram, and 20GB SSD which should be enough for this article.

The next section which is Add Block Storage which we can ignore for now.

Next choose a region close to where you are. Ideally this should be close to where the users of your app will most likely be.

You can then add Select additional options, but this is not necesarry for now.

The next section is the important one. We need to add a SSH key to enable us access our droplet remotely.

I have a couple of options because I've added ssh keys before.

SSH keys provide a more secure way of logging into a virtual private server with SSH than using a password alone. While a password can eventually be cracked with a brute force attack, SSH keys are nearly impossible to decipher by brute force alone.

Click on the New SSH key option. A Modal will pop up for you to add your ssh key.

You can go through Generating a new SSH key and adding it to the ssh-agent by Github. Note that if you are using Windows, you need to have Git Bash installed. You can do this by downloading git for windows, and enabling the Git Bash option during installation.

But it generally involves the following commands

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Which will then be followed by a couple of questions.

The one thing to note is where the SSH key will be stored. Since you need to copy it.

Once you've generated you ssh key, add it by clicking on the New SSH Key button Paste in your SSH key and give it a name, then click on the Add SSH Key button.

The new SSH Key will be selected by default.

In the last section, you can choose whether to create more than one droplet, and edit the name of your droplet. You can leave them as they are, and click on the Create Button

We'll see some cool animation there, it should take a few seconds to create your droplet.

You can see we've been assigned an IP address. Mine is 138.197.80.147, which I'll use for this article and delete after I'm done. So whenever I refer to your droplet IP address, I'm referring to this address.

If you click on the droplet, it should take you to the droplet's settings and info

The ON toggle at the top right indicates that our droplet is running.

Accessing Digital Ocean Droplet

If you generated an ssh key, go to your terminal and access your droplet with this syntax. If you are using windows, make sure you are using the Git Bash.

$ ssh <user>@<droplet_ip_address>

So we'll ssh into our droplet with this. Remember to replace the IP Address with the one generated for you in the Control Panel

$ ssh root@138.197.80.147

SSH usually warns you about the authenticity of a new host, so type in yes when you are prompted. You will then be prompted to change your password. Digital Ocean should have sent you a root password in the email. If you did not receive one, just click on the Access tab, then select Reset Root Password

Once this is done, you should see an ubuntu bash.

You can see running ls / lists the root file system of an ubuntu distro.

Hosting the Node JS app.

So we already have our node js app on this github repo, or the one that you created.

We used the One Click apps to set up our droplet, so we have all the dependencies we need. If we hadn't done this, we'd have to follow these steps to do it run our app.

  1. Get into our droplet
  2. Install Git
  3. Install NodeJS
  4. Clone our repo
  5. Serve the app.

Now, we can only focus on the last two.

Get into droplet

Lets ssh into the droplet with the IP. Remember to replace the IP with your IP address from the Digital Ocean control panel. We should have a prompt like this.

$ ssh root@138.197.80.147
root@nodejs-512mb-nyc3-01:~#

Note your terminal may ocasionally hang depending on your internet connection, because SSH needs to maintian an open connection. In case this happens, just close the terminal, and start again.

Install Git and NodeJS

We already have these installed. We can just confirm by

root@nodejs-512mb-nyc3-01:~# git --version
git version 2.7.4

root@nodejs-512mb-nyc3-01:~# node -v
v6.9.2

Clone repo and start the app

To clone the application,

root@nodejs-512mb-nyc3-01:~# git clone https://github.com/gangachris/DO-nodejs
root@nodejs-512mb-nyc3-01:~# cd DO-nodejs
root@nodejs-512mb-nyc3-01:~# npm install
root@nodejs-512mb-nyc3-01:~# npm start

This should start the application inside your droplet. If you open a new tab in your browse and go to <your_ip_address>:3000, you should see the app running.

Awesome, right.

One problem though, if you close your ssh session, npm will stop and your app will be offline. We need to use something that will ensure our app keeps running.

We'll use forever js. Stop you running app with Ctrl + C

root@ubuntu-512mb-nyc3-01:~/DO-nodejs# npm install -g forever
root@ubuntu-512mb-nyc3-01:~/DO-nodejs# forever start index.js

Going to <your_ip_address>:3000 on the browser should still be running your app. Our app will run forever.

Stopping the app should be intuitive,

root@ubuntu-512mb-nyc3-01:~/DO-nodejs# forever stop index.js

That was the first approach. Let's look at the next one.

Docker Machine Approach

Docker is an Open Source Containerization platform that allows us to run our applications inside containers.

To Dockerize an application, you usually need a Dockerfile, that gives instructions to docker on how to run our applications.

We recently Dockerized an Express App. Feel free to go through it.

In this instance, our app is pretty small. We'll create a Dockerfile for it.

# Create image from nodejs base image
FROM node:6

# Clone the repo from github
RUN git clone https://github.com/gangachris/DO-nodejs

# Change workind directory to the cloned repo
WORKDIR /DO-nodejs

# Install all the dependencies
RUN npm install

# Expose port
EXPOSE 3000

# Run the application
CMD ["npm", "start"]

I've commented on the Dockerfile, to clearly explain each step.

To build this image and test if it works, we need to have docker installed. If you don't have docker installed, Install Docker for your respective platform. To ensure docker is intalled, just run

$ docker -v
Docker version 1.12.5, build 7392c3b

To build our app's image using the Dockerfile, simply use this syntax

$ docker build -t <image_name>:<tag> <directory_with_dockerfile>

So in this case, the command will be.

$ docker build -t digital-ocean-node:dev .

The .(dot) refers to the current Directory. If you run docker images, you should see the image you just built.

Once the image is built successfully, we run a container based on the image with this syntax.

$ docker run -d -p <host_port>:<container_port> --name <contianer_name> <docker_image>

In this case, the command will be.

$ docker run -d -p 3000:3000 --name digital-ocean-container digital-ocean-node:dev

The -d tells docker to run the container in detached mode, so you don't get stuck inside the container. Running docker ps should list the running containers.

Going to localhost:3000 in your browser should load the app.

Docker Machine

Docker Machine is a tool that lets you install Docker Engine on virtual hosts, and manage the hosts with docker-machine commands.

We have Digital Ocean, which will act as our virtual host.

Since Docker Machine enables running docker on multiple hosts, developers can make and distribute their own plugin for any virtualization technology or cloud provider. Docker machine comes with some plugins/drivers, including, Amazon Web Services, Digital Ocean, Google Compute Engine. This list shows some of the common Docker Machine plugins.

Make sure you have docker-machine installed by runnning

$ docker-machine -v
docker-machine version 0.8.2, build e18a919

If not installed, you can go through this installation guide.

Once installed, Instructions for running docker-machine with the digital ocean driver can be found here.

The command required has this syntax.

$ docker-machine create --driver digitalocean --digitalocean-access-token=aa9399a2175a93b17b1c86c807e08d3fc4b79876545432a629602f61cf6ccd6b test-this

The test-this part refers to the name we want to give to the virtual docker host.

From the command, we see that we need a digitalocean-access-token. Go to the API tab in your Digital Ocean account

Then click on Generate New Token

Leave the read and write permissions checked. Then click on the Generate New Token button.

Your token should be displayed in the section I've blacked-out.

Once you have all this, run the command now with the correct parameters. Replace the token section with your api-token.

$ docker-machine create --driver digitalocean --digitalocean-access-token=<your_api_access_token> digital-ocean-node

This will create a new droplet in your Digital Ocean Control Panel, once it completes. If it fails, you may have to delete the previous droplet you created. If you look at your droplets on Digital Ocean you should see a new one.

Now we need to point our docker installation to use the Virtual Host docker we just intalled in our virtual server. Right now if we type in

$ docker images

We'll see both the node and the digital-ocean-node:dev image present. When we switch docker to point to our Virtual Host, we should not see these images, since no image build or pull has been done in the Virtual Host.

To point our docker to the Virtual Host, first run this command to see available hosts.

$ docker-machine ls
NAME                 ACTIVE   DRIVER         STATE     URL                        SWARM   DOCKER
digital-ocean-node   -        digitalocean   Running   tcp://45.55.254.215:2376           v1.12.5   

You can see we have a docker-machine-node, which we created earlier. The IP should correspond to the IP address we saw in in the Digital Ocean Control Panel.

To see how to change docker to point to this virtual host, simply run this.

$ docker-machine env digital-ocean-node
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://45.55.254.215:2376"
export DOCKER_CERT_PATH="/Users/ganga/.docker/machine/machines/digital-ocean-node"
export DOCKER_MACHINE_NAME="digital-ocean-node"
# Run this command to configure your shell:
# eval $(docker-machine env digital-ocean-node)

We are instructed to run eval $(docker-machine env digital-ocean-node) to point our docker to the Virtual Host docker environment. So we run that.

 $ eval $(docker-machine env digital-ocean-node)

Done. Now running docker images should return an empty result since we are pointing to the Digital Ocean Virtual host.

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

So we need to do a new image build, and run a container based on the image.

$ docker build -t digital-ocean-node:dev .

Now running docker images should give us the images.

$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
digital-ocean-node   dev                 8834fa7b0496        2 minutes ago       658.6 MB
node                 6                   faaadb4aaf9b        11 days ago         655.5 MB

The last thing we need to do is run the container. The only difference from how we ran the container earlier is that We're going to point the default HTTP port 80 to 3000 from the container, so that we can access the container with just the IP address in the browser.

$ docker run -d -p 80:3000 --name digital-ocean-node digital-ocean-node:dev
225c7f305839864c25acfea47bf46921d235c44c23f6011518926a2ba6b08c0e

Going to your the IP that was created for the droplet should show the app running. Mine was 45.55.254.215, so

Note To change your docker to point back to your local host, simply run

$ eval $(docker-machine env -u)

The -u stands for unset.

Last Note. Remember to either stop or destroy the droplets you are not using, since you'll end up being billed if they are running.

Conclusion

We've seen how easy it is to deploy a nodejs app to digital ocean. I personally prefer the docker approach, since updating my app will only involve doing new builds, and running them without ever going to the Control Panel.

The first approach, while it's also easy, will require you ssh-ing into your droplet often, unless you set up some continuous deployment platform.

Hope this was helpful.

Ganga Chris

10 posts

I'm a Full Stack Developer. (Mostly JavaScript & Go). Recently got into Blockchain tech.

{{-- intercom --}}