Start a team blog
Start a team blog, invite your team, and start publishing.

Post hidden from Hashnode

Posts can be hidden from Hashnode network for various reasons. Contact the moderators for more details.

Indie DevOps - Deploying Your Applications (Part 3)

Indie DevOps - Deploying Your Applications (Part 3)

the ludicrous blog's photo
the ludicrous blog
·Dec 27, 2020·

5 min read

Welcome to the next part of the "Indie DevOps" series. This post will show you how to set up and deploy your applications with a simple git push.

We will be using Dokku (a self-hosted heroku), which supports deploying with a Dockerfile or any of the following Heroku buildpacks.

  1. Ruby
  2. Node.js
  3. Clojure
  4. Python
  5. Java
  6. Gradle
  7. JVM
  8. Grails 3.x
  9. Scala
  10. Play 2.x
  11. PHP
  12. Go and more...

Provisioning The Server

We are going to use DigitalOcean for all of our server needs. You can go with another VPS provider, however, keep in mind that DigitalOcean comes with a One-Click Dokku installer to make setup easy.

First, create a new Dokku instance on DigitalOcean. Here is a supplementary guide on how to set that up. For this guide, we will call the droplet "web" as this is where all of our web applications will be deployed (if we choose not to use Kubernetes).

Deploying an App with Dockerfiles

We almost always use Dockerfiles as opposed to buildpacks because they tend to deploy faster (due to layer caching) and are more portable (in case we need to host somewhere else or debug). If you want to use buildpacks, you can still follow the guide; just skip anything related to Docker and make sure to set up any custom buildpacks if you need. The rule of thumb is if you can push to Heroku, you can push to Dokku!


Before we do anything else, we need to create our application on the server so it is ready to accept a git push. For this tutorial, our application will be called myapp. To start, first ssh into your server:

ssh root@YOUR_IP_HERE

Once you're in, create your application with the following command:

dokku apps:create myapp

You can then do the following additional tasks if you need:

1. Add custom environment variables

Adding environment variables to your Dokku app can be done with the following command:

dokku config:set myapp DOPPLER_TOKEN="secret" ANOTHER_SECRET="shhh"

In our case, we use Doppler to manage our secrets, so we only need to set DOPPLER_TOKEN.

To see all of the secrets for a certain app, we can run:

dokku config:show myapp

2. Add a custom domain

To add a custom domain, we can run the following command:

dokku domains:add myapp www.myapp.com

Then, you can check to see if it was added by running:

dokku domains:report myapp

If you enabled "virtual hosts" when you first set up Dokku, you may see additional domains listed here. If you don't need any of them, you can remove them with:

dokku domains:remove myapp unwanted.domain.com

3. Set up SSL certificates with LetsEncrypt

One of the best features of Dokku is that it has a Letsencrypt plugin to automatically provision and maintain SSL certificates for your domains. To get started, first run:

sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

This will install the Letsencrypt plugin to your Dokku instance. Next, we need to provide an email address to Letsencrypt for the SSL certificate. We can do that through the following command:

dokku config:set --no-restart myapp DOKKU_LETSENCRYPT_EMAIL=your@email.tld

After that, we can provision the certificate:

dokku letsencrypt myapp

If it fails to generate, you may need to take a look at the logs to see what went wrong. If you are using Cloudflare, follow this guide.

Finally, we should set up Dokku to automatically renew the certificates with a CRON job:

dokku letsencrypt:cron-job --add

4. Set up Docker-based deployments

Dokku was initially created for Heroku-like deployments, however, we find that the Docker based deployment is faster, more portable, and easier to set up. If you intend to use Dokku exactly like Heroku, then please skip this step.

To set up Dockerfile based deployments, we just have to run one command to tell Dokku which port to map the webserver to:

dokku proxy:ports-add myapp http:80:5000

Dokku should automatically map port 443 for you, but it if it doesn't, you can do so manually with the same command. Be sure to replace 5000 with the port your app is going to run on.

The Dockerfile

If you intend to use Heroku-like deployments, please skip this section!

At ludicrous we mostly use Node.js so our Dockerfiles will be node-related. If you use another language, please refer to the best practices for creating Dockerfiles. There are plenty of online sources which you can copy-paste from.

To get started, create a Dockerfile:

FROM node:alpine


RUN apk add --no-cache build-base python curl
RUN npm config set python /usr/bin/python

RUN (curl -Ls https://cli.doppler.com/install.sh || wget -qO- https://cli.doppler.com/install.sh) | sh

COPY package*.json ./

RUN npm ci

COPY . .

ENV NODE_ENV=production
ENTRYPOINT ["doppler", "run", "--"]
CMD ["npm", "start"]

There is a lot going on here so let's dissect the important parts:

The first few lines just pull the latest alpine image for node and install python which we some of our dependencies need.

Next, we install Doppler:

RUN (curl -Ls https://cli.doppler.com/install.sh || wget -qO- https://cli.doppler.com/install.sh) | sh

This will inject our environment variables when we start our application. If you haven't tried Doppler, we highly recommend checking it out; it has saved us a lot of time. We wrote another blog post on how we set up and use Doppler at ludicrous.

After installing Doppler, we copy our package.json and package-lock.json (if you are using yarn, you will need to change this to yarn.lock) and install the packages.

After installing dependencies, we move on to COPY . ., which copies our entire source code into the container. Finally, we end by setting up our environment and providing the start command for our server.

The Push

After everything is configured correctly, the last thing we need to do is push to the Dokku repository. First, make sure to commit all your changes including your Dockerfile. Then, add the Dokku server as a remote with the following command:

git remote add dokku dokku@YOUR_SERVER_IP:myapp

And that's it! Run

git push dokku master

to deploy your application! You will need to make sure that your domain's DNS is configured properly to point to the DigitalOcean server, but once that is done you should be able to visit the URL and see your newly deployed application.

Dokku supports zero-downtime deployments so the next time you deploy, it will first set up everything in the background, ensure it's working, and then replace the live version of the site with the new version without losing any requests.