Deploying a Node.js Application on Digital Ocean Using dokku

Deploy a Node.js Application on Digital Ocean Using dokku and enable TLS using Cloudflare.

Today I’m going to cover a possible solution you can follow to deploy your node.js application to a Digital Ocean droplet running dokku. We’ll also use floating IPs along with Cloudflare to serve content over TLS.

I’ll assume you’re familiar with node.js/express applications already and have purchased your domain. You can find the sample express app here.

Note: At the time of this article, Digital Ocean’s one-click dokku image is using version 0.7.2, but we’ll install 0.8 manually via SSH.

cloud-config

We’re going to use a cloud-config script to handle most of our droplet setup.

When we create our droplet this will do a couple of useful things for us:

  • Perform apt update and apt upgrade operations
  • Install some common packages
  • Disable password login
  • Disable root login
  • Create the app user with sudo priviliges
  • Add app and dokku users to the allowed SSH list

Replace PUB_KEY with your own SSH public key file contents. Commonly found at ~/.ssh/id_rsa.pub.

Create the Droplet

On Digital Ocean go ahead and begin creating your new droplet.

Note: dokku recommends a minimum 1GB of RAM. I have been bitten by this in the past when using a 512MB RAM droplet. You’ll end up seeing errors along the lines of: remote: /tmp/buildpacks/02_buildpack-nodejs/lib/dependencies.sh: line 10: 340 Killed, which is common when the process runs out of memory.

Complete the following:

  • Select Ubuntu 16.04.1 x64
  • Select your region
  • Select the $10/month 1GB of RAM size
  • Check the User data and Monitoring boxes
    • Paste the cloud-config into the User data text area
    • Don’t forget to replace PUB_KEY with your own
  • Select an SSH key for root login, or skip for an email to be sent containing the password
    • Password and root login will be disabled via SSH after the cloud-config runs
  • Give your droplet a hostname, I’ll use express-app

When you’re ready click Create.

Tailing cloud-config

Give the box a few seconds to make the IP availabe, then from your terminal: ssh app@droplet-ip. You may get denied a few times when logging in with SSH, just retry after a few seconds and SSH should be available. Once inside, we can tail the cloud-config progress by running: tail -f /var/log/cloud-init-output.log. Feel free to watch the progress until the tailing stops and the output ends with OK. When your satisfied everything looks good, run sudo reboot as the system will probably need it.

Give the server a moment to reboot then verify that you can SSH via ssh app@droplet-ip. You’ll notice you can no longer SSH using root.

Assigning a Floating IP

We’ll use a floating IP to ensure our droplet IP doesn’t change on us. On Digital Ocean click the Networking link in the navigation, then Floating IPs and assign one to your droplet. Floating IPs are not free. You are charged $0.006/hour and only pay if you reach at least $1 (at the time of this article).

Setup Cloudflare

Go ahead and signup for a Cloudflare account. We’re going to use their free tier to get TLS for our appliacation. Cloudflare will also not expose our floating IP which is pretty handy. Just keep in mind without some custom DNS configuration to bypass Cloudflare, you’ll still SSH via the floating IP, not your domain.

When you login, begin by adding a site. Enter your domain name and click Begin Scan. You should see something along the lines of:

When the scan is complete, click Continue Setup. At this point Cloudflare will ask that you verify all your DNS records. We’ll want to add two A records for our droplet:

  • Name: yourdomain.com IPv4 Address: Floating IP
  • Name: www IPv4 Address: Floating IP

Then click Continue.

On the next screen, select the Free Website plan. Click Continue.

You will now be shown your custom nameservers. You will need to configure these on your domain provider. For example on Namecheap, this will look something like:

At this point we just need to wait for Cloudflare to verify the configuration. This can take up to 24 hours, but in my experience it never does.

Generating Origin Certificates

So the next thing we need are Origin certificates from Cloudflare. They provide certificates with a lifetime of up to 15 years. Select your domain and click DNS. From here scroll until you see Origin Certificates and click Create Certificate. You’ll see something like:

We’ll keep the defaults and click Next.

On the following screen you will be instructed to save two RSA keys, one as domain.pem and another as domain.key. Save them somewhere on your harddrive and create another file - domain.crt, by typing: cat domain.pem > domain.crt. We will use the .crt and .key files to prepare a tar file for dokku.

To create the tar file, run: tar cvf certs.tar domain.crt domain.key. We’ll use this after we create the express app on dokku to enable TLS.

Installing dokku

Login to your droplet using your floating IP and run wget https://raw.githubusercontent.com/dokku/dokku/v0.8.0/bootstrap.sh followed by sudo DOKKU_TAG=v0.8.0 bash bootstrap.sh.

Wait for the installation to finish, this can take a few minutes. Once complete, visit your domain and you will see a screen like:

Note: If your domain is not resolving, you probably just need to wait until the DNS has propagated.

Replace the Hostname IP with your domain name and for now leave virtualhost naming unchecked (virtualhost naming is handy for having multiple apps on a single dokku droplet), we won’t use it for this application. Click Finish Setup.

Verify dokku

If you’re logged into your droplet, logout, then run ssh dokku@droplet-ip to see the dokku help information. dokku is now setup.

Create the dokku Application

Creating a dokku application is pleasantly easy: ssh dokku@droplet-ip apps:create app-name. I’ll use the app name express-app.

Reminder: You can find the node.js application repo here.

Add the dokku Remote

We need to track the dokku application so we can deploy with git push. You can add the remote using: git remote add dokku dokku@droplet-ip:app-name.

app.json & Procfile

The next step is to create an app.json file, which contains some repository and buildpack information. We’ll also create a Procfile containing a startup command. This will all feel very familiar to those who have used Heroku.

app.json

{
  "name": "express-app",
  "repository": "https://gitlab.com/jakeklassen/express-app",
  "buildpacks": [
    {
      "url": "https://github.com/heroku/heroku-buildpack-nodejs"
    }
  ],
  "env": {
    "NPM_CONFIG_PRODUCTION": false
  }
}

Update the repository field with your own. The name must match the dokku application name.

Note: NPM_CONFIG_PRODUCTION is used to allow for devDependencies to be installed. I like to build the application after deployment.

Procfile

web: node dist

This command will run the application.

Deploy

Finally, let’s deploy the application with: git push dokku master. After the deployment has completed you can access the site using your domain name.

You can deploy a custom branch to dokku using: git push dokku branch-name:master. You always deploy to dokku master. This can be handy to test out ideas with local branches as well.

TLS

Let’s get our https:// support going. Remember that certs.tar file we made? Let’s put it to use. To enable TLS simply run ssh dokku@droplet-ip certs:add app-name < certs.tar, dokku will handle the rest. You can now access your site using https:// and any attempt to access the insecure page will be redirected.

When you need to update the certs (in 15 years…), generate new certificates on Cloudflare and re-tar the files again. Then you can run ssh dokku@droplet-ip certs:update app-name < certs.tar. Piece of cake.

Conclusion

Hopefully this has shed some light on a resonable setup using Digital Ocean and a Heroku like platform. dokku has proven pretty handy for me both at work and in personal projects. I’m looking forward to moving on to platforms like Clever Cloud and serverless to alleviate some repetitive work when dealing with servers in this way.

A nice logical step after this is to integrate your CI. Setting up Gitlab to run tests followed by deployment on success is a nice flow.

 
comments powered by Disqus