I got tired of Bitly limiting me to 10 links/month for free and TinyURL having zero analytics. So I built meshalive.com — a free URL shortener with real-time click analytics, dynamic QR codes, custom slugs, and a REST API. Here's how it's built.
The stack
- Backend: Go + Fiber — fast, minimal, compiles to a single binary
- Database: PostgreSQL with sqlc for type-safe queries (no ORM)
- Cache: Redis for sub-2ms redirect lookups — the short slug is looked up from Redis, DB is the fallback
- Frontend: Next.js 15 (App Router) + TypeScript, zero UI framework, all inline styles
- Infra: A single $6/mo VPS, Docker Compose, Nginx reverse proxy, Cloudflare in front
- Auth: JWT access tokens (15min TTL) + HttpOnly refresh cookies (7 days), rotated on every refresh
- Short domain: msha.live → every shortened link resolves through the Go API in <2ms
How the redirect works
Browser → Cloudflare → Nginx → Go API
slug lookup: Redis first → Postgres fallback
→ 301 to destination
→ async click event written to Postgres
The redirect path never touches Next.js — it goes directly to the Go API so there's no Node.js cold start penalty.
What's free (forever)
- Shorten any URL instantly — no account needed
- 100 saved links with a free account
- Click analytics — geo, device, referrer
- Dynamic QR codes (update destination after printing)
- Custom slugs (msha.live/your-brand)
- Full REST API on paid plans from $4/mo
Why self-hosted on one VPS instead of cloud functions?
Cost. A Lambda function + RDS + ElastiCache would run $40–80/mo for the same workload. The VPS runs everything for $6. Docker Compose means zero ops complexity — docker compose up -d and it's running.
What I learned
- NEXT_PUBLIC_ env vars in Next.js are baked at build time, not runtime — cost me an hour
- Docker bypasses UFW via iptables — remove port bindings from docker-compose.yml instead of using ufw deny
- backdropFilter: blur() on a parent element breaks position: fixed for any child — the mobile nav drawer was invisible for this reason
- Cloudflare caches 301 redirects in browsers permanently — test route changes in incognito
Try it: meshalive.com — shorten a URL, no account needed.
Happy to answer questions about the Go API, the sqlc setup, or the Nginx config.
Top comments (0)