Deploying a Go App with Dokku
Deploying a Go App with Dokku
Deploying a Go App with Dokku
 
Edit 02/07/2021: Thanks to all the Golang Reddit community. My post got featured and reached the top hot section 🔥.
 
Dokku is an easy and cost-effective approach to deploy your project in a language-agnostic way. It's an open-source and free alternative to Heroku on your own servers. Once set up, a simple git push command will update your app on your server.
 
In this tutorial, we will use a simple Go HTTP server and deploy it from scratch on our Linux server. The Go HTTP server consists of a simple REST API which let user create, update, get and list Todos.
 
 

Summary

  • Choose a server
  • Install dokku
  • Web installation
  • Create the app
  • Install PostgreSQL
  • Deploy your app
  • Configure domain and HTTPS
  • Manage environment variables
  • Github auto deployment
  • Final note
 

Choose a server

 
Since we will self-host our app, you need to have a server. Any provider or home server will be fine but if you're looking for a cheap one, you can check Digital Ocean or Vultr. They both provide VPS for a couple of euros or dollars.
 
Choose a Linux distribution and then you're done!
 
We will use a custom domain to deploy our app. So make sure you created a DNS record of the domain or subdomain of your choice to your Server IP.

Install dokku

 
Now that our server is running, we can connect to it via SSH and start installing dokku. I recommend you to refer to the main page to install it with the latest version and for your distribution (debian, apt, or arch).
 
On a Debian distribution, the command to install dokku is the following:
 
wget https://raw.githubusercontent.com/dokku/dokku/v0.24.10/bootstrap.sh;
sudo DOKKU_TAG=v0.24.10 bash bootstrap.sh
 
The installation can take a couple of minutes, it will install all the decencies and start a web server for installation purposes.
 

Web installation

 
Then you have to open your browser and navigate enter your VPS IP. Here you can setup:
  • Paste your Public Key, which can be a one you generate or an existing one
  • Set the Hostname which can be your domain name if you have one (example.com)
  • Enable the virtualhost option
 
Enabling these options will let you use custom subdomains when deploying your apps. For example, if your hostname is example.com deploying a web app will be publicly accessible at web.example.com instead of your VPS IP address.
 

Create the app

 
Now that your server is fully set up with dokku you have to create your first app. You should create an app for each app you want to deploy on your server.
 
Connect on your server and execute the following commands:
 
dokku apps:create go-example
 

Install PostgreSQL

 
Since our Go app requires a PostgreSQL instance, we will install it with dokku. To do so we just have to install the Postgres plugin:
 
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
 
And then create our PostgreSQL instance and link it to our Go app:
 
dokku postgres:create example
dokku postgres:link example go-example
 
The postgres:create command will create a new PostgreSQL instance with the example name and the postgres:link will link the database to our app and add a DATABASE_URL environment variable to it which contains all the information to connect the database.
 

Deploy your app

 
Now that our app and database are ready we can start deploying our app for the first time. By default, dokku will detect your Go code base and build a custom Docker image for you, but in some cases, it will use an old Go version. To use the latest Go version there are two solutions.
 
  • Adding a // +heroku goVersion VERSION annotation to the go.mod file.
  • Creating a Dockerfile at the root of your project and use the latest go version
 
Since it's the simplest solution, we will add the following comment to our go.mod:
 
// +heroku goVersion 1.16

module github.com/shellbear/dokku-go-example

....
 
Then you can configure git to push your code to your dokku server. Just replace YOUR_VPS_IP with your VPS IP address:
 
git remote add dokku dokku@YOUR_VPS_IP:go-example
git push dokku main
 
Wait some minutes and tada! Your app should be deployed on your server. But wait, you can't yet access publicly your app, we have to make some further configuration to make it accessible.
 

Configure domain and HTTPS

 
Connect back to your VPS with SSH and install Let's Encrypt so we can have free HTTPS support for your custom domain:
 
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=your-email@your.domain.com
 
Now that Let's Encrypt plugin is installed you can configure your domain and HTTPS for your app:
 
# set a custom domain that you own for your application
dokku domains:set go-example go-example.example.com

# enable letsencrypt
dokku letsencrypt:enable go-example

# enable auto-renewal
dokku letsencrypt:cron-job --add
 
Note: if you have any error during this step such as acme: error: 403 :: urn:ietf:params:acme:error:unauthorized, make sure that your correctly configured your domain name so it points to your VPS IP.
 
If everything worked, you should be able to access your Go app at the domain you defined, with HTTPS support out of the box.
 
From now, every time you will git push dokku main, your code will be automatically deployed, on your server.
 

Manage environment variables

 
If you app need further environment variables, you can manually add ENV variables to your app with the config:set command:
 
dokku config:set go-example VARIABLE_NAME=value SECOND_VARIABLE=other_value
 
You can also view the existing environment variables:
 
dokku config:show go-example

=====> go-example env vars
....
SECOND_VARIABLE:       other_value
VARIABLE_NAME:         value
 
And you can easily remove environment variables with the config:unset command:
 
dokku config:unset go-example VARIABLE_NAME SECOND_VARIABLE
 
Every change will trigger a deployment, so you don't have to do it manually after changes.
 

Github auto deployment

 
As you saw every deployment requires to manually execute git push command on your host machine. You certainly want to automate this process and automatically deploy your code on Git changes.
 
Since we're using Github we can create a Github Action to automatically deploy our code on changes.
 
Create a .github/workflows/deploy.yml with the following content:
 
---
name: 'deploy'

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Cloning repo
        uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: Push to dokku
        uses: dokku/github-action@master
        with:
          git_remote_url: 'ssh://dokku@YOUR_VPS_IP:22/go-example'
          ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}
 
This Github action will be executed when any change is made on the main branch. Then you have to create the SSH_PRIVATE_KEY secret. Go in the Settings and then Secrets section of your repository and copy your SSH private key.
 
A good practice is to create a new key only for this Github Deploy action. If someone steals your private key, you can just revoke the old one and generate a new one.
 
If you want to generate a new SSH key, execute the following command on your host machine:
 
ssh-keygen -f dokku_rsa
 
This will generate a dokku_rsa private key and dokku_rsa.pub which is the public key. Copy the content of dokku_rsa and paste it into the Github secret value.
 
notion image
 
And then the newly create key to your dokku server:
 
cat dokku_rsa.pub | ssh cloud@YOUR_VPS_IP dokku ssh-keys:add github
 
This one-line command will pipe the content of your public key to the ssh-keys:add of your VPS.
 
Now every time you push some code, it will automatically be deployed on your VPS.
 

Final note

 
As you saw, deploying a Go app with dokku is really fast and easy. Having auto-deployment and HTTPS in a few minutes is really a big plus.
 
Using dokku should be fine for low or moderate production workload. But dokku is not yet made for HA. There are some schedulers plugins to deploy on either Kubernetes or Nomad. This can be a solution if you have higher load needs.
 
Make sure to check the code at: https://github.com/shellbear/dokku-go-example
 
Thanks for reading 👋

Antoine Ordonez

Mon Jun 28 2021