Deploy an Always-On Node.js Express Application with Docker

Updated on October 1, 2020
Deploy an Always-On Node.js Express Application with Docker header image

In this article, you'll learn how to deploy a simple NodeJS Express web application within a Docker container, using the Vultr One-Click Docker app.

1. Create the Docker Instance

The One-Click Docker application automatically installs Docker for you and creates a docker user and group for limited access. Use the steps in the One-Click Docker article to set up the instance.

  1. Create an instance using the Docker application for Server Type.

  2. SSH to the server as root. Install NodeJS and NPM, the Node package manager.

     # curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
     # sudo apt-get install -y nodejs
  3. log into the pre-created Docker user.

     # su - docker

2. Create the Node Application

Set up a simple Express app that listens on port 80 and responds to requests at http://<server-ip>/ with "Hello from Docker!".

  1. Make a directory named src in the docker user's home directory and navigate into it:

     $ mkdir ~/src
     $ cd ~/src
  2. Initialize the ~/src directory as a NodeJS application:

     $ npm init

    When prompted for the package name, enter hello_node_docker. Press Enter for the remaining prompts.

  3. Install the express package, which also creates a package.json file that tells node how to run your application.

     $ npm install express
  4. Create an index.js file, which contains the application code.

     $ nano index.js

    Paste the following code:

     var express = require('express');
     var app = express();
    
     app.get('/', (req, res) => {
         res.send("Hello from Docker!");
     });
    
     app.listen(80, () => {
         console.log("Listening on port 80!");
     });
  5. Save and exit the file.

So far, you've created a basic NodeJS application that has Express as a dependency, listens on port 80, and responds to GET requests at / with "Hello from Docker!".

3. Create the Dockerfile

  1. Create a Dockerfile that describes how Docker will build your application.

     $ nano Dockerfile
  2. Paste the following contents into the file.

     FROM node:latest
     COPY ./ .
     EXPOSE 80
     CMD ["node", "index.js"]
  3. Save and exit the file.

The Dockerfile tells Docker to:

  • Use the latest version of node
  • Copy the code to the docker image
  • Expose port 80
  • Run the command node index.js to start your application.

4. Create the Docker Image

Create the docker image using the application code and the Dockerfile. Run the command below, replacing example-name/example-application with your name and the name of your application (without spaces):

$ docker build -t example-name/example-application .

This command will build a Docker image and tag (-t) it with name/application.

The command may take a few minutes to complete.

Step 5: Run the Docker Container

After building the image, run the container with the following command:

docker run -p 80:80 --restart unless-stopped -d example-name/example-application

If you changed example-name/example-application, be sure to update it in the command above.

This command will:

  • Run the Docker container named example-name/example-application.
  • Expose port 80 of the Docker container to port 80 of your Vultr instance with: -p 80:80.
    • The number on the right is the port of the Docker container, which is exposed to the port number on the left of the Vultr instance.
  • Restart the application if stopped, unless you stop it manually. The -restart unless-stopped directive will automatically restart the app if the code crashes or if the instance restarts, making it ideal for running long-term processes like a web server.

Understanding Restart Policies

A restart policy for a Docker container can be specified using the --restart flag (such as the --restart unless-stopped used in the previous command). Restart policies are especially helpful when configuring Docker containers, as they can help you manage unintended failures and avoid unnecessary downtime associated with crashes or bugged code.

The default option for a container's restart policy is to do nothing. If no option is specified, the container will stop if it crashes or the process exits (and will not restart automatically).

This guide uses the --restart unless-stopped option. This option tells Docker to restart your container unless the container is stopped manually.

The --restart on-failure restart policy tells Docker only to restart the container if its process exits due to an error (non-zero exit code). It is possible to specify the maximum number of attempted restarts by adding :max-retries to the end. For example, to only make three restart retries due to non-zero exit codes, specify --restart on-failure:3.

The final restart policy is --restart always. This directive tells Docker to restart your container any time it exits (for any reason, error, or not). The container will automatically start whenever the Docker daemon starts.

Testing Your Application

In a web browser, navigate to your instance's IP address. You should see "Hello from Docker!" printed in the browser.

Cleaning Up

  1. List the running Docker containers:

     $ docker container list

    Optionally, list all containers:

     $ docker container list -a
  2. Look for the container you created. You should see a column named CONTAINER ID.

  3. Copy the id and replace CONTAINER_ID in the following commands with your container's ID.

To stop your container:

docker container stop CONTAINER_ID

The application will exit, and requests to your app will fail.

To delete the container:

docker container rm CONTAINER_ID