Blog Case studies Services
Michael Rode
Cook of tasty food, Coder of loved Elixir, Creator of products and dad of a wonderful family.

Deploying Elixir and Phoenix with Dokku and Docker

Looking to deploy your Elixir and Phoenix app the smart way? Here's a comprehensive guide to get you up and running with Dokku, covering everything from setting up your VPS to automating deployments with SSL and backups.

Prerequisites

Before we start, make sure you have:

  • A Phoenix application ready for deployment
  • Basic knowledge of Git and command line
  • A VPS provider account (Hetzner, DigitalOcean, etc.)
  • A domain name pointing to your VPS

1. Setting Up Your VPS with Dokku

First, spin up a VPS with your preferred provider. We'll use Ubuntu 22.04 LTS for this guide.

Installing Dokku

# Download and run the Dokku installation script
wget -NP . https://dokku.com/install/v0.35.13/bootstrap.sh
sudo DOKKU_TAG=v0.35.13 bash bootstrap.sh

Initial Dokku Setup

After installation, configure Dokku by visiting your server's IP address in a browser, or run:

# Set your domain
echo 'yourdomain.com' | sudo tee /home/dokku/VHOST

# Add your SSH key for deployments
cat ~/.ssh/id_rsa.pub | sudo dokku ssh-keys:add admin

For detailed installation instructions, visit the official Dokku documentation.

2. Creating Your Dokku Application

SSH into your Dokku server and create a new application:

# Create the application
dokku apps:create myapp

# Set your domain
dokku domains:set myapp myapp.yourdomain.com

# Verify the domain configuration
dokku domains:report myapp

3. Setting Up PostgreSQL Database

Install the PostgreSQL Plugin

# Install the official PostgreSQL plugin
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git

Create and Link Database

# Create a PostgreSQL service
dokku postgres:create myapp-postgres

# Link the database to your application
dokku postgres:link myapp-postgres myapp

# Verify the database connection
dokku postgres:info myapp-postgres

This automatically sets the DATABASE_URL environment variable for your application.

4. Dockerizing Your Phoenix Application

Phoenix provides a built-in generator to create Docker configuration and release setup:

# Generate Docker and release configuration
mix phx.gen.release --docker

# This creates:
# - Dockerfile
# - .dockerignore
# - rel/overlays/bin/server
# - rel/overlays/bin/migrate
# - Updates config/runtime.exs

# Commit the generated files
git add -A
git commit -m "Add Docker support and release configuration"

Key Files Created

  • Dockerfile: Multi-stage build optimized for production
  • rel/overlays/bin/migrate: Database migration script
  • rel/overlays/bin/server: Application startup script
  • config/runtime.exs: Runtime configuration for releases

5. Configuration

Environment Variables

Set up the required environment variables for your Phoenix application:

# Generate a secret key base
secret_key=$(mix phx.gen.secret)

# Set environment variables
dokku config:set myapp SECRET_KEY_BASE="$secret_key"
dokku config:set myapp PHX_HOST=myapp.yourdomain.com
dokku config:set myapp PORT=4000

# Optional: Set the mix environment
dokku config:set myapp MIX_ENV=prod

Port Configuration

Ensure your Dockerfile exposes the correct port. The generated Dockerfile should include:

EXPOSE 4000

If your application doesn't expose a port, Dokku defaults to port 5000. Configure port mapping:

# Map external ports to internal port 4000
dokku ports:add myapp http:80:4000
dokku ports:add myapp https:443:4000

6. Deploying Your Application

Now deploy your Phoenix application to Dokku:

# Add Dokku as a Git remote
git remote add dokku dokku@yourdomain.com:myapp

# Deploy your application
git push dokku main:main

Dokku will automatically:

  1. Build your Docker image
  2. Create a container
  3. Run database migrations (if configured)
  4. Start your application

Monitor the deployment process and check for any errors in the output.

7. Post-Deploy Scripts and Database Migrations

Automate database migrations and other post-deploy tasks:

Automatic Migrations

The generated rel/overlays/bin/migrate script handles database migrations. To run migrations automatically after deployment:

