Skip to main content

Deployment Guide

Insights is a single Go binary with independently toggleable subsystems. How you configure them determines the deployment topology.

Subsystems​

SubsystemFlagDefaultDescription
Scraper--scrapertrueScrapes $SYS endpoints from a target NATS system
Indexer--indexertrueProcesses scrape stream into DuckDB
Web UI--webtrueHTTP server for the dashboard
Embedded Sink--sink.embedtrueIn-process NATS server with JetStream
Simulator--simulatorfalseIn-process NATS clusters with traffic workloads
Prometheus--prometheustruePrometheus-compatible /metrics endpoint
Version checker--updatertruePeriodic check for a newer release (notification only)
Telemetry--telemetrytrueProduct usage pulse, in trial builds only (see Telemetry)

The API service (NATS micro) starts on any node that indexes or scrapes a system. A web-only node is a client of it and serves no API of its own.

Each toggle is a shorthand: --web=false on the command line, INSIGHTS_WEB=false in the environment. Both spell the same thing as the verbose --web.enabled=false / INSIGHTS_WEB_ENABLED=false, which still parse but are hidden from --help. In YAML, use a web: section with enabled:; see the Configuration reference.

Deployment Topologies​

The following diagrams show which subsystems run in each topology.

Demo (Simulator)​

Zero-config mode for evaluation. Starts an embedded NATS simulator with traffic workloads. All data is ephemeral.

./insights --simulator

Everything runs in-process: simulator, embedded sink, scraper, indexer, web UI. No external NATS required.

Choose a profile to control deployment size:

./insights --simulator --simulator.profile super-medium

Available profiles: core-{small,medium,large}, js-{small,medium,large}, super-{small,medium,large}, leaf-{small,medium,large}, super-leaf-{small,medium,large}.

All-in-One (Ephemeral)​

Monitor a real NATS deployment. Requires system account credentials for $SYS access.

./insights \
--sys.server nats://target:4222 \
--sys.creds /path/to/sys.creds

Or with a NATS context:

./insights --sys.context my-system

The database and the JetStream store are written to a temporary directory, and the data is lost on restart.

All-in-One (Persistent)​

Same as above with durable storage that survives restarts.

./insights \
--sys.server nats://target:4222 \
--sys.creds /path/to/sys.creds \
--data-dir /data/insights
FlagDefaultPurpose
data-dir(temp dir)Base directory for DuckDB (insights.db, or systems/<id>.db per system on a node with several systems), the embedded server's JetStream (nats/), and the identity snapshot (identity.json)

The default web.session-seed is "insights", which preserves sessions across restarts out of the box. For production, set it to a unique secret:

--web.session-seed "your-secret-seed"

External NATS Sink​

Disable the embedded NATS server and use an external NATS cluster with JetStream for the scrape stream. This decouples the scraper from the indexer and enables distributed topologies.

./insights \
--sys.server nats://target:4222 \
--sys.creds /path/to/sys.creds \
--sink.embed=false \
--server nats://sink-cluster:4222 \
--creds /path/to/sink.creds \
--data-dir /data/insights

The nats.* config is the top-level connection used by the API, indexer, and scraper sink (unless overridden). A node that scrapes a system creates that system's stream on whichever sink it writes to, embedded or external, named scrape_<id> and capturing $INS.sys.<id>.scrape.>, where <id> is its system.id. A stream that already exists is used as-is and never updated, so one you pre-created keeps its own limits.

Stream shape​

The stream is a buffer between scraper and indexer; the database keeps the history. Size it with the sink settings:

FlagDefaultPurpose
sink.retention24hBuffer depth, enforced by pruning whole epochs rather than by the stream's max_age (0 = unlimited)
sink.replicas1Stream replicas. Above 1 requires a clustered external sink; the embedded server is a single node and the config is rejected
sink.storagefilefile or memory. Memory storage suits a deployment that can afford to lose the buffer on restart
sink:
embed: false
retention: 6h
replicas: 3
storage: file

Separate NATS connections​

You can override the NATS connection for the indexer or scraper independently:

nats:
server: nats://api-cluster:4222

indexer:
nats:
server: nats://data-cluster:4222

scraper:
nats:
server: nats://data-cluster:4222

The indexer uses indexer.nats, or the top-level nats if that is unset. The scraper uses scraper.nats, then the indexer's connection, then the top-level nats.

Sink connection permissions​

