Prudent Devs

Step by step guide to dockerizing a hapijs app

How to dockerize an existing hapijs application so that you can deploy with ease and confidence

#code , #hapijs , #nodejs , #devops

Docker has drastically enhanced how we develop and deploy web applications. With docker, we can isolate our development environment and resemble the production environment as close as possible. When our development environment resembles the production environment, we deploy with confidence.

We can even go a step further. With automated tests, and few other tools, we can automate the deployment. That brings ease and confidence — for us, for our teams, and for our clients. In software development, ease and confidence is value.

In this tutorial, I’m going to show you how to dockerize an existing hapijs application.

dockerizing a hapijs app

Hapijs is a nodejs framework from Walmart. They use it to power their e-commerce system. If you require an introduction to hapijs, you can read my introductory post about hapijs.

First, we are going to create a simple hapijs application. To do that let us create the package.json file.

  "name": "sample-hapijs-inside-docker",
  "version": "1.0.0",
  "description": "Hapijs app in docker container",
  "main": "index.js",
  "scripts": {
	  "start": "node src/server.js",
	  "test": "echo \"Error: no test specified\" && exit 1"
  "author": "Joseph Jude",
  "license": "ISC",
  "dependencies": {
    "hapi": "14.0.0"

This is a common package.json file. I want you to notice just two lines here.

We are using a start script: node src/server.js. It will become clear as we go along. Just keep this in mind.

Also, notice that we are using hapijs version 14.

Now let us create the server.js file.

const Hapi = require('hapi');

const server = new Hapi.Server();
server.connection({ port: 8080 });

    method: 'GET',
    path: '/',
    handler: function (request, reply) {
        reply('Hello, docker!’);

server.start((err) => {

    if (err)
        throw err;

    console.log('Server running at:',;

Nothing special here. We instantiate a Hapi server at port 8080 and print Hello docker when the server comes up.

We can pull an existing nodejs docker container and build our application on top of it. Or, we can build a container from scratch. We are going to build it from scratch.

We are going to use alpine as the base OS for our container. Why alpine? Alpine is both small and secure.

We are going to create a text file named Dockerfile in the same directory where we created the above two files. Dockerfile contains the instructions to build the container.

So our directory structure looks like this:

├── Dockerfile
├── package.json
└── server.js

Let us build the Dockerfile step by step. It looks like this to start with:

FROM alpine:3.4
RUN apk update && apk upgrade
RUN apk add nodejs
RUN rm -rf /var/cache/apk/*

What does these lines mean?

Line 1: We are basing our container from alpine Line 2: Update the OS Line 3: Add nodejs Line 4: remove apk cache

If we build a container with these lines, we will get a nodejs container. We want a hapijs one. So let us go on.

Remember, we already created a package.json and server.js files. Let us copy them into the container. Append these lines to Dockerfile.

COPY . /src
RUN cd /src; npm install
CMD ["node", "/src/server.js"]

Let me explain these lines.

Line 1: We are instructing the docker engine to copy the entire directory to a folder src within the docker container. Line 2: Install the required dependencies. This will install hapijs. Line 3: Notice that in the server.js we are running the hapijs server at 8080. In this line we instruct docker to expose 8080 port to the outside world, so that we can access the server from our host machine. Line 4: Lastly we instruct docker to run the server with the command node /src/server.js. Commands and parameters are given in the fashion as in this line.

Our complete Dockerfile looks like this:

FROM alpine:3.4
RUN apk update && apk upgrade
RUN apk add nodejs
RUN rm -rf /var/cache/apk/*

COPY . /src
RUN cd /src; npm install
CMD ["node", "/src/server.js"]

We can build the container. Open the terminal and issue this command:

docker build -t jjude/hapi .

Docker needs a dockerfile to build a container. We can either provide the full path or instruct to use the dockerfile in the current directory. We are instructing the build process to use the Dockerfile from the current directory.

It is also a good practice to tag the container with <user_name>/<application_name>.

When you issue this command, it will start pulling the necessary components (os, nodejs, hapijs) from the web and build a container. You will start seeing the output that goes like this:

Sending build context to Docker daemon 5.632 kB
Step 1/8 : FROM alpine:3.4