Persistent storage
Where Uptimer keeps data and config, and how to persist them.
Uptimer keeps state under one data directory and reads settings from one config file. Mount both from the host so they survive restarts.
Inside the image
/app/configs/default.yml # default (dev) config
/app/uptimer # the binary
/data/ # data_dir — database, keys, identities (mount this)
The data directory
general.data_dir (default /data, env UPTIMER__GENERAL__DATA_DIR) holds:
| File | What |
|---|---|
server.pem / server.uuid | Server identity — signs API keys, validates workers. |
worker.pem / worker.uuid | Worker identity. |
server_db.sqlite | Control-plane database (SQLite only). |
docker run -p 2517:2517 -v uptimer-data:/data ghcr.io/myuptime-info/uptimer:edge
Lose server.pem and existing API keys and UI sessions stop validating; lose a worker’s
identity and it must be re-registered. Back up the volume — or use PostgreSQL plus a secret
store for the keys.
Custom config
Extract the default to edit it, then mount it back:
docker create --name tmp ghcr.io/myuptime-info/uptimer:edge
docker cp tmp:/app/configs/default.yml ./uptimer.yml
docker rm tmp
docker run -p 2517:2517 \
-v "$PWD/uptimer.yml:/app/configs/config.yml" \
ghcr.io/myuptime-info/uptimer:edge --cfg /app/configs/config.yml server
--cfg is optional (defaults to configs/default.yml). Every key also has a UPTIMER__…
environment override — see Configuration.
Unlike dev, the server command needs a server identity on the /data volume first — if it
exits with a missing server.uuid, run server init once against the
same volume before starting it.
Database
Only the server has a database. The DSN scheme picks the backend — sqlite3:// or
postgres://.
SQLite — dev
Zero setup: a file under /data, created and migrated on boot.
server: { db: { dsn: sqlite3:///data/server_db.sqlite } }
PostgreSQL — production
Point the DSN at Postgres. One database is enough:
server: { db: { dsn: "postgres://uptimer:secret@db:5432/uptimer_server?sslmode=disable" } }
Create it before first start (a Postgres init script is the easy way).
Changed in 1.4.0 — workers no longer have a database. A worker keeps its rules in memory and receives them over gRPC, so
worker.db.dsnandUPTIMER__WORKER__DB__DSNare no longer read. Both are still accepted and ignored, so an existing configuration keeps working untouched — but you can now delete the setting, and drop the seconduptimer_workerdatabase once no 1.3.x worker is left running against it.A worker still needs its
/datavolume:worker.uuidandworker.pemare its identity, and losing them means re-registering it in the dashboard.
Migrations
- SQLite is auto-migrated on boot — convenient for dev, not guaranteed safe across upgrades.
- PostgreSQL uses versioned migrations (schema changes + data backfills). By default they
run at boot (
server.db.boot_migrate: true). For production, run them once with the dedicateduptimer migratejob and setboot_migrate: falseon the app containers — the schema is then brought to head atomically, once, instead of by each booting replica.
Background: Choosing a database.
Bootstrap identities
server init / worker init generate the keys and UUIDs (add --force to regenerate — note
that regenerating the server key invalidates existing sessions):
docker run -v uptimer-data:/data ghcr.io/myuptime-info/uptimer:edge server init