How to Ship an Automated ML Product Solo, Without AWS

For Solo builders and indie hackers shipping ML products · Based on Egor Howell Production-Grade ML Deploy Framework

// TL;DR

If you're a solo builder shipping an ML product, this framework gives you a lean, professional stack that avoids AWS overhead while staying fully automated. You'll design a two-domain system (forecast + optimise), structure code by action, and manage dependencies with Poetry. GitHub Actions retrains your model daily and deploys on every merge to main; Supabase stores predictions as a backend-as-a-service; and a Streamlit dashboard runs 24/7 on a VPS via systemd behind Nginx. The philosophy is to ship a working baseline first, then improve — so your product is live and running unattended fast.

Why should solo builders avoid AWS for their first ML product?

Because complex cloud infrastructure is usually overkill for a solo project — it slows you down, adds a steep learning curve, and doesn't deliver proportionate value. The Production-Grade ML Deploy Framework favours a lean stack that professionals actually use: Poetry, Pyenv, CircleCI, GitHub Actions, Supabase, Streamlit, and a single VPS. Combined correctly, it's fast to ship and just as credible.

For a solo builder, speed and maintainability matter more than infinite scalability you'll never use. Get the system live, running unattended, and improving — that beats an elegant architecture that never ships.

How do you design an ML product that actually does something?

Build a two-domain architecture. Your model shouldn't just predict — it should drive an action. Map it explicitly: what does the model forecast, and what decision does that forecast trigger? A demand forecaster feeds an inventory optimiser that recommends restocking quantities. An injury-risk model feeds a squad-selection optimiser. This 'predict + act' structure makes the product genuinely useful, not just a dashboard of numbers.

Use a plug-and-play model like Prophet or XGBoost. The engineering and automation are the hard, valuable parts — don't burn time on model sophistication that users won't notice.

How do you keep the whole thing running unattended?

Automate with GitHub Actions. A cron workflow (e.g. `0 9 *`) reruns your pipeline daily: checkout, set up Python, install via Poetry, and run `poetry run python src/main.py`, which writes fresh predictions to Supabase. A separate deploy workflow triggers on merge to main, SSHes into your VPS, and runs `scripts/deploy.sh` to git pull and restart your Streamlit service.

On the VPS (reference: Hostinger KVM2 — 8GB RAM, 2 cores, Ubuntu), configure Streamlit as a systemd service with `Restart=always` so it recovers from crashes automatically. Put Nginx in front as a reverse proxy and Certbot on top for HTTPS. The Streamlit service polls Supabase roughly every 300 seconds and re-renders when new predictions arrive.

How do you keep quality high when you're the only reviewer?

Let automation be your second pair of eyes. A Makefile exposes `make check`, which runs formatting, linting, type-checking, and pytest in one command. CircleCI runs the same checks on every push, and protecting main means even you can't merge broken code without passing. Write at least two or three tests per function — more test lines than source lines — so you catch regressions before they hit your live product. Store all secrets in environment variables and GitHub repository secrets; never hardcode credentials in a public repo.

How do you avoid over-engineering as a solo builder?

Follow 'do it first, then do it right, then do it better.' Ship Streamlit before considering a JavaScript front-end. Use Supabase before building a custom backend. Use a VPS before touching Kubernetes. Each principle points the same way: complexity should earn its place. Neglecting the downstream action layer or choosing an algorithm purely for sophistication are both named pitfalls that waste solo builders' scarcest resource — time.

Next step: Scaffold the canonical repo, define your Supabase table columns to match your prediction keys, and get `main.py` running end-to-end locally. Then provision a VPS, wire the daily and deploy GitHub Actions workflows, and watch your product update itself every morning.

// FREQUENTLY ASKED QUESTIONS

What does the reference VPS setup cost and require?

The reference is a Hostinger KVM2 VPS — 8GB RAM, 2 cores, running Ubuntu. You SSH in and install Python, Pyenv, Poetry, and Nginx, clone your repo, add Supabase credentials to a .env file, configure a systemd Streamlit service with Restart=always, set up Nginx as a reverse proxy, and add Certbot for SSL. This hosts your app 24/7 affordably for a solo product.

Can I run everything without paying for CI?

CircleCI and GitHub Actions both offer free tiers suitable for a solo portfolio-scale project, and Supabase has a free tier for its Postgres database. The framework's lean stack is deliberately chosen to be low-cost and fast to ship, so you can get a fully automated, deployed product live without significant infrastructure spend.

How do I make sure my live product doesn't silently break?

Protect main and require CircleCI checks to pass before merging, so broken code never deploys. Configure the Streamlit systemd service with Restart=always so it recovers from crashes. Validate the full pipeline before relying on it: confirm predictions land in Supabase with correct timestamps, the dashboard renders, and a dummy merge triggers a successful deploy.