re: Migrating Rails Apps to VPS - worth it? VIEW POST


Hey Arit!

I always get nervous when migrating off of a platform such as Heroku and onto ones own Virtual Machines. I help clients do it all the time, but before we proceed I make sure I really understand why they're doing it. Heroku does an amazing job of encapsulating a lot of the costs of hosting an app, so much so that it becomes easy to take what it does for granted. Hosting an app with any significant traffic on a self-maanged virtual machine will likely result in someone needing to respond to an issue in off-hours; which means ~12x more bad-days per year.

You will also now need a database provider with a backup and recovery strategy; so that you don't lose all that user data if the virtual machine the database is running on falls over. Oh, and if your traffic spikes and you need a bigger machine right now? Well, hope-to-god your investment in infrastructure automation wasn't neglected so you can spin up a replacement web or database server within a few minutes; like you can on Heroku.

This is compounded by the fact that most Virtual machine providers do not guarantee individual machines up-time. The expectation is that you will have multiple machines operating behind a load balancer, so that if an instance falls over, the other instance will stay up.

That said, it would be 100% shitty if I second-guessed your question and moonwalked away; so I'll try and provide the help you asked for and not the help you didn't.

To understand how to go about solving the problem, I'm going to restate the question and unpack the assumptions I'm making.

How do I go about hosting multiple Rails applications on a virtual machine, then directly requests to the correct application based upon which sub-domain the request is coming from?

There are two main problems to solve:

  1. How do I configure, deploy and run multiple rails applications on a single virtual machine?
  2. How do I route traffic from sub-domains to different rails applications on a single server?

I'll start with problem 1 and then go into problem 2.

> How do I configure, deploy and run multiple rails applications on a single virtual machine?

First, a story. Because I'm old and a little high. A long, long time ago I mostly wrote PHP code. The really cool thing about PHP is that the when you write a PHP program, you can literally copy and paste the files from your personal computer into a folder on the server and the program is ran by the server. Just like that! No re-booting, no "dynos deploying." This worked because the PHP language's interpreter is ran inside the process of the Apache web server itself as an extension.

Each PHP file was, in effect, it's own application and each HTTP request would run that particular application from start to finish. This meant only one process, Apache, was listening to port 80 and 443 for HTTP and HTTPS requests and taking responsibility for choosing which program would handle it.

That's what Phusion/Passenger does - It runs as many Ruby/Rails applications as you want within a single(ish) process. Nginx winds up doing the heavy lifting of the http stuff, while Phusion/Passenger runs the Ruby code and makes sure each application is as isolated as it can be.

Puma, however, follows a different process model. Puma expects that it will be running a single application across many processes. Puma then exposes a single Rack-compliant application (In your case, a Rails app) on a single network port to provide access to that application. You would then run Nginx and configure it to direct traffic that matches a particular pattern to that particular port.

The pros and cons of each solution, single-process, many apps or single-app, many processes is not obvious. Which is part of why people complain "Rails doesn't scale" or "Rails doesn't perform." The single-process, many applications solution is perfect for environments where you "scale vertically." Scaling vertically is when you increase the disk, processor and memory performance of a server to better support high traffic. This is perfect for processes that may take a while to start, or if each request has a lot of work to do before it can safely be returned to the client. If you were to have many processes handling requests, you would likely see the server CPU "thrashing" with a bunch of processes fighting to use up all 100% of the processor power and failing because there's really only 2~4 "real" processors on the virtual machine.

Single-app, many process designs such as Puma + Nginx are well suited to situations where individual response time must be incredibly low, and a lot of the work can be delegated until after the response is sent to the HTTP client. Each request may take very little processing power to execute upon, so having a number of processes handling each request is unlikely to result in a lot of thrashing.

To be honest, picking the "right" scaling model becomes one of those really good problems to have! The nice thing about Rails applications is it's possible to use either or, and switch based upon how your application winds up being used. Here's two guides from linode on running Nginx with Rails:

I apologize for mixing and matching linux distributions, but I couldn't find good instructions for different technologies on matching distros :(.

OK, on to question two!

> How do I direct traffic to the appropriate application based upon the sub-domain?

Story time again! Apache and PHP allowed you to direct traffic to the appropriate application using mod-rewrite Someone coming to accounts.your-company.example.com? Host up the PHP files in ~/site/accounts! Done! Nginx also provides a mechanism for this using their block configuration. There are a number of really powerful ways to make routing decisions and I can't walk you through each of them, but the one you'll want to look out for to do sub-domain level direction to different applications is server_name; and the one you want to look out for to point it at which application on which port is proxy_pass

I am super lazy and tend to reference this full example of the nginx configuration options when I'm trying to figure out my nginx configuration.

THere is a third, secret, unasked question which is:

> How do I keep track of all this stuff so I can spin the server back up if it goes down?

The answer to that is there is an entire swathe of tools designed for storing your server configuration and then using that configuration to re-create servers. I personally prefer ansible but I haven't had to do server management in a very long time, so the cool kids may be using something else nowadays. Back in the day I used Capistrano which still looks like it's maintained and is designed for Ruby people.

Good luck! Hopefully this wasn't too rambly and if you have further questions I'll do my best to reply more specifically.


Wow Zee! THANK YOU! I owe you a coffee :) Please look for a direct message for me, where I share more about my particular situation. I'm so grateful.

Note: I think you need to follow me to allow me direct-message you :)


Hmm, not sure how direct messages work on here, but if you go to my twitter or github you'll be able to find my email, and my twitter DMs are always open.

If you follow one another you can DM.

Open DMs coming at some point.

And yeah, amazing response.

Code of Conduct Report abuse