# apps/obs — rebno-obs (OpenObserve)

[doc->REQ-DEP-06]

Self-hosted observability backend for rebno-staging + rebno-prod.
Single-binary OpenObserve, Tigris-backed columnar storage,
flycast-only OTLP ingestion (private 6PN). UI access via Fly proxy
IP allowlist + admin password (CONTEXT D-15).

## One-time provisioning (per Fly org)

Pitfall 7: the Tigris bucket MUST exist before first `fly deploy`.

```sh
# 1) Create the Fly app shell.
fly apps create rebno-obs --org <your-org>

# 2) Provision the persistent volume (1 GB plenty for v1).
fly volumes create obs_data -a rebno-obs --region lax --size 1

# 3) Provision the per-app Tigris bucket. This injects AWS_* + BUCKET_NAME
#    secrets that apps/obs/docker-entrypoint.sh remaps to ZO_S3_*.
fly storage create -a rebno-obs

# 4) Set the admin password. CONTEXT D-15: rotate via `fly secrets set` on demand.
fly secrets set ZO_ROOT_USER_PASSWORD="$(openssl rand -base64 24)" -a rebno-obs

# 5) (Optional) Allowlist operator IPs for UI access (D-15).
#    Skip if you only need OTLP ingest from game-server apps.
fly ips allocate -a rebno-obs --network <wireguard-network>

# 6) Deploy.
fly deploy -a rebno-obs --config apps/obs/fly.toml --dockerfile apps/obs/Dockerfile

# 7) Verify (from a wireguard-connected operator machine):
curl -i https://rebno-obs.flycast:5080/healthz
```

## OTLP endpoint consumed by game-server

`apps/server/fly.{staging,prod}.toml` sets:
```
OTEL_EXPORTER_OTLP_ENDPOINT = "http://rebno-obs.flycast:5080/api/default"
```

The OTel SDK (apps/server/src/otel-init.ts) auto-appends
`/v1/traces`, `/v1/metrics`, `/v1/logs` (Pitfall 5).

## Secret rotation

See `docs/runbooks/RESTORE.md §Secret Rotation` for ZO_ROOT_USER_PASSWORD,
Tigris key, and BETTER_AUTH_SECRET rotation procedures.