# Set up automatic migrations
dokku config:set myapp DOKKU_DOCKERFILE_CACHE_BUILD=false
dokku config:set myapp RELEASE_COMMAND="/app/bin/migrate"

Custom Release Commands

You can also configure custom release commands in your config/runtime.exs:

if System.get_env("RELEASE_COMMAND") do
  case System.get_env("RELEASE_COMMAND") do
    "migrate" -> MyApp.Release.migrate()
    "seed" -> MyApp.Release.seed()
    _ -> :ok
  end
end

Manual Migration

To run migrations manually:

# Run a one-off command for migrations
dokku run myapp /app/bin/migrate

8. Adding SSL with Let's Encrypt

Secure your application with free SSL certificates using Let's Encrypt:

Install Let's Encrypt Plugin

# Install the Let's Encrypt plugin
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

# Set your email for Let's Encrypt notifications
dokku letsencrypt:set --global email your@email.com

Enable SSL

# Enable SSL for your application
dokku letsencrypt:enable myapp

# Set up automatic certificate renewal
dokku letsencrypt:cron-job --add

# Verify SSL configuration
dokku letsencrypt:list

Force HTTPS

Optionally, redirect all HTTP traffic to HTTPS:

# Force HTTPS redirects
dokku config:set myapp DOKKU_LETSENCRYPT_EMAIL=your@email.com
dokku proxy:ports-set myapp http:80:4000 https:443:4000

9. Database Backups to S3

Protect your data with automated backups to S3-compatible storage:

Install Backup Plugin

# Install the S3 backup plugin
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git

Configure S3 Backup

# Set S3 credentials and configuration
dokku config:set --global DOKKU_POSTGRES_S3_BACKUP_AUTH_TOKEN="your-s3-access-key"
dokku config:set --global DOKKU_POSTGRES_S3_BACKUP_SECRET_ACCESS_KEY="your-s3-secret-key"
dokku config:set --global DOKKU_POSTGRES_S3_BACKUP_REGION="us-east-1"
dokku config:set --global DOKKU_POSTGRES_S3_BACKUP_BUCKET="your-backup-bucket"

# Enable automatic backups
dokku postgres:backup-auth myapp-postgres your-s3-access-key your-s3-secret-key
dokku postgres:backup-schedule myapp-postgres "0 2 * * *" your-backup-bucket

Manual Backup

# Create a manual backup
dokku postgres:backup myapp-postgres your-backup-bucket

# List backups
dokku postgres:backup-schedule-cat myapp-postgres

10. Automated GitHub Actions Deployment

Set up continuous deployment with GitHub Actions:

Create GitHub Actions Workflow

Create .github/workflows/deploy.yml:

name: Deploy to Dokku

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Deploy to Dokku
        uses: dokku/github-action@master
        with:
          git_remote_url: 'ssh://dokku@yourdomain.com:myapp'
          ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }}

Configure GitHub Secrets

  1. Generate an SSH key pair:

    ssh-keygen -t rsa -b 4096 -C "github-actions"
  2. Add the public key to your Dokku server:

    cat ~/.ssh/id_rsa.pub | dokku ssh-keys:add github-actions
  3. Add the private key as SSH_PRIVATE_KEY in your GitHub repository secrets.

Alternative: Simple Git Push Deploy

For a simpler approach without GitHub Actions:

name: Simple Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        run: |
          git remote add dokku dokku@yourdomain.com:myapp
          git push dokku main:main
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}

Troubleshooting Common Issues

Application Won't Start

# Check application logs
dokku logs myapp --tail

# Check container status
dokku ps:report myapp

# Verify environment variables
dokku config myapp

Database Connection Issues

# Verify database is running
dokku postgres:info myapp-postgres

# Test database connection
dokku postgres:connect myapp-postgres

# Check database URL
dokku config:get myapp DATABASE_URL

SSL Certificate Issues

# Renew certificates manually
dokku letsencrypt:renew myapp

# Check certificate status
dokku letsencrypt:list

Conclusion

You now have a production-ready Phoenix application deployed on Dokku with:

  • Docker containerization
  • PostgreSQL database
  • SSL certificates
  • Automated backups
  • CI/CD pipeline

This setup provides a robust, scalable foundation for your Elixir applications with minimal operational overhead.

Additional Resources