An unrestricted JetStream user needs no grants. For a least-privilege user, grant the subjects below. The connection creates and fills the scrape stream, consumes it for the indexer, serves the $INS API (NATS micro), and stores webhook delivery history.

Insights publishes to:

SubjectPurpose
$INS.>$INS API replies, scrape stream ($INS.sys.<id>.scrape.>), and webhook delivery log ($INS.node.<node_id>.webhook.delivery.*)
$JS.API.>Create, inspect, and purge the scrape stream and webhook delivery stream; drive the indexer consumer
$JS.FC.>JetStream consumer flow-control replies
_INBOX.>Reply inbox for API, micro, and JetStream requests

Insights subscribes to:

SubjectPurpose
$INS.>The $INS API this node serves
$SRV.>NATS micro discovery
_INBOX.>Replies to requests this node makes

Endpoint configuration is held in memory; only the delivery history is stored in JetStream. The webhook delivery stream (webhook-deliveries_<node_id>) is created only when at least one notification endpoint is configured, so its $JS.API.> grant is needed only on a node that delivers notifications; <node_id> is node.id, which on a node serving a system defaults to that system's id. To scope the connection to one system, narrow $INS.> to $INS.sys.<id>.>, $INS.node.<node_id>.>, and $INS.ping; $JS.API.> narrows to INFO, STREAM.CREATE/UPDATE/INFO/PURGE, CONSUMER.>, and STREAM.MSG.GET. INFO is the account info a scraping node reads to report its JetStream domain. Scrape streams are created once and never updated, but the webhook delivery store reconciles its stream with CreateOrUpdateStream, so STREAM.UPDATE is needed on every restart after the first on a node that delivers notifications; drop STREAM.CREATE if the streams are pre-created.

Server config​

Attach the permissions to a user on the sink's JetStream-enabled account:

accounts {
INSIGHTS {
jetstream: enabled
users = [
{
# the sink user's public nkey (U…)
nkey: UAINSIGHTSSINKEXAMPLEPUBLICUSERNKEY0000000000000000000
permissions {
publish {
allow = [
"$INS.>"
"$JS.API.>"
"$JS.FC.>"
"_INBOX.>"
]
}
subscribe {
allow = [
"$INS.>"
"$SRV.>"
"_INBOX.>"
]
}
}
}
]
}
}

Decentralized JWT (nats auth)​

Enable JetStream on the account, then attach the permissions to a scoped signing key (a reusable template) or directly to the user:

nats auth account edit INSIGHTS --jetstream --js-memory 1G --js-disk 10G

nats auth account keys add INSIGHTS insights-sink \
--pub-allow '$INS.>' \
--pub-allow '$JS.API.>' \
--pub-allow '$JS.FC.>' \
--pub-allow '_INBOX.>' \
--sub-allow '$INS.>' \
--sub-allow '$SRV.>' \
--sub-allow '_INBOX.>'

# issue a user under that scoped key (it inherits the template) and write its creds
nats auth user add insights-sink INSIGHTS --key <SIGNING_KEY> --defaults
nats auth user credential sink.creds insights-sink INSIGHTS

Attach the same --pub-allow/--sub-allow flags directly to nats auth user add … --defaults to skip the signing-key template.

Without the Web UI​

Run without the web UI. The NATS micro API remains available for direct nats req queries.

./insights \
--sys.server nats://target:4222 \
--sys.creds /path/to/sys.creds \
--web=false

Query via the NATS CLI:

nats req '$INS.sys.default.db.query' '{"sql": "SELECT * FROM hx.servers LIMIT 5"}'

default is the system.id a node uses when none is set; every system-scoped subject carries it. insights db query resolves the id for you.

Indexer-Only​

Consume from an existing scrape stream without running the scraper. Useful when a separate instance or process handles scraping.

./insights \
--scraper=false \
--sink.embed=false \
--server nats://data-cluster:4222 \
--system.id prod \
--node.id prod-indexer \
--data-dir /data/insights

This node neither scrapes nor mirrors the system, so it creates no stream: scrape_<system.id> must already exist, and system.id must match the node that fills it. The two nodes share a system id in different roles (scrape and catalog), which is allowed. They must not share a node id, and node.id defaults to the system id on both, so name at least one of them. Insights checks both rules over $INS.ping at startup and refuses to start on a clash.

Split Web Tier​

