Creating a static web server with Node.js, Express and Docker

Published on May 14, 2018

About 5 minutes read

This website is created using Middleman. Middleman includes a server that allows you to serve your development website, making the development process even faster. It also supports live-reloading so whenever you make any change the page reloads and you see the result of your change with having to press the Refresh button. Using the built in Middleman server is fine when you have to change things around constantly and you need the server to reload your browser to reflect the changes instantly. The only real problem with this process is a speed penalty that you incur, especially as the size of your website increases. The page load times that you will see when using the built in server will not be the same as using a "proper" HTTP server. I wanted to see how fast (or slow) my website would be when I launched it so I decided to use an HTTP Server to serve my page. I initialy thought of using MAMP, which I have used for years, when developing Wordpress projects, but I thought I'd give the Express static server a chance. This is where this little project comes in.

What we'll be building

Express is the most commonly used Node.js framework for building web applications. It's relatively easy to use and doesn't need a ton of boilerplate to get started. Contrary to Ruby On Rails, you build your application from the ground up, including only the things you need. What we'll need here is the static library that will allow us to serve static files.

Anatomy of the application

The end product can be broken down into 3 parts: 1. the package.json file where all the information about the applicagion is held, including all node dependencies 2. the server directory that hosts the index.js that holds the logic for the server and 3. the www directory that stores all the files that will be served by the server.

Creating package.json

Create the folder in which you want to have your express static server. You can create the directory on your terminal by using mkdir *directory_name* and setting the directory name of your choice. Once that's done, cd into that directory and run npm init or yarn init (depending on your dependency manager of choice). This will instruct npm or yarn to create a new project. Go through the questions (or use the -y flag when running the init command) and once you're done you'll be left with a package.json in the root of your new directory. Now we can add the dependecies to our project. I like to use Yarn to manage my javascript dependencies, so in order to add a new dependency you use yarn add *dependecy*. In this case we'll use yarn add express. This will pull express and all its dependencies and add it to our project node_modules folder. Now we're ready to get on with writting our server component.

The Server component

We'll create a server directory inside the root of our project folder and create an index.js file to it. You can call the folder and file any way you want. I just like to use this kind of structure because I feel it's cleaner and more concise. You can use your editing platform of choice to modify the file (mine is Sublime Text).

This is the way that the file will look in the end:

// Define the requirements
const express = require('express');
const path = require('path');
const app = express();

// Define the port the web server will listen to
app.set('port', 8081);

// Use Express to serve the static assets
app.use(express.static(path.join(__dirname, '../www')));

// Start the server and report the port on which it is running
const server = app.listen(app.get('port'), function() {
  console.log('The server is running on: ' + app.get('port'));
});

You can substitute ../www in app.use(express.static(path.join(__dirname, '../www'))); to use your Middleman build directory instead. You can either use a symlink or copy the files you want in the www folder. I copy over the contents of the build directory that middleman creates to the www folder to keep my middleman project folder clean and tidy.

Creating a startup script

Instead of navigating to the server folder and running node server/index.js all the time, we can define a task that will allow us to run the same command from our project root and that would be easier to read. Open your package.json file and add the following after the dependencies section:

"scripts": {
  "start": "node server/index.js"
}

In order to execute your server all you have to do is run yarn start (or npm start) and you're off! (You can stop the server by using CTRL + C at any time).

Trying it out

After all this (not so) hard work, it's time to test out our server! Open your browser and navigate to localhost:8081 (or to localhost and whatever port you used when you built your server) and you should be greeted with the homepage of your website. You can copy the contents of your static pages in the www folder and try it out for yourself.

Bonus Step: Dockerizing the tiny HTTP Server

Create a file named Dockerfile inside the root of the project and paste in the following:

# Use a prebuilt node image
FROM node:9

# Set the working directory to /app
WORKDIR /app

# Copy the package.json file that contains all the dependencies to the container
COPY package.json /app

# Run yarn to retrieve all dependencies
RUN yarn

# Copy the rest of the project files in the container
COPY . .

# Expose port 8081 so that it can be accessed when the container runs
EXPOSE 8081

# Start the server
CMD ["yarn", "start"]

In order to run a container we first must build an image that hosts all of our code and its dependencies. We can do that using the following command: docker build -t express-static-web-server .

Next step is to start the docker container. We can do that using the following command: docker run -d -p 8081:8081 express-static-web-server (the -d switch starts the container in background mode and -p switch creates a route from the localhost port 8081 to the exposed container port 8081).

In order to find out what containers are running, you can use docker ps and in order to stop a running container you can use docker stop CONTAINER_ID.

Resources

You can find the complete project here and you can find more information about the Express serve-static functionality here.

You can also use something like HTTP Server, which is a similar application to this one, but more featureful.