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:
- Build your Docker image
- Create a container
- Run database migrations (if configured)
- 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
Generate an SSH key pair:
ssh-keygen -t rsa -b 4096 -C "github-actions"
Add the public key to your Dokku server:
cat ~/.ssh/id_rsa.pub | dokku ssh-keys:add github-actions
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.