Deployment
Ship spyglass to a server: Docker and docker-compose, the cross-compiled static binary, the install script, dashboard authentication, retention, and backup.
spyglass is one static binary plus one data directory. There is no database server to run, no cache to provision, nothing to cluster. Deploy it on the smallest machine you have; it targets under 50MB RAM under load.
Docker (recommended)
The repo ships a multi-stage Dockerfile
that builds the dashboard, compiles a static binary, and packs it into a
distroless nonroot image. With docker-compose.yml:
SPYGLASS_PASS='a-strong-password' docker compose up -dThat brings up the collector on port 7474 with:
- a named volume
spyglass-datamounted at/data(your SQLite + replays), and ./spyglass.config.jsonmounted read-only at/etc/spyglass/spyglass.config.json.
Point dataDir at /data in your config so state lands on the volume:
{ "dataDir": "/data", "listen": ":7474", "...": "..." }To build and run the image directly:
docker build -t spyglass .
docker run -d -p 7474:7474 \
-e SPYGLASS_PASS='a-strong-password' \
-v spyglass-data:/data \
-v "$PWD/spyglass.config.json:/etc/spyglass/spyglass.config.json:ro" \
spyglassThe binary
spyglassd is a single cross-compiled, statically linked executable.
modernc.org/sqlite is pure Go, so there's no C toolchain and no shared
libraries to ship.
Build from source
Needs Go 1.25+ and Node 22+ (to build the embedded dashboard once):
make build # dashboard + collector for this host
make release # static binaries for darwin/linux ร amd64/arm64 โ collector/dist/
make run # build, then run against spyglass.config.json
make test # Go + SDK test suitesInstall script
For a host with a published release:
curl -fsSL https://raw.githubusercontent.com/foundanand/spyglass/master/scripts/install.sh | shIt detects your OS/arch, fetches the matching spyglassd, and installs it to
/usr/local/bin (override with PREFIX=$HOME/.local/bin). Then:
spyglassd --config spyglass.config.json
spyglassd --versionRunning it as a service
spyglassd is a plain foreground process that handles SIGINT/SIGTERM with a
graceful shutdown. Wrap it in whatever you already use (systemd, a process
manager, Docker restart: unless-stopped). There is nothing spyglass-specific to
configure.
Authentication
Ingest and reads are gated separately:
- Ingest (
POST /v1/events,POST /v1/replay) authenticates with the per-app key from your config. This is what the SDK presents. It is never behind the dashboard password; the SDK must always be able to post. - Dashboard + query endpoints are gated by
auth.dashboard_passwordvia HTTP Basic auth (any username, that password, compared in constant time). Set it for any deployment others can reach.
When the password is empty the read side is open, acceptable on localhost only.
Put the collector behind your own TLS-terminating reverse proxy (or the Docker host's) for HTTPS; spyglass speaks plain HTTP and expects to live on a trusted network or behind a proxy.
Retention & backup
- Replays auto-expire after
retention.replays_days(default 21). Events are kept forever unless you setretention.events_days. The sweep runs on boot and every 24 hours. See Configuration. - Backup is
cp. The entire state isdataDir; copy the directory (or snapshot the volume). The database is a single WAL-mode SQLite file; copy it while running and you get a consistent snapshot, or stop the process for a guaranteed-clean copy.
Sizing
Reference math, not limits:
- 60 users ร ~600 events/day โ 36k rows/day โ 13M rows/year, trivial for SQLite, which holds hundreds of millions of rows comfortably. 10ร the users doesn't change anything.
- Replay โ 1โ5MB compressed per active hour. Worst case ~1โ2GB/day; with 21-day retention that's tens of GB at most. Scale retention with disk, not architecture.
- Collector RAM target is under 50MB under load. If it climbs past that, something is wrong: that's a bug to fix, not a reason to scale out.
Dashboard
A tour of every dashboard view: live feed, user timeline, errors, replay, insights, and the incident view that turns any error or bug report into a cued replay slice.
Privacy
What spyglass records, what it never records, and how to tune masking and body capture. Internal does not mean careless: sensible defaults, everything on your own machine.