Bugsink on Dokku

Klaas van Schelven
Klaas van Schelven; April 7 - 5 min read
Software Developer, looking at Bugsink on Dokku

Bugsink is the error tracker tool I built to help developers track and fix errors in their applications. It has a strong focus on being easy to self-host. As part of the efforts to make Bugsink easy to self-host, I have been working on making it easy to deploy on various platforms.

Dokku is “an open source PAAS alternative to Heroku, that helps you build and manage the lifecycle of applications from building to scaling.”

The below is a short overview of my experience setting up Dokku and deploying Bugsink on Dokku. The whole process (excluding the writeup) took me less than 30 minutes.

Getting Started with Dokku

Dokku is a platform as a service (PaaS) that allows you to deploy applications and services on your own server, i.e. it’s ““bring your own server”.

This means that the first step was to get a server up and running. I went with Hetzner, which is a great an affordable option for hosting.

For this experiment, I simply clicked on the cheapest VM I could find, which was a CX22, 2 vCPUs, 4 GB RAM, 40 GB with a dedicated IP. I chose Ubuntu 24.04 as the operating system, and configured the server with a single public IP and my SSH key.

While skimming through the dokku documentation I saw some notes about amd64 and arm64 architectures, which seemed to indicated that getting up and running with arm64 might be a bit more involved. Since I was going for the 30-minute speedrun, I made sure to pick an amd64 server.

Installation was indeed a breeze; I simply SSH’d into the server and ran the following 3 commands:

wget -NP . https://dokku.com/install/v0.35.16/bootstrap.sh
sudo DOKKU_TAG=v0.35.16 bash bootstrap.sh
cat ~/.ssh/authorized_keys | dokku ssh-keys:add admin

DNS settings

I also had to set up a domain name for the server, which I did by creating an A record in my DNS provider. I went with dokku.bugsink.com (I own the domain bugsink.com, so this was easy).

In the terminal, I ran the following command to set up the domain name:

dokku domains:set-global dokku.bugsink.com

Since I was already at the UI of my DNS provider, I also created a wildcard subdomain for *.dokku.bugsink.com to the same IP address. Dokku deploys applications to subdomains, so having a wildcard subdomain makes it easier to deploy the actual application that we care about.

Deploying Bugsink on Dokku

Dokku allows you to deploy applications using a git push. This means that you can deploy Bugsink by simply pushing the code to the Dokku server. Since Bugsink is source-available, you can simply clone the repository and push it to Dokku.

Docker or Buildpacks?

Dokku supports both buildpacks and Dockerfiles. It seems that the default is buildpacks, and that buildpacks may be slightly easier to use. I’ve also used deployed Bugsink on the python buildpack while helping out some former colleagues, and it worked great.

However, since I didn’t have access to the work I did for them, and I recently did some work on the Dockerfile to ensure that it works even more smoothly, I decided to go with the Dockerfile for this experiment.

Creating the app

The first step is to create a new app on the Dokku server. This can be done by running the following command:

dokku apps:create bugsink

This will create a new app called bugsink on the Dokku server. You can then push the code to the Dokku server by running the following on your local server:

git clone git@github.com:bugsink/bugsink.git
cd bugsink

git remote add dokku dokku@dokku.bugsink.com:bugsink
git push dokku main

This actually failed, but luckily it did so in a way that was easy for me to understand:

