Create your own Heroku with Dokku on DigitalOcean
By: Alejandro Akbal
Tags: Servers, Heroku, Docker, Dokku, Ubuntu

Introduction

So, you want to have your own infrastructure while having the best commodities to push your code to production, right?

Then you have found your guide. We will go through every single thing that you will need.

We will set up a server on DigitalOcean, configure your application for usage with Dokku, learn how to push your code directly to production and finalize the guide by adding TLS/SSL to your application.

The best thing? This is all free. (*)

(*) If you are a new user on DigitalOcean and register through a referral link.

0. Before we start

What is Dokku

You might be wondering what Dokku is.

Dokku is a docker-powered Platform-as-a-Service (PaaS) that helps you build and manage the lifecycle of applications.

This means that it shares many similarities with Heroku, so if you have used Heroku before, this will come to you as familiar. For example, you can push code to deploy, use buildpacks, scale processes, etc

Preface

For this guide I will be using Windows 10 with the Git Bash terminal, but everything should be the same on any GNU/Linux system.

The server will be a DigitalOcean’s Ubuntu 20.04 image with Dokku already set up.

As an example application we will use this NodeJS getting started project by Heroku.

Requirements

A DigitalOcean account

A Domain

A Terminal

A SSH key pair

Requirements info

If you don’t have a DigitalOcean account, you should create one, its free! And if you use my referral link you will receive \$100 as credit for free!

If you don’t have a SSH Key pair, then follow this tutorial to learn how to generate and add them to your DigitalOcean account.

1. Droplet creation

This might be the easiest step, as DigitalOcean offers a Ubuntu 20.04 image with Dokku already set up, just follow that link and create a droplet.

Then just choose whatever options meet your needs.

⚠ You should choose a Datacenter that is near you or your clients. ⚠

Once it’s created, go to the “Networking” tab of your new droplet and assign a floating IP.

Visit that IP on your browser and you’ll find the Dokku set up.

Just fill the details with your public SSH Key and the domain you will be using. I recommend enabling virtualhost naming , as its easier and more common than using ports.

Tip: If you had added the public SSH Key to your DigitalOcean before, the Public SSH Key form should have been filled automagically!

For the sake of this guide, I will be using the subdomain dokku on my own domain, akbal.dev.

2. Domain management

My current domain manager is CloudFlare, but you can use any other domain registrar or manager, the instructions should be the same. 😊

DNS records

We have to configure our DNS settings to point to our new droplet’s floating IP.

Start by adding a A type record with the hostname and floating IP you assigned earlier in the Dokku set up.

You should also add a catch-all rule so anything you deploy on a subdomain is automatically forwarded to the droplet.

If you’re using CloudFlare and have trouble connecting in the next steps, try to set the DNS record proxy to DNS only instead of Proxied , as it seems to cause trouble.

3. Local configuration

Before we start, we should configure some things on our end.

💻 These steps are done on our local machine.

Add SSH Key

We have to add our Private SSH Key to our local terminal so we can authenticate and connect to the droplet.

eval `ssh-agent -s` # Start the agent that holds on to our keys

ssh-add '~/path/to/ssh/private.key' # Add our private SSH key

⚠ This is an important step, if you don’t add the private SSH key to the terminal, you won’t be able to push code to Dokku later!

We should check that the key was added successfully. If the output is empty, the key was not added.

ssh-add -l

Then lets try to connect to our droplet via SSH as the root user.

ssh root@<domain> # E.g.

ssh root@dokku.akbal.dev

Voilà, we are in!

4. Application set up

We will need an application to run on Dokku, don’t we?

💻 These steps are done on our local machine.

Clone repository

Lets clone the example application.

git clone https://github.com/heroku/node-js-getting-started.git cd node-js-getting-started

Notice that there is a file that you should be familiar with if you have used Heroku before, the Procfile . We will be talking about it in the next step.

Getting familiar

Now that we have cloned the repository we can install the dependencies and play with the application if we want to.

npm install # Install dependencies npm run start # Start the application

Now if we visit http://localhost:5000 on our browser we should see the application running.

5. Application configuration

We should configure our application so Dokku is able to run it.

