How to deploy a rails app in under 30 mins and less than $5 per month

It’s October 2023 and we have Rails 7.1 released. The whole community is excited with the new release and countless people are awaiting to start new projects with Rails. I believe Rails has one of the best productivity oriented ecosystems. It’s not just a framework, it’s a complete ecosystem with tools, knowledge and communities supporting it.

Ruby on Rails is my default tech stack choice for my personal projects. I have some of them running online, but the usual problem is, I do not like to pay too much money for for-fun projects which do not generate any income. Previously, I was running my projects on Heroku, but with their pricing changes, I had to take them down as it became too expensive to run those projects where usually I was the only user.

With the introduction of Kamal and the great pricing of Hetzner Cloud, now there is an opportunity to actually run a rails project in under $5 per month. To make my life easier, I decided to write some automation scripts so that every time I setup a new application, I do not have to remember all the detailed steps I need to take. Let’s elaborate on this.

Typical rails setup

On my personal projects the typical setup 3 components:

  • The rails app
  • The postgresql database
  • The redis db (used for cache and background jobs)

For projects that are under development, have no significant user base or the project is at the stage of idea trying, I just need a setup that works and is easily set up. So… this is the solution I use.

Setup of the cloud VM

The VM setup of my choice is named CAX11 on Hetzner cloud. It has 2 shared vCPUs, 4 GB of RAM and 40 GB of disc space. Good enough to run all those components in one server and at the time of writing it costs less than $5 per month

Screenshot from https://www.hetzner.com/cloud, accessed on 12 Oct 2023

I wrote a terraform script which creates this server and a firewall rule to limit the open ports to ssh and http. Now I can easily provision the servers for my setups by just running this terraform script. More about it below.

Setup of deployment

With the introduction of Kamal, now we can easily have a Heroku like easy deployment process for containerized rails application. It takes care of not only rails application, but also of the necessary auxiliary infrastructure as database and redis. While playing with kamal, I realized, while it is very easy to use and makes deployment fun, I still had to spend a couple of hours to tweak the configuration details to make it work. These kind of tweaks are usually are not found in one documentation page as they are custom to your setup, but anyway I had to loose the time to google the info and make it work. So I decided to write a ruby scrip to automate this.

Here is what exactly this script does:

Phase 1: It collects input

  1. It asks for the root folder of the project
  2. Then it asks for your docker registry username
  3. Next it asks for the IP of the server, the DB and Redis (they can also all be the same IP)

Prepares the rails app

  1. It extracts the name of the rails app from database.yml
  2. it creates the kamal deployment file to setup all these components
  3. It creates/appends .env file to add two keys:
    • RAILS_MASTER_KEY – reads it from config/master.key and copies here. Itused when running rails docker container
    • POSTGRES_PASSWORD – used for postgres container
  4. Disable force_ssl so the application can be accessed using http

With the preparation, now your application is ready to be deployed using Kamal

What about previous versions of rails?

If you want to use the scripts with apps older than rails 7.1 you need to prepare them to be dockerized. The script expects to be able to dockerize the app and use the generated image for deployment. If you add a working docker file to your older rails app, the setup will work.

Where can you get the scripts?

I packaged the scripts and a readme file for each of them into one zip file and published them as a digital product. You can grab them from here: https://ariancelina.lemonsqueezy.com

You can get the scripts and use for your own project. If you like them or if you have any feedback, please write me, I’d love to hear from you.

My language learning framework

The most important lesson that I have learned in my career of almost 15 years in software development is that programming languages are just tools to solve real life or business problems. About 5 years ago I was doing full time .NET, then I jumped to Java for about two years, then I switched to Ruby and Rails, and just recently I started using Kotlin to create two microservices (don’t ask me why, the business needed it ;)).

Because of this, there is no point whatsoever to be bound to a language/platform religiously. The languages are tools but it’s the core knowledge of computer science and software development practices that prevail.

These changes have been inspired by different rationales, sometimes influenced by the employer and sometimes by the economic conditions of the runtime environment. E.g. hosting a Java web application during 2006 was way more expensive than a PHP application, therefore, I used PHP as a primary language for my web facing pet projects. So during my career so far, I have used Java, .NET, PHP and Ruby as my core languages and also have implemented small solutions using Kotlin, Javascript, and Python.

To adapt to this changing environment of ours I have noticed I had created a framework, which I call my language learning framework. The framework itself is not about the language per se, but about the whole ecosystem around that language. It came as a result of identifying unchanging things around any language ecosystem. E.g. no matter the type of language, there is a way to deal with strings, numbers or arrays. Or the language has some sort of collections.

With almost every language that I have used, I have had the need to also learn a framework to develop web applications, a framework to do testing, and other common things around the application. So out of this experience, here I share with you my language learning framework. It lists the things I try to learn or pay attention to when I start learning a new language.

I. Language
1. Runtime & ecosystem (general knowledge)
2. Syntax
3. Data types (if there are types)
4. Main constructs
4.1. packages/modules, classes and methods/functions
4.2. loops & conditioning
4.3. arrays
5. Core libraries
5.1. String manipulations
5.2. collections (lists, arrays, maps, sets)
5.3. math (rounding, sqrt, pow, PI)
5.4. important packages/gems/etc. and any language/platform specific library
II. Frameworks
1. Application development (evaluate popular ones and pick one)
2. Testing (unit & integration)
3. Main design patterns and in that language
III. Toolset & Other
1. IDE platform specifics
2. CI/CD
3. Deployment (does the docker & Kubernetes work or is there anything platform specific)
4. Community
5. important learning resources

Some of these items on the list are dead clear so you just follow it, but some of them are hard, like choosing which framework to use. How do you choose which framework to pick. Well, in those cases, I use different inputs to make my decision but most often it is an educated guess. What I consider is, I ask my colleagues/friends if they have experience with any of the ones I am considering and get their opinions. I also evaluate possible blog posts about them and also try to measure the popularity by checking the number of contributors, how often does a major version gets released, how many job openings I find requiring that framework, and based on all these inputs I narrow my list to two options. Then I try both of them with a certain simple scenario and I try to evaluate how easily I could implement that scenario and get a feeling of both and then decide. Out of all the factors I consider, how much I like it and how many job vacancies are there requiring that framework are two criteria that weigh most with me. The pleasure to work with is very important for me, but also having an opportunity to use it (have an employer/business which actually uses the framework) is also important in my opinion.

One important thing is, when I try to jump on a new language, I try to do all these steps in a relatively short period, potentially with max 2-3 months, and then try to repeat it at least 2 times with 2-3 sample projects. In this way I make it possible for my brain to remember it, otherwise, if it takes too long to go through the list, I forget things in between and the end result is not satisfactory.

This is not a definitive list and doesn’t include everything we need to learn to be productive in one language/platform, but it certainly serves as a good starting point for me when I want to jump into a new language.

Do you have a different approach? Share with us!