← Back to posts

Part: 1 - Deploy All Your Rails Apps On One Server Using Kamal

This is the first part of a four-series post in which I’ll explore how we can host all of our rails apps on one Hetzner virtual machine using Kamal. Why? Because we're cheap and it's a great exercise to get to know Kamal and Docker.

I've see a bunch of posts around the web that talk about the basecamp's Kamal. Here I'd like to show one way of how you can use Kamal to deploy not only one, but many of your hobby rails applications on one single Hetzner VM... That's right, for the price of around EUR 4 per month, you'd be surprised how much you can host.

Please note that this setup is only recommended for hobby apps or experiements. But it should be easy enough to switch from this setup to a more scalable one, once your requirements grow..

How?

Kamal automatically installs Docker, builds your containers, pushes them to a container repository. Zero-downtime deployment is done by starting up the new version before switching over to the new one. Kamal uses Traefik to direct internet traffic to our app's containers (which are like isolated environments for running our app). It also helps us get security certificates from a service called Let's Encrypt, which proves our website is safe. We’ll create a setup for a typical Ruby on Rails application, with a PostgreSQL relational database, Sidekiq, and a Redis key-value store. But I'll talk more about these components in the sections below.

I've structured this article into four seperate posts:

  1. Deploy All Your Rails Apps On One Server Using Kamal
  2. Rails Setup to Deploy Your App on One Hetzner Machine
  3. Rails Docker Setup to Host your Apps on One Virtual Machine
  4. Deploy With Kamal And Add More Apps To Your Server

This is the first part. Let's do it 🚀

Docker

First of all you'll need to install Docker Desktop (For Mac, Windows or Linux) and create an account with Docker Hub if you don't have one already.

Once you've created your account, on your dashboard you'll find your docker username, looking something like this:
Screenshot 2023-12-05 at 09.46.59.png
Also under your account settings, you can find your Access Token under Security. You'll later need both the username and the access token to setup Kamal, so note them down somewhere. We'll come back to Docker later to finish our setup. In the meantime, just leave your Docker desktop running in the background.

Hetzner

Create a cloud account with Hetzner and then go to your console. It should look something like this:
Screenshot 2023-12-05 at 10.29.19.png
Go ahead and create a new project. Within that project, click Add Server. Choose your favourite location, add a Ubuntu server and go for a shared vCPU, with an Arm64 (Ampere) architecture. Then choose the CAX11, the cheapest machine available ✌️. Leave the Networking as it is (Public IPv4 and 6) and go to SSH Keys.

SSH Keys

This is an important step, as it identifies your local machine as trustworthy, meaning you'll be able to interact with your server directly form your terminal, without any additional passwords, authentication, etc. Hetzner has an article about how to do it. Or do this in your terminal:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Then you should be able to read your SSH Key:

cat ~/.ssh/id_rsa.pub

You should see a very long Hash. Copy the whole thing into your clipboard and paste it into your Hetzner server (SSH Keys). If all is right, the Name field should be automtically filled with your email address. Leave the rest of the setup form as it is and jump the end to give your virtual machine a name (Can be anything).
On your right you should see a summary of your order. At the time of writing this, it was EUR 4.08 per month 🤯

Go ahead and Create & Buy now

Now you're able to go into that newly-created server. You'll immediately see on your overview page the Public IP address. Write that down in a note next to your Docker credentials.

But before we continue, we need to set up a firewall. For that, find the Firewalls link inside the sidebar on the left or wherever in your project. Click Create Firewall and add the following rules to ensure your server can only be accessed via specific endpoints:
Screenshot 2023-12-05 at 11.04.46.png
Awesome. If everything is set up correctly, you now should be able to access your server from your terminal, like this:

ssh root@YOUR-HETZNER-IP-ADDRESS

If it works, you've now set up your VM to host your hobby app, for a very reasonable price. Let's move over to your domain setup. If not, make sure you're able to access your server via CLI. Check if the SSH Key is stored properly on Hetzer or ask ChatGPT 😅

Cloudflare & Domain

First of all, set up an account with Cloudflare if you don't already have one. Cloudflare is a content delivery network (CDN) and security platform. As a CDN, it caches static content (like images, CSS, and JavaScript files) from your website on servers around the world, so that content is delivered to users from a location geographically closer to them, reducing load times. On the security front, Cloudflare provides protection against DDoS attacks, which are attempts to make a website unavailable by overwhelming it with traffic. It also offers a Web Application Firewall (WAF) to help block malicious requests and can manage DNS settings for your domain, including providing SSL/TLS for secure connections. We'll route out traffic through Cloudflare for additional security.

Once you've bought your domain on a registrar, proceed on Cloudflare:

  1. Add your domain to the home dashboard. Pick the free plan.
  2. In your domain dashboard, click on DNS -> records and get your Cloudflare Nameservers
  3. Add the custom DNS nameservers to your registrar (e.g. Namecheap. Google how you can do this, if it's not clear on the registrar's page. Once set up, you can manage your DNS records on Cloudflare.
  4. Still on the DNS page, add the following records to your DNS management:
  5. Two A records: The name of the first one should be @. This one points to the bare url (e.g. my-app.com). The other one should be www, which points to the www. subdomain (e.g.www.my-app.com). Content for both should be your Hetzner IP address (from the Hetzner setup above). Leave the rest as is.
  6. Two AAAA records: The names are the same as above but the content should be your Hetzner IPv6 address. You'll find that on your Hetzner account, inside of your project > your-server on the main dashboard. There you should find a number looking something like this: 3a02:5d7:1k1e:574c::/64. Copy that number, paste it into the content field on cloudflare and remove the last /64.
  7. Next click on SSL/TLS on the sideboad and set your SSL/TLS encryption to Full.

That's it, your traffic will now be directed through Cloudflare.

Let's move over to part 2, where we're setting up our Rails app.