rsigma engine daemonπ
Run as a long-running daemon with hot-reload, health checks, and Prometheus metrics.
Synopsisπ
Descriptionπ
Loads rules and pipelines, opens an event source, evaluates events as they arrive, fans the detections out to one or more sinks, and stays alive until it receives SIGTERM/SIGINT. Reloads rules and pipelines on file change, SIGHUP, or POST /api/v1/reload. Exposes Prometheus metrics, REST control endpoints, and OTLP log ingestion on the same --api-addr.
This is the long-running counterpart of engine eval. Use it when you need state to survive restarts, hot-reload across rule changes, or a Prometheus-scrapeable detection engine.
For narrative coverage see Streaming Detection. For NATS-specific operations (auth, replay, consumer groups, DLQ) see NATS Streaming.
Flagsπ
Requiredπ
| Flag | Description |
|---|---|
-r, --rules <RULES> | Path to a Sigma rule file or directory of rules (recursive). |
Event inputπ
| Flag | Default | Description |
|---|---|---|
--input <URL> | stdin | Event source. Schemes: stdin, http (accepts POST /api/v1/events), nats://<host>:<port>/<subject>. |
--input-format <FORMAT> | auto | Input log format: auto, json, syslog, plain. With features: logfmt, cef. |
--syslog-tz <OFFSET> | +00:00 | Timezone offset for RFC 3164 syslog (+HH:MM or -HH:MM). |
--jq <JQ> | unset | jq filter to extract the event payload from each JSON object. Mutually exclusive with --jsonpath. |
--jsonpath <JSONPATH> | unset | JSONPath (RFC 9535) query to extract the event payload. |
Output sinks and DLQπ
| Flag | Default | Description |
|---|---|---|
--output <URL> | stdout | Detection sink. Schemes: stdout, file://<path>, nats://<host>:<port>/<subject>. Repeatable for fan-out. |
--dlq <URL> | unset | Dead-letter queue for events that fail parsing or sink delivery. Same schemes as --output. When unset, failed events are logged and discarded. |
--include-event | off | Embed the full event JSON in every detection match. |
--pretty | off | Pretty-print JSON output. |
Pipelines and dynamic sourcesπ
| Flag | Description |
|---|---|
-p, --pipeline <PIPELINES> | Processing pipeline(s) to apply. Builtin names (ecs_windows, sysmon) or YAML file paths. Repeatable. |
--source <FILE_OR_DIR> | External source file(s) or directory of source files. Repeatable. Loads dynamic source declarations independently of any pipeline file. A file path loads one YAML file with a top-level sources: block; a directory path loads all *.yml/*.yaml files in it, alphabetically. Source IDs must be unique across all --source files and all pipeline-embedded sources: blocks. See Dynamic Pipeline Sources. |
--allow-remote-include | Allow include: directives in pipelines to reference remote (HTTP/NATS) sources. Off by default for security. |
Post-evaluation enrichmentπ
| Flag | Description |
|---|---|
--enrichers <PATH> | YAML file declaring post-evaluation enrichers. Hot-reloaded on SIGHUP, file-watcher changes, and POST /api/v1/reload; failed reloads keep the previous pipeline active. See Enrichers for the schema, the four primitives, and the recipes catalog. |
The enrichers file accepts max_concurrent_enrichments: <N> at the top level (default 16) plus a list of enricher entries, each declaring kind: detection | correlation, a primitive type: (template / lookup / http / command), an inject_field, and primitive-specific keys (template, url / headers / cache_ttl, command, source / extract / default, ...). Cross-namespace template references are rejected at startup with a clear error pointing at the offending field.
API serverπ
| Flag | Default | Description |
|---|---|---|
--api-addr <ADDR> | 0.0.0.0:9090 | Bind address for /healthz, /readyz, /metrics, /api/v1/*, and (with the daemon-otlp feature) /v1/logs. |
TLS (requires the daemon-tls build feature)π
When TLS is configured, the daemon terminates TLS in-process for every protocol on --api-addr (HTTP REST API, /metrics, OTLP/HTTP, OTLP/gRPC). The negotiation advertises both h2 and http/1.1 via ALPN so legacy REST clients and modern gRPC clients share one socket.
| Flag | Env | Default | Description |
|---|---|---|---|
--tls-cert <PATH> | unset | unset | PEM-encoded leaf certificate (with any intermediates) for the API listener. Requires --tls-key. |
--tls-key <PATH> | unset | unset | PEM-encoded private key. PKCS#8, PKCS#1 (RSA), and SEC1 (EC) formats are accepted. Requires --tls-cert. |
--tls-key-password <PASS> | RSIGMA_TLS_KEY_PASSWORD | unset | Password for an encrypted --tls-key. Currently rejected at startup with a clear error; decrypt with openssl rsa -in key.pem -out key-decrypted.pem first. |
--tls-client-ca <PATH> | unset | unset | PEM bundle of trusted CA certificates used to verify inbound client certificates. Enables mutual TLS: clients without a cert signed by one of the listed CAs are rejected during the handshake. |
--tls-min-version <1.2\|1.3> | unset | 1.3 | Minimum TLS protocol version. Drop to 1.2 only for legacy agents that cannot negotiate TLS 1.3. |
--allow-plaintext | unset | off | Permit plaintext on a non-loopback --api-addr. Without this flag (and without --tls-cert/--tls-key) the daemon refuses to start on any public address. Loopback (127.0.0.0/8, ::1) always allows plaintext for local development. |
Hot-reload: every reload trigger funnels through the daemon's central debounced reload task, so a single POST /api/v1/reload (cross-platform, including Windows), kill -HUP <pid> (Unix), or a YAML file change picked up by the file watcher rotates rules, pipelines, enrichers, and the TLS certificate in one pass. The active rustls::ServerConfig is swapped atomically via Arc<ArcSwap<β¦>>, so new handshakes pick up the rotated material without dropping inflight TLS connections. Failed reloads keep the previous certificate active, bump rsigma_reloads_failed_total, and log an error so a typo in the cert path cannot black-hole the listener.
Observability: the /metrics endpoint exposes rsigma_tls_certificate_expiry_seconds (signed; negative once the cert has expired) and rsigma_tls_active_connections. A single WARN is logged at startup (and after every reload) if the active certificate expires within 30 days.
See TLS deployment for a deeper dive, including ACME / sidecar reverse proxy alternatives that this feature replaces.
Correlation behaviorπ
| Flag | Default | Description |
|---|---|---|
--suppress <DURATION> | unset | Suppress duplicate correlation alerts within the window (5m, 1h, 30s). |
--action <ACTION> | alert | Post-fire action: alert (keep state, re-alert on next match) or reset (clear window state). |
--no-detections | off | Suppress detection output for correlation-only base rules. |
--correlation-event-mode <MODE> | none | none, full (deflate-compressed full bodies), refs (timestamp + ID only). |
--max-correlation-events <N> | 10 | Cap on stored events per correlation window. |
--timestamp-field <FIELD> | unset | Field name to prepend to the timestamp extraction list. Repeatable. |
--timestamp-fallback <MODE> | wallclock | Behavior when no timestamp is found: wallclock (use wall clock time) or skip (skip correlation state for that event). Use skip for forensic replay. |
State persistenceπ
| Flag | Default | Description |
|---|---|---|
--state-db <PATH> | unset | SQLite database for persisting correlation state across restarts. When set, state is loaded on startup and saved periodically and on shutdown. |
--state-save-interval <SECONDS> | 30 | Periodic snapshot interval. No effect without --state-db. |
--clear-state | off | Clear stored state on startup. With --replay-from-*, forces a clean slate even if the replay starts after the stored position. |
--keep-state | off | Force restore stored state even during replay. Use for forward catch-up where you want to preserve cross-boundary correlation windows. Mutually exclusive with --clear-state. |
Throughputπ
| Flag | Default | Description |
|---|---|---|
--buffer-size <N> | 10000 | Bounded mpsc capacity for sourceβengine and engineβsink queues. |
--batch-size <N> | 1 | Maximum events per engine lock acquisition. Raise to 64 or 128 under load to amortize mutex overhead. |
--drain-timeout <SECONDS> | 5 | Seconds to wait for in-flight events to drain on shutdown. |
NATS (requires the daemon-nats build feature)π
| Flag | Env | Description |
|---|---|---|
--nats-creds <FILE> | NATS_CREDS | NATS credentials file (.creds) for JWT + NKey authentication. |
--nats-token <TOKEN> | NATS_TOKEN | NATS authentication token. |
--nats-user <USER> | NATS_USER | NATS username (requires --nats-password). |
--nats-password <PASS> | NATS_PASSWORD | NATS password (requires --nats-user). |
--nats-nkey <SEED> | NATS_NKEY | NATS NKey seed. |
--nats-tls-cert <FILE> | unset | TLS client certificate for mutual TLS with NATS. |
--nats-tls-key <FILE> | unset | TLS client private key for mutual TLS with NATS. |
--nats-require-tls | off | Refuse to connect to a NATS server that does not negotiate TLS. |
--replay-from-sequence <SEQ> | unset | Replay from a specific JetStream sequence number. |
--replay-from-time <TIMESTAMP> | unset | Replay from a wall-clock time (ISO 8601: 2026-05-15T10:00:00Z). |
--replay-from-latest | off | Start from the last existing message in the stream, then deliver new ones. |
--consumer-group <NAME> | RSIGMA_CONSUMER_GROUP | Consumer group name for JetStream load balancing across daemon instances. |
The auth methods are mutually exclusive. See NATS Streaming for the full operational guide.
Performance (advanced)π
| Flag | Default | Description |
|---|---|---|
--bloom-prefilter | off | Enable per-field bloom over positive substring needles. See Performance Tuning. |
--bloom-max-bytes <BYTES> | 1048576 | Memory budget for the bloom index (1 MiB default). No effect without --bloom-prefilter. |
--cross-rule-ac | off | Enable cross-rule Aho-Corasick. Available with the daachorse-index build feature. See Performance Tuning. |
Examplesπ
Minimal daemon: stdin β stdoutπ
Reads NDJSON from stdin, writes detections to stdout. Default API on 0.0.0.0:9090.
HTTP ingest with persistent stateπ
rsigma engine daemon -r rules/ \
--input http \
--state-db /var/lib/rsigma/state.db \
--pipeline ecs_windows
Accepts POST /api/v1/events for ingest; correlation state survives restarts.
NATS source + sink + DLQπ
NATS_CREDS=/etc/rsigma/nats.creds \
rsigma engine daemon -r /etc/rsigma/rules/ \
--input "nats://nats.internal:4222/events.>" \
--output "nats://nats.internal:4222/detections" \
--dlq "file:///var/log/rsigma/dlq.ndjson" \
--state-db /var/lib/rsigma/state.db \
--buffer-size 50000 \
--batch-size 128 \
--drain-timeout 30 \
--nats-require-tls \
--api-addr 0.0.0.0:9090
Multi-output fan-outπ
rsigma engine daemon -r rules/ \
--output stdout \
--output "file:///var/log/rsigma/detections.ndjson" \
--output "nats://nats.internal:4222/detections.urgent"
HTTPS with mutual TLSπ
rsigma engine daemon -r rules/ \
--input http \
--api-addr 0.0.0.0:9090 \
--tls-cert /etc/rsigma/tls/server.crt \
--tls-key /etc/rsigma/tls/server.key \
--tls-client-ca /etc/rsigma/tls/clients-ca.crt
Clients connecting to https://daemon:9090/v1/logs (OTLP/HTTP) or https://daemon:9090/api/v1/events (REST) must present a certificate signed by clients-ca.crt or the handshake is rejected. Rotate the server cert with cp new.crt /etc/rsigma/tls/server.crt && kill -HUP $(pidof rsigma) on Unix, or cp new.crt β¦ && curl -X POST https://daemon:9090/api/v1/reload on any platform (including Windows, where SIGHUP does not exist).
Forensic replay from a NATS sequenceπ
rsigma engine daemon -r rules/ \
--input "nats://localhost:4222/events.>" \
--replay-from-sequence 1001 \
--state-db /var/lib/rsigma/replay-state.db \
--timestamp-fallback skip
--timestamp-fallback skip prevents wall-clock contamination of correlation windows when replaying old events.
Health and readinessπ
| Endpoint | Returns | Probe wiring |
|---|---|---|
/healthz | 200 once the listener is up. | Liveness probe. |
/readyz | 200 once rules + pipelines are loaded; 503 during startup or after a failed reload. | Readiness probe. Drain traffic when 503. |
/metrics | Prometheus text format. ~20 metrics at startup; up to 27 once dynamic sources and OTLP fire. | Scrape every 15-30 s. |
Full HTTP API reference: HTTP API. All metric definitions: Prometheus metrics.
Shutdownπ
SIGTERM and SIGINT trigger a graceful drain bounded by --drain-timeout. In-flight events are processed and acknowledged before the daemon exits. With --state-db, the final correlation state snapshot is written during shutdown.
Exit codesπ
| Code | Meaning |
|---|---|
0 | Normal shutdown. |
2 | Rules path could not be read at startup. |
3 | Configuration error: bad -p, malformed --suppress, invalid --input URL, etc. |
See alsoπ
- Streaming Detection for the daemon walkthrough.
- NATS Streaming for auth, replay, consumer groups, and DLQ details.
- OTLP Integration for the OTLP receiver and agent recipes.
- Performance Tuning for
--bloom-prefilter,--cross-rule-ac,--batch-size, and--buffer-size. - Observability for the RUST_LOG targets, tracing spans, and metric alerting recipes.
engine evalfor the one-shot evaluation counterpart.