File "/tmp/pip-build-env-jetzbuye/overlay/lib/python3.12/site-packages/setuptools_scm/_get_version_impl.py", line 117, in _version_missing
        raise LookupError(
    LookupError: setuptools-scm was unable to detect version for /app.

    Make sure you're either building from a fully intact git repository or PyPI tarballs. Most other sources (such as GitHub's tarballs, a git checkout without the .git folder) don't contain the necessary metadata and will not work.

    For example, if you're using pip, instead of https://github.com/user/proj/archive/master.zip use git+https://github.com/user/proj.git#egg=proj

    Alternatively, set the version with the environment variable SETUPTOOLS_SCM_PRETEND_VERSION_FOR_${NORMALIZED_DIST_NAME} as described in https://setuptools-scm.readthedocs.io/en/latest/config.
    [end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.

What’s going on here? The answer is that Bugsink (using setuptools_scm) cannot determine its own version because there is no git repository in the directory. This is because Dokku does, by default, not include the .git directory when pushing the code to the server.

This is a good default choice for reasons of security and performance, but it does mean that we’ll have to do some more work. Since I was speedrunning this, I didn’t want to spend too much time on it, so I decided to go with the simple solution of just including the .git. This can be done by configuring Dokku to keep the git directory when deploying, like so:

dokku git:set bugsink keep-git-dir true

Two more notes on this:

  • In the “general case” of deploying Bugsink the above is not a problem, because typically you wouldn’t deploy from source (using a Dockerfile), but instead from either a Python .whl or a Docker image, both of which come with the correct version number already built into them (and without any .git directory).

  • It’s probably possible to fix the above without including a full .git directory by environment variable setuptools expects with Dokku’s GIT_REV-equivalent

Getting the env-vars right

Pushing again got me to the following error:

monofy starting with pid 7
monofy 'pre-start' process: bugsink-manage check --deploy --fail-level WARNING
SystemCheckError: System check identified some issues:
WARNINGS:
?: (security.W009) Your SECRET_KEY has less than 50 characters, less than 5 unique characters, or it's prefixed with 'django-insecure-' indicating that it was generated automatically by Django. Please generate a long and random value, otherwise many of Django's security-critical features will be vulnerable to attack.

Clear enough, and perhaps I should have actually read my own installation instructions before pushing arbitrary code live. In any case, this was easily fixed (and also a reminder to copy the other environment variables from the installation instructions) by providing a few env-variables.

dokku config:set bugsink CREATE_SUPERUSER=admin:admin \
    SECRET_KEY=hBzd1CQQ0v9s4pOjTg0y7CTqSVQU4BCuIbufzZLp4splQ24Aug \
    BASE_URL=https://bugsink.dokku.bugsink.com

Any such configuration-change triggers an immediate redeploy, so I didn’t have to push the code again, and this time it worked. After seeing my application start up, I was able to visit it at http://bugsink.dokku.bugsink.com.

I resisted the temptation to log in, because doing so would send my super-secret credentials in plain text over the wire. I wanted to set up HTTPS first.

Setting up https

I’m a happy let’s-encrypt user, so I was happy to see that Dokku has a built-in plugin for setting up Let’s Encrypt certificates. This is a great feature, and it was easy to set up. I simply ran the following commands:

dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku letsencrypt:cron-job --add
dokku letsencrypt:set bugsink my@email.com
dokku letsencrypt:enable bugsink

Finally, I told Bugsink it is deployed behind a reverse proxy which uses HTTPS. (Bugsink needs to know this so it can correctly look for the X-Forwarded-Proto header and set the correct protocol in the links it sends out.)

dokku config:set bugsink BEHIND_HTTPS_PROXY=true

Further work

For this test I set up Bugsink in “ephemeral” mode, which means that it uses an SQLite database, which is tied to the filesystem of the Docker image and disappears when the container is stopped.

A more robust setup would be to use either the MySQL or PostgreSQL backing services, which are both supported by Dokku. For me personally there was little value in testing those, since I already know they work well with Bugsink, and people using Dokku are likely to be familiar with setting up those services.

I noticed a message saying “No healthchecks found in app.json for web process type”. This would seem to indicate that Dokku can be configured to use healthchecks, which would be a nice addition to the setup. I didn’t look into that further though, since I was happy with the setup as it was.

Feel free to reach out if you set this up and want to share your experience and any improvements you made to the setup, or if you have questions about the process.

Conclusion

I was pleasantly surprised by how easy it was to deploy Bugsink on Dokku. The process was straightforward, and the documentation was clear and easy to follow. I was able to get a working installation of Bugsink up and running in less than 30 minutes, including setting up the server and configuring the domain name.

If you’re reading this quick write-up as a tutorial or guide to deploying Bugsink on Dokku, I hope you found it helpful. In that case, the next step would probably be to go through the the after-install quickstart.

A cleaned up version of this post is available as a tutorial on the Dokku tutorials page.