跳转到主要内容

WRITING

One-Person Full-Stack Infrastructure

April 8, 20263 min readTianli Zeng
indie-devdevopsvpsautomation
One-Person Full-Stack Infrastructure

Why I Don't Use a PaaS

Vercel, Railway, Render — these platforms are convenient, but they come with a few problems:

  1. Unpredictable cost: a traffic spike can produce a frightening bill
  2. Vendor lock-in: migration cost grows exponentially over time
  3. Limited flexibility: running a cron job or websocket starts hitting walls
  4. Shallow learning: you stay ignorant of the underlying stack and have nowhere to start when something breaks

A single VPS ($30/month) can run everything, fully under your control.

The Big Picture

Architecture overview: the Cloudflare edge returns to origin on port 8443 into a single Nginx entry point, which routes by subdomain to systemd services, Docker containers, and static files
All traffic passes through the Cloudflare edge (DNS/CDN/Access), returns to origin on port 8443 into a single Nginx entry point, then fans out by subdomain to 24 systemd services, 4 Docker containers, and static files — one $30/month VPS carries the entire production stack.

Network Layer

  • Cloudflare: DNS resolution + CDN caching + DDoS protection
  • CF Access: Zero-trust authentication via email verification — replaces a self-hosted login system
  • Origin Rule: All traffic flows through CF and falls back to port 8443 on the VPS

Nginx

A single entry point that routes by subdomain:

server {
    server_name tianli.cyou;
    location / { proxy_pass http://127.0.0.1:3000; }
}
server {
    server_name dashboard.tianli.cyou;
    location / { proxy_pass http://127.0.0.1:3001; }
}
# ... more subdomains

Service Management

Every service runs under systemd:

# View status of all services
systemctl list-units --type=service --state=running | grep -E "website|dashboard|hydro"

# Deploy a new release
cd /var/www/website && bash deploy.sh
# deploy.sh handles: git pull → build → restart

Automation

Automation pipeline: the four-step deploy.sh, plus a monitoring loop of health_check, a public status page, and a daily briefing email
Deployment is the same four-step deploy.sh in every project; once live, services are probed by health_check, published on a status page, and summarized in a daily morning briefing email — from release to monitoring, one person can run it all hands-free.

Deployment

Every project ships with a deploy.sh:

git pull origin main
pnpm install --frozen-lockfile
pnpm build
sudo systemctl restart website

Monitoring

  • health_check.py: periodically checks every service's HTTP response
  • status.tianli.cyou: a public status page
  • briefing system: emails a daily morning summary of system health

DNS Management

# List all DNS records
python3 ~/Dev/tools/dev/lib/tools/cloud/cf_api.py dns list

# Add a new subdomain
python3 ~/Dev/tools/dev/lib/tools/cloud/cf_api.py dns add hydro-new A 104.218.100.67

Cost

ItemMonthly
VPS (PureVoltage 4C/8G)$30
Domain (tianli.cyou)~$1
Cloudflare$0 (Free plan)
Total~$31/month
Monthly cost comparison: about $1.3 per service on a self-hosted VPS, versus 4-15x that for entry-level per-service PaaS pricing
Spreading $31/month (VPS $30 + domain ~$1 + Cloudflare $0) across 24 services works out to $1.3 per service; the same service on a PaaS starts at 4-15x that.

$31/month for 24 services — about $1.30 per service per month. No PaaS comes close.

Takeaways

  1. systemd is the best process manager — no need for PM2, supervisor, or anything else
  2. Cloudflare Free is enough — CDN, DDoS protection, SSL, Access, all free
  3. Standardize the deploy script — keeping every project's deploy.sh structurally identical reduces cognitive load
  4. Don't over-containerize — simple Node.js/Python apps run fine under systemd; reserve Docker for the cases that genuinely need isolation

FOLLOW

New posts land here first. Subscribe via RSS: /feed.xml

AUTHOR

Tianli Zeng

Hydraulic engineer. I write about AI methodology, daily investment reviews, and engineering practice.

Found a mistake, or have something to add?