Run the web UI on its own node as a pure client of a remote indexer/scraper node over NATS. The web tier owns no database, runs no scraper or indexer, and validates no license. It discovers the systems on its NATS over $INS.ping and each backend's capabilities (geo enrichment, realtime feed, scrape interval, retention, license) over $INS.sys.<id>.ops.info. Useful for placing the UI close to operators, scaling it independently, or exposing it in a different network zone from the data plane.

insights web \
--server nats://data-cluster:4222 \
--web.hostname 0.0.0.0 --web.port 8080

insights web reads the web:, prometheus: and updater: sections of a config file, and telemetry.enabled, as well as their flags.

The same read-only NATS query API also backs insights mcp (a read-only MCP server for AI assistants) and insights http (an HTTP gateway for HTTP-only clients such as Grafana's Infinity data source). Each runs as an independent pure client. See the CLI reference.

Multiple Systems on One Node​

One node can monitor several NATS systems. List them under systems: and each gets its own DuckDB database (<data-dir>/systems/<id>.db), its own stream, its own indexer and check thresholds, and its own $INS.sys.<id>.* API. An entry with a scrape: block is scraped by this node; an entry without one is filled by a collector.

node:
id: us-east # required on a node serving several systems

data-dir: /var/lib/insights

nats:
server: nats://central:4222
creds: /etc/insights/insights.creds

sink:
embed: false

db:
memory-limit: 4GiB # per system: each has its own DuckDB instance

systems:
- id: core-prod
scrape:
nats:
server: nats://core.internal:4222
creds: /etc/insights/core-prod.creds
interval: 20s
retention: 24h # stream buffer depth; the database keeps history
- id: edge-west # collector-fed: no scrape block
retention: 6h

The list is YAML-only and replaces the flat single-system config rather than sitting beside it: systems: together with a non-default system.id, a sys.* connection, the simulator, or the indexer turned off is a config error. A single-system node keeps the flat system:/sys:/scraper:/sink: config. db.memory-limit is per instance, so three systems at 4GiB can use 12GiB.

A system whose database will not open (a corrupt file, a bad path) is logged, skipped, and retried every minute while the other systems serve; a node where no database opens at all exits non-zero. The web UI serves each system under /systems/<id>/ and lists them on a Systems page. See the systems configuration reference for every per-entry key.

Federated​

To monitor NATS systems at several sites, run Insights at each site and connect the sites to a central NATS server over leafnodes. One web UI then shows every site. Each site runs either a full Insights node or a collector that only scrapes. See Federated Deployment.

NATS Authentication​

All NATS connections support the same authentication options:

MethodFlagsDescription
Credentials file--*.creds /path/to/file.credsNKey + JWT bundled file
NATS context--*.context my-contextNamed context from nats context
Basic auth--*.user X --*.password YUsername/password
NKey--*.nkey SEEDNKey seed string
JWT--*.jwt TOKENUser JWT string

Replace * with the connection prefix: nats, sys, indexer.nats, or scraper.nats. In YAML, a multi-system entry takes the same keys under systems[].scrape.nats. For the top-level connection, every subcommand (serve, db, checks, ops, config, system, node, web, mcp, http, prometheus) uses the unprefixed nats-CLI-style flags: --server, --creds, --context, --user, --tls-ca-cert, and so on; the --nats.* names remain as hidden aliases.

TLS​

--sys.tls-cert /path/to/cert.pem \
--sys.tls-key /path/to/key.pem \
--sys.tls-ca-cert /path/to/ca.pem

Use --*.tls-first when the server requires TLS handshake before the NATS protocol.

SOCKS Proxy​

Route NATS connections through a SOCKS proxy:

--sys.socks-proxy socks5://proxy:1080

System Account Permissions​

When you give the sys connection a dedicated, restricted user instead of full system-account credentials, grant the subjects below. The * in $SYS.REQ.SERVER.*.<endpoint> matches both the PING broadcast token and a concrete server-id, so it covers the default broadcast scrape and the per-server requests Insights issues when a scrape filter excludes part of the deployment.

The endpoint token is enumerated deliberately. Do not collapse it to $SYS.REQ.SERVER.*.*. That wildcard would also grant the administrative RELOAD, KICK, and LDM actions (reload server config, disconnect a client, drain a server into lame-duck mode), which Insights does not use and which turn a read-only monitoring credential into one that can disrupt the deployment.

Insights publishes to these request subjects (request/reply; replies arrive on _INBOX, below):

SubjectPurpose
$SYS.REQ.SERVER.PINGServer discovery
$SYS.REQ.SERVER.*.VARZServer metrics
$SYS.REQ.SERVER.*.CONNZConnections
$SYS.REQ.SERVER.*.SUBSZSubscriptions
$SYS.REQ.SERVER.*.ROUTEZRoutes
$SYS.REQ.SERVER.*.GATEWAYZGateways
$SYS.REQ.SERVER.*.LEAFZLeaf nodes
$SYS.REQ.SERVER.*.ACCOUNTZPer-server account details
$SYS.REQ.SERVER.*.JSZJetStream
$SYS.REQ.SERVER.*.HEALTHZHealth
$SYS.REQ.SERVER.*.RAFTZRaft groups
$SYS.REQ.SERVER.*.IPQUEUESZInternal queues
$SYS.REQ.ACCOUNT.PING.STATZAccount stats

Insights subscribes to these event subjects:

SubjectPurpose
$SYS.ACCOUNT.*.DISCONNECTReal-time client disconnect events (incl. mid-session auth failures/timeouts)
$SYS.SERVER.*.CLIENT.AUTH.ERRReal-time connect-time authentication rejections (not captured by DISCONNECT)
_INBOX.>Replies to the request subjects above

The following publish subjects are optional. Omitting them only disables on-demand server diagnostics:

SubjectPurpose
$SYS.REQ.SERVER.*.PROFILEZOn-demand server profiling
$SYS.REQ.SERVER.*.EXPVARZOn-demand server runtime variables

The two subscribe subjects feed the realtime events view: DISCONNECT surfaces clients that drop after connecting (including sessions whose credentials expire or fail re-authentication), while CLIENT.AUTH.ERR surfaces clients rejected during the connect handshake, which never reach a connected state and so produce no DISCONNECT. Both are subscribed by Insights directly; neither is consumed by the scraper. Omit CLIENT.AUTH.ERR if you don't need connect-time auth-failure visibility.

_INBOX.> is subscribe-only: Insights is the requester, so the server publishes replies to its inbox, so no publish permission on _INBOX is needed. No $SRV.> or scrape-control permissions are required: the scraper's on-demand control service runs on the Insights connection, not the monitored system.

Server config​

In a server configuration file, attach the permissions to the system-account user:

accounts {
SYS {
users = [
{
# the monitoring user's public nkey (U…)
nkey: UAINSIGHTSMONITOREXAMPLEPUBLICUSERNKEY00000000000000000
permissions {
publish {
allow = [
"$SYS.REQ.SERVER.PING"
"$SYS.REQ.SERVER.*.VARZ"
"$SYS.REQ.SERVER.*.CONNZ"
"$SYS.REQ.SERVER.*.SUBSZ"
"$SYS.REQ.SERVER.*.ROUTEZ"
"$SYS.REQ.SERVER.*.GATEWAYZ"
"$SYS.REQ.SERVER.*.LEAFZ"
"$SYS.REQ.SERVER.*.ACCOUNTZ"
"$SYS.REQ.SERVER.*.JSZ"
"$SYS.REQ.SERVER.*.HEALTHZ"
"$SYS.REQ.SERVER.*.RAFTZ"
"$SYS.REQ.SERVER.*.IPQUEUESZ"
"$SYS.REQ.ACCOUNT.PING.STATZ"
]
}
subscribe {
allow = [
"$SYS.ACCOUNT.*.DISCONNECT"
"$SYS.SERVER.*.CLIENT.AUTH.ERR"
"_INBOX.>"
]
}
}
}
]
}
}
system_account: SYS

Decentralized JWT (nats auth)​

With operator/account JWTs, attach the permissions either to a scoped signing key (a reusable template, so every user issued under it inherits the same grants) or directly to the user.

Scoped signing key (define the template once on the account, then issue users under it):

nats auth account keys add SYS insights-monitor \
--pub-allow '$SYS.REQ.SERVER.PING' \
--pub-allow '$SYS.REQ.SERVER.*.VARZ' \
--pub-allow '$SYS.REQ.SERVER.*.CONNZ' \
--pub-allow '$SYS.REQ.SERVER.*.SUBSZ' \
--pub-allow '$SYS.REQ.SERVER.*.ROUTEZ' \
--pub-allow '$SYS.REQ.SERVER.*.GATEWAYZ' \
--pub-allow '$SYS.REQ.SERVER.*.LEAFZ' \
--pub-allow '$SYS.REQ.SERVER.*.ACCOUNTZ' \
--pub-allow '$SYS.REQ.SERVER.*.JSZ' \
--pub-allow '$SYS.REQ.SERVER.*.HEALTHZ' \
--pub-allow '$SYS.REQ.SERVER.*.RAFTZ' \
--pub-allow '$SYS.REQ.SERVER.*.IPQUEUESZ' \
--pub-allow '$SYS.REQ.ACCOUNT.PING.STATZ' \
--sub-allow '$SYS.ACCOUNT.*.DISCONNECT' \
--sub-allow '$SYS.SERVER.*.CLIENT.AUTH.ERR' \
--sub-allow '_INBOX.>'

# issue a user under that scoped key (it inherits the template) and write its creds.
# <SIGNING_KEY> is the insights-monitor key from `nats auth account keys ls SYS`.
nats auth user add insights SYS --key <SIGNING_KEY> --defaults
nats auth user credential insights.creds insights SYS

Directly on the user (the same --pub-allow/--sub-allow flags, on user add):

nats auth user add insights SYS \
--pub-allow '$SYS.REQ.SERVER.PING' \
--pub-allow '$SYS.REQ.SERVER.*.VARZ' \
--pub-allow '$SYS.REQ.SERVER.*.CONNZ' \
--pub-allow '$SYS.REQ.SERVER.*.SUBSZ' \
--pub-allow '$SYS.REQ.SERVER.*.ROUTEZ' \
--pub-allow '$SYS.REQ.SERVER.*.GATEWAYZ' \
--pub-allow '$SYS.REQ.SERVER.*.LEAFZ' \
--pub-allow '$SYS.REQ.SERVER.*.ACCOUNTZ' \
--pub-allow '$SYS.REQ.SERVER.*.JSZ' \
--pub-allow '$SYS.REQ.SERVER.*.HEALTHZ' \
--pub-allow '$SYS.REQ.SERVER.*.RAFTZ' \
--pub-allow '$SYS.REQ.SERVER.*.IPQUEUESZ' \
--pub-allow '$SYS.REQ.ACCOUNT.PING.STATZ' \
--sub-allow '$SYS.ACCOUNT.*.DISCONNECT' \
--sub-allow '$SYS.SERVER.*.CLIENT.AUTH.ERR' \
--sub-allow '_INBOX.>' \
--defaults
nats auth user credential insights.creds insights SYS

Add --pub-allow '$SYS.REQ.SERVER.*.PROFILEZ' --pub-allow '$SYS.REQ.SERVER.*.EXPVARZ' (or the matching allow entries in the server config) to enable the optional on-demand diagnostics.

Scraper Tuning​

Interval and Timeout​

--scraper.interval 1m # Time between scrape cycles (default: 1m)
--scraper.timeout 30s # Per-request timeout (default: 30s)

Indexer Tuning​

Retention​

Limit how much historical data is kept in DuckDB:

--db.retention.duration 24h # Keep last 24 hours (default: 768h)
--db.retention.interval 10m # Minimum time between sweeps (default: 10m)

Stream Position​

Control where the indexer starts consuming:

--indexer.stream-latest # Start from the latest message
--indexer.stream-epoch 500 # Start from a specific epoch number

Filtering and Downsampling​

Process only specific endpoint types or reduce resolution:

--indexer.stream-filters varz,jsz,connz # Only process these endpoints
--indexer.stream-interval 60s # Skip epochs closer than 60s apart

Version Checker​

Periodically checks GitHub for a newer release and notifies via a log message and a badge in the web UI. Does not download or replace the binary automatically. insights-collector and insights web take the same settings. See Version Updates for details.

--updater \
--updater.interval 1h

Official release binaries and container images are stamped with a version string; the checker only runs when a real version is present (binaries reporting dev are skipped). See Version Updates for how the check works.

Web Server​

--web.hostname 0.0.0.0 # Bind to all interfaces (default: 127.0.0.1)
--web.port 8080 # Bind port (default: 8080)

Monitoring with Prometheus & Grafana​

Insights exposes check failure metrics via a Prometheus-compatible endpoint, enabled by default on 127.0.0.1:9091/metrics.

--prometheus # Enable/disable the endpoint (default: true)
--prometheus.hostname # Bind hostname (default: 127.0.0.1)
--prometheus.port # Bind port (default: 9091)

For full setup instructions including Prometheus scrape configuration, Grafana dashboard import, and alerting rules, see the Grafana guide.

Environment Variables​

Every flag has a corresponding environment variable with the INSIGHTS_ prefix. Nested configs add their prefix:

FlagEnvironment Variable
--serverINSIGHTS_NATS_SERVER
--sys.credsINSIGHTS_SYS_CREDS
--data-dirINSIGHTS_DATA_DIR
--scraper.intervalINSIGHTS_SCRAPER_INTERVAL
--db.retention.durationINSIGHTS_DB_RETENTION_DURATION
--web.portINSIGHTS_WEB_PORT
--sink.embedINSIGHTS_SINK_EMBED
--simulatorINSIGHTS_SIMULATOR
--log-levelINSIGHTS_LOG_LEVEL

Config File​

Pass a YAML config file with --config:

./insights --config /etc/insights/config.yaml

See config.example.yaml for all options. Configuration priority (highest wins):

  1. CLI flags
  2. Environment variables
  3. Config file
  4. Defaults

Validate a config file before a rollout. insights config check loads exactly what serve would and reports what it would reject, without opening a database, starting a listener, or connecting to anything:

./insights config check --config /etc/insights/config.yaml

Containers and Supervisors​

Container images​

The Linux images run as UID and GID 1000, not root, and carry a pre-created /var/lib/insights owned by that user. Point --data-dir there:

docker run -d --restart unless-stopped \
-p 8080:8080 \
-v insights-data:/var/lib/insights \
-v /path/to/sys.creds:/etc/insights/sys.creds:ro \
registry.synadia.io/insights:1.2.0 \
--sys.server nats://your-nats:4222 \
--sys.creds /etc/insights/sys.creds \
--data-dir /var/lib/insights \
--web.hostname 0.0.0.0

A named volume mounted at /var/lib/insights inherits that ownership. A named volume mounted anywhere else, a bind mount, and a Kubernetes PersistentVolumeClaim do not, and startup fails with permission denied (for example write identity.json: ... permission denied, or create data dir: ... permission denied for a directory below the mount). Make the directory writable by UID 1000:

chown -R 1000:1000 /var/lib/insights # a bind-mounted host directory

In Kubernetes, set securityContext.fsGroup: 1000 on the pod. The Helm chart runs as UID/GID 1000 and sets fsGroup for you. The images have no shell; attach a debug container rather than exec into one. The collector image (the -collector tag, entrypoint insights-collector) runs as the same user, and needs no data directory: run it as docker run -v /path/to/collector:/etc/insights:ro registry.synadia.io/insights:1.2.0-collector -c /etc/insights/collector.yaml.

Restart policy​

Run Insights under a supervisor that restarts it: a Kubernetes Deployment or StatefulSet, a systemd unit with Restart=, or --restart on a container. If DuckDB recovery after a fatal database error cannot complete within 30 seconds, Insights exits with a non-zero status so the supervisor can start a fresh process, rather than keep serving a database that cannot answer. Startup exits non-zero the same way when no database opens at all.

Stopping​

Insights shuts down cleanly on SIGTERM or SIGINT: it stops the scrapers and indexers, stops the web and API listeners, and checkpoints each DuckDB database before closing it, so the next start does not replay the write-ahead log. Databases are checkpointed one at a time and each checkpoint is bounded to 5 seconds, so give the supervisor a stop timeout of at least 5 seconds per system; docker stop waits 10 seconds by default and Kubernetes 30. A process killed before shutdown completes replays its write-ahead log on the next start.

Health probe​

GET /healthz on the web listener returns 200 with the body ok, unauthenticated. The listener binds only after the databases are built, so a success means Insights itself is serving. Point container, Kubernetes, and load-balancer probes at it rather than at a page route.

The web UI has no built-in authentication. If an authenticating proxy sits in front of it, exclude /healthz from authentication, or the probe gets a login redirect.

Example: Production Deployment​

A persistent deployment monitoring a real NATS system with all features enabled:

# /etc/insights/config.yaml
log-level: info

data-dir: /data/insights

sys:
server: nats://nats.internal:4222
creds: /etc/insights/sys.creds

web:
hostname: 0.0.0.0
port: 8080
session-seed: "your-stable-secret"

db:
retention:
duration: 72h

scraper:
interval: 20s

updater:
enabled: true
interval: 1h
./insights --config /etc/insights/config.yaml