All posts

Deploying on Free Tier: What Actually Works

I wanted to deploy Aegis2FA without paying for hosting. Here's the stack I ended up with.

2 min read
dockerdeploymentdevopsbackend

I wanted to deploy Aegis2FA somewhere real, not just run it locally. But I didn't want to pay for hosting for a learning project.

Turns out, you can run a full Node.js app with PostgreSQL and Redis for $0/month if you're willing to work within free tier limits.

The Stack

  • Fly.io for the Node.js app (3 free VMs)
  • Supabase for PostgreSQL (500MB free)
  • Upstash for Redis (10K commands/day free)

That's enough for a learning project or low-traffic side project.

The Docker Part

I spent too long on the Dockerfile before realizing most of it doesn't matter for a small project. Here's what I actually care about:

dockerfile
FROM node:20-alpine
 
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY dist ./dist
 
# Don't run as root
RUN adduser -D appuser
USER appuser
 
CMD ["node", "dist/main.js"]

Multi-stage builds are nice for reducing image size, but for a learning project, a simple Dockerfile is fine. I got it down to ~150MB which is good enough.

Docker Compose for Local Dev

This is the part that actually saved me time:

yaml
services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: aegis2fa
      POSTGRES_PASSWORD: postgres
    ports:
      - '5432:5432'
 
  redis:
    image: redis:7-alpine
    ports:
      - '6379:6379'

One docker compose up and I have the same databases locally that I use in production. No "works on my machine" issues.

Deploying to Fly.io

Fly.io has a CLI that makes deployment pretty painless:

bash
fly launch
fly secrets set DATABASE_URL="..." REDIS_URL="..."
fly deploy

The free tier gives you 3 shared VMs. The catch is they spin down after inactivity and take a few seconds to wake up. Fine for a portfolio project, annoying for anything real.

What I Learned

Free tiers have limits that matter. Supabase's 500MB sounds like a lot until you realize Prisma migrations and indexes add up. Upstash's 10K commands/day is fine for low traffic but would run out quickly under load.

Health checks are worth setting up. Fly.io can restart your app if it crashes, but only if you have a health endpoint it can ping.

Environment variables everywhere. I should have used them from the start instead of hardcoding connection strings. Made deployment way easier once I fixed it.

Cost If You Outgrow Free Tier

If the project ever got real traffic:

  • Fly.io: ~$5/month for a dedicated VM
  • Supabase: $25/month for more storage
  • Upstash: $10/month for more commands

About $40/month total. Not bad, but free is nicer for something nobody's using.

The Dockerfile and docker-compose.yml are in the Aegis2FA repo if you want to see the full setup.