Can You Build a SaaS Using Only Bash and Python? I Tried.
Tired of bloated stacks and 1000-dependency projects, I set out to build a real SaaS product using just Bash scripts and Python.

What if I told you you don’t need Node.js, Docker, or Kubernetes to launch your next SaaS?
Can You Build a SaaS Using Only Bash and Python? I Tried.
Every modern SaaS tutorial seems to start with the same tech stack: React frontend, Node.js backend, PostgreSQL, Docker, Stripe, and some CI/CD tool you’ve never heard of.
But what if you threw all that out the window? No frontend frameworks. No containers. Just Bash and Python — the OG tools of the command-line world.
That’s exactly what I decided to try.
Could I build and deploy a simple SaaS using only these two tools?
Here’s how it went.
The Rules of the Experiment
Before I get into the weeds, here were my self-imposed constraints:
- Only Python for backend logic. No Django, Flask, or FastAPI. Just the standard library and maybe
http.server
orsocketserver
. - Only Bash for scripting and automation. Setup, deployment, cron jobs — all done with Bash.
- No external infrastructure tools. No Docker, no Kubernetes, no CI/CD pipelines.
- Database: I allowed SQLite (since it comes bundled with Python).
- Frontend: HTML templates rendered via Python. No JavaScript frameworks.
- Hosting: A cheap $5/month VPS (DigitalOcean).
The idea was to prove that if you know just Python and Bash, you can get a SaaS out in the world — even today.
What I Built: A Dead-Simple SaaS
To keep the scope reasonable, I built a minimalist SaaS:
A daily habit tracker with email reminders.
Users can sign up, track habits (via a form), and receive daily email summaries. It includes:
- User registration (email + password)
- Login + sessions
- Add/edit/delete habits
- Daily email digest via cron job
Sounds simple. But even a “simple” SaaS includes a surprising amount of moving parts.
Backend: Python’s Standard Library Can Go a Long Way
Instead of a full framework, I used http.server
as the starting point:
from http.server import BaseHTTPRequestHandler, HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(200)
self.end_headers()
self.wfile.write(b'Welcome to the Habit Tracker!')
# More routes here...
httpd = HTTPServer(('0.0.0.0', 8080), MyHandler)
httpd.serve_forever()
Yes, it’s bare-bones. But it’s fast to spin up, and surprisingly flexible.
Other Python standard library tools I leaned on:
sqlite3
for data storagesmtplib
for sending emailshashlib
+secrets
for password hashing + tokenscgi
for parsing form datastring.Template
for HTML templating
What worked:
- Python’s standard lib is more capable than most devs realize.
- Development was fast because I didn’t spend time configuring frameworks.
What sucked:
- Writing route logic manually gets tedious.
- HTML templating is clunky without Jinja2 or similar.
http.server
doesn’t support concurrency — so every request is blocking.
Deployment & Automation: Bash Still Rules
Here’s where Bash really shines.
I wrote a simple deploy.sh
script to:
- SSH into the VPS
- Pull the latest code from GitHub
- Restart the Python server
#!/bin/bash
ssh user@myvps.com << EOF
cd ~/habit-tracker
git pull origin main
pkill -f server.py
nohup python3 server.py > out.log 2>&1 &
EOF
For email reminders, I used a cron job that ran a Python script daily:
0 7 * * * /usr/bin/python3 /home/user/habit-tracker/send_emails.py
What worked:
- Bash is still the best glue between systems.
- Easy to automate and troubleshoot.
What sucked:
- Writing portable Bash scripts is hard.
- No built-in error handling — you have to be paranoid.
- Debugging can be cryptic.
User Authentication Without a Framework? Possible.
Here’s how I handled sessions and passwords:
- Passwords were hashed with
hashlib.pbkdf2_hmac
. - Sessions were tracked with secure random tokens stored in a
sessions
table in SQLite. - Cookies were set via response headers manually.
Sample password hash:
import hashlib, os
salt = os.urandom(16)
hashed = hashlib.pbkdf2_hmac('sha256', b'password123', salt, 100000)
Was it safe? Reasonably.
Was it fun? Not even a little.
Hosting: No Docker, No Problem
On the VPS, I installed:
- Python 3.11
- SQLite (already included)
- Nginx (to reverse-proxy and serve static files)
No containers. No orchestrators. Just good old systemd + Bash:
[Unit]
Description=Habit Tracker Service
[Service]
ExecStart=/usr/bin/python3 /home/user/habit-tracker/server.py
Restart=always
[Install]
WantedBy=multi-user.target
It took less than an hour to get it all running from scratch.
The Results: Does It Actually Work?
Surprisingly… yes.
- The app handles ~100 users just fine.
- Daily emails are going out.
- Uptime has been solid (except for one time I forgot to
nohup
the server).
Here’s what I learned:
1. Complexity is a choice.
You don’t need a microservices architecture for a simple SaaS. A monolith is fine.
2. Python’s standard library is underrated.
You can build full apps without installing a single dependency.
3. Bash is glue — not duct tape.
Used right, Bash can replace entire deployment pipelines. But you need to respect its limits.
4. You can launch faster by doing less.
No containers, no build system, no CI/CD. Just working code in production.
Would I Do It Again?
For a side project or MVP? Absolutely.
For a production-grade SaaS with paying customers? Probably not.
Eventually, you’ll want:
- A real framework for maintainability
- Robust error handling and logging
- A frontend better than raw HTML forms
- Easier scaling and monitoring
But here’s the kicker:
You don’t need all that just to start.
Most devs spend months prepping their stack for scale… and never ship.
I shipped in a weekend.
Final Thoughts
You don’t need the latest framework to build something valuable. Bash and Python are enough to launch. And once you’re live, you’ll know exactly what you actually need to improve.
Forget the hype. Start small. Iterate fast.
Who knows? Maybe your next SaaS doesn’t need Kubernetes either.