Runtime model
Understand what runs in nginx, what belongs to broker authority, and where blocking sinks execute.
Architecture guideCitusIO is one product with three deliberate runtime boundaries plus a packaged operator console. The boundaries matter more than the process count: they keep nginx workers non-blocking while making broker state and external side effects explicit.
Nginx modules
Nginx accepts every inbound device and operator connection, terminates TLS, parses bounded protocol input, applies cheap admission policy, and publishes pointer-free commands into shared-memory rings. Inbound gateway and platform modules validate their operator configuration during nginx -t.
Nginx does not own cross-worker session state, durable commits, or blocking database and HTTP clients.
nginz-iotd
The broker daemon is the authority for shared MQTT sessions, subscriptions, retained messages, delivery sequencing, rules, schema state, durable recovery, snapshots, and writer-term ownership. It also initiates active industrial acquisition: Modbus TCP polling and OPC UA client sessions, subscriptions, reconnect, backfill, and governed writes. The node initiates those outbound client connections.
Nginx and the daemon must agree on ring namespace, generation, term, capacity, record size, and operating profile. A mismatch fails closed.
All processes attached to the same node-local rings must also resolve producer identity in the same IPC and PID namespaces. This is automatic for ordinary host services. Container deployments must join both namespaces; sharing only /dev/shm can make a live producer appear dead during MPSC recovery.
nginz-iot-bridge
The bridge daemon runs blocking sink clients and the public Bridge SDK. It owns bounded retry, backpressure, outbox replay, and dead-letter behavior for PostgreSQL, webhook, MQTT-to-MQTT, and qualified adapter profiles.
It is not a separately licensed product. It ships in every self-hosted tier and starts only for configured external actions. One stable guardian supervises a separate worker for each bridge target. Workers do not share adapter address spaces, health, or restart deadlines, so a native fault replaces only its worker and does not disturb sibling bridges or broker authority.
Operator console
The console is a static bundle served by nginx on the same origin as the admin API. It consumes redacted snapshots and governed command endpoints. It does not attach to rings, read WAL files, or decide HA ownership.
Free, Pro, and Max ship read-only console routes. Enterprise adds SSO/CSRF and the four governed mutations. See Operator console.
Configuration flow
- Select a lane and start from its immutable image.
- Configure the inbound nginx modules included in that lane.
- Configure
nginz-iotdwith the same deployment, generation, term, and ring namespace. Configure Modbus and OPC UA acquisition here when selected. - Configure
nginz-iot-bridgeonly when the selected rule graph emits external actions. - Run
nginx -tfor inbound surfaces and each daemon’s--test-configbefore startup or reload.
Direction is the simple rule: inbound device and operator traffic enters through nginx; active industrial acquisition runs in
nginz-iotd; outbound sinks run innginz-iot-bridge.
A successful ring enqueue is not automatically a durability acknowledgement. The selected lane and store acknowledgement policy define when a message is considered committed.
This page is a customer-oriented guide. The source contract remains authoritative for exact behavior and release evidence.
docs/architecture-decisions/ADR-0022-nginx-native-bridge-boundaries.md