Nah.pet
Rewriting paths with bad energy - An alternative to TinyURL, YOURLS, Shlink
> **Nah.pet** – _"Rewriting paths with bad energy"_ ✨ > Open-source URL shortener with custom domains and analytics. The project is written primarily in Svelte, distributed under the MIT License license, first published in 2025. Key topics include: link-shortener, shlink, short-url, shorten-urls, shortener.
🐾 Nah.pet – Open Source URL Shortener
Nah.pet – "Rewriting paths with bad energy" ✨
Open-source URL shortener with custom domains and analytics.
✨ Features
- ✂️ URL Shortening with custom slugs
- 🔐 Password protection for sensitive links
- ⏰ Automatic link expiration
- 📊 Detailed analytics (clicks, geolocation, browsers)
- 🌐 Custom domains with complete isolation
- 👥 Admin system with manual approval
- 🔑 REST API with API key authentication
- 🌍 Multilingual interface
🌍 Translation Status
Managed with Paraglide JS and Weblate for type-safety.
🌐 Custom Domains
Why cat.yourDomain.tld?
The cat. prefix bypasses CORS restrictions from Cloudflare and other CDNs by using a dedicated subdomain.
DNS Setup
-
Domain verification:
- DNS: TXT record with token
- File:
/.well-known/nah-pet-verification.txt
-
CNAME configuration:
dnsType: CNAME Name: cat.example.com Value: cat.nah.pet TTL: 300 -
Redirection:
https://cat.example.com/abc123 → CNAME → cat.nah.pet → nah.pet
Each custom domain is fully isolated—no access to system routes (
/admin,/login, etc.).
🚀 Installation
🐳 Docker Compose
bashgit clone https://github.com/anhostfr/nah.pet cd link-shortener cp .env.example .env # Edit variables # DATABASE_URL=postgresql://user:password@postgres:5432/nahpet # PUBLIC_MAIN_DOMAIN=your-domain.com # ADMIN_EMAIL=admin@example.com # OAUTH_CLIENT_ID=your_oauth_id (optional) # OAUTH_CLIENT_SECRET=your_oauth_secret (optional) # PUBLIC_DOC=false (set to 'true' for public API docs) # PUBLIC_ALLOW_REGISTRATION=true (set to 'false' to disable registration) docker-compose up -d
Access:
- Web interface:
http://localhost:3000 - API:
http://localhost:3000/doc
🛠️ Manual Installation
bashbun install createdb nahpet cp .env.example .env # Edit variables bunx prisma migrate deploy bun run dev
🔌 REST API
Built with sveltekit-api from JacobLinCool, OpenAPI 3.0 specification.
Main Endpoints
GET /api/v1/links– List linksPOST /api/v1/links– Create a linkGET/PUT/DELETE /api/v1/links/{id}– Manage a linkGET /api/v1/stats– Global statisticsGET /api/v1/stats/{slug}– Link statisticsPOST /api/v1/links/bulk– Bulk operationsGET /api/v1/stats/export– Export data
SDK Generation
bashnpm install @openapitools/openapi-generator-cli -g curl -o openapi.json https://your-domain.com/api/v1/openapi.json openapi-generator-cli generate \ -i openapi.json \ -g typescript-axios \ -o ./sdk-typescript
Authentication
bashcurl -H "Authorization: Bearer YOUR_API_KEY" \ "https://your-domain.com/api/v1/links"
🏗️ Tech Stack
- Frontend/Backend: SvelteKit 5 + TypeScript
- Runtime: Bun 1.x
- Database: PostgreSQL + Prisma ORM
- Authentication: Lucia Auth + OAuth2
- Styling: TailwindCSS 4 + Shadcn/ui
- i18n: Paraglide JS
- API: Sveltekit-api (OpenAPI)
- Deployment: Docker + Docker Compose
Project Structure
src/
├── routes/ # Pages and API
├── lib/
│ ├── components/ # Svelte components
│ ├── server/ # Server logic
│ └── paraglide/ # Translations
└── api/v1/ # API definitions
🛠️ Development
bashbun run dev # Development bun run build # Production bun run check # TypeScript check bun run format # Prettier formatting bunx prisma studio bunx prisma generate bunx prisma migrate dev
Environment Variables
envDATABASE_URL=postgresql://postgres:password@localhost:5432/nahpet PUBLIC_MAIN_DOMAIN=localhost:5173 ADMIN_EMAIL=admin@example.com OAUTH_CLIENT_ID=your_oauth_client_id (optional) OAUTH_CLIENT_SECRET=your_oauth_client_secret (optional) # Access control (optional) PUBLIC_DOC=false # Set to 'true' to make API docs public PUBLIC_ALLOW_REGISTRATION=true # Set to 'false' to disable registration
Screenshots
<table> <tr> <td align="center"> <img src="static/screenshots-demo/dashboard.png" alt="Dashboard Screenshot" width="300"/><br/> <sub>Dashboard</sub> </td> <td align="center"> <img src="static/screenshots-demo/analytics.png" alt="Analytics Screenshot" width="300"/><br/> <sub>Analytics</sub> </td> <td align="center"> <img src="static/screenshots-demo/analytics-slug.png" alt="Analytics Slug Screenshot" width="300"/><br/> <sub>Analytics (Slug)</sub> </td> </tr> </table>🤝 Contributing
Translations
bashcp messages/en.json messages/es.json # Add Spanish # Add "es" in project.inlang/settings.json
Code
- Fork the repository
- Create a branch
feature/my-feature - Develop with
bun run dev - Check with
bun run check+bun run format - Open a Pull Request
📄 License
MIT – see LICENSE
🙏 Acknowledgements
<div align="center"> <em>"It's a no from us, dawg." – but it's a yes for open source!</em> </div>
Contributors
Showing top 4 contributors by commit count.
