bruno@cabado:~$ cat projects/shortener.md

← projects/

Shortener

Up (live demo)

  • Full Stack
  • DevOps
  • Self-hosted

Self-hosted URL shortener with click analytics, custom aliases, and Docker-based deployment on personal infrastructure.

Context

Most URL shorteners are SaaS products tied to third-party platforms. Shortener was built to run entirely on my own infrastructure — no Vercel or Supabase dependencies — as a practical tool I could deploy on Proxmox and operate long-term with full control over data and uptime.

What I built

Shortener includes:

  • A home page to shorten URLs with optional custom aliases and expiration (7/30/90 days)
  • QR code generation from the result card or stats table
  • URL title preview while typing a destination link
  • A stats dashboard with searchable link table, CSV export, and delete actions
  • Analytics for daily clicks, top links, top referrers, and configurable date ranges
  • Light/dark theme toggle across the UI

Technical approach

I implemented a split architecture: a Next.js frontend with Tailwind CSS and Recharts, backed by a FastAPI API with SQLAlchemy and PostgreSQL. The stack runs via Docker Compose with automatic SQL migrations on API startup, rate limiting on create/delete/redirect endpoints, and optional ADMIN_API_KEY protection for write operations. Operational scripts cover backup, restore, and zero-downtime upgrades, while GitHub Actions runs lint, tests, and Docker builds on every push.

Outcome

Shortener is a production-ready self-hosted utility rather than a prototype. It combines a polished shortening workflow with meaningful click analytics, and the Docker-first design makes it straightforward to deploy, upgrade, and maintain on personal hardware without sacrificing features found in hosted alternatives.

## Project gallery

Shortener home page with URL shortening form
Shortener statistics dashboard with click analytics
1/2Shortener home page with URL shortening form

bruno@cabado:~$ mail hi@brunocabado.com# I share work, research and product experiments in AI systems

$ send-message$ wget cv.pdf$ open linkedin$ open github

© 2026 Bruno Cabado · designed & developed in Galicia with Astro

↑↓ navigate · Enter open · Esc close

key bindings

0–8select window
n / pnext / previous window
ctalk to the agent pane
% / " or -split side by side / stacked (up to 3 panes, each shows a window)
Spacenext layout (side by side → stacked → main + stack → main + row)
qshow pane numbers, then press one to jump there
{ / }swap the focused pane with the main one
Shift+←↑↓→resize (main pane smaller / larger)
o · Ctrl+b ←↑↓→focus next pane · pane in that direction
zzoom the focused pane (again to restore)
xclose the focused pane (closing the main one promotes the split)
ttoggle theme (dark ⇄ latte) · :theme next cycles gruvbox, nord, tokyo, dracula
/ · Ctrl+ksearch the whole site
:command prompt
:set keys offdisable single-key shortcuts (the prefix still works)
Ctrl+bprefix — every key above also works after it; % " x and arrows need it

commands: search · select-window <name|n> · open <query> · ask <question> · split-window [-h|-v] [name] · kill-pane · zoom · swap-pane · layout · theme [mocha|latte|gruvbox|nord|tokyo|dracula] · ls · exit · help
agent: type /clear to reset the conversation