MSK Shortener
A self-hosted URL shortener with click statistics, QR codes, and password protection: the first web project in the MSK ecosystem.
- Live instance: s.msk-scripts.de
- Source code: github.com/MSK-Scripts/msk-shortener
- License: AGPL-3.0-or-later
What is MSK Shortener?
MSK Shortener turns long URLs into short, shareable links, like Bitly or TinyURL, but without the tracking. It is built for personal use, team workflows, and small communities that want their own short-link domain.
The hosted instance at s.msk-scripts.de is free to use. If you want your own short domain (e.g. s.example.com), you can self-host it on your own server, see Installation.
Features
- Auto-generated short codes (default 7 characters) using nanoid
- Custom short codes: pick your own (3–20 chars,
[a-zA-Z0-9_-]) - Click statistics: anonymous timeline, browser/OS/device aggregations, top referrers
- QR codes: download as PNG or SVG with MSK branding
- Password protection with bcrypt (cost 12) and brute-force throttling
- Expiration dates: let links auto-expire at any future ISO timestamp
- Delete tokens: remove links without an account
- REST API for every UI feature
- Bilingual UI (German / English) with cookie-based language switching
- Global statistics page with anonymous aggregate data
- SSRF protection: private IP ranges (RFC 1918, loopback, link-local) are rejected as targets
- No tracking cookies, no GeoIP, no third-party analytics
Tech stack
| Layer | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript (strict) |
| Database | MariaDB (via mysql2) |
| Styling | Tailwind CSS + MSK design tokens |
| Validation | Zod 4 |
| i18n | next-intl v4 |
| Passwords | bcryptjs (cost 12) |
| Short codes | nanoid |
| QR codes | qrcode |
| Charts | Recharts |
| UA parsing | ua-parser-js |
| Web server | Apache2 (reverse proxy) |
| Process manager | systemd |
How click tracking works
Unlike MSK Paste (which only counts views), MSK Shortener stores anonymized per-click rows for richer statistics, but no piece of data identifies the visitor:
| Stored | Not stored |
|---|---|
| Timestamp | IP address (plain text) |
Browser family (e.g. Firefox) | Full user agent |
OS family (e.g. Linux) | GeoIP / country |
Device type (desktop / mobile / tablet) | Cookies |
| Referrer host | Query strings |
| HMAC-SHA-256(IP) | Account / session info |
IPs are hashed with a server-side secret (IP_HASH_SECRET) using HMAC-SHA-256, they cannot be reversed without the secret.
Where to go next
- Installation: self-host MSK Shortener on your own Debian/Ubuntu server
- Usage: walkthrough of creating, managing, and tracking links
- REST API: programmatic access for scripts and CLI tools
- Privacy & Security: how your data is (and isn't) stored
- FAQ: common questions and troubleshooting