Published: 2026-01-24
I had been using Kamal for deployment for quite awhile cause it's a really simple orchestrator.
Docker + SSH + Rails = Kamal, basically.
But deploying manually was always manual cause I didn't really have a good orchestrator in my homelab environment where this website currently resides. I also didn't want to enable SSH traffic to my internal host, so I finally bit the bullet and implemented Tailscale. And by implemented, I mean I ran a few installers across my hosts. Tailscale is so ridiculously easy to use, I don't know how I didn't ever use it before. The WireGuard protocol is very interesting, too, but that's not what this post is about.
If you want to know what the final working config looks like, here is my config:
name: Kamal Deploy
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Tailscale Up
uses: tailscale/github-action@v4
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:prodweb
ping: docker01
- uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy command
run: bundle exec kamal deploy
env:
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
KAMAL_REGISTRY_USERNAME: ${{ secrets.DOCKER_REGISTRY_USER }}
KAMAL_REGISTRY_PASSWORD: ${{ secrets.DOCKER_REGISTRY_KEY }}
DATABASE_PROD_URL: ${{ secrets.DATABASE_PROD_URL }}
RAILS_ENV: production
My first step was implementing the Tailscale Github Action. The action requires setting up tags to the machine you're deploying to, as well as oauth trust credential or an auth key. I chose to create an OAUTH client and I specifically only gave it permission to read/write auth keys to my prodweb tagged servers. The tailscale action stays active through the entire github action and will tear itself down when complete.
The rest are basic settings using Kamal, which if you don't know how to do that, this guide is fairly succint and has the benefit of being part of the official documentation. I setup repository secrets for docker, rails master key and the RAILS_ENV. Many many commits later, I was finally successful. Now every commit to main will be auto deployed to my server. Yay for CI/CD.