Configuration
This page is generated from the Open Location Hub source documentation and should not be edited in the website repository.
All runtime configuration is environment-driven.
Runtime lifecycle behavior:
- the hub process runs from a single signal-aware root context created from
SIGINTandSIGTERM - startup failures return structured process errors instead of panicking during early config or logger initialization
- graceful shutdown uses a bounded timeout so HTTP shutdown and internal event-publisher fan-out can complete deterministically after a stop signal
Core
HTTP_LISTEN_ADDR(default:8080)HTTP_REQUEST_BODY_LIMIT_BYTES(default4194304)LOG_LEVEL(defaultinfo)HUB_ID(optional UUID bootstrap or reset value for the persisted hub identity)HUB_LABEL(optional bootstrap or reset value for the persisted human-readable hub label)RESET_HUB_ID(true/false, defaultfalse; whentrue, overwrite stored hub metadata with explicitly supplied env values)POSTGRES_URL(defaultpostgres://postgres:postgres@localhost:5432/openrtls?sslmode=disable)MQTT_BROKER_URL(defaulttcp://localhost:1883)WEBSOCKET_WRITE_TIMEOUT(duration, default5s)WEBSOCKET_READ_TIMEOUT(duration, default1m)WEBSOCKET_PING_INTERVAL(duration, default30s)WEBSOCKET_OUTBOUND_BUFFER(default256)EVENT_BUS_SUBSCRIBER_BUFFER(default1024)NATIVE_LOCATION_BUFFER(default2048)DERIVED_LOCATION_BUFFER(default1024)
Hub metadata bootstrap behavior:
- the hub persists one durable metadata row in Postgres containing the stable
hub_idand operator-facing label - on first startup,
HUB_IDseeds that row when provided; otherwise the hub generates a UUIDv7 - on first startup,
HUB_LABELseeds that row when provided; otherwise the hub defaults to the machine hostname and falls back toopen-rtls-hubif hostname lookup is unavailable - on later startups, the stored row is the source of truth when
HUB_IDandHUB_LABELare omitted - if supplied env values disagree with the stored row, startup fails with a clear mismatch error unless
RESET_HUB_ID=true - when
RESET_HUB_ID=true, only explicitly supplied values overwrite the stored row; omitted fields are preserved
HTTP request decoding behavior:
- JSON request bodies are capped by
HTTP_REQUEST_BODY_LIMIT_BYTESbefore decode work proceeds - the REST/RPC handler layer accepts exactly one JSON document per request body and rejects trailing JSON tokens
- unknown JSON object fields remain allowed so forwards-compatible clients are not rejected solely for extension data
Stateful Processing
STATE_LOCATION_TTL(duration, default10m)STATE_PROXIMITY_TTL(duration, default5m)STATE_DEDUP_TTL(duration, default2m)METADATA_RECONCILE_INTERVAL(duration, default30s)RPC_TIMEOUT(duration, default5s)RPC_ANNOUNCEMENT_INTERVAL(duration, default1m)RPC_HANDLER_ID(defaultopen-rtls-hub)COLLISIONS_ENABLED(true/false, defaultfalse)COLLISION_STATE_TTL(duration, default2m)COLLISION_COLLIDING_DEBOUNCE(duration, default5s)
Stateful ingest behavior:
- duplicate location/proximity payloads inside
STATE_DEDUP_TTLare suppressed in the in-memory processing state before fan-out work - latest provider-source location state, trackable latest-location state, proximity hysteresis state, fence membership state, and collision pair state are all kept in process memory with the configured expiry semantics
- metadata is loaded from Postgres at startup, updated immediately after successful CRUD writes, and reconciled in the background every
METADATA_RECONCILE_INTERVAL - durable hub metadata is also loaded from Postgres at startup before the service begins accepting traffic
- WebSocket delivery uses a per-connection outbound queue capped by
WEBSOCKET_OUTBOUND_BUFFER; when that queue fills, outbound payloads are dropped instead of backpressuring ingest or disconnecting the subscriber - WebSocket liveness uses server ping frames every
WEBSOCKET_PING_INTERVALand considers the connection stale when no inbound message or pong arrives beforeWEBSOCKET_READ_TIMEOUT - internal event-bus subscribers such as MQTT and WebSocket consume behind
EVENT_BUS_SUBSCRIBER_BUFFER - native location publication is queued behind
NATIVE_LOCATION_BUFFERso ingest can decouple from transport fan-out - post-native decision work such as future filtering, alternate-CRS publication, geofence evaluation, and collision evaluation is queued behind
DERIVED_LOCATION_BUFFER - when the native, decision, event-bus, or outbound socket queues are full, the hub drops newer work on those non-critical paths instead of slowing raw location ingest
- the
metadata_changesWebSocket topic emits lightweight{id,type,operation,timestamp}notifications for zone, fence, trackable, and location-provider CRUD or reconcile drift - when
COLLISIONS_ENABLED=true, the hub evaluates trackable-versus-trackable collisions from the latest active WGS84 motion state and keeps short-lived collision pair state in memory forCOLLISION_STATE_TTL COLLISION_COLLIDING_DEBOUNCElimits repeatedcollidingemissions for already-active pairs
RPC behavior:
RPC_TIMEOUTis the default wait time for request-response style RPC calls when the client does not supply_timeoutRPC_ANNOUNCEMENT_INTERVALcontrols how often the hub republishes retained MQTT availability announcements for hub-owned methodsRPC_HANDLER_IDis the handler identifier announced for hub-owned RPC methods and the identifier clients may use with_handler_idto target the hub directlycom.omlox.identifyreturns the persisted hub label asnameplus the stablehub_id
Proximity Resolution
PROXIMITY_RESOLUTION_ENTRY_CONFIDENCE_MIN(number, default0)PROXIMITY_RESOLUTION_EXIT_GRACE_DURATION(duration, default15s)PROXIMITY_RESOLUTION_BOUNDARY_GRACE_DISTANCE(number, default2)PROXIMITY_RESOLUTION_MIN_DWELL_DURATION(duration, default5s)PROXIMITY_RESOLUTION_POSITION_MODE(defaultzone_position; supported value:zone_position)PROXIMITY_RESOLUTION_FALLBACK_RADIUS(number, default0)PROXIMITY_RESOLUTION_STALE_STATE_TTL(duration, default10m)
Proximity resolution behavior:
- proximity updates are resolved to a zone before the hub emits a derived
Location - the first valid proximity observation enters immediately
- the hub keeps the current zone for a short grace period to reduce flapping between nearby zones
- zone-specific overrides may be supplied through
Zone.properties.proximity_resolution Proximity.propertiesis preserved into derived location metadata but does not override configured policy
Auth
AUTH_ENABLED(true/false, defaulttrue)AUTH_MODE(none|oidc|static|hybrid, defaultnone)AUTH_ISSUER(OIDC issuer URL)AUTH_AUDIENCE(comma-separated)AUTH_ALLOWED_ALGS(comma-separated, defaultRS256)AUTH_STATIC_PUBLIC_KEYS(comma-separated PEM blocks or JWKS URLs)AUTH_CLOCK_SKEW(duration, default30s)AUTH_OIDC_REFRESH_TTL(duration, default10m)AUTH_HTTP_TIMEOUT(duration, default5s)AUTH_PERMISSIONS_FILE(YAML path, defaultconfig/auth/permissions.yaml)AUTH_ROLES_CLAIM(JWT claim used for role extraction, defaultgroups)AUTH_OWNED_RESOURCES_CLAIM(JWT object claim for owned resource IDs; seedocs/auth.mdfor format and usage)
See docs/auth.md for the full auth model, Dex setup, and permission file format.
Telemetry
OTEL_ENABLED(true/false, defaultfalse)OTEL_METRICS_ENABLED(true/false, defaulttruewhen telemetry is enabled)OTEL_TRACES_ENABLED(true/false, defaulttruewhen telemetry is enabled)OTEL_LOGS_ENABLED(true/false, defaulttruewhen telemetry is enabled)OTEL_EXPORTER_OTLP_ENDPOINT(base OTLP HTTP endpoint such ashttp://localhost:4318)OTEL_EXPORTER_OTLP_TRACES_ENDPOINT(optional full traces endpoint override)OTEL_EXPORTER_OTLP_METRICS_ENDPOINT(optional full metrics endpoint override)OTEL_EXPORTER_OTLP_LOGS_ENDPOINT(optional full logs endpoint override)OTEL_EXPORTER_OTLP_HEADERS(comma-separatedkey=valueheaders for collector auth or routing)OTEL_EXPORTER_OTLP_INSECURE(true/false, defaultfalse)OTEL_EXPORTER_OTLP_TIMEOUT(duration, default10s)OTEL_METRIC_EXPORT_INTERVAL(duration, default30s)OTEL_METRIC_EXPORT_TIMEOUT(duration, default10s)OTEL_TRACE_SAMPLE_RATIO(number between0and1, default1)OTEL_SERVICE_NAME(defaultopen-rtls-hub)OTEL_SERVICE_VERSION(optional override for release tagging)OTEL_DEPLOYMENT_ENVIRONMENT(optional deployment environment label such aslocal-demoorproduction)OTEL_DEBUG_IDENTIFIERS(true/false, defaultfalse)
Telemetry behavior:
- the hub exports OTLP metrics, traces, and logs directly to a collector and does not expose a separate Prometheus scrape endpoint in this slice
service.name,service.version,deployment.environment, and the persistedhub.idare attached to the OTel resource when available- invalid telemetry configuration fails startup only when telemetry is enabled
- metrics are intentionally low-cardinality and are labeled only with bounded dimensions such as transport, signal type, stage, feature, and outcome
- entity identifiers such as
trackable_id,provider_id,zone_id,fence_id, and collision pair identifiers are emitted on spans and structured logs for drill-down, not on normal metric series - runtime metrics cover ingest acceptance and deduplication, end-to-end processing latency, queue occupancy and wait time, fence evaluation, collision evaluation, MQTT/WebSocket publication, metadata reconcile, auth, and RPC outcomes
- the local demo stack under
local-hub/enables all three OTLP signals by default and routes them to SigNoz
RPC Security Defaults
For production deployments:
- keep
AUTH_ENABLED=true - treat
GET /v2/rpc/availableas sensitive because it reveals reachable control functions - use per-method RPC permissions in the auth registry to control who may invoke which methods
- grant
com.omlox.core.xcmdonly to tightly controlled operator or automation roles - keep direct MQTT broker access limited to the hub and trusted device/adaptor components