Watch
1
0
Fork
You've already forked nicelink
0
mirror of https://knot1.tangled.sh/did:plc:ekyghaf6k5iecrabwh4s7jyg synced 2026-11-03 20:29:35 +00:00
A little baby link shortener that *can't* track you. (Mirror) https://tangled.org/poss.dog/nicelink
  • Go 88%
  • Shell 7.4%
  • HTML 3.6%
  • Dockerfile 1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
reilly d7a3e9977c perf(deploy): suspend the idle machine instead of stopping it
auto_stop_machines = "suspend" resumes in a few hundred ms instead of a
~1.5s cold start, at the same compute cost (suspended machines bill no
CPU/RAM; the volume bills either way). Suspend is not durable — deploys,
host migration, or capacity pressure can discard the snapshot and fall
back to a cold start — which is harmless here: no in-app TLS, JWTs, cron,
or caches to be skewed by the post-resume clock wobble, and bbolt is
crash-safe with only ever one machine holding the file lock.

deploy.sh now wakes the machine with a real HTTPS request before its
post-deploy checks: with min_machines_count = 0 a deploy can leave the
machine stopped, and the old status-only check raced autostop and failed
with 'no started app machine after deploy'.
2026-10-29 17:22:06 -05:00
cmd/nicelink feat(deploy): add Fly.io deployment with persistent volume for bbolt state 2026-10-29 15:20:18 -05:00
.dockerignore feat(deploy): add Fly.io deployment with persistent volume for bbolt state 2026-10-29 15:20:18 -05:00
.gitignore feat(deploy): add Fly.io deployment with persistent volume for bbolt state 2026-10-29 15:20:18 -05:00
AGENTS.md perf(deploy): suspend the idle machine instead of stopping it 2026-10-29 17:22:06 -05:00
clone_database.sh feat(deploy): clone_database.sh resolves machine ID via fly status --json + jq 2026-10-29 16:12:45 -05:00
deploy.sh perf(deploy): suspend the idle machine instead of stopping it 2026-10-29 17:22:06 -05:00
Dockerfile feat(deploy): add Fly.io deployment with persistent volume for bbolt state 2026-10-29 15:20:18 -05:00
fly.toml perf(deploy): suspend the idle machine instead of stopping it 2026-10-29 17:22:06 -05:00
go.mod Rename project to 'nicelink' 2026-09-23 20:54:51 -05:00
go.sum feat: urls are now encrypted server-side, requests are now rate-limited 2026-08-13 21:33:25 -05:00
LICENSE.md docs: convert LICENSE to Markdown as LICENSE.md 2026-10-21 01:50:18 -05:00
README.md feat(deploy): add deploy.sh with database-safety guards 2026-10-29 16:27:59 -05:00

nicelink

🤖 This code was written by a human-led AI agent.

A little baby link shortener. Zero trackers, server-side URL encryption.

Usage

Use the web frontend at t.l.lc, or make a POST request:

# Get a random alias
curl -X POST 'https://t.l.lc/?url=https://example.com/'
# → {"short_link":"/qlbUh"}

# Optionally specify a custom alias
curl -X POST 'https://t.l.lc/?url=https://example.com/&alias=example'
# → {"short_link":"/example"}

Building

go build -o nicelink ./cmd/nicelink

# Cross-compile
GOOS=linux GOARCH=amd64 go build -o nicelink ./cmd/nicelink

Deploying (Fly.io)

The app runs on Fly.io with its state on a persistent volume, so links survive restarts and redeploys:

  • Dockerfile builds a minimal image (PORT=8080, DATA_DIR=/data)
  • fly.toml mounts the volume nicelink_data at /data and runs exactly one machine (bbolt holds an exclusive lock on the DB file, so it cannot scale horizontally)
fly volumes create nicelink_data --size 1 --region iad -a possdog-nicelink --yes
fly ips allocate-v4 -a possdog-nicelink --yes
./deploy.sh                  # vet+test, deploy, then verify: https://possdog-nicelink.fly.dev/

After changing source code, run ./deploy.sh. It refuses to deploy unless fly.toml still mounts the nicelink_data volume at /data, and after deploying it confirms the volume is attached and still contains link_shortener.bolt + secret.key — so the production database is left intact.

Both link_shortener.bolt and secret.key live in /data; losing either the volume or the secret loses every link. To import an existing database, run ./clone_database.sh from the directory containing the old link_shortener.bolt and secret.key — it resolves the machine ID via fly status --json + jq, stages each file under a .incoming name (flyctl sftp put takes one file at a time and never overwrites), swaps them in over SSH, and restarts the machine.