You can skip this step if you are using the example application, since it already has been configured.

💻 These steps are done on our local machine.

Buildpacks trivia

Dokku uses Heroku’s own Buildpacks to build your applications and detect what language it is using.

In this guide we are using a NodeJS application, so Dokku will detect and use Heroku’s NodeJS Buildpack.

Learn more about the NodeJS buildpack.

Procfile

Dokku needs a Procfile to identify what process types and commands our application uses, for example, to start a web server.

You should create this file if you haven’t. A common NodeJS Procfile looks like this:

web: node index.js # Or like this

web: npm run start

Learn more about the Procfile and process types.

Node version

Dokku will download and use the NodeJS version specified in the engines section of our package.json .

// ...

"engines": {

"node": "12.x"

},

You should add this part, otherwise Dokku will chose a version of NodeJS that might or might not work with your application.

Further configuration

You should check out the Buildpack documentation of the language you’re using to further configure things!

6. Server configuration

Now that we can connect to the droplet and have set up our application, lets configure the server a bit.

🖥 These steps are done on the Dokku droplet.

RAM Swap

Chances are that you will be using Dokku on a low memory (<2GB) droplet.

To fix possible failures due to low memory, we should create a bigger swap file. Read this tutorial to learn how to do so.

7. Server security

While securing a server is not an easy task, the following instructions will take care of the most common problems.

🖥 These steps are done on the Dokku droplet.

Root user

We have been using the root user, but it is a security risk. We shouldn't be using it for everything, we should use instead our own user with root privileges.

Follow this guide to learn how to create a new user with sudo privileges.

Once you have done that, we should copy the Public SSH Key from the root user to our own user.

USER=<user> # Set the user variable

mkdir -p /home/$USER/.ssh # Create ssh directory

chmod 700 /home/$USER/.ssh # Apply directory permissions

cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys # Copy the ssh authorized key

chown -R $USER:$USER /home/$USER/.ssh # Apply user and group permissions

sudo chmod 600 /home/$USER/.ssh/authorized_keys # Apply file permissions

# As a one-liner

USER=<user>; mkdir -p /home/$USER/.ssh && chmod 700 /home/$USER/.ssh && cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys && chown -R $USER:$USER /home/$USER/.ssh && sudo chmod 600 /home/$USER/.ssh/authorized_keys # E.g.

USER=alejandro; mkdir -p /home/$USER/.ssh && chmod 700 /home/$USER/.ssh && cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys && chown -R $USER:$USER /home/$USER/.ssh && sudo chmod 600 /home/$USER/.ssh/authorized_keys

Now try to reconnect to the droplet with the new user.

ssh <user>@<domain> # E.g.

ssh alejandro@dokku.akbal.dev

Perfect. It has worked like a charm.

SSHD

The default droplet configuration allows anyone to log in as the root user, this should be disabled as it is a security risk.

Look at the first step of this guide to learn how to configure SSHD and disable root user login.

Docker ports

Docker ports are open by the default on the firewall, we should shut them, as it can be a security concern.

sudo ufw status # Optional, check the current rules on the firewall # Delete Docker rules

sudo ufw delete allow 2375/tcp

sudo ufw delete allow 2376/tcp sudo ufw status # Optional, check that Docker's ports are deleted

UFW is Ubuntu’s firewall manager, learn more.

Fail2Ban

Fail2Ban is a utility to protect your server from brute-force and automated attacks. It blocks repeated connection attempts and bans them temporarily.

Here is an easy guide on how to install, configure and use it.

8. Dokku

Now that every step of configuration is complete, we can move to the actually interesting step: actually using Dokku!

🖥 These steps are done on the Dokku droplet.

Dokku CLI

Dokku is used from the terminal, it doesn’t have an interface or a web view, and that is its strong point, as it consumes less resources of your system that your applications will need.

To start using Dokku just type dokku on the terminal.

dokku

Common Dokku commands

These are some commands that you will definitely have to use, so visit the documentation links and get familiar with them.

App creation

First step will be to create an application.

dokku apps:create <app> # E.g.

dokku apps:create my-app

