Node.js Dokku Guide

Preparing the App

If it doesn't exist, create a package.json in your project's root directory. Specify the desired version of Node.js. We recommend using an up-to-date LTS version, as these are stable and patched for security vlnerabilities.

{
  "name": "my-app",
  "version": "1.0.0",
  "description": "A sample Node.js app using Express",
  "engines": {
    "node": "16.x"
  },
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "node test.js"
  },
  "dependencies": {
    "ejs": "^3.1.5",
    "express": "^4.15.2"
  },
  "devDependencies": {
    "got": "^11.3.0",
    "tape": "^4.7.0"
  }
}

Create a file named Procfile in your project's root directory to define the command used to start your app (in a production environment, in most cases):

web: npm start

This declares a single process type, web, and the command needed to run it. The name web is important here - this process type will be able to receive web traffic when deployed. This command will use the start script that is specified in the package.json.

Procfiles can contain additional process types. For example, you might declare one for a background worker process that processes items off of a queue.

Create the Dokku App on the Server

Connect to the Healthcare Blocks virtual machine:

ssh username@server-id.healthcareblocks.com

Tip: alternately, use the Dokku Client directly from your local machine instead of connecting to the server.

Create a new Dokku app:

dokku apps:create my-app

Configure Environment Variables

Define app-specific environment variables that your framework can use to control environment-specific behavior:

dokku config:set my-app PORT=3000 FOO=another_value

In Node.js, these settings can be retrieved via process.env:

process.env.PORT

Healthcare Blocks recommends storing sensitive values, including database credentials, in an .env file or equivalent on the server. See this topic for details.

Be sure your application is configured to communicate with any non-local databases using SSL/TLS. Details here.

Configure a Buildpack

Dokku uses an auto-detect function to identify which buildpack is best suited for your application type, however, Healthcare Blocks recommends explicitly configuring the buildpack to avoid any issues.

If you'd like to always use the latest version of the NodeJS buildpack, use the following format:

dokku buildpacks:add my-app \
  https://github.com/heroku/heroku-buildpack-nodejs.git

If you'd like to lock in a specific buildpack release, append the GitHub tag name to the end of the URL:

dokku buildpacks:add my-app \
  https://github.com/heroku/heroku-buildpack-nodejs.git#v195

Release tags can be found here, and the corresponding change log is here.

Reference

Deploy your App

On your local machine, ensure you've initialized your local git repository and committed all files that will be deployed to the server. Development logs and assets and temporary files should be excluded in your .gitignore file.

Define a local git remote that references the Healthcare Blocks server and the app you created above:

git remote add hcb \
 dokku@server-id.healthcareblocks.com:my-app

Notice the "dokku" username. Even though you have a dedicated Linux user on the server, your SSH key is also associated with a dokku user that is used for handling deployments and remote commands.

To deploy the app:

git push hcb main

Main (or master in older git repositories) is the name of the branch you are pushing to on the server and should not be changed. To deploy a different local branch, for example, "integration":

git push hcb integration:main

Alternative Deployment Methods

Dokku is flexible and supports additional options besides buildpacks / git push:

Using Dockerfiles instead of Buildpacks

See Dockerfile Deployment.

Using External Docker Images

If you are already building a Docker image externally and want to use it as the basis for your Dokku app, see Initializing an app repository from a Docker image.

Other External Sources

Instead of using git push from a local machine, you can initialize/update a Dokku app using an archive file or external repository (including private ones).

Frequently Asked Questions

How should the app handle exceptions so that it recovers automatically?
By default, Dokku will automatically attempt to restart app containers whose main process exits and returns what is known as a "non-zero" status. Process exit codes are a historical Linux operating system convention. For guidance about handling process-related exceptions, please check out these resources:

How do I prevent a build from consuming all of my server resources?
The build step associated with Node.js apps can be resource intensive as NPM compiles dependencies. You can set CPU resource limits for the build step as demonstrated here.

How do I handle background job processing in Dokku?
First, add support for Bull and Throng to your Node app, testing everything locally. Update your Procfile with the following startup command:

worker: node worker.js

On the server, install the Dokku Redis plugin in your environment (or create a support ticket requesting assistance), start an instance of Redis, linking it to your app

Deploy your app and scale up your worker process:

dokku ps:scale my-app worker=1

How do I optimize concurrency in my application?
Node.js apps can fork processes to take advantage of parallel processing. Since forking requires additional memory, smaller servers typically don't have enough resources to take advantage of process clustering. However, if you are running on a larger server, then fine tuning concurrency can provide significant gains. When using a worker manager such as Throng, you can specify concurrency via an environment variable:

var WORKERS = process.env.WEB_CONCURRENCY || 1;

And then update the Dokku app's config:

dokku config:set my-app WEB_CONCURRENCY=2

The appropriate value for concurrency is based on total system memory divided by per app process memory. If you need input from our technical support team, please create a ticket.

How do I automatically run database migrations during a release?
Add a release statement to your Procfile with the proper command. See this page for details.

Reference Application

The following Node.js apps are compatible with Dokku