Dokku: my favorite personal serverless platform
What is Dokku?
Dokku is an open-source Platform as a Service (PaaS) that runs on a single server of your choice. It’s like Heroku, but you own it. It is a great way to get the benefits of Heroku without the costs (Heroku can get quite expensive!). I need to deploy many applications for my LLM consulting work. Having a cost-effective, easy-to-use serverless platform is essential for me.
I run a Dokku server on a $7/month VPS on OVHcloud for non-gpu workloads. These applications include things like nbsanity and data cleaning tools for LLMs.
Some of the features I love about Dokku:
- Easy to use (like Heroku).
- Automatic SSL certificate management via Let’s Encrypt.
- Basic Auth support so I can password-protect sites.
- Scale up and down with a single command.
- Flexibility to handle any application (Node, Python, etc), including defining a Docker container.
- Lots of official plugins that do almost anything I want.
- Easily deploy with git commands.
Minimal Dokku Examples
Make sure you install Dokku on your VPS. As I mentioned, I use OVH.
Deploying Apps as A Docker Container
An easy way to deploy applications is with a Docker container.
To deploy a Docker container, I put a Dockerfile in the root of my git repo like this:
Dockerfile
FROM python:3.10
COPY . /app
WORKDIR /app
# Install the local package
RUN pip install .
# This directory contains app.py, a FastApi app
WORKDIR /app/
ENTRYPOINT ["./entrypoint.sh"]
The entrypoint.sh
script allows me to easily run the app locally or in a Docker container. It looks like this:
entrypoint.sh
#!/bin/bash
exec uvicorn main:app --port "$PORT" --host 0.0.0.0
On the Dokku host, create the app:
dokku apps:create myapp
Locally, set up access to the Dokku host and name it dokku
in your ~/.ssh/config
file. For example, here is mine:
Host dokku
HostName <The external IP address of your Dokku host>
User ubuntu
IdentityFile /Users/hamel/.ssh/dokku
Locally, add the Dokku host as a remote and push to it:
git remote add dokku dokku@dokku:myapp
git push dokku main
That’s it - your app should be running on the Dokku host! Your local logs will print the URL that your application is served on, which by default will be myapp.yourdomain.com
. You can also scale it up/down with the following command:
#scale to two workers
dokku ps:scale myapp web=2
We are just scratching the surface. For more details, see the Dokku docs.
Static Sites
GitHub Pages is annoying in that you can’t easily deploy private static sites without paying for an expensive Enterprise account. With Dokku, you can easily deploy a static site from a private GitHub Repo and password-protect it.
We will assume that you have a static site in a git repo in a folder named _site
.
On the Dokku host, create an app named mysite
and set the NGINX_ROOT
environment variable to _site
:
dokku apps:create mysite
dokku config:set static-site NGINX_ROOT=_site
Also on the Dokku host, install basic auth and set permissions so the plugin can work properly.
# do setup for the auth plugin that we will use later
sudo dokku plugin:install https://github.com/dokku/dokku-http-auth.git
sudo chmod +x /home/dokku
Then execute the following commands from the root of your git repo that contains the static site. :
1touch .static
2echo BUILDPACK_URL=https://github.com/dokku/buildpack-nginx > .env
3git remote add dokku dokku@dokku:mysite
- 1
-
tells
dokku
that this is a static site - 2
-
tells
dokku
to use the nginx buildpack for static sites (it will usually automatically detect this, but if you have a project with code and a static site, you need to tell it to use the nginx buildpack so it doesn’t get confused). - 3
-
add the
dokku
host as a remote. For this to work, make suredokku
is a hostname in your~/.ssh/config
file as described in the previous section.
Finally, deploy your application:
git push dokku main
You can now add auth by running the following command on the Dokku host:
dokku http-auth:enable mysite <username> <password>
You can add multiple usernames/passwords and even filter specific IPs. See the docs.
It’s often desirable to have HTTPS for your site. Dokku makes this easy with the Let’s Encrypt Plugin, which will even auto-renew for you. I don’t use this, because I’m letting Cloudflare handle this with its proxy.
If you are using Cloudflare this way, activating this plugin will mess things up (don’t worry its easy to disable). Honestly, I think it’s easier to let Cloudflare handle it if you are already doing so.
Deploying With GitHub Actions
You can automatically deploy Dokku apps with GitHub Actions, which is helpful if you don’t want to fiddle with pushing to the Dokku host. Here is an example GitHub Action workflow that does this:
deploy-dokku.yml
name: CI
on:
workflow_dispatch:
push:
branches: [main]
concurrency: # Cancel previous jobs to avoid deploy locks on dokku
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
deploy-dokku:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install SSH key
run: |
echo "${{ secrets.DOKKU_SSH_PRIVATE_KEY }}" > private_key.pem
chmod 600 private_key.pem
- name: Add remote and push
run: |
git remote add dokku dokku@rechat.co:llm-eval GIT_SSH_COMMAND="ssh -i private_key.pem -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" git push dokku main -f
Miscellaneous Tips
These are things I often forget, so I’m writing them down here. For these examples, assume my app is named llm-eval
and my host is rechat.co
.
Run commands remotely
You don’t have to ssh into the Dokku host just to execute commands. You can execute them remotely via the dokku
user like this:
# https://dokku.com/docs/deployment/application-management/
ssh dokku@rechat.co apps:list
Docker cache
This is how you can invalidate the docker cache for a fresh build:
ssh dokku@rechat.co repo:purge-cache llm-eval
Rebuild without pushing
Sometimes you want to rebuild without pushing. There are many ways to do this, but one way is like this:
ssh dokku@rehcat.co ps:rebuild llm-eval
Why Did I Write This?
I had to dig up these details whenever I wanted to deploy a new app, so I had to write it up anyway. I hope you find it useful, too!