The app shell is now created, but empty. Until we push code it won’t do anything.

But before doing so we should configure other aspects, like the domain it is going to use.

Read more about application management in Dokku.

Domain configuration

Lets add a domain so we can access our application easily from our browser once its deployed.

dokku domains:add <app> <domain> # E.g.

dokku domains:add my-app my-app.dokku.akbal.dev

Read more about managing domains in Dokku.

Environment configuration

If our application uses any environment variables, for example an .env file, you should add them through Dokku.

dokku config:set <app> <variables> # E.g.

dokku config:set my-app NODE_ENV=production # You can add multiple environment variables.

dokku config:set my-app NODE_ENV=production SECURITY_KEY=XXX

Keep in mind that executing this command will restart the application.

Read more about managing environment variables in Dokku.

Deploying code

Now its time for the real deal, we have configured everything on our local machine and on the server, so lets deploy!

💻 These steps are done on our local machine.

Lets add Dokku as a git remote so we can push code to it.

git remote add <remote-name> dokku@<remote>:<application> # E.g.

git remote add dokku dokku@dokku.akbal.dev:my-app

Only thing left is to push the code, lets try!

git push <remote-name> <local-branch>:master # E.g.

git push dokku main # Or if your branch is already master

git push dokku master

And that is it! Once the code is pushed you should see Dokku detecting and building your application! 🥰

If this step is giving you trouble, chances are that you might not have added your private SSH Key to your current terminal, learn more in the Add SSH Key step.

Once Dokku is done it will output a link to visit your application in your browser, do that!

_The website might not work because Dokku forces HSTS, and we haven’t configured TLS/SSL yet. Learn how to disable HSTS._

TLS/SSL configuration

We will add the lets encrypt plugin to Dokku so the application will be served with HTTPS.

First add the letsencrypt plugin to Dokku.

Then add a required letsencrypt contact email through environment variables.

dokku config:set <app> DOKKU_LETSENCRYPT_EMAIL=<email> # E.g.

dokku config:set my-app DOKKU_LETSENCRYPT_EMAIL=contact@akbal.dev # We can set the contact email globally too, so it works for any application.

dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=<email>

Now its time to generate a certificate for our application.

dokku letsencrypt <app> # E.g.

dokku letsencrypt my-app

It was that easy to add HTTPS.

Check our super secure site!

Read more about configuring the letsencrypt plugin.

Scale processes

Scaling the processes is really easy, you just have to tell Dokku and it will handle everything.

🖥 These steps are done on the Dokku droplet.

dokku ps:scale <app> <process-type>=<count> # E.g.

dokku ps:scale my-app web=1 # Even multiple types

dokku ps:scale my-app web=1 worker=2

Read more about scaling processes in Dokku.

9. Misc

Further knowledge

I encourage you to go to the Dokku documentation and toy with your now complete Dokku set up. You will learn many great things like how to read the logs of your application.

Troubleshooting

I need to identify what is going wrong

Enable Trace Mode.

In this mode output will be more verbose, helping you locate any error!

Can’t push code to Dokku remote

This might be because you have not added the private SSH Key to your terminal, try adding it!

Dokku remote Git branch is ahead of time

I’ve been in a situation where I had commited to Dokku and went back locally to an earlier commit, this created many problems when trying to push again, because Dokku’s own git repository was in the future. Thankfully, theres a very easy solution: force push! 💪

git push --force dokku <branch> # E.g.

git push --force dokku main

Agent returned different signature type ssh-rsa (expected rsa-sha2–512) (Windows 10)

It seems that the ssh binaries on windows 10 are outdated and the connection is refused by the server, a solution is to use Git Bash or any other terminal with updated binaries, more on this issue here

10. End

I hope you have enjoyed my complete guide and find it useful, It has taken many days to bring you this knowledge.

Useful links

These are some resources that can be very useful through your Dokku journey.

Self promotion

If you have found this tutorial useful then you should follow me, I will be posting more interesting content! 🥰

Or support me financially. 💸

If you want to continue learning check out this “How to completely secure an Ubuntu server” article by myself.

Credit

This guide was made possible thanks to many wonderful people.