Summarized using AI

From FTP to Kamal: 20 Years of Deploying Rails

Ben Curtis • July 10, 2025 • Philadelphia, PA • Talk

Introduction

This talk, delivered by Ben Curtis at RailsConf 2025, explores the 20-year evolution of deploying Ruby on Rails applications. Curtis takes the audience on a historical journey, highlighting the technologies, tools, and processes that have defined and transformed Rails deployment from the early days of the web to the present, culminating with today's Docker- and Kamal-driven workflows.

Key Points

  • Early Web Deployments (1991–late 90s):

    • Initial web pages were plain HTML, deployed via editing files directly on servers (often using vi) or via FTP.
    • The advent of CGI (Common Gateway Interface) in the early '90s enabled interactivity and dynamic content, typically using Perl scripts. Deployment still relied on insecure methods like FTP.
    • Shared hosting was common, with little user control over server configurations.
  • Emergence of Server-Side Scripting:

    • PHP 3.0 (1997) simplified deployment by embedding the interpreter within the web server (e.g., Apache), eliminating the need for CGI process spawning.
    • Attempts to similarly integrate Ruby via mod_ruby existed but suffered from reliability and security issues, making it unsuitable for serious use.
    • SCP and rsync started overtaking FTP as more secure deployment mechanisms.
  • Rise of Ruby on Rails and Early Deployments (2004–mid 2000s):

    • Rails' debut in 2004 leveraged learnings from PHP, integrating best practices like view templating and database abstraction.
    • Early Rails apps were deployed via CGI and mod_ruby, both of which were problematic for production use due to performance and security limitations.
    • FastCGI, borrowed from the Windows/IIS world, emerged as a solution, running apps as a separate daemon. This improved performance but introduced operational brittleness and frequent need for manual restarts.
  • Mongrel and Clustered Deployment:

    • Mongrel introduced efficient HTTP parsing, enabling Rails apps to handle requests directly. Apache became a proxy to Mongrel processes.
    • Mongrel Cluster allowed running multiple Mongrel instances for handling concurrent requests.
    • This era saw the rise of system administration and process management tools like Monit and God to ensure process uptime.
  • Capistrano and Deployment Automation:

    • Capistrano (formerly SwitchTower) launched as a deployment automation tool, reducing the complexity of multi-step manual deployments using SSH and Git/SVN integration.
  • Passenger and Further Abstraction:

    • Passenger incorporated Rails directly into web servers like Apache and Nginx, improving isolation, Ruby version management, and simplifying deployments further.
    • Shared hosting began to fade, encouraging greater adoption of VPS providers and more control over environments.
  • Modern App Servers (2009–onward):

    • Unicorn, Puma, and Thin brought new approaches to handling concurrency (processes, threads, and event-driven models respectively), with process management features built in.
  • Heroku and the PaaS Revolution:

    • Heroku revolutionized developer experience with 'git push heroku', removing the need for server administration and making Rails deployment effortless, albeit at a higher cost.
  • Docker and Container-based Deployments (2013–present):

    • Docker solved versioning and environment consistency issues, enabling developers to create portable application containers.
    • Modern deployments leverage CI/CD pipelines to automate building and deploying containers.
    • Kamal (described as Capistrano 2.0) automates deployment of Docker containers across multiple servers, inspired by Capistrano's approach but focused on container workflows.
    • Alternatives like Dokku and Coolify provide Heroku-like Docker-based deployment on personal VPS.

Conclusion / Takeaways

  • Deploying Rails applications has evolved from insecure and manual FTP-based approaches through fast CGI, clustered servers, automation tools like Capistrano, the simplicity of Heroku, and today’s containerized workflows with Docker and Kamal.
  • The Rails deployment journey reflects broader trends in web development: increased automation, abstraction, improved security, and a relentless drive for developer productivity and convenience.
  • While many tools and methods have come and gone, the overarching lesson is one of continual adaptation and innovation in pursuit of simpler, more reliable ways to deliver Rails applications to production.

Overall Message

This talk is a celebration of the Rails operations community and the remarkable technical progress over 20 years, encouraging attendees to recall the past and appreciate how much simpler, safer, and more flexible deployment has become.

From FTP to Kamal: 20 Years of Deploying Rails
Ben Curtis • Philadelphia, PA • Talk

Date: July 10, 2025
Published: July 23, 2025
Announced: unknown

RailsConf 2025 marks the end of an era—so let's take a ride through Rails history, deployment-style! From the Wild West days of FTP and CGI to the golden age of Capistrano, Passenger, and Heroku, all the way to Docker and Kamal, Rails deployment has been a journey of innovation, frustration, and occasional existential dread.

In this talk, we’ll revisit the tools, hacks, and battle scars of Rails deployment over the last 20 years. Remember Mongrel? FastCGI? The magical experience you had the first time you ran 'git push heroku'? We’ll celebrate the evolution of Rails ops, the community that shaped it, and what lessons we should take into the next 20 years.

Whether you deployed your first Rails app last week or you've been around since script/server, this talk is for you. Expect nostalgia, war stories, and callouts to the projects that paved the way to (and give some background on) what we have today. No grand lessons. No deep takeaways. Just a celebration of how far we’ve come.

RailsConf 2025

