Hello and welcome to my TED Talk.
Today I will be talking about a problem that all of us can relate to as developers with ultra-cool side projects in GitHub that have 0 stars: how to host lots of half-baked tiny apps for as cheaply as possible.
As a public-sphere-oriented side project, I built a small web app to show Canadians their next holiday. It’s a zippy little express app with a bunch of server-rendered pages and an embedded DB, and it’s open-source so anyone can use it (even non-Canadians).
http://localhost:3000, the point of websites is really that other people can see them, so you gotta find somewhere to host them. But not every app is gonna make you a ton of cash or be an ad vehicle — sometimes you just want to host a cutesy little app without having to come up with a business plan.
So what’s the best option for hosting a basic web app while paying as little as possible? Well, if this was a mystery novel, I would introduce 12 shifty characters right around now, but the answer is you should use Cloud Run.
Cloud Run is easy to set up and it’s basically free for low-volume apps.
However, anyone who’s ever had a Grade 3 math teacher knows it’s important to show your work, so I’m going to go over some of the options I looked at and how they stack up against each other.
In roughly chronological order, I started with free hosting options and then moved on to paid options. In general, free hosting comes with limitations that you can either accept or pay your way out of, so what you end up looking for is a good balance of uptime vs cost.
eg, Github Pages or Surge
Static hosting services are super reliable and super free (😻), but the major caveat here is that they restrict you to static sites (or in-browser JS, to split a hair). Does this work for you? Maybe, if you’re using a “compiles to static” framework like Gatsby or Next.js (both Very Fun™️ in their own right). But not if you have picked up a more traditional MVC framework, like Flask, Rails, Laravel, or, in my case, express.
If all you need is a totally static site — a bunch of HTML files — or you’re building a Single-Page App that offloads the logic onto a web browser, then you should probably just use a static hosting service and call it a day. (eg, My personal website is running on GitHub Pages).
However, if you’re writing server-side logic to listen for requests and build your pages, you might have leveled-up and out of this category.
Usually you have to pay for server uptime, but a few prominent companies have a category called “the free tier”. PaaS products like Heroku or Glitch offer this: they will host your app for free (!!) but — like Jurassic Park after Dennis Nedry leaves — will shut it down after [x] minutes without traffic. Once your app is down, the next request that comes in can take 20 or 30 seconds to load because it needs to spin up a whole server for the first request. For not-serious prototypes or little “Hello World!” tutorial apps, this is probably fine because your entire audience is your roommate and your mom. But once you want a site that will actually be usable, you come to two realizations:
- this is untenable, and
- more like “the free tear 😢” because it’s what happens to your eyes after staring at 20 seconds of a white page
Maybe it’s time to bite the bullet and pay to host. Okay fine, I reason to myself, I am not bankrupt. Truth be told, I regularly pay money for things (eg, groceries and other necessities). But I’m also not Geoff Bezos, who makes more money in the time it takes for him to read this article than you or I will make in a year. So let’s see what’s on offer, but let’s also try to be cost-conscious.
eg, Upgrading Heroku/Glitch, using Digital Ocean, or GoDaddy
Traditional server hosting is a well-trod path here, with many commodity services competing to sell you uptime. Whether you want to upgrade your Heroku or Glitch plan, squeeze out a Digital Ocean droplet or poach yourself a big ol’ HostGator, the principle is pretty much the same. You pay a fixed rate for permanent server uptime and then your app runs all the time until either you die or you run out of money. If you’re looking for the cheap plans, they’re usually around $5-9 (USD!!) a month.
Sure, not like it’s the end of the world, but I can also buy Netflix for $10/month (CAD) and get like a million shows I’ll never watch. So it would be good if there were some cheaper options here, because $10/month quickly adds up to $9,360.00 (79 years being the average human lifespan).
The reason we’re getting such crap experiences with the free tier is that dynamic sites need a server to do some computation before they return pages. To use my Canadian holidays site as an example, I look up how many days until the next holiday, so I need to check the current date every time a request comes in.
Building a page itself is pretty quick, but booting up a hibernating server takes a while. For the fastest responses, we end up keeping the engine idling 24/7. This way, our server is always ready to respond to incoming requests, but at the cost of a lot of uptime we don’t need.
So how do we split the difference? If we could find a way to pay only for the time that we are serving web traffic (💡) then we can launch fleets of rarely-visited websites for next-to-free. Sounds simple enough, but how does it work in practice?
eg, AWS Lambda or Google Cloud Functions
Probably you’ve heard of serverless functions, aka Lambdas, aka Functions as a Service (FaaS): the idea is you run individual functions rather than a big fat web framework. “Server-less” makes more sense as two words in this context, because we need less of a server than all of one. What if, instead of our web server listening 24 hours a day for requests, we handled each request with a function that only runs when requests come in, and we pay only for the time it took to run those functions?
What we’re talking about here is function invocations, which, for small projects, end up being cheap as chips. At 10k requests a month, you’re looking at an estimate of ~21 cents. There’re a lot of options in this space: the Big Three (AWS, Azure, GCP) all offer FaaS services, as well as more upstart-y platforms like Vercel or Netlify.
But wait! Is this going to work with express or Rails or whatever? Erm, there are options I suppose (eg, serverless express). But out of the box, no.
To be clear, if this works for you, then this is a great option. For low-volume sites, you are looking at pennies a month. But if you already have a conventional web app, it probably means a big, fat rewrite: a thing I was definitely not interested in, and I would posit that you shouldn’t be either.
at long last, Cloud Run
If you read the title of this post or the earlier-mentioned ‘TL;DR’, you might have guessed this, but for super unobservant people, the moment you have been waiting for is here.
✨ Cloud Run ✨ is the gold at the end of this rainbow. Instead of paying for the time it takes to run function invocations, Cloud Run charges you for time spent running your app as a container — but the trick is that the container only runs when requests come in. Unlike traditional server-hosting, the time to boot up a container is dramatically less than it takes to spin up a server. You don’t have to provision a VM or download anything: containers bundle together everything they need at build time. Building a container can take a while (sometimes several minutes), but starting them up is pretty zippy.
It’s a really neat way to slice the Gordian knot here. As we’ve seen, the other options are:
- be static
- deal with downtime
- pay a lot for uptime you don’t need
- rewrite your whole damn app
With Cloud Run, get the best of both worlds: you get the pay-per-use model of serverless functions without overly constraining how you build your app. And since we’re talking about low-volume side projects presumably without much in the way of growth hacking, most of the time you’re not paying anything.
You know the phrase, “make money while you sleep”? Well, this is similar: only it’s more like “most of the time you’re asleep, you’re not paying for Cloud Run.” And Cloud Run has a free tier too, which means if you’re really unpopular, hosting is free!
Glad you asked! Basically, the catch is you need a
Dockerfile. Unlike with FaaS platforms, you don’t have to carve up your app like an LA plastic surgeon, but you do need to be able to run it as a container, which isn’t always part of the “Hello World!” tutorial you started with.
The good news is that if you’re using a pretty established framework, examples abound. Google’s excellent “Build and Deploy” Quickstart tutorial includes sample Dockerfiles for 8 major programming languages. The JS one is 6 lines of code but I am a little more
l33t than they expected so I got mine up to 15.
If you need an intro to Docker, check out this excellent guide by Robert Cooper.
If you’re still not convinced and you want to do more research, then that’s fine too. A good place to start is at the beginning of this article. Otherwise, you should give it a shot! Here are a few more resources to help you on your way.
- Hit up Google’s “Build and Deploy” Quickstart for Cloud Run
- Learn how much cheaper it is to use Cloud Run than App Engine
- Deploy automatically to Cloud Run using Github Actions
Thanks for reading! Happy devving!