Skip to content

Ports & firewall

Yagra needs very few holes in a firewall. The core host exposes two TCP ports, the poller opens UDP listeners only for the passive-intake features you turn on, and everything else — all five stores and the bus — stays on the internal Docker network. Outbound connections are strictly per-feature: a fresh install with no notification channels, no forwarding destinations, and no AI provider configured makes no egress at all (except image pulls).

Port Protocol Service Notes
8080 TCP (HTTP) Core API One port serves the REST API (/api/v1), the Prometheus endpoint (/metrics), the health probes (/healthz, /readyz), and — when YAGRA_ENABLE_MCP is on — the MCP tool surface at /mcp (off by default; the route 404s). Host port via YAGRA_API_PORT (compose) or YAGRA_API_ADDR (native).
443 TCP (HTTPS) WebUI nginx (rootless, container port 8080) serving the frontend over TLS; it proxies /api and /mcp to core, so browsers only ever need this port. Host port via YAGRA_WEB_PORT443 on the deploy composition, 8443 on the single-node build composition. There is no plain-HTTP listener unless you set YAGRA_WEB_TLS=off.
8081 TCP (HTTP) Second core (HA overlay only) The two-core high-availability overlay maps the standby core’s API to a distinct host port. /readyz answers 200 only on the leader (a standby returns 503), so a load balancer can route on it.

The UI and API carry the login password, bearer tokens, and (pre-encryption) device credentials. The WebUI port is HTTPS by default and needs nothing in front of it. Core’s API port is still plaintext — do not publish 8080 beyond a trusted LAN, and once your machine clients have moved to the TLS edge, close it entirely with YAGRA_API_BIND=127.0.0.1.

All poller listeners are opt-in: each exists only when its *_BIND variable is set (the compose files set the first three by default; set the variable empty in .env to disable one). The container binds unprivileged ports; compose maps the standard low ports on the host.

Container port Host default Protocol Service Enable / disable
1514 514 (YAGRA_SYSLOG_PORT) UDP syslog intake YAGRA_SYSLOG_BIND
1162 162 (YAGRA_TRAP_PORT) UDP SNMP trap intake (v1/v2c + inform) YAGRA_TRAP_BIND
2055 2055 (YAGRA_FLOW_PORT) UDP NetFlow v5/v9 / IPFIX intake YAGRA_FLOW_BIND
6343 6343 (YAGRA_SFLOW_PORT) UDP sFlow v5 intake YAGRA_SFLOW_BINDoff by default; the host mapping exists but nothing listens until you set the bind
9100 TCP (HTTP) Poller Prometheus /metrics (fixed 0.0.0.0:9100) Not published by the compose port mappings; reachable when the poller runs with host networking (the remote-site composition) or natively

Only open the corresponding host ports to the network segments your devices send from. Event→node correlation keys on the datagram source IP, so anything that rewrites it (NAT between device and poller) breaks attribution — place pollers close to their devices.

These services must stay on the internal Docker network. None of the compose files publish them, and nothing outside the stack ever needs to reach them — keep it that way.

Port Service Role
5432 PostgreSQL Metadata store (nodes, config, users, alert history)
6379 Redis Ephemeral poller liveness/assignment mirror (rebuildable)
4222 NATS The core⇄poller bus. Job messages carry plaintext device credentials, so this port may be published only with the TLS + authentication configuration in place — and only when you run remote-site pollers.
8428 VictoriaMetrics Metrics time-series store
9428 VictoriaLogs Passive-event log store (optional)
8123 ClickHouse Traffic-flow store (optional)

Every outbound connection Yagra can make, and which process makes it. Nothing on this list happens until you configure the feature.

Feature Destination Protocol From
Webhook notifications The webhook URL(s) you configure HTTP/HTTPS core
Email notifications YAGRA_SMTP_HOST (default port 465, implicit TLS) SMTP core
PagerDuty notifications events.pagerduty.com (EU accounts: events.eu.pagerduty.com, via the channel’s API URL) HTTPS core
Jira Service Management notifications api.atlassian.com HTTPS core
Forwarding — relay destinations The collector host:port you configure UDP, TCP, or TLS core (the active/leader core — not the pollers)
Forwarding — BigQuery destination bigquery.googleapis.com and oauth2.googleapis.com; plus the GCE metadata server 169.254.169.254 when using Workload Identity instead of a stored key HTTPS core
AI root-cause analysis Only the one configured provider: api.anthropic.com (Claude), generativelanguage.googleapis.com (Gemini), or {location}-aiplatform.googleapis.com (Vertex AI, stays in your GCP project). Default off — no provider configured means zero egress. HTTPS core
Single sign-on (OIDC) Your identity provider’s issuer URL HTTPS core
Cisco Meraki monitoring api.meraki.com (or the regional api.meraki.cn / api.gov-meraki.com) HTTPS the poller pool that runs Meraki jobs
Distributed tracing Your OTLP collector (YAGRA_OTEL_ENDPOINT, e.g. :4318) OTLP/HTTP core and pollers
IP→ASN enrichment dataset iptoasn.com (weekly fetch) HTTPS the ipasn-updater sidecar — the only container that needs egress for this feature

Two points worth repeating for a locked-down core host:

  • Forwarding egress originates from core, not pollers. Pollers carry received bytes to core over the bus; core does all relaying and BigQuery streaming. Only the core host needs firewall exceptions for forwarding destinations.
  • A TLS relay destination verifies the collector’s certificate against the system trust store (plus an optional operator-supplied CA certificate). There is no flag to disable verification, so a TLS destination behind an interception proxy will not connect.

A remote-site poller is designed to need one outbound rule and no inbound rules at HQ:

  • The poller dials out to the central NATS bus (tls://…:4222). The central firewall publishes exactly one port — the TLS + authenticated bus (YAGRA_NATS_PORT, default 4222) — and nothing else. No hole is opened toward the poller; all job assignment, results, events, and flow batches travel over that single outbound connection, which also crosses NAT without port forwarding at the site.
  • The remote poller composition uses host networking, so passive listeners bind the host’s ports directly and the device’s real source IP survives for event correlation (a Docker bridge would rewrite it).
  • The poller runs non-root (file-capability NET_RAW only), so it cannot bind ports below 1024. Use the default high ports (1514, 1162) and either point devices at them directly or redirect the standard ports in the site firewall:
Terminal window
# Redirect the standard syslog/trap ports to the poller's unprivileged listeners
iptables -t nat -A PREROUTING -p udp --dport 514 -j REDIRECT --to-ports 1514
iptables -t nat -A PREROUTING -p udp --dport 162 -j REDIRECT --to-ports 1162

So that forwarding can relay exactly what a device sent, pollers always carry the original bytes to core: passive events cost roughly 1.5–1.6× their raw syslog/trap volume on the bus, and every received flow datagram is relayed verbatim alongside the aggregated stream. Budget 0.4–0.8 Mbit/s per 1,000 flows/s of relayed flow — up to ~1 Mbit/s with densely packed exporters (≈4–8 Mbit/s at 10,000). If the WAN drops, the poller’s store-and-forward buffer keeps polling locally and replays metrics on reconnect, so a flapping link costs history nothing.

  • Configuration reference — every environment variable, including the bind and port-mapping variables named above.
  • Installation — the compose files these mappings come from, and the remote-site poller setup.