A self-hosted, single-file web admin UI for libSQL / Turso sqld databases running as Docker containers — think a lightweight, modern "phpMyAdmin" for libSQL.
Built with Bun. No build step, no framework — one server.ts.
See AI.md for an LLM-friendly deployment contract, safety rules, discovery questions, systemd/reverse-proxy examples, verification checks, upgrade instructions, and a copy-ready prompt.
The AI guide deliberately uses placeholders and keeps secrets outside the repository. Give it to your coding assistant together with the target server's non-secret infrastructure details.
- Dashboard — server health (load / memory / disk), per-database status, uptime, CPU bars, and a live alerts banner.
- Per-database pages (
#/db/<name>) — connection string, auth token (copy / rotate), live CPU & memory, and tabs for:- Tables — browse tables with sizes, view rows, truncate
- SQL manager — run arbitrary SQL, see results
- Slow queries — redacted fingerprints, rows processed, severity, impact scoring, and recommendations
- Database event stream — scoped container/service logs, audit activity, runtime metrics, slow-query evidence, filters, live tail, pagination, and CSV export
- Storage (main / WAL / snapshots, VACUUM), Backups (create / download), CPU Log, Memory Report, and Diagnostics (health, restarts, WAL, integrity, response time)
- Monitoring — 24h charts (memory, CPU, response time, disk IO).
- Logs center — database-scoped host/container resources, CPU flight recorder, slow-query forensics, redacted cross-service logs, and user/action/database audit trails.
- Log controls — database, source, severity, operation, time-window, and free-text filters; live tail; pagination; configurable retention/rotation; and redacted CSV/developer-report exports.
- System pressure evidence — system memory, swap, OOM events, zombie processes, top containers, host processes, and per-database memory evidence.
- Alerts — live in-UI alerts plus optional email (SMTP) alerts on memory / disk / unhealthy thresholds.
- Users — admin + scoped read users (argon2 password hashes, JWT sessions).
- Client-side hash routing for every view.
- A Linux host with Docker running your libSQL (
ghcr.io/tursodatabase/libsql-server) containers. - Bun ≥ 1.0.
- Each database is a folder under
DATABASES_DIRnamed<name>-db/containing:data/— the sqld data directory (bind-mounted into the container)auth/public.pem— the JWT public key.env— withLOCAL_PORT=,DATABASE_URL=,DATABASE_AUTH_TOKEN=
- The admin reads/writes its own state in
DATABASES_DIR/admin/(users.json,settings.json,metrics.json).
git clone <your-repo-url> libsql-admin && cd libsql-admin
bun install
cp .env.example .env && $EDITOR .env # set ADMIN_USER / ADMIN_PASS / DATABASES_DIR
bun run server.tsIt listens on 127.0.0.1:$PORT (default 3456). Put it behind nginx/Caddy/Traefik with TLS and you're done.
[Unit]
Description=libSQL Admin
After=docker.service
Wants=docker.service
[Service]
WorkingDirectory=/opt/libsql-admin
EnvironmentFile=/opt/libsql-admin/.env
ExecStart=/usr/local/bin/bun run server.ts
Restart=always
[Install]
WantedBy=multi-user.target| Env var | Default | Description |
|---|---|---|
ADMIN_USER |
– | Initial admin username (required) |
ADMIN_PASS |
– | Initial admin password; also the session-signing secret (required) |
PORT |
3456 |
Port to listen on (bound to localhost) |
DATABASES_DIR |
/srv/databases |
Directory holding your *-db/ database folders |
DATABASE_DOMAIN |
database.example.com |
Base hostname used for newly created database URLs and Traefik routes |
- The admin manages Docker and your databases — run it behind a reverse proxy with TLS, and restrict access.
- Sessions are signed JWTs; the secret is derived from
ADMIN_PASS. Use a strong password. - It needs access to the Docker socket /
dockerCLI to read stats and start/stop containers. - Log and audit exports are redacted on a best-effort basis. Do not log secrets or sensitive row contents in your applications, and review exports before sharing them.
- Runtime state, audit files, backups, metrics,
.envfiles, and database data are excluded from Git by.gitignore; keep them out of commits and container images.
MIT — see LICENSE.
The built-in create / rename / delete database flow can create a public subdomain per database. Set DATABASE_DOMAIN and adapt the generated Docker Compose networking/Traefik labels to match your reverse-proxy setup. The rest of the admin (dashboard, SQL, tables, monitoring, backups) works independently of public routing.