00:00:16.960 So excited to be here. Happy to talk
00:00:18.720 about this topic. I figured we're in
00:00:21.039 this city with a fantastic amount of
00:00:22.720 history. We should talk about history.
00:00:24.160 So today we're going to have a little
00:00:25.359 history lesson for those of you who
00:00:27.199 haven't been around since forever. But
00:00:28.880 for those of you who have been around
00:00:30.080 since forever, hopefully this will be a
00:00:31.920 nostalgia fest. We can enjoy some good
00:00:33.840 memories together. Maybe some uh maybe
00:00:35.760 some battle scars, maybe might trigger
00:00:37.680 some things. Uh so if you feel like
00:00:39.520 you're going to pass out, you need to go
00:00:40.719 against some water, that's fine to do
00:00:42.559 that. All right. So from FTP to Kimal or
00:00:46.800 in other words, an oral history of
00:00:48.239 deploying Rails apps, right? But I'm not
00:00:50.480 gonna talk about Windows because I don't
00:00:51.680 do Windows. Um I'm not gonna talk about
00:00:53.920 Java either because I don't do Java
00:00:55.199 either. Sorry. So let's get going. Um,
00:00:57.120 this is a little bit more about me. Uh,
00:00:59.199 slash205 there was this post about Ruby
00:01:01.840 on Rails and I was checked this out and
00:01:03.840 saw this video. I'm like, that's pretty
00:01:05.280 cool. Let me play with that. And, uh, I
00:01:08.799 as I got into looking into Rails and
00:01:10.240 actually how did it do what it what it
00:01:11.920 does? Uh, I discovered I love Ruby. And
00:01:14.880 so I like to say that I came for the
00:01:16.240 Rails and I stayed for the Ruby and I've
00:01:18.240 been doing that ever since. Love Ruby
00:01:20.479 and happy that I get to do that
00:01:22.159 full-time every day. Uh I was so
00:01:24.479 enamored within a few months I was like
00:01:26.640 got to leave my job. I was a PHP Pearl
00:01:28.799 guy and I knew that our organization
00:01:30.720 would not change and so I was like well
00:01:32.400 time to move and so I did and then that
00:01:34.880 job shut down about a year later because
00:01:36.799 it was a startup and it went out of
00:01:38.079 business. Uh and then I started
00:01:39.280 freelancing. Um along that time I
00:01:42.000 released the Faker Gym. You may have
00:01:43.200 heard of it. It's uh it's in a lot of
00:01:44.640 it's on a lot of apps. I love it. It was
00:01:46.560 it was a port from the Pearl. Oh
00:01:50.560 thank you. Uh it was it was definitely a
00:01:52.880 labor of love. Um Pearl had a library
00:01:55.200 that did faker stuff and I'm like I want
00:01:56.799 that in Ruby. So there it is. Um a few a
00:01:59.759 little while later released a SAS
00:02:00.719 Railskit. You may have heard of that. Um
00:02:02.479 if you want to do billing in an
00:02:03.920 application, you could just add my code
00:02:05.520 to your code and all of a sudden you got
00:02:06.799 billing. It was it was pretty cool. And
00:02:08.720 then uh 2012, May of 2012, I decided to
00:02:12.239 start a new app. So I did Rails New
00:02:14.160 Honey Badger. That was version three
00:02:15.440 back in those days. And uh within about
00:02:17.920 a month or so we had our first
00:02:19.920 deployment where we deployed uh to
00:02:21.520 appreio. So been doing that ever since
00:02:24.080 and really having a good time doing
00:02:25.760 that.
00:02:27.520 So today we're going to use the wayback
00:02:30.319 machine. We're going to join with Mr.
00:02:32.000 Peabody and Sherman. We're going to go
00:02:33.760 visit some of the highlights of the past
00:02:36.000 uh 20 or maybe 30 years of history of
00:02:38.560 deploying Rails. So let's head back to
00:02:41.200 1991. And you might say, "Hey Ben, wait
00:02:43.200 a minute. Like Rails has not been around
00:02:44.879 since 1991. what are you talking about
00:02:46.400 here? Like well I want to go way way
00:02:48.640 back to the launch the public launch of
00:02:50.800 the web, right? World of web August 1991
00:02:53.599 is when you could actually like publish
00:02:54.959 a web page and someone else could
00:02:56.319 actually see it and it was pretty cool
00:02:58.400 back then. What were we deploying? We
00:03:00.080 were deploying HTML, right? That was all
00:03:01.840 there was. Uh there weren't even images
00:03:03.440 the first time uh when when the web was
00:03:06.159 launched. I remember actually the first
00:03:07.280 time I walked into a computer lab and I
00:03:08.640 saw images on a web page. I'm like, "Oh
00:03:10.239 hell, there goes all of our bandwidth
00:03:11.519 and the stupid images, right?" Um, so
00:03:14.159 what what how did you deploy back in
00:03:15.920 those days? Well, typically you were
00:03:17.840 well typically you were at an
00:03:19.040 educational institution. You're probably
00:03:20.239 out of college and you were on some
00:03:22.159 shared son workstation or whatever and
00:03:24.400 you had a home directory and you could
00:03:25.760 drop a file in there and you know if you
00:03:28.319 could figure out the permissions after
00:03:29.599 being a man page then you could actually
00:03:31.280 get your file served on the on the
00:03:32.879 website and you would use your textbased
00:03:34.959 browser to go and view that awesome web
00:03:36.560 page because again there were no images,
00:03:38.239 right? So it was all cool, right? This
00:03:39.599 was like the the pinnacle of information
00:03:41.920 sharing. It was awesome. But you know,
00:03:44.159 like almost as soon as the first web
00:03:45.920 page was published, someone said, "You
00:03:47.280 know what? This is great, but I want
00:03:48.720 something interactive. I actually want
00:03:50.080 to do something besides just looking at
00:03:51.840 links, right?
00:03:53.840 So, we had to come up with a plan for
00:03:56.560 how do we get an interactive web page?"
00:03:58.319 So, we were deploying to shared hosting.
00:04:00.560 We might use FTP, but typically we're
00:04:02.959 using VI, right? Typically, we're on the
00:04:04.480 server. We're editing files because
00:04:05.519 that's how we did it back in the old
00:04:06.560 days. And sometimes some of us still do
00:04:08.080 that these days. It's it's still good,
00:04:09.599 right? But we needed some interactivity.
00:04:11.840 So, we have to jump in the wayback
00:04:14.000 machine and head forward just a little
00:04:15.599 bit of time, just a couple years to
00:04:17.040 1993. And there's a nice little acronym
00:04:19.840 that you might be familiar with. It's
00:04:21.359 CGI, right? The common gateway
00:04:23.440 interface. Yep. Someone's like, "Woo,
00:04:25.759 this is so awesome." Right now, I can
00:04:27.759 actually post to a thing and something
00:04:30.400 dynamic comes back. It was fantastic.
00:04:32.800 Right.
00:04:34.400 Here's how it worked. Your browser said,
00:04:36.080 "Hey, web server, give me some stuff."
00:04:38.080 and the web server said I don't know how
00:04:39.440 to handle this thing but if I shell out
00:04:41.600 to this Pearl script that Pearl script
00:04:43.680 will do some stuff and whatever it tells
00:04:45.759 me I will then give back to the browser
00:04:48.240 and it literally that's exactly how it
00:04:50.080 worked. uh it forked a new process. It
00:04:52.479 booted up whatever was going to run
00:04:54.320 usually a pearl script and it created a
00:04:56.479 bunch of environment variables like you
00:04:58.000 know query string or path info and that
00:05:01.120 Pearl script can do some stuff with
00:05:03.040 those environment variables and with
00:05:04.320 that standard input and then it would do
00:05:06.800 some standard output and that goes right
00:05:08.479 back to the browser. It is a worked
00:05:10.880 awesomely and it still works today 30
00:05:12.960 years later, right? So you would see a
00:05:14.880 URL like this, like it was always CGI
00:05:17.280 bin because someone decided that was the
00:05:18.560 way it was going to be and that's the
00:05:19.440 way it was and it was form handler.po
00:05:22.000 and you put in your query and then you
00:05:23.280 get these environment variables showing
00:05:24.639 up in your Pearl script. And if those
00:05:26.400 look familiar because we still have them
00:05:28.800 today, right? If you've ever wondered
00:05:30.880 where that stuff comes from in rack
00:05:32.320 where it's like end and query string,
00:05:34.240 this is where it comes from 30 years
00:05:36.000 ago. Still loving it. I mean these guys
00:05:38.080 were smart, right? that they built
00:05:40.400 something with duct tape and bailing
00:05:42.639 wire and 30 years later we're still
00:05:44.160 doing the same thing.
00:05:46.800 So here's what an Apache config look
00:05:48.400 like. Say, hey, we got the CGI bin path.
00:05:50.320 Go over there and if anything's in that
00:05:52.400 folder, and if it ends with CGI, then go
00:05:54.639 ahead and run it and we'll just trust
00:05:56.800 that thing to run whatever it wants to
00:05:58.560 run, right? Absolutely no problems
00:06:00.880 whatsoever, right? Yeah. And so CVES
00:06:04.080 were invented, right? Okay. Uh this is a
00:06:07.039 typical Pearl script. This is what it
00:06:08.240 looked like. You had again you you got
00:06:10.319 to do all the things. So you spit out
00:06:11.600 your headers. It's a content HTML. And
00:06:13.840 I'm gonna parse my query string and do
00:06:15.520 some stuff. There is a subtle bug in
00:06:17.280 here that you might find if you look
00:06:18.560 closely, but I'm not gonna dwell on
00:06:20.080 that. All right, because we like Ruby.
00:06:22.319 So, here's a Ruby version. Again, you
00:06:24.080 probably would not see Ruby CGI scripts
00:06:26.000 because everyone did Pearl in those
00:06:27.120 days. But here you go. You know, looks
00:06:29.520 pretty straightforward, right?
00:06:31.919 All right. Uh, how did we deploy these
00:06:34.240 lovely Ruby scripts, but usually Pearl
00:06:35.759 scripts? Again, FTP was the tool of
00:06:38.160 choice. We didn't believe in security
00:06:39.360 back then. We didn't have SSH and SCP
00:06:41.759 doing all this cool stuff for us. So, we
00:06:43.360 just threw bits out there in the ether
00:06:44.639 and just let them get there if they got
00:06:45.759 there, right? Um, but again, always of
00:06:47.919 course vi is always your option. So, a
00:06:50.160 lot of stuff was deployed that way. And
00:06:52.160 you were typically going to deploy to
00:06:53.840 some host that you didn't control. Like
00:06:55.440 most people didn't touch an Apache
00:06:56.800 config in those days because someone
00:06:57.840 else touched that and you just got
00:06:59.280 permission to run your little slice of
00:07:00.639 thing over your little home directory,
00:07:01.919 right? Till it in and you're off to the
00:07:03.520 races.
00:07:05.039 Okay. CGI was awesome
00:07:08.720 until something else came along 1997.
00:07:12.880 There was this really smart Danish
00:07:14.479 programmer. Oh, not that one. This one.
00:07:16.880 His name was Raasmus and he created
00:07:19.280 something you may have heard of called
00:07:21.520 PHP, right? And in 1997, PHP version
00:07:25.039 three came out. Now, versions one and
00:07:26.720 two were fine. They were good, but
00:07:28.160 version three was where it really got
00:07:29.840 good. And most of us who are familiar
00:07:31.360 with PHP, this is what we know as PHP,
00:07:34.400 right? And basically Raasmus is like,
00:07:36.160 you know what, CGI is cool and all, but
00:07:37.680 like spawning up a process for every
00:07:39.840 single request. Maybe we can do a little
00:07:41.919 bit better than that. Maybe we just put
00:07:43.599 the interpreter inside of the web server
00:07:46.240 and then we don't have to spawn up
00:07:47.840 anything, right? And so that's that's
00:07:49.360 how PHP was born. That's what it does.
00:07:51.120 Apache is loading the PHP interpreter
00:07:53.280 entirely and then a request comes in, it
00:07:55.680 loads up the script, it interprets the
00:07:57.280 script, is out the output, and we're
00:07:58.400 good to go. It's like it was amazing. It
00:08:00.319 was amazing. And you could do this with
00:08:04.080 your config. Again, it looks very
00:08:05.440 similar to CGI bin. You say, "Hey, if
00:08:06.960 it's a PHP file, tell the mod PHP to go
00:08:09.360 handle it. Everything was based in mime
00:08:11.280 types in those days." So that's how it
00:08:12.800 worked. I know it's kind of weird for us
00:08:14.000 now, but that's how it was. And then you
00:08:16.319 had a PHP script, which if you squint a
00:08:19.039 little bit, you could like replace some
00:08:20.479 things and it looks kind of like ERB.
00:08:22.319 There's a reason for that. Like, hey,
00:08:23.840 that's a good idea. Let's borrow that,
00:08:25.360 right? Um, so yeah, you just have some
00:08:27.840 and in fact, PHP was borrowed from Cold
00:08:29.520 Fusion. So, there's a lot of sharing
00:08:30.720 going on in the world. It's all good.
00:08:32.080 Like, we take good ideas wherever they
00:08:33.680 pop up, right? So, this is your PHP
00:08:35.519 script that spits out a bunch of stuff.
00:08:37.440 Very cool. All right. Did you know there
00:08:40.159 was a mod Ruby?
00:08:42.479 Yeah. Yeah. Who knew there was a mod
00:08:43.919 Ruby? Okay. Right on. Did you ever try
00:08:46.959 using mod Ruby? And did that last for
00:08:49.040 more than 30 seconds? No.
00:08:51.920 Okay. Maybe sometimes if you're really a
00:08:53.680 glutton for punishment. Uh Mod Ruby was
00:08:55.760 the same idea as mod PHP. It's like,
00:08:57.600 hey, why don't we put the Ruby
00:08:58.959 interpreter inside of Apache? That's a
00:09:01.040 great idea, right? It'll make things
00:09:02.560 faster. Except it just didn't work very
00:09:05.279 well. I mean, it actually did run Ruby
00:09:06.880 stuff and you could serve a page or two
00:09:08.480 or three and then it would crap out on
00:09:09.839 you and have to restart Apache and start
00:09:11.600 over with keep repeating that cycle over
00:09:13.440 and over again. or heaven forbid someone
00:09:16.000 else on your member shared hosting.
00:09:18.399 Someone else was also running Mod Ruby
00:09:20.560 in Apache and now their application is
00:09:22.800 interacting with your application and
00:09:24.480 they've monkey patched string and you're
00:09:26.000 like what the hell is going on over
00:09:27.360 here? Because it just there was no like
00:09:30.160 separation of anything, right? That was
00:09:32.399 Mod Ruby and and if you wanted a Rails
00:09:34.399 app to run in Mod Ruby, you had to turn
00:09:36.080 off the security flag. It's like
00:09:37.680 security off and that's how you got
00:09:39.360 Rails to run, right? just like kind of
00:09:41.360 sketchy, but that's that's what we did,
00:09:43.600 you know. So, and this is what the
00:09:44.880 Apache config looks like. Very similar.
00:09:46.480 Mod Ruby, go run the the Ruby thing, and
00:09:48.800 then it's all good. Uh, if you want to
00:09:50.320 just do ERB, you can do that, too. Hey,
00:09:52.720 just name your file HTML. Bam. Now, you
00:09:55.360 can throw some ERB in there. All right.
00:09:58.720 So, we're still doing FTP. We're now
00:10:01.519 getting into SCP because now we're
00:10:02.880 figuring out, hey, maybe we should
00:10:04.080 actually care if someone can intercept
00:10:05.839 our stuff before it gets to the server,
00:10:07.200 right? So SCP, you know, secure a copy
00:10:09.279 over secure shell. And if you were
00:10:11.120 really advanced, use arsen because then
00:10:13.120 you could like you could you could push
00:10:14.720 stuff up and not but not all the stuff
00:10:16.399 because that now we're getting like
00:10:17.680 megabytes of things we're trying to
00:10:18.880 upload at once and SCP is like no no
00:10:21.200 dude, just like the stuff that changed
00:10:22.720 like that's that's genius, right? Okay.
00:10:25.760 So still going to shared hosts and
00:10:27.360 that's that was great if you're doing
00:10:29.519 PHP, not so great if you're doing Mod
00:10:31.519 Ruby. Um, but at this time we're like,
00:10:34.720 you know, maybe maybe we need to start
00:10:36.399 doing BPS's because if we're going to be
00:10:38.560 using mod Ruby, we got to actually like
00:10:40.480 only be be the only person actually
00:10:42.160 using Apache on our host so that not,
00:10:44.240 you know, our brother over here isn't
00:10:45.680 seeing all of our login stuff happening.
00:10:47.279 Yeah.
00:10:49.920 Okay. So, we hop on the way back
00:10:51.839 machine. We've got, you know, all this
00:10:53.279 cool stuff happening and we fast forward
00:10:55.760 to 2004. We all know what happened in
00:10:58.000 2004, right? Rails is publicly available
00:11:01.360 in 2004. The first public release summer
00:11:03.680 2004 and it come out comes out and it's
00:11:06.880 it's takes off like wild, right? I
00:11:08.880 remember seeing uh was it do version11 I
00:11:11.279 think it was. I'm a PHP guy still and
00:11:13.040 I'm looking I'm like you know what this
00:11:14.320 is pretty cool like all the things that
00:11:16.640 we had learned over those what seven
00:11:18.160 years or so of PHP like using a view
00:11:20.959 layer like templates and smarty
00:11:22.720 templates if you if you were a PHP guy
00:11:24.399 right um using a database abstraction
00:11:26.800 layer things like that like all this
00:11:28.560 stuff was like baked into Rails from the
00:11:30.320 beginning because well David was a PHP
00:11:32.480 guy right and so he had also been down
00:11:34.240 the same path and he was taking all
00:11:35.600 these learnings and putting into Rails
00:11:36.959 which was freaking awesome Right.
00:11:42.560 And what did we have to deploy Rails?
00:11:44.959 CGI. Actually, we did have I asked I
00:11:48.000 asked David like when you first deployed
00:11:50.240 your first Rails app, David, what'd you
00:11:51.680 use? And he said CGI. And he said, but
00:11:54.000 you know, the framework was only like a
00:11:55.279 thousand lines of code and and the app
00:11:57.120 that he was running was, you know, tiny
00:11:58.720 too. So it's like you can pay that
00:12:00.160 penalty for every request. Remember it
00:12:01.680 has to spawn the process. Can you
00:12:03.360 imagine today if you wanted to run your
00:12:04.560 Rails app with CGI? Think just think
00:12:06.560 about how long it takes your Rails app
00:12:07.680 to boot, right? We're not talking about
00:12:09.200 20 milliseconds here. It's like three or
00:12:10.880 four seconds, whatever it is, every
00:12:12.560 request. No. So, I mean, that lasted for
00:12:14.560 about a hot minute, right? Before we're
00:12:16.079 like, okay, that's just that's just not
00:12:18.000 going to work long term, right? Uh what
00:12:20.560 else is available though if you didn't
00:12:21.839 want to do CGI? Well, you had mod Ruby
00:12:24.240 and we've talked about how that is also
00:12:26.959 sad panda, right? Not not good. All
00:12:28.800 right, so people are scratching their
00:12:30.160 heads. All right, what do we do? Uh what
00:12:31.920 can we find? What can we do? And lo and
00:12:34.000 behold, there was this technology that
00:12:35.680 most of us in the Unix world didn't
00:12:37.120 really know about, but some people in
00:12:38.560 the Windows world knew about and that
00:12:40.639 was fast CGI because in the IIS land,
00:12:43.920 the internet information server, it was
00:12:45.680 also sucked. And uh they had to use fast
00:12:48.160 CGI to do anything basically. And so
00:12:49.920 we're like, hey, let's borrow that
00:12:51.279 technology. And so what fast CGI was and
00:12:53.120 and SCGI also came along did basically
00:12:55.279 the same thing. They said, "Hey, what if
00:12:57.360 we have a separate damon that's running
00:13:00.000 and it's separate from the web server
00:13:01.839 and it and the web server can talk to
00:13:03.680 this thing somehow and that somehow is
00:13:05.839 like some special protocol that you
00:13:07.279 really don't want to care about or know
00:13:08.639 about. And then that thing that's
00:13:10.800 running can then respond via this
00:13:12.399 protocol that you don't want to know
00:13:13.360 about and then the web server will
00:13:14.800 return that response, right? So it's
00:13:16.000 like hm that sounds pretty good. So
00:13:17.839 let's do that. And that's a lot of
00:13:19.920 deployments back in the early Rails days
00:13:21.839 were fast CGI, right? And we got to a
00:13:24.800 point where like ah we love fast egi so
00:13:26.320 much. Apache is kind of holding us back.
00:13:28.480 And so this new web server came out.
00:13:30.079 Well I don't know if it was new but it
00:13:31.200 was new to us. It was called lighty and
00:13:33.519 uh it was great for running fast. The
00:13:36.079 problem though with fastgi was that it
00:13:37.839 was very brittle. Like your app could be
00:13:40.000 running your your ruby things going on.
00:13:41.440 It's got memory leaks. It's happy you
00:13:42.880 know whatever as back in the day it was
00:13:45.200 memory leagues were like the number one
00:13:46.480 problem. And all of a sudden your app is
00:13:48.800 dead. Uh it's just not responsive. You
00:13:50.880 don't know what's going on. It looks
00:13:52.160 like it's alive, but the web server
00:13:53.839 can't talk to it and something is broken
00:13:55.519 and it was typically fasti's fault. And
00:13:57.519 so like, okay, I restart my app and
00:13:59.600 maybe that works. I restart Apache,
00:14:01.040 maybe that works. I restart both of them
00:14:02.160 at the same time and yeah, that works
00:14:03.360 for like five requests and it was just
00:14:05.279 it was painful. So like now we're
00:14:06.480 restarting apps all the time and we're
00:14:08.480 becoming system administrators as well,
00:14:10.240 right? Because now we have to deal with
00:14:11.680 processes and blah blah blah blah. So
00:14:13.600 this is again Apache config for fast
00:14:15.839 CGI. Not too exciting. And this is what
00:14:19.519 uh a fast CGI loader would look like.
00:14:21.440 This came distributed in Rails. This I
00:14:23.199 think this is Rails 2, Rails 3 or so.
00:14:25.199 And uh it was basically just a little
00:14:27.040 Ruby script and fastgi boots this thing
00:14:29.440 and that loads up. You see the app call
00:14:31.279 there near the bottom. That kind of
00:14:32.320 looks familiar, right? You kind of got
00:14:33.600 rack going on here. Um yeah, and that's
00:14:36.160 how your your rails approed.
00:14:40.639 So we got kind of frustrated with SVGI
00:14:42.720 and we thought what if we do something
00:14:44.880 crazy I don't know and actually like
00:14:46.480 work with HTTP instead of this weird
00:14:49.120 protocol that comes from the Windows
00:14:50.959 world right and uh so we got this
00:14:53.600 brilliant uh invention called the rail
00:14:56.000 parser which allowed us to parse HTTP
00:14:58.800 very efficiently uh before this there
00:15:01.040 were pure Ruby implementations of HT
00:15:02.560 parses and they all sucked but then rail
00:15:04.560 came along it's actually built in C and
00:15:06.079 so it's actually fast enough to use and
00:15:08.000 mongrel was based on that mongrel
00:15:09.839 understood rack, which was still new at
00:15:11.680 the time. Can you believe it? Like we
00:15:12.880 had a pre-Rack era when we were
00:15:14.480 deploying apps. Uh, and was
00:15:16.320 fantastic. Mongrel would take your app,
00:15:18.079 it would boot it, and we would configure
00:15:20.079 Apache to proxy traffic over to Mongrel.
00:15:23.920 So instead of Apache having to parse
00:15:25.680 stuff, it would just just shove it over
00:15:27.199 to the app and let the app handle it,
00:15:28.720 right? Because now the app had an HT
00:15:30.800 HTTP parser in it and it could do get
00:15:33.600 the headers and blah blah blah and then
00:15:35.279 re return the result. So Apache became
00:15:37.680 pretty dumb actually at this point.
00:15:39.120 Right? It was just a proxy server.
00:15:42.079 The problem was you only had one process
00:15:44.639 and every request went through that one
00:15:46.639 process and it could only handle one
00:15:48.560 request at a time. Now we weren't
00:15:50.399 booting every time but still it was it
00:15:51.759 was pretty slow and serial. So we're
00:15:53.440 like how can we do better? Oh no, we'll
00:15:55.199 spin up multiple processes. And now we
00:15:57.680 have Mongle cluster which allowed us to
00:15:59.519 say, "Hey, I want three mongrels
00:16:01.120 running. Please go boot those for me."
00:16:02.800 And now I can handle, you know, three
00:16:04.320 concurrent requests. And it was
00:16:05.839 fantastic, right? And this is what it
00:16:08.320 looked like. Down at the bottom, you can
00:16:09.680 see the configuration change. I've got
00:16:11.519 three different ports I need to traffic
00:16:13.279 to, and it'll load balance across those
00:16:15.440 ports. It was beautiful.
00:16:19.600 The problem was, as I mentioned briefly,
00:16:22.160 now we were system administrators. We
00:16:24.320 want to be programmers and now we have
00:16:26.720 to be system administrators. And what
00:16:28.160 the hell do we do about this? Because
00:16:29.440 we're used to deploying PHP scripts. All
00:16:31.040 we have to do is FTP something. Now I
00:16:32.800 have to care about things running. And
00:16:34.160 you know what? By the way, Mongle
00:16:35.519 actually does crash from time to time
00:16:36.800 because my app still has memory leaks,
00:16:38.560 right? Uh so so we came up with a couple
00:16:41.600 ways to manage these demons. Uh one was
00:16:44.079 called Monet. I think it was based in C.
00:16:46.000 and it was the the system
00:16:47.040 administrator's version of how you do
00:16:48.560 things and then the other was God which
00:16:50.639 was written by I can't remember exactly
00:16:53.120 who but someone in the Ruby community
00:16:54.399 and it was sorry Ryan was it uh it was
00:16:58.240 actually pretty cool aside from the name
00:16:59.920 because I'm a religious guy and I just
00:17:01.440 every time I had to deal with it it's
00:17:02.800 frustrating but you know aside from that
00:17:05.199 uh it was very cool written in Ruby and
00:17:07.039 you could tell it basically hey go watch
00:17:08.799 these processes and if they ever die
00:17:11.039 restart them I mean turn it on again
00:17:13.120 right so here's a monet configuration
00:17:16.160 and you would say, "Okay, I've got these
00:17:17.839 I've got this Mongle cluster process
00:17:19.280 that I want you to watch and it's it's
00:17:20.880 dropped this PID file at this place." So
00:17:23.039 if that PID file ever go the process ID
00:17:24.959 file, if that ever goes away, my thing
00:17:26.880 has crashed, so please start it again or
00:17:29.360 also checks that port. If port 80 stops
00:17:31.840 port 80,000 stops responding, then
00:17:33.600 please like reboot my app, like start it
00:17:35.520 up again. And this worked surprisingly
00:17:38.320 well. Like you could go a whole day
00:17:40.080 without having to worry about your app
00:17:41.520 because Monet was rebooting it for you
00:17:43.520 all the time. It was fantastic. Uh, and
00:17:45.679 then there's your cluster config
00:17:47.200 down below where you say, "Hey, listen
00:17:48.640 on this port and have three Mongols
00:17:50.480 running for me." It's fantastic. Like,
00:17:53.200 we loved it.
00:17:55.919 And around the same time uh 2006ish
00:17:59.520 switch tower which became known as
00:18:01.200 Capistrano later came out and it really
00:18:04.480 was the bee's knees when it came to
00:18:05.840 deploying stuff because remember we're
00:18:07.039 still FTPing stuff times SCP arsync we
00:18:09.679 had all these tools and you people had
00:18:10.880 their favorites and there was like flame
00:18:12.080 wars what's you know and then uh Jamus
00:18:14.480 comes out with capestrono and it is just
00:18:16.559 amazing what it does is it you configure
00:18:20.160 it and tell it hey I've got an app and
00:18:22.160 there's my git repository well in the
00:18:24.480 early days it's actually a subversion
00:18:25.840 repository. So if you remember
00:18:26.880 subversion, yeah, but later on became a
00:18:29.039 git repository and this is where I want
00:18:31.440 to deploy it. Here's the server I wanted
00:18:32.720 to go to and go to town like start my
00:18:35.120 mongrels do all the things for me and
00:18:36.799 Capashana was just a bunch of Ruby code
00:18:38.559 and it would SSH into your server for
00:18:40.480 you and it would do all the things. It
00:18:42.960 was awesome unless your server happened
00:18:45.360 to have a different Ruby version than
00:18:46.559 you were running and then things just
00:18:48.160 were like not awesome, right? Uh but for
00:18:51.039 the most of the time it worked really
00:18:52.480 really really well.
00:18:54.480 And then we got Passenger which was
00:18:57.039 weird because it actually had this
00:18:58.799 enterprise thing where they sold stuff
00:19:00.640 to you. But that aside still was a cool
00:19:03.120 open source project where basically they
00:19:04.960 said all right you know that whole web
00:19:06.400 server thing the PHP thing we think
00:19:08.320 that's a good idea and mod Ruby they
00:19:10.000 were on to something they just just
00:19:11.440 didn't get it the implementation quite
00:19:12.880 right. And so passenger said what if we
00:19:14.880 actually run Ruby in the web server
00:19:17.360 engine X or Apache and we actually do it
00:19:20.080 with you know isolated so that your app
00:19:22.799 is just you're you got that environment
00:19:24.960 and this other app got this environment
00:19:26.640 and it worked worked really well right
00:19:28.640 and so this became pretty popular pretty
00:19:30.559 quickly. You didn't have to manage a
00:19:32.480 separate process because now it's just
00:19:33.919 your web server had your app all loaded
00:19:36.320 in it. It's very cool. still had a few
00:19:38.240 of those Ruby version problems, but
00:19:39.600 Passenger actually allowed you to
00:19:40.880 specify which Ruby you wanted on the
00:19:42.799 disc you wanted to use. So you could
00:19:44.000 actually have two apps on the same
00:19:45.600 machine, different versions of Ruby. It
00:19:47.280 was mindblowingly awesome. It was it was
00:19:49.760 great.
00:19:51.600 And this is what it looked like. Very
00:19:53.120 simple because now we've gotten away
00:19:54.320 from Apache. Now we're moving to
00:19:55.520 Engineext because EngineX is awesome.
00:19:57.520 And uh yeah, you just say, "Hey, send
00:19:59.760 the traffic to the app and it's all
00:20:00.960 good."
00:20:03.120 So Capestrono really took over on
00:20:05.039 deployment side in the Rails world. just
00:20:06.400 do cap deploy and now your app is
00:20:07.840 running in production. Uh shared hosting
00:20:09.840 was pretty much in the in the in the
00:20:11.840 past like some shared hosts try to do
00:20:13.760 the passenger thing. It just didn't work
00:20:15.360 out. We had stuff like engineard came
00:20:17.360 out at that time around this time where
00:20:19.200 you could just give them your code and
00:20:20.559 they would run it for you. It was
00:20:21.520 amazing if you didn't want to be a
00:20:22.720 system admin. Uh but a lot of people
00:20:24.960 went with like slice host or lode or
00:20:27.120 something. They learned how to start a
00:20:28.240 VPS and how to install Apache and get
00:20:30.159 all this stuff going and so a lot of
00:20:31.760 education going on.
00:20:33.120 Never update it again.
00:20:34.240 Never update it again. That is
00:20:35.840 definitely true. All right, so we'll hop
00:20:39.039 back in the wayback machine and we'll
00:20:40.960 head to about 2009. The date here is a
00:20:44.240 little fuzzy because there's a lot of
00:20:45.520 stuff going on, but we had things like
00:20:47.919 Unicorn and Puma and Thin show up. And
00:20:51.120 these are all web servers. You're
00:20:52.640 probably familiar with at least one of
00:20:53.840 them because most everybody uses Puma
00:20:55.840 today. But these were remarkable for
00:20:58.240 their time because they said, "Okay,
00:20:59.440 that Mongle thing that's that's a really
00:21:01.039 good idea. We like the idea of having an
00:21:02.320 HTTP server that we can we can parse
00:21:03.919 that stuff. But what if instead of
00:21:05.840 having to like have multiple processes
00:21:08.000 that you have to manage yourself,
00:21:09.440 unicorn says, "What if I just manage
00:21:10.960 that for you?" And so you start up your
00:21:12.640 unicorn and it starts up a parent
00:21:14.400 process and it spawns children processes
00:21:17.200 and those handle the requests and the
00:21:19.360 parent process handles the routing to
00:21:20.960 those children. And if any of the
00:21:22.559 children get a memory leak or die or
00:21:24.720 whatever, it respawns the children for
00:21:26.320 you. You don't have to worry about it.
00:21:27.280 Unicorn's got you covered, right? And so
00:21:28.960 now your proxy configuration is just
00:21:30.640 push it to that one port and you're good
00:21:31.919 to go. Puma said, ' Love that idea, but
00:21:34.799 what if we did threads instead of
00:21:36.320 processes? Also cool. And then Finn
00:21:39.200 said, 'Yeah, ah, how about that, but
00:21:41.120 event driven? And so it uses this gem
00:21:43.600 called event machine, which everything
00:21:45.039 was an event- driven loop and you had to
00:21:46.880 rewrite your entire app and all your
00:21:48.320 gems to use it because it was really
00:21:49.520 weird, but some people really loved it
00:21:51.760 and uh it's still around today. You
00:21:53.440 might you might still use it, but like
00:21:54.640 if you've ever used engine X or you've
00:21:56.159 ever used node, those are also event
00:21:57.520 driven. So that was kind of popular at
00:21:58.960 the time. It was pretty exciting and
00:22:00.640 that was a thing. Uh so all these things
00:22:03.280 still you're of course managing a
00:22:04.720 process that's running but by then we
00:22:06.320 gotten pretty good at it and so we kind
00:22:07.679 of knew what was going on and the all
00:22:09.200 three of these use that same rage roll
00:22:10.799 parser so it's all super fast and super
00:22:12.720 awesome
00:22:14.640 and then Heroku happened and all of a
00:22:17.120 sudden developers didn't have to be a
00:22:19.039 system administrator anymore all you had
00:22:20.240 to do is get pushu and you know sell
00:22:22.480 them your first child because that's how
00:22:23.840 much it cost to run stuff on but it was
00:22:26.000 awesome uh just it changed everything
00:22:29.280 right so that's it get that's why it
00:22:30.480 gets its own slide You don't need any
00:22:32.080 introduction to Heroku. Okay. So again,
00:22:34.720 we're using Capistrano all the time
00:22:36.400 until we start using Heroku and we're
00:22:39.200 we're deploying to our same old Lode
00:22:40.880 server which has not been updated since
00:22:42.400 1997. Uh and we may move to EC2 or might
00:22:46.480 be using engine or use this new fangle
00:22:48.400 thing called elastic beantock which
00:22:50.159 actually sucked a whole lot but you know
00:22:51.840 some people love it. I don't know. All
00:22:53.760 right, one one last trip in the way back
00:22:57.280 machine all the way up to 2013. And you
00:23:01.280 might already know what happened in 2013
00:23:03.440 or you may be like, didn't that happen
00:23:05.120 like in I don't know 2015 or 2017
00:23:08.080 because it it kind of flew under the
00:23:09.520 radar for a little bit. But Docker
00:23:12.000 changed the world, right? Docker was
00:23:14.159 released in 2013. Uh I resisted it for
00:23:17.440 the very longest time because by this
00:23:19.440 point I'm admin, right? I know how to
00:23:20.960 run things. I don't need you to, you
00:23:22.159 know, but anyway, now we're all convers
00:23:24.080 now. We all use Docker because Docker is
00:23:25.679 awesome. So, you know, what did Docker
00:23:27.679 solve? Well, uh, Docker solved the Ruby
00:23:30.559 version problem, right? Because now, you
00:23:32.240 know, the whole joke, well, it works on
00:23:33.760 my machine. Okay, well, we'll just ship
00:23:35.039 your machine to production. Okay, I'll
00:23:37.840 just Docker the whole thing up and off
00:23:39.679 it goes, right? Uh, so you don't have to
00:23:41.600 worry about different Ruby versions or
00:23:43.280 what's installed or how am I going to
00:23:44.400 get it there. Just all I got to do is
00:23:45.919 make a Docker container, put it on the
00:23:48.000 ship, and it's gone, right?
00:23:52.080 And thanks to Docker, uh, we got Kimal.
00:23:55.760 And you're probably familiar with Kamal,
00:23:57.520 but basically it's Capestrono version
00:23:59.120 two, right? It does the same idea like
00:24:01.520 I've got your code. I'm going to push it
00:24:03.360 out to some servers for you. Uh it's a
00:24:06.320 they're now it's a Docker container
00:24:07.760 rather than actual bits flying out from
00:24:09.360 from Git, but it's the same concept,
00:24:11.279 right? You just bundle it all up and
00:24:13.120 ship it to a server and you're golden.
00:24:16.400 And this is what a Kamal configuration
00:24:18.000 looks like. Looks a bit like, you know,
00:24:19.840 Capistrano, not accidental.
00:24:25.120 And for a lot of people uh like
00:24:26.880 Honeybadger, they don't even touch
00:24:28.880 anything these days because it's all in
00:24:30.720 CI/CD, right? Once you have a Docker
00:24:32.960 pipeline like what we do is we have a
00:24:34.799 GitHub action that as soon as all the
00:24:36.720 tests pass, it creates a Docker image
00:24:39.200 and then there's another thing that
00:24:40.320 triggers it sends it off to Amazon's
00:24:42.559 elastic container repository, right? And
00:24:44.400 then triggers elastic container service
00:24:46.960 and just all that happens automatically.
00:24:48.960 Never have to worry about it. I love
00:24:50.320 life. You know, it might take half an
00:24:51.919 hour, but hey, I don't have to touch
00:24:53.360 anything, right? uh or you might be
00:24:55.440 using Kamal. You can still use
00:24:56.480 Capestrono today. There's nothing. It
00:24:58.240 still works. It's still out there. So,
00:24:59.520 if you have your VPS that you haven't
00:25:00.720 updated since 1997, you can uh still use
00:25:03.200 Capistrano. Uh but these days, you also
00:25:05.520 have some additional options on your
00:25:07.200 VPS. You can use Docku or Koolifi, which
00:25:10.480 basically give you a Heroku like
00:25:11.919 environment, right? They say, "Hey, we
00:25:13.440 all you do is get pushed to the thing
00:25:14.799 that I'm running and I'll make your
00:25:16.240 Docker container for you and I will run
00:25:17.600 it for you." And it's pretty cool. Or
00:25:19.679 you can you do the old school way if you
00:25:21.760 still like doing vi on the server. You
00:25:23.440 can hop on your server, you can run
00:25:24.559 Docker Swarm, you could do Docker
00:25:25.919 Compose, you could even just do Docker
00:25:27.520 run, you know, right? And you can run
00:25:29.279 your containers on your own VPS
00:25:30.799 yourself. Or if you're really if you're
00:25:33.520 really into self punishment, you can
00:25:34.799 look at Kubernetes and uh play with
00:25:36.480 Docker containers there. Um I will not
00:25:38.640 talk about that because that's not my
00:25:40.080 that's not my jam. Um but you know,
00:25:42.960 there's really there's there's no
00:25:44.080 shortage of options today. You got fly,
00:25:45.760 you can push your container there. You
00:25:47.440 got render. I mean, there's probably one
00:25:49.039 that was launched yesterday that I don't
00:25:50.240 know about yet. Um yeah, so so many
00:25:52.720 Docker options you just we're spoiled
00:25:54.480 today today.
00:25:56.400 So that's our trip through history.
00:25:58.000 We've uh reached now the present day.
00:25:59.919 Hope you've enjoyed this trip in the
00:26:01.279 wayback machine and I hope you go out
00:26:03.120 there and ship it. Thanks.
Explore all talks recorded at RailsConf 2025
Manu Janardhanan
Christopher "Aji" Slater
Hartley McGuire
Yasuo Honda
Ben Sheldon
Chad Fowler
John Athayde
Mike Perham
+77