A production-ready URL shortener and link analytics backend built entirely in Lua on the Telamon HTTP framework.
| Feature | Detail |
|---|---|
| Shorten URLs | Auto-generated 6-char codes or custom vanity codes |
| Click tracking | Every redirect records a click + timestamp |
| Tags | Attach arbitrary tags to links; filter the list by tag |
| Auth | API-key guard on all write/admin endpoints |
| HTML dashboard | / renders live stats in a polished dark-theme page |
| Pure file-based storage | One JSON file; no database required |
| Structured JSON API | All endpoints return consistent JSON envelopes |
/etc/telamon/
├── config.toml # Telamon config
├── telamon.service # systemd unit
├── data/
│ └── db.json # link store (auto-created)
└── scripts/
├── index.lua # GET / — dashboard
├── health.lua # GET /health — health check
├── r/index.lua # GET /r?c=CODE — redirect + click tracking
├── lib/
│ ├── store.lua # JSON persistence helpers
│ ├── auth.lua # API key validation
│ └── utils.lua # code gen, URL building, time_ago
└── api/
├── shorten/index.lua # POST /api/shorten
├── links/index.lua # GET /api/links
├── link/index.lua # GET /api/link?c=CODE
├── stats/index.lua # GET /api/stats
└── delete/index.lua # DELETE /api/delete?c=CODE
| Method | Path | Description |
|---|---|---|
GET |
/ |
HTML dashboard with live stats |
GET |
/health |
JSON health check |
GET |
/api/stats |
Global stats + top-10 + tag leaderboard |
GET |
/r?c=CODE |
Redirect to original URL (records click) |
| Method | Path | Description |
|---|---|---|
POST |
/api/shorten |
Create a short link |
GET |
/api/links |
List all links (?tag=X, ?sort=clicks|created|code) |
GET |
/api/link?c=CODE |
Detail for one link |
DELETE |
/api/delete?c=CODE |
Permanently delete a link |
- Telamon binary installed at
/usr/local/bin/telamon lua.unsandboxed = trueinconfig.toml(required forioandos)systemd-based Linux server (or run manually for dev)
chmod +x install.sh
sudo ./install.sh# 1. Build Telamon (from the Telamon source directory)
go build -o /usr/local/bin/telamon .
# 2. Create directories and copy files
sudo mkdir -p /etc/telamon/{scripts,static,data}
sudo cp config.toml /etc/telamon/
sudo cp -r scripts/* /etc/telamon/scripts/
# 3. Install systemd unit
sudo cp telamon.service /etc/systemd/system/
sudo systemctl daemon-reload
# 4. Set your API key
sudo sed -i 's/changeme-admin-key/YOUR_SECRET_KEY/' \
/etc/systemd/system/telamon.service
sudo systemctl daemon-reload
# 5. Enable and start
sudo systemctl enable --now telamon
sudo systemctl status telamonSet via the TELAMON_API_KEY environment variable:
# /etc/systemd/system/telamon.service
[Service]
Environment=TELAMON_API_KEY=my-super-secret-keyAfter changing:
sudo systemctl daemon-reload && sudo systemctl restart telamonFor local dev without systemd:
export TELAMON_API_KEY=my-super-secret-key
telamon --config config.tomlexport HOST="http://localhost"
export KEY="my-super-secret-key"
# ── Create links ───────────────────────────────────────────────────────────
# Auto-generated code
curl -s -X POST $HOST/api/shorten \
-H "Content-Type: application/json" \
-H "X-API-Key: $KEY" \
-d '{"url":"https://example.com","title":"Example Site","tags":["demo"]}'
# Custom vanity code
curl -s -X POST $HOST/api/shorten \
-H "Content-Type: application/json" \
-H "X-API-Key: $KEY" \
-d '{"url":"https://anthropic.com","code":"claude","title":"Anthropic"}'
# ── Use links ──────────────────────────────────────────────────────────────
# Follow redirect (records a click)
curl -L "$HOST/r?c=claude"
# ── Analytics ─────────────────────────────────────────────────────────────
# Public stats
curl -s $HOST/api/stats | python3 -m json.tool
# List all (sorted by clicks, default)
curl -s -H "X-API-Key: $KEY" $HOST/api/links
# Filter by tag
curl -s -H "X-API-Key: $KEY" "$HOST/api/links?tag=demo"
# Sort by creation date
curl -s -H "X-API-Key: $KEY" "$HOST/api/links?sort=created"
# Single link detail
curl -s -H "X-API-Key: $KEY" "$HOST/api/link?c=claude"
# ── Delete ─────────────────────────────────────────────────────────────────
curl -s -X DELETE -H "X-API-Key: $KEY" "$HOST/api/delete?c=claude"{
"ok": true,
"code": "aBc4dE",
"short_url": "http://your-host/r?c=aBc4dE",
"url": "https://example.com",
"title": "Example Site",
"tags": ["demo"],
"clicks": 0,
"created_at": 1719532800
}{
"ok": true,
"total_links": 42,
"total_clicks": 1337,
"top_links": [
{ "code": "claude", "title": "Anthropic", "clicks": 420, "created_at": 1719532800 }
],
"top_tags": [
{ "tag": "demo", "count": 5 }
],
"server": { "version": "1.0.0", "timestamp": 1719619200 }
}{
"error": "Bad Request",
"message": "URL must start with http:// or https://"
}Links are stored in /etc/telamon/data/db.json. The directory is auto-created on first write.
Schema:
{
"links": {
"aBc4dE": {
"code": "aBc4dE",
"url": "https://example.com",
"title": "Example Site",
"tags": ["demo"],
"clicks": 7,
"created_at": 1719532800,
"last_clicked": 1719619200
}
},
"meta": {
"total_clicks": 7,
"total_links": 1,
"created_at": 1719532800
}
}Backup: Simply copy
/etc/telamon/data/db.json.
Concurrency note: Telamon creates a new Lua VM per request; there is no built-in locking. For high write concurrency, add a mutex in Go or run behind a queue.
All scripts follow the Telamon notation rules:
-- Colon notation for request/response (methods with implicit self)
response:json({ ok = true })
request:getParam("c")
-- Dot notation for stateless utilities
json.encode(data)
telamon.log("message")Shared modules are loaded by adjusting package.path at the top of each script:
package.path = "/etc/telamon/scripts/?.lua;" .. package.path
local store = require("lib.store")MIT