Rails CI/CD with Dokku & GitHub Actions

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
Search for a command to run...

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
No comments yet. Be the first to comment.
This comprehensive series will equip readers with practical knowledge and skills in deploying Rails applications using Kamal, Dokku, and other relevant tools.
The Challenge: Modernizing Rails Deployment When I recently needed to deploy my Rails 8 application with multiple databases, I faced a common dilemma: choosing between expensive managed solutions and complex self-managed servers. My requirements were...
Motivation After building several Shopify embedded apps, I've learned valuable lessons about what works (and what definitely doesn't) in the embedded app environment. Today, I'm sharing these insights to help you avoid common pitfalls and build bette...

As a developer working with Shopify's ecosystem, I recently built a multi-tenant SaaS application that synchronizes customer data between Shopify stores and external services. In this article, I'll share my experience and technical insights into crea...

The Challenge: Modernizing Rails Deployment When I recently needed to deploy my Rails 8 application with multiple databases, I faced a common dilemma: choosing between expensive managed solutions and complex self-managed servers. My requirements were...

The Cost-Benefit Realization As a Rails developer who recently migrated from Heroku to Dokku, I want to share my journey and the surprising benefits I discovered. This transition wasn't just about cost savings—it opened up new possibilities for my de...

As developers, we're always looking for ways to streamline our deployment process while maintaining security and reliability. Today, I'm excited to share my experience setting up an automated deployment pipeline for a Rails application using Dokku and GitHub Actions. This setup has transformed our deployment process from a manual, error-prone task into a smooth, automated workflow.
Managing production deployments can be tricky. You want something robust like Heroku but with more control over your infrastructure. Enter Dokku - a lightweight, open-source Platform as a Service (PaaS) that gives you Heroku-like features on your own server.
Before we dive in, make sure you have:
A Dokku server set up and running
%[https://sulmanweb.com/rails-8-production-dokku-deployment-guide]
An existing Rails application deployed to the server
Administrative access to both the server and your GitHub repository
The first step in our automation journey is setting up secure SSH keys for deployment. This is crucial for allowing GitHub Actions to securely communicate with our Dokku server.
# On your production server
ssh-keygen -t ed25519 -f dokku
This command generates two files:
dokku - Your private key (keep this secret!)
dokku.pub - Your public key (safe to share)
Next, we need to configure Dokku and the server to trust these keys:
# Add the key to Dokku
echo "YOUR_PUBLIC_KEY_CONTENT" | dokku ssh-keys:add github
# Add to authorized keys for additional security
echo "YOUR_PUBLIC_KEY_CONTENT" >> ~/.ssh/authorized_keys
With our keys in place, we need to store the private key securely in GitHub. Here's how:
Navigate to your repository's Settings → Secrets and variables → Actions
Create a new secret named PRODUCTION_DOKKU_SSH_PRIVATE_KEY
Paste your private key content
This secret will be securely encrypted and only accessible during the deployment process.
Now for the exciting part - setting up our automated deployment pipeline. Create or modify .github/workflows/ci.yml:
deploy_production:
needs: [ test ]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
steps:
- name: Cloning repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Push to dokku
uses: dokku/github-action@master
with:
branch: 'main'
trace: '1'
git_push_flags: '--force'
git_remote_url: 'ssh://dokku@SERVER_IP:22/APP_NAME_IN_DOKKU'
ssh_private_key: ${{ secrets.PRODUCTION_DOKKU_SSH_PRIVATE_KEY }}
Let's break down what's happening here:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
This condition ensures deployments only happen when code is pushed to the main branch - perfect for a trunk-based development workflow.
needs: [ test ]
By specifying needs: [ test ], we ensure our tests pass before any deployment occurs. This is crucial for maintaining code quality!
The dokku/github-action@master action handles the heavy lifting:
branch: 'main' - Specifies which branch to deploy
trace: '1' - Enables detailed logging for troubleshooting
git_push_flags: '--force' - Ensures clean deployments
git_remote_url - Connects to your Dokku server
ssh_private_key - Securely authenticates using our previously configured key
With everything set up, deploying is as simple as:
git push origin main
This triggers the following sequence:
Your code is pushed to GitHub
GitHub Actions detects the push to main
The test suite runs
If tests pass, the deployment job begins
Your code is securely deployed to the Dokku server
Through implementing this setup, I've learned some valuable lessons:
Security First: Always use dedicated deployment keys and never store sensitive information in your repository.
Test Dependencies: Make deployment dependent on test success to prevent broken code from reaching production.
Logging Matters: The trace: '1' option has saved hours of debugging by providing detailed deployment logs.
This setup has dramatically improved our deployment workflow, but there's always room for enhancement. Future improvements might include:
Adding staging environment deployments
Implementing automatic database backups pre-deployment
Setting up deployment notifications in Slack
Remember, the goal of automation isn't just to save time - it's to build confidence in your deployment process and free up mental energy for solving more interesting problems.
Have you implemented a similar setup? I'd love to hear about your experiences and any improvements you've made to this workflow!
Happy deployments!