Website Logo
/ blog
/ serverless-python-websites

Serverless Python Websites

Introduction

Over the last couple months, I rewrote a small hobby project that visualises Strava activities to be completely serverless. The website is now serverless, but the process was certainly not painless. I wanted to share some thoughts about my process in case it helps anyone.

Why rewrite it to be serverless Python?

In short, and order of importance:

  1. It's cheap.
  2. It's already in Python, and I want to rewrite as little as possible.
  3. I want to learn more about AWS Lambda.

In long, but still in order of importance:

It's cheap

An IQ scale meme showing that smart and dumb people use VPS's, but average people try to go serverless

Something I see on the internet a lot is "just rent a cheap box from Hetzner/digitalocean/EC2 instance" and put everything on that. Problem solved. You can run a normal Python server, development will be easy, and you'll totally never have any problems again. Python has loads of ways to run normal servers (see Flask/Django/FastAPI and more) so you can just get ChatGPT to write 90% of your app, and you'll be golden.

Except one problem. That costs money. The smallest EC2 instance costs ~$200 a year at the time of writing this, and the smallest box didn't have enough RAM to run npm run build, so I had to use a larger one. For my small hobby project, the smallest box I could get away with was ~350 USD a year. The blogs I read always say something like: "Just use a VPS, for $600 a year you won't have any problems". Well, that $600 a year IS the problem. If I'm running some money-making enterprise, that $600 is a drop in the ocean compared to developer salaries, so then it makes sense to use a VPS, but my project is a small hobby project that:

It's a tiny project. But it still represents hundreds of hours of time and effort, and it's a useful tool people might stumble upon. I don't want to take it down over $300/year.

The other problem with this is that active-statistics isn't my only hobby project. Rather than have 1 web project that I can run on a VPS, I have lots of small silly websites that barely anyone uses at all. Heck, if you read this blog post, you're probably the only person who'll read it today! If I need to pay for a hefty VPS for each project, that's $300 × N where N = number of projects I want to have. That's O(n) cost scaling, and if stupid SWE job interview questions have taught me anything, it's that I should be aiming for O(1).

It's already in Python and I want to rewrite as little as possible.

Previously, the backend was a Flask app. Hours of work have already already been put into visualisation, data analysis, charting, and interfacing with Strava's API, and it's all already bug-free and in Python. I wanted to do as little additional work as possible to make it serverless. There might be better serverless ecosystems for other languages (this website is next.js on Vercel, so I know what's possible) but I want to keep the backend Python.

Also I use Python for work every day, so I'm curious to learn what it has to offer in this space.

I want to learn more about AWS Lambda.

I know superficially how it works - just instantaneous compute that turns on and off - but in a past job a devops colleague was explaining to me how the backend worked, and while explaining said: "You know how lambdas are created right?" and I was like "no" and they were like: "Well that's too much to explain right now". I felt inadequate, and making my own serverless website with lambda is good excuse to use them in anger and learn how they work. Plus making your website serverless feels like flossing your teeth. You can walk around and judge everyone who hasn't flossed. You can be smug. And being smug is fun.

The Python Serverless Ecosystem

The Python serverless ecosystem feels like walking through a graveyard. Sad, fairly empty, and lots of dead projects. When I set out to make this, I considered:

What I did:

What I would have liked to have done in hindsite:

How I came to this choice.

In a perfect world I could re-create my application using each of these methods and then report back to you about what's best, but sadly that's not possible. My evaluations of the following after making the website are:

How it's going

When everything seemed to be working, I shared the website in a Reddit post that gained some traction. Over the next few weeks, thousands of people used my website.

Here are the total lambda invocations over the first week of deployment. There is one data point per hour, so you can see the maximum number of invocations I handled in an hour was ~1.5k.

An image showing the total number of lambda invocations over the first week of deployment with one data point per hour. It's exponentially decaying with a peak of 1.5k invocations per hour.

Over this time, the maximum number of concurrent lambdas running was 7.

An image of the maximum number of concurrent lambdas firing over the first week of deployment. The max concurrent lambdas was 7 at any one time.

And most importantly of all, here is my AWS account cost breakdown after deployment.

An image showing the cost breakdown of my AWS account, showing it dropping from ~20 USD per month, to ~2 USD per month.

As you can see, my average monthly bill has been reduced from $20 USD to $2 USD. Servicing all these requests costs me nothing, and I'm only paying a tiny amount for Route53 records and ECR storage fees.

Thoughts

Serverless is hard. It's hard because the infrastructure and configuration to get anything running is orders of magnitude more complex than just running a VPS. When running a VPS you:

Serverless is:

It's also sort of hard for me to believe that there isn't some Python package that wraps up some AWS CDK code so you can essentially call: deploy_serverless(stack_name="my-app") and all the infra is deployed manually.

I imagine the hard bit about some generic package is that everyone's use case will be different and users will want to bring their own DB solutions, be it Dynamo/Aurora/something with another cloud provider entirely, and if you attempt to satisfy most people + monetise it, you end up with something that looks like serverless anyway.

Conclusion

My serverless project is done, deployed, working, and currently costs $0/year for me to host to my glorious userbase of ~500 people/year. I'll probably continue to deploy my hobby projects in a similar way, and use AWS CDK instead of SAM.

I hope something comes along in a year or two that makes deploying serverless apps with Python backends a lot easier (and keeps it cheap), and I look forward to migrating to such a solution.