Deploying on Free Tier: What Actually Works
I wanted to deploy Aegis2FA without paying for hosting. Here's the stack I ended up with.
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:
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:
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:
fly launch
fly secrets set DATABASE_URL="..." REDIS_URL="..."
fly deployThe 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.