Hello there!
I was curious about Kamal and wanted to give it a try to host a simple application on a cheap VPS. With this guide, I'll walk you through the process step by step that I used to create and deploy your first Rails application with KAMAL on a Hetzner VPS.
For this tutorial, we'll keep things as simple as possible. We'll deploy an application that uses an SQLite database.
What you will need first:
- a Docker account with an Api key
- an Hetzner account
Assuming you have that ready you should be able to deploy you first app with Kamal
in less than 10 minutes
Scaffold a Rails Application
First, let's scaffold an application. At the time of writing this guide, it's important to use the --main
flag to use the Rails 7.1 alpha version.
new rails_kamal_hetzner -a propshaft --main -c tailwind -j esbuild
cd rails_kamal_hetzner
bundle add tailwindcss-rails
bin/rails tailwindcss:install
git add .
git commit -m "rails new"
rails g scaffold post title:string content:text
rails db:create db:migrate
Next, you'll need to update your routes.
# config/routes.rb
- # root "articles#index"
+ root "posts#index"
Create a VPS on Hetzner
Now that we have a basic app set up, let's create a VPS on Hetzner. You'll need to navigate through the sign-up and confirmation process, after which you can create a new project from your account.
For this tutorial, we'll select the CAX11, one of the most affordable VPS options with 2vCPU and 4GB RAM.
Please note that at the time of writing, KAMAL does not support IPv6, so you need to retain IPv4.
You'll also need to add an SSH key to your server. Here's how to copy and paste the key:
pbcopy < ~/.ssh/id_rsa.pub
Then test your SSH access to the server with this command:
ssh root@your_server_ip
If you encounter the prompt, "Are you sure you want to continue connecting (yes/no/[fingerprint])?", answer 'yes'.
If you're unable to SSH into the server, you'll need to resolve this issue before proceeding further.
Deploying with KAMAL
With our application and server ready, it's time to put KAMAL into action. First, install it with the following command:
gem install kamal
Then run kamal init
. This will create several files, including config/deploy.yml
and .env
.
In the .env
file, update the RAILS_MASTER_KEY
value and the KAMAL_REGISTRY_PASSWORD
with a key created in your Docker account.
Next, update the config/deploy.yml
file as follows:
service: rails_hetzner_kamal
image: adrienpoly/rails_hetzner_kamal
servers:
- hetzner_ip_v4
registry:
username: adrienpoly
password:
env: KAMAL_REGISTRY_PASSWORD
env
:
secret:
- RAILS_MASTER_KEY
ssh:
user: root # important to change it here as by default Kamal use app and Hetzner root
You can omit the other files for now. Commit your changes and then run the command to bootstrap servers with curl and Docker.
kamal server bootstrap
Once this operation is successful, you can execute your first deploy with kamal deploy
. The first deployment might take a few minutes and should conclude with a successful health check message.
At this point, you should be able to visit the IP address in a browser and see your Rails app! Et voilà!
Persisting the Data
Well well well, not really voilà yet. If you create a Post
and make a new deployment, you'll notice that the data is lost. This happens because the SQLite database is running inside the Docker image by default. Each time a new container is built, it erases the data.
To solve this, you need to add a volume to the Docker container. In the config/deploy.yml
file, add this line:
volumes:
- "storage:/rails/storage"
Now, the data is written outside of the container and persists across deploys.
And that's it! You've deployed your first Rails application with KAMAL on a Hetzner VPS.
Happy deploying!
[15-11-2023] Updated to reflect the name change from MRSK to Kamal
PS : Here is my referral link if you want to test Hetzner https://hetzner.cloud/?ref=gyPLk7XJthjg it gives you a 20€ credit to test
Top comments (11)
Wow! It's that simple? I heard DHH talk about it a while ago (if I remember correctly) and thought to myself, "this has to be pretty complicated."
I currently use Dokku + Digital Ocean and I'm happy with it, but I'd like to try this one out.
Thanks for making this post.
Really nice. Never heard of MRSK before! Thanks for the article!
No matter how many times I try, I can never get this to run.
Do I need a SSL Certificate? I always get:
`This site can’t be reached5.78.92.233 refused to connect.
Try:
Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED`
I can connect to the server and docker ps shows everything up:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c2e4f9fedad8 rjnawara/my-hertzner-app:f6fe46ed0ee6583762587f8038152fa2ebf728e7 "/rails/bin/docker-e…" 4 minutes ago Up 4 minutes (healthy) 3000/tcp my-hertzner-app-web-f6fe46ed0ee6583762587f8038152fa2ebf728e7
74a3188bb817 traefik:v2.9 "/entrypoint.sh --pr…" 4 minutes ago Up 4 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp traefik
Any ideas as to what I screwed up?
Thanks, Ray
Are you able to run
ssh root@server-ip
make sure force_ssl is set to false on your Rails app - until you are ready to wire up your domain and add ssl termination.
Is there an easy way to ask kamal to configure SSL?
(Does it happen on the hetzner server, or inside the image?)
Excellent article!!! Everything very well explained and detailed. Kudos!!!
The only thing with me rn is that I try to connect via ssh root@ip and even with SSH key already configured and added into the server config in hetzner cloud, I only can enter the console inside hetzner webapp, but not in my local console from my mbp. Same pass. On hetzner's cloud app works, but on my mbp in local, doesn't. Still trying to process what can be the error or the mistake I'm making.
It dosen't work actually if do as same as you did
What are your specific errors? What dit you try ?
good article. thanks.
What is a right way to run migrations on each kamal deploy?