This is yours to edit, not just configure.
- Custom or random short codes, tags, and expiring links
- Password-protected links (hashed)
- Per-link click analytics - 14-day chart, top referrers, countries, device types
- QR codes generated straight from the dashboard
- Multiple domains, with the admin dashboard restricted to your main one (see Multiple domains)
- Zero dependencies
- Single JSON file storage
| File | Purpose |
|---|---|
server.js |
The application. |
store.js |
JSON-file storage layer. |
package.json |
Marks this as an ES module project; no dependencies. |
warplet.service |
systemd unit template. Ships with a placeholder token, never a real one. |
install.sh |
One-command installer (below). |
.gitignore |
Keeps your live data/ folder out of git. |
data/links.json — your link database
On a Raspberry Pi or any systemd-based Linux box with SSH access:
curl -fsSL https://raw.githubusercontent.com/pipchell/WarpletPublic/main/install.sh | bashThis installs Node.js if missing, clones the repo, generates a random access token, writes the systemd service, and starts Warplet running permanently in the background. At the end it prints your dashboard URL and access token. The access token is also written to .access_token.txt in the install directory as a fallback.
Re-running the command later is safe. It pulls the latest code but won't touch an existing service or token.
Customize with environment variables before piping into bash:
| Variable | Default | Purpose |
|---|---|---|
WARPLET_REPO |
https://github.com/pipchell/WarpletPublic.git |
Repo to clone |
WARPLET_DIR |
$HOME/warplet |
Install location |
WARPLET_PORT |
8787 |
Listening port |
WARPLET_PORT=9000 curl -fsSL https://raw.githubusercontent.com/pipchell/WarpletPublic/main/install.sh | bashIf you'd rather see every step: install Node 18+, git clone this repo, generate a token with openssl rand -hex 32, test it with ACCESS_TOKEN=... node server.js, then install it as a service:
sudo cp warplet.service /etc/systemd/system/warplet.service
sudo nano /etc/systemd/system/warplet.service # set WorkingDirectory, ACCESS_TOKEN, DATA_FILE
sudo systemctl daemon-reload
sudo systemctl enable --now warplet.service
sudo systemctl status warplet # confirm it's runningAll settings are environment variables, set on the command line or in warplet.service.
Useful service commands: sudo systemctl status warplet, sudo systemctl restart warplet, journalctl -u warplet -f (live logs).
ACCESS_TOKEN is your dashboard password. The quick installer generates one for you automatically and prints it at the end, so you only need to do this yourself if you're installing by hand or rotating an existing token.
openssl rand -hex 32That prints a 64-character string — copy the whole thing. Where it goes depends on how you're running Warplet:
- As a systemd service: put it in
warplet.serviceasEnvironment=ACCESS_TOKEN=<the-string>, then apply it withsudo systemctl daemon-reload && sudo systemctl restart warplet. - Running directly (testing, not as a service):
ACCESS_TOKEN=<the-string> node server.js.
To rotate a token later, generate a new one the same way, update it wherever it's currently set, restart the service, and the old token stops working immediately.
Edit the BRAND object near the top of server.js:
const BRAND = {
name: 'Warplet',
accent: '#902efe',
logo: '/logo.png',
wordmark: '/wordmark.png'
};If you own more than one domain, point DNS for each at this server, then set:
Environment=DOMAINS=go.example.com,short.example.orgWith 2+ domains configured, a domain picker appears when creating links, and the dashboard shows/filters by domain. The dashboard and its management API (/api/links*) only respond on your first listed domain. Every other domain (and any bare IP) gets a plain "not found. "Short-link redirects and the password-check page are unaffected and work identically on every configured domain. With zero or one domain set, nothing about this changes.
Base URL is your server (e.g. http://<pi-ip>:8787). Pass the token as a token field, ?token= query param, or X-Token header.
| Endpoint | Auth | Purpose |
|---|---|---|
GET / |
— | Dashboard page (main domain only, see above) |
GET /api/links |
token | List all links |
POST /api/links |
token | Create a link — body: {url, code?, tags?, domain?, expiresAt?, password?} |
PUT /api/links/:code |
token | Update a link |
DELETE /api/links/:code |
token | Delete a link |
GET /api/links/:code/stats |
token | Per-link analytics |
POST /api/verify/:code |
— | Check a visitor-entered password (public) |
GET /:code |
— | The redirect itself (public, works on every domain) |
password fields store a SHA-256 hash, never the plaintext. expiresAt is a millisecond Unix timestamp. Full request/response shapes are in the code — each handler in server.js is short and readable.
- Cloudflare Tunnel (recommended) - See Cloudflare's setup guide.
- Port forward + Dynamic DNS + reverse proxy — more manual; Caddy gives free automatic HTTPS with a two-line config.
cp /home/pi/warplet/data/links.json ~/warplet-backup-$(date +%F).jsonAutomate with crontab -e: 0 3 * * * cp /home/pi/warplet/data/links.json /home/pi/backups/warplet-$(date +\%F).json. Restore by stopping the service, copying a backup over data/links.json, and starting it again.
cd /home/pi/warplet && git pull && sudo systemctl restart warpletRe-running install.sh does the same thing without touching your token. data/links.json is untouched by updates.
| Symptom | Fix |
|---|---|
EADDRINUSE |
Something's already on that port. sudo lsof -i :8787, or change PORT. |
| "Wrong token" | Typo, or you're pointed at a different instance. |
| Can't reach it from another device | Check hostname -I, sudo systemctl status warplet, and your firewall. |
| QR codes don't load | They're fetched from api.qrserver.com by your browser. |
| Country stats always "XX" | Expected unless you're behind a Cloudflare Tunnel, which adds the header that populates this. |
A Pi 4 (1GB+) is comfortable; even a Pi Zero 2 W can run it. Use Raspberry Pi OS Lite to keep RAM free. The data file rewrites on every click. A non-issue at personal scale, but consider a USB SSD over the SD card for heavier use or long-term peace of mind.
sudo systemctl stop warplet
sudo systemctl disable warplet
sudo rm /etc/systemd/system/warplet.service
sudo systemctl daemon-reload
rm -rf /home/pi/warplet # deletes the app AND your link database — back up data/links.json first