clone

a self-hosted sync node for lofi apps: jazz sync over iroh, ticket-gated, with no static ip or cloud needed

feat/write-verdict-foundations
lofi-node / docs / site / configuration.md
configuration.md 3.5K rendered
1# Configuration23<!-- Source: FelineStateMachine/lofi-node src/config.ts (NodeConfig, migration) and4 src/appticket.ts (tickets.json). -->56A node's durable state is two JSON files in its data directory, plus a small set of environment7variables. Both files are owned by the node; edit `config.json` only with the daemon stopped.89## config.json (v2)1011```jsonc12{13 "v": 2,14 "appId": "cfe52e44-…", // Jazz app id, generated at init (UUID — required by the engine)15 "backendSecret": "lofi_backend_…", // Jazz credential; server-side only16 "adminSecret": "lofi_admin_…", // authorizes schema/permission administration17 "listenPort": 4802, // optional fixed public port; auto-allocated when absent18 "access": "ticket", // "ticket" (CLI-init default) | "open" (dev; library default)19 "storage": { "type": "sqlite", "path": "/mnt/nas/lofi" }, // or { "type": "memory" }20 "publicUrl": "http://192.168.1.10:4802", // base embedded in issued tickets21 "upstream": "none", // "none" | { "url": "wss://…" } | { "peer": "endpoint…" }22 "relay": "n0", // "n0" (default when absent) | { "urls": ["https://…"] } | "disabled"23 "allowLocalFirstAuth": true24}25```2627- **`access`** — `ticket` puts the access gate in front of everything; `open` proxies28 unauthenticated (the gate still owns the public port and the Jazz server still binds29 loopback-only).30- **`storage`** — the honest engine surface: a SQLite directory (optional path, probed writable at31 boot) or memory. See [storage choices](storage-choices.md).32- **`upstream`** — `"none"` for a root node; `{ "peer": … }` for an iroh-paired leaf33 ([pairing](pair-two-homes.md)); `{ "url": … }` for a plain HTTP(S) upstream Jazz server.34- **`relay`** — which relay servers the node's iroh endpoint uses for hole-punching assistance and35 as a fallback path when a direct connection cannot be established. `"n0"` (the default when36 absent) uses the public n0-computer relays: rate-limited, no SLA, meant for development and37 testing. `{ "urls": […] }` points at relays you run ([bring your own relay](beyond-the-lan.md));38 `"disabled"` forgoes relays entirely, including relay-assisted address discovery. The elected39 relay travels inside this node's pairing tickets, so peers need no matching configuration.40- **Secrets** stay in this file and never transit issued tickets; a provision-scoped ticket causes41 the gate to inject `adminSecret` server-side rather than revealing it.4243**v1 migration**: v1 files load transparently with legacy defaults applied (`access: "open"`, SQLite44storage) and are rewritten as v2 on the next save.4546## tickets.json4748```jsonc49{50 "v": 1,51 "tickets": [52 {53 "id": "a1b2c3d4e5f6", // first 12 hex chars of the secret's SHA-25654 "scope": "provision", // absent means "sync"55 "label": "laptop-admin",56 "secretHash": "…", // full SHA-256 hex — the secret itself is never stored57 "createdAt": "2026-07-18T…",58 "revokedAt": "2026-07-19T…" // present only once revoked59 }60 ]61}62```6364The CLI writes this file; a running daemon only reads it, picking up changes by modification time —65which is why `ticket issue` and `ticket revoke` need no IPC and no restart.6667## Environment variables6869| Name | Effect |70| ----------------- | --------------------------------------------------------------------- |71| `LOFI_NODE_DEBUG` | `1` enables `[gate]`/`[tunnel]` debug logging to stderr. |72| `LOFI_NODE_IROH` | Explicit path to the native transport library, overriding resolution. |