Git-based deployment with Dokku
Introduction
In the vein of the Kirby Meets Docker Recipe, Dokku allows you to containerize and run multiple apps/domains on a single server, manage deployments with git and easily manage domains and certificates with Let’s Encrypt. Dokku can be very helpful for the following reasons:
- Zero-downtime deployment with git
- Easily manage multiple apps/domains/certificates on one server
- Can be simpler to setup/manage than Docker itself
What is Dokku?
According to the Dokku documentation:
Dokku is an extensible, open source Platform as a Service that runs on a single server of your choice.
Behind the scenes, Dokku makes use of Docker containerization to run any number of applications on your server. It allows you to essentially create your own PaaS or something like Heroku where you can deploy and manage your apps. In fact, Dokku will make use of the official Heroku PHP Buildpack to run your Kirby site.
Prerequisites and Requirements
- Access to cloud servers such as Hetzner or Digital Ocean
- A fresh installation of Ubuntu 18.04/20.04 x64, Debian 9+ x64 or CentOS 7 x64 (experimental) with the FQDN set
- At least 1 GB of system memory. Workaround for less than 1GB
- Basic familiarity with Linux and the command line
- Git and composer installed locally
- An SSH key
- A domain name, the ability and knowledge to configure DNS
Goals of this recipe
- Set up two remote Kirby installs on the same server (dev and live)
- Set up persistent storage for the sites (necessary to keep content between deployments)
- Set up domains and SSL certificates with Let’s Encrypt
- Bonus: Deployment via GitHub actions
- Tips: How to enter a running app, how to add packages to the container
Install Dokku
Start a fresh cloud server instance (in my case, I will be using Ubuntu 20.04 x64 on Hetzner). You may also follow the Dokku install instructions to ensure you are installing the latest version.
Then connect your SSH key (i.e. the public key on your local machine, or wherever you plan to deploy from) and set up the domain accordingly.
Pay attention to the domain name on the last line. For example if your domain is example.domain
, you would want to run dokku domains:set-global example.domain
Create Dokku apps
You can create as many apps as you want. In the case of our tutorial, we will create two apps named live
and dev
to show how we are able to run multiple apps/sites on one server and deploy to them independently.
Dokku commands typically follow a syntax such as
If you are unsure of commands, you can simply run dokku
to see a list and then use the command without arguments for more specific help. For example, to learn more about app management, type dokku apps
.
You will see we create apps with apps:create <app>
, so we will go ahead and create our apps:
Clone the Kirby Starterkit to your local machine
Open your local machine, open a terminal and type
Generate composer.lock and adjust .gitignore
I prefer taking vendor items out of the repository and relying on composer
to install our packages for us on deploy. Open the .gitignore
file in the starterkit and add to the top of the file. I also prefer removing content from version control which would typically be necessary if you are running multiple instances anyhow:
Then commit your changes with
In the terminal, run composer update
to generate a composer.lock
file. Commit the new composer.lock
file.
In order to run the panel install remotely, you will want to edit /site/config/config.php
accordingly:
Add and commit your changes to the git repository:
After things are up and running, you should remove this or set up domain specific config files.
Set up direct git deployment to dokku
To deploy directly to our new apps, you will want to add corresponding git remotes for each app.
Amazingly, Dokku autodetects our app and knows to use the Heroku PHP Buildpack automatically, so we can already go ahead and deploy our app. If you need more control, you will want to create a Procfile
in the root of your repository and have a look at the documentation.
Let's start by deploying our live
app:
You will see a fair bit of output which should end with a successful deployment:
Set up a dev branch and corresponding remote
Say we also want a dev branch to be able to show updates without affecting our live site.
Then we can also deploy accordingly:
Set up persistent storage
When a dokku app is deployed or rebuilt, everything within is destroyed. Thus it is critical to set up persistent storage so that your content, accounts etc remain between deployments.
Typically, I would create a separate storage for live
and for dev
:
This creates the two following directories and sets their permissions correctly (dokku apps make use of the 32767:3267 user:group):
The folders I would typically persist across deployments are the content
, media
and site/accounts
folders. Thus we mount the storage to our apps accordingly:
When complete, you can confirm the set up with dokku storage:report
. Then you will want to restart your apps to set up the persistent storage accordingly:
You should now see the new folders created:
Load the starterkit content and test
As the content
is no longer part of the repository, you will need to manually copy the starterkit content. The easiest way would be to do so on the server directly:
Test things out by setting up the panel and an account on the live
app: https://www.example.domain/panel
You should see a working panel and all the starterkit content. Try adding a new Note
in the panel called 'Test Note'.
Confirm that test-note
was created in the storage folder:
Set up domains and DNS
You can see which domains are assigned to our apps:
Let's set the www
subdomain to our live
app:
If you would like to add other domains you can do so with the domain:add
command:
Confirm your settings are correct:
When you are satisfied with your domains, set up A records through your DNS management to point to the server's IP address. If you don't have a domain name, you could try a service like FreeDNS.
In the worst case, you could also edit your hosts file so you can test without using a domain/DNS. This would allow you to visit the page without SSL, but will prevent you from using Let’s Encrypt or making the site available to others.
Once complete, you should be able to visit your sites without encryption. Open your browser and try visiting the pages.
Setup SSL and Let’s Encrypt
The dokku-letsencrypt plugin allows you to configure and manage Let’s Encrypt very easily. Get started by installing the plugin:
Once installed, you will have many commands available, but first you will need to configure an email address for your apps so that Let’s Encrypt can notify you of issues (upcoming expirations, issues with renewal etc):
Then you can go ahead and enable Let’s Encrypt on your apps:
If your domains/DNS are setup correctly you should see a fair bit of output, and in particular:
If you are having trouble, it is possible your DNS settings have not yet propagated or are not setup correctly.
You should now be able to visit your sites with valid encryption certificates: https://www.example.domain, https://dev.example.domain
The certificates should automatically renew, but should you ever have to do so manually you can run dokku letsencrypt:auto-renew
Bonus: Deployment with Github Actions
If you are using GitHub, you can connect this to your deployment via GitHub Actions. With this, you are able to deploy to GitHub, which will in turn deploy to your dokku instance.
Go ahead and create a new GitHub repository and add a remote accordingly. For the purposes of this tutorial, I will create a repository called kirby-dokku-example
and push everything up to GitHub.
In your repository, create the folder/file:
On your local machine, generate a private key for the deployment which will be used by the GitHub action via the ${{ secrets.PRIVATE_KEY }}
variable.
- On GitHub, click on the
Settings
tab and then clickSecrets
in the left-hand column. - Click on
New repository secret
- Name the secret
PRIVATE_KEY
and paste in the contents of the key you just generated. (The private key file without the .pub extension, it should begin with-----BEGIN OPENSSH PRIVATE KEY-----
) - Add the public key to your dokku server:
Commit the new workflow/action and GitHub should automatically deploy your app:
If you navigate to the Actions
tab on GitHub, you should already see the workflow in progress. Clicking on it, you should see the Deploy
action underway.
By setting up different workflows, you could choose to set up certain branches to deploy to different apps accordingly. For example, you could also create a deploy-live
and deploy-dev
branch, and thus keep the running apps separate from your work in progress.
Tips
- If you need to open a shell inside one of your apps, try
dokku enter <appname>
. For example,dokku enter live
. Sometimes, you will need to also include the process:dokku enter live web
. - The buildpacks are very minimal, if you want a text editor included inside your container, create a file named
apt-packages
at the root of the repository and add the necessary packages, for examplevim-tiny
. You will also need to install the dokku-apt plugin. - You can view the nginx/server logs on an app with
dokku logs <appname>
- If you are having issues, try turning trace mode on with
dokku trace:on
. The output will be significantly more verbose, but may help you pinpoint issues that are otherwise hidden.