rama.nz

Deploying Phoenix applications with Dokku

20 November, 2025

I've been working with Elixir and Phoenix recently for a SaaS I'm developing, and I got to the stage of needing to deploy a hosted test version. After looking through this Reddit post about deployment strategies, I decided to go with Dokku considering I already have a VPS provided by Hetzner.

It's... not a super intuitive process but this post from shuirong got me most of the way there: Deploying Phoenix with Dokku (Pitfall Guide Included) . Look through these extra notes before you follow that guide, however.

Buildpacks

Procfile

The buildpacks seem to require a Procfile otherwise default tasks would be run, so I added the following:

web: mix phx.server
release: mix ash.migrate

I'm using Ash in my application, otherwise it'd be mix ecto.migrate.

Environment variables

I use nvir which patches the system environment variables, meaning I can provide a .env file and if I'm building the :dev environment for my local machine I can load that file, otherwise it will default to the system's env vars (for test and production, in my case).

In Dokku, you will need to set all of your environment variables. An example:

dokku config:set my-app ENV=prod

SSL with Let's Encrypt

Pretty straightforward.

# Install the plugin and enable for your app
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
dokku letsencrypt:set --global email [email protected]
dokku letsencrypt:enable my-app

# Automatic cert renewal
dokku letsencrypt:cron-job --add

# Review configuration
dokku letsencrypt:list

Next steps

Adding an app.json with a healthcheck specified would be wise:

remote:  !     No healthchecks found in app.json for web process type
remote:        No web healthchecks found in app.json. Simple container checks will be performed.
remote:        For more efficient zero downtime deployments, add healthchecks to your app.json. See https://dokku.com/docs/deployment/zero-downtime-deploys/ for examples

It's still a bit magic and definitely not as streamlined as deploying a full stack TypeScript application but I was able to get this up and running fairly quickly, that too without a Dockerfile. Build times are not phenomenal though, but there's almost certainly more optimisations I could make.