https://hamel.dev/blog/posts/dokku/ * Blog * OSS * Talks * Notes * Hire Me On this page * What is Dokku? * Minimal Dokku Examples + Deploying Apps as A Docker Container + Static Sites * Deploying With GitHub Actions * Miscellaneous Tips + Run commands remotely + Docker cache + Rebuild without pushing * Why Did I Write This? * Edit this page Subscribe for updates Dokku: my favorite personal serverless platform infra severless Like Heroku, but you own it. Author Hamel Husain Published January 9, 2024 [serverless] With Dokku, you can turn a VPS into a powerful 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"] Tip 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 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. : 1 touch .static 2 echo BUILDPACK_URL=https://github.com/dokku/buildpack-nginx > .env 3 git 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 sure dokku 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 Note You can add multiple usernames/passwords and even filter specific IPs. See the docs. SSL / HTTPS 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! * * * * Edit this page