In Chapter 2: What we've tried, we talked about the journey from very simplistic PythonAnywhere PaaS hosting to coordinating 1, then 3, and eventually up to 8 small servers in DigitalOcean. At each step of that journey, those were the right choices for Talk Python and for me managing them.
Now, we'll cover how Talk Python of today (2024) is hosted. It's a massive improvement on many fronts and has opened a bunch of new opportunities for us while reducing the complexity.
First, we need to talk about leaving the cloud.
The title of this chapter is inspired by David Heinemeier Hansson (DHH). He's the creator of Ruby on Rails and co-founder of Basecamp. A couple of years ago, they got entirely fed up with the complexity and the cost of hyperscaler cloud platforms (AWS in their case). They decided that all the complexity of S3, lambdas, managed DBs, etc., was just too much. The cost was entirely out of control. So, they moved all their apps onto a single huge physical system at a colocation-based data center.
DHH wrote extensively about this on his blog. The entire series is well worth a read. Start with these two: "We have left the cloud" and "The Big Cloud Exit FAQ," then follow the links for more within those articles.
Now, this probably doesn't apply apples to apples to you. It definitely does not to Talk Python. But it offers powerful lessons that apply to Talk Python and to you, too.
Here are the key points from Basecamp's journey:
These bullet points don't do justice to the whole idea, so read the two articles linked above.
What pertinent lessons can we take from this?
With those principles laid out, you can guess our setup today. I shut down all eight servers one by one. They were migrated to a single large cloud VM running Ubuntu Linux. Large is relative, of course. We are currently using an 8 vCPU + 16GB RAM machine.
When I wrote this chapter, that previous paragraph ended with "running at DigitalOcean." But, part way through this book and largely because of this book, I decided to move to Hetzner. There you'll get faster CPUs and faster networks for much lower prices. I wrote this whole migration up to be included here. You'll find it in Chapter 15: Moving to Hetzner (a Retrospective).
On this central server, we're no longer running our Python apps directly. Instead, everything is containerized using Docker. These different apps and their dependencies are managed via Docker Compose. I intentionally avoided Kubernetes for the time being. It feels like Kubernetes adds significant operational complexity and makes monitoring our running apps harder than pure Docker. Your mileage may vary.
So what does this cost? That depends! But for any operating business, it's truly negligible. Here are some prices based on the hosting company:
We've been using DigitalOcean for many years, and they have been great. However, the German company Hetzner recently opened a US-based data center. Look at the pricing. It's 6x cheaper than DO and a whopping 20x cheaper than Azure. We could double the server to a whopping 16 vCPU and 32 GB RAM for only $50/mo. We'll go way deeper into this in Chapter 15: Moving to Hetzner (a Retrospective).
Bandwidth costs are another massive consideration. Recall that we're doing around 15 TB/mo of traffic. AWS and Azure charge $0.09/GB. That might seem fine. But for 15 TB, that's 15 x 1,024 x $0.09 = $1,382.40. Wow! In practice, we only have about 1 TB/mo running through our web servers directly. The included bandwidth at Hetzner covers this entirely, so it's $0 more. The rest is through a CDN, for which we pay roughly $40/mo. We have a whole chapter on CDNs later.
The beautiful thing about this setup is that when I wanted to try hosting at Hetzner, it was literally just a data export and restore migration. I didn't have to rewrite our apps for their equivalent of S3 or lambda or whatever. I don't think they have them anyway. Nor do I want them.
With this infrastructure, we typically handle at least 9M requests to the backend Python code and associated database each month. This could go much higher. The typical server load is 5%, with spikes to 20-30%.
Plus, we do zero caching. None. The web app is so fast it's just not needed. A typical request through NGINX -> Python -> Database -> Python -> NGINX response is 30-50ms. Even if we pushed the response time to 0ms, no one would notice. But adding some caching would allow an even higher load on the same server.
Buying dedicated servers and hosting them in a co-location data center like Deft makes little sense for Talk Python. We can still mirror these benefits by getting a single, large, affordable VM on dedicated hardware at a state-of-the-art data center. This might as well be a dedicated server on real hardware we colocated somewhere else. We saw the price is incredible with Hetzner and DigitalOcean.