Configuration reference
Every key EdgeGuard reads from edgeguard.toml — 151 of them across
21 tables. Types, defaults and descriptions are generated from
src/config.rs, so this page cannot describe a binary that does not
exist. If a key is listed here, the parser accepts it.
None of it is required to start. edgeguard init writes a working file and
edgeguard doctor tells you what it would do with it before any traffic
arrives. Begin there and come back for the one key you need.
[server]
Listener, upstream, and the private ops port.
| Key | Type | Default | What it does |
|---|---|---|---|
port | integer | 8080 | Public listen port. Overridden by the PORT env var. |
app_port | integer | 3000 | Internal port the wrapped/upstream app listens on. Overridden by APP_PORT. |
upstream | string | "" | Full upstream base URL. Overridden by UPSTREAM. If empty, derived from app_port. |
trust_forwarded_for | boolean | false | Trust the X-Forwarded-For header for client identity. Enable ONLY when EdgeGuard sits behind a trusted proxy/load balancer that sets it (e.g. a PaaS edge). When false (default) the peer socket address is used, so clients can't spoof their IP to defeat per-IP rate limiting or forge access-log entries. |
admin_port | integer | 0 | Private listener port for the internal /__edgeguard/* ops endpoints (health, readiness, metrics). 0 (default) keeps them on the public port. When non-zero, EdgeGuard binds a second, plain-HTTP listener on admin_addr:admin_port that serves those endpoints, and the public port serves only the proxy (plus the browser-facing CSP report sink) — so metrics/health aren't exposed on the internet. Overridden by ADMIN_PORT. (Point your platform's health check at this port when you enable it.) |
admin_addr | string | "127.0.0.1" | Address the private admin listener binds when admin_port is set. Defaults to 127.0.0.1 (same-host only — e.g. a sidecar scraper); set to 0.0.0.0 to expose it on a private network interface (rely on your network policy to keep it off the internet). |
[auth]
Who is allowed through the front door.
| Key | Type | Default | What it does |
|---|---|---|---|
mode | string | "none" | "none" | "basic" | "apikey" | "jwt". Selects the gate applied to every proxied request; the internal /__edgeguard/* endpoints are always exempt. |
realm | string | "EdgeGuard" | Realm shown in the WWW-Authenticate challenge on a 401, i.e. the name the browser's password prompt displays. Only used when mode = "basic". |
users | table | BTreeMap::new() | username -> password. Value may be plaintext (dev) or a $argon2... PHC hash. Used when mode = "basic". |
api_keys | string list | vec![] | Accepted API keys (compared in constant time). Used when mode = "apikey". A request may present a key either as Authorization: Bearer <key> or in api_key_header. Overridable from the env via EDGEGUARD_API_KEYS (comma-separated) so keys need not live in the config file. |
api_key_header | string | "X-API-Key" | Header carrying the API key (in addition to Authorization: Bearer), default X-API-Key. Used when mode = "apikey". |
jwt | JwtCfg | JwtCfg::default() | JWT verification policy. Used when mode = "jwt". |
[auth.jwt]
JWT verification, when auth mode is jwt.
| Key | Type | Default | What it does |
|---|---|---|---|
algorithm | string | "HS256" | Expected signature algorithm, e.g. "HS256", "RS256", "ES256". The token's own alg header must match this (we never trust the token to pick its own algorithm — that is the classic JWT downgrade/alg=none foot-gun). |
secret | string | "" | Shared secret for HS* algorithms. Prefer the EDGEGUARD_JWT_SECRET env var over putting it in the config file. |
public_key_pem | string | "" | Static PEM public key (SPKI or PKCS#1) for RS*/ES*/PS* verification, as an alternative to jwks_url. |
jwks_url | string | "" | JWKS endpoint to fetch verification keys from (RS*/ES*/PS*). Keys are cached and selected by the token's kid. |
jwks_cache_secs | integer | 300 | How long (seconds) to cache a fetched JWKS before refetching. Default 300. |
issuer | string | "" | If set, the token's iss claim must equal this. |
audience | string | "" | If set, the token's aud claim must contain this. |
leeway_secs | integer | 60 | Clock-skew leeway (seconds) applied to exp/nbf validation. Default 60. |
[ratelimit]
How much any one caller may ask for.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | true | Master switch for rate limiting. On by default: an unlimited front door is not a front door. Turn it off only when something ahead of EdgeGuard already limits. |
rate | string | "60/min" | Default per-client-IP limit, e.g. "60/min", "10/sec", "1000/hour". |
burst | integer | 20 | How many requests may arrive at once before rate applies. The bucket refills at rate, so this is the size of a legitimate spike you are willing to absorb. |
routes | list of tables | vec![] | Per-route overrides. A request whose path starts with path uses that route's limit (still keyed per client IP) instead of the global one; the longest matching prefix wins, so /api/admin/ can be stricter than /api/. |
per_key | PerKeyRateLimit | PerKeyRateLimit::default() | An additional limit keyed by the authenticated principal (API-key id or JWT subject) rather than IP, so a single credential can't fan out across many IPs. Only applies to authenticated requests. |
store | string | "local" | Where limiter state lives: "local" (default) is the in-process governor limiter (fast, no dependency, but per-replica). "redis" shares GCRA state across replicas via a Redis store, so N instances enforce one global limit. "memory" uses the same shared-store code path backed by an in-process map (a single-replica/testing backend). All three honor the same rate/burst/route/per-key settings above. |
redis_url | string | "redis://127.0.0.1:6379" | Redis connection URL for store = "redis", e.g. redis://host:6379 or (TLS) rediss://host:6379. Prefer the EDGEGUARD_REDIS_URL env var over this file. |
redis_prefix | string | "edgeguard" | Key prefix/namespace for the shared store, so multiple EdgeGuard deployments can share one Redis without colliding. Keys look like <prefix>:ip:<addr>. |
fail_open | boolean | false | What to do when the shared store is unreachable. false (default) fails closed — a store error returns 503, so an outage can't silently disable rate limiting. true fails open — a store error allows the request (favor availability over strict limiting). Only relevant for store = "redis". |
[ratelimit.per_key]
Per-principal limits layered on the global one.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Apply a second, per-principal limit on top of the global one. Off by default, because it only means something once requests are authenticated. |
rate | string | "1000/hour" | Sustained rate per authenticated principal, same syntax as ratelimit.rate (e.g. "1000/hour"). Applies per key, not per IP. |
burst | integer | 100 | Burst allowance per principal. See ratelimit.burst. |
[validation]
Request and response size and time bounds.
| Key | Type | Default | What it does |
|---|---|---|---|
max_body | string | "2MiB" | e.g. "2MiB". Requests with a larger body are rejected with 413. |
max_response_body | string | "0" | Cap on the upstream response body EdgeGuard buffers, e.g. "16MiB". "0" disables the cap (unbounded). Protects against an upstream OOM-ing the proxy; raise it if you proxy large downloads. |
upstream_timeout | string | "30s" | Max time to wait for the upstream response and to read its body, e.g. "30s", "500ms", "2m". "0" disables the timeout. Bounds a stalled upstream so it can't pin a handler task indefinitely; on elapse the proxy returns 504. |
max_header_bytes | string | "0" | Cap on the total size of incoming request headers (sum of name + value bytes), e.g. "32KiB". "0" disables the cap (default). Requests over the limit get 431. This is a policy limit enforced by EdgeGuard on top of hyper's own transport-level header cap. |
allow_methods | string list | vec![] | Allowed HTTP methods; empty list means allow all. |
stream_passthrough | boolean | false | Stream (don't buffer) responses whose Content-Type is text/event-stream. Off by default: the proxy normally buffers the whole upstream body so it can cap size (max_response_body) and account exact egress bytes. That buffering defeats Server-Sent Events / chunked streaming — the client only sees the body once the upstream finishes. Turn this on to forward SSE responses frame-by-frame as they arrive (preserving time-to-first-byte). When a response is streamed this way the max_response_body cap and the body-read deadline don't apply (the connect/first-byte upstream_timeout still does); egress bytes are tallied as frames flow. Non-SSE responses are unaffected. |
websocket_passthrough | boolean | false | Tunnel WebSocket (and other Upgrade) connections through to the upstream. Off by default: the normal path strips the hop-by-hop Upgrade/Connection headers, so an upgrade request would be forwarded as a plain HTTP request and the handshake would fail. When on, an authenticated, rate-limited upgrade request is forwarded *with* its upgrade headers and, on the upstream's 101 Switching Protocols, EdgeGuard splices the two connections into a raw bidirectional tunnel. Response hardening / WAF body inspection don't apply to a tunneled connection (there is no buffered response). Non-upgrade requests are unaffected. |
compress_responses | boolean | false | gzip-compress responses for clients that send Accept-Encoding: gzip. Off by default. Skips already-compressed content types and (always) text/event-stream, so SSE streaming is never buffered by the compressor. Applied at the listener, so toggling it needs a restart (it is not part of the hot-reloadable policy). |
[headers]
Response hardening: CSP, HSTS, cookies, leaky headers.
| Key | Type | Default | What it does |
|---|---|---|---|
hsts | boolean | true | Send Strict-Transport-Security, telling browsers to refuse plain HTTP for this host in future. Only meaningful once the site is genuinely HTTPS-only: a browser that has seen it cannot be talked out of it for the max-age. |
csp | string | "default-src 'self'" | Content-Security-Policy value. The default is deliberately strict and will block inline scripts and third-party assets; widen it once you know what the app loads, and use csp_report_only while you find out. |
csp_report_only | boolean | false | Send the CSP as Content-Security-Policy-Report-Only instead of enforcing it. Lets you roll out / tighten a policy by collecting violations first without breaking the page. |
csp_report_uri | string | "" | If set, a report-uri <value> directive is appended to the CSP so browsers POST violation reports there. Point it at EdgeGuard's own sink ("/__edgeguard/csp-report") to have them logged, or at any external collector. |
referrer_policy | string | "no-referrer" | Referrer-Policy value. The default sends no referrer at all, so internal URLs cannot leak to third parties through ordinary navigation. |
permissions_policy | string | "geolocation=(), microphone=(), camera=()" | Permissions-Policy value. The default denies geolocation, microphone and camera, which an app that needs them must explicitly re-enable. |
frame_options | string | "DENY" | X-Frame-Options value: DENY, SAMEORIGIN, or empty to omit the header. Clickjacking protection for browsers predating CSP frame-ancestors. |
force_secure_cookies | boolean | true | Add Secure to every Set-Cookie the upstream returns, so cookies are never sent over plain HTTP. See httponly_cookies for the separate HttpOnly control. |
httponly_cookies | boolean | true | Add HttpOnly to Set-Cookie responses that lack it. On by default. Turn off (or use httponly_cookie_exempt) for apps that intentionally expose a cookie to JavaScript — e.g. a double-submit CSRF token the frontend must read from document.cookie. |
httponly_cookie_exempt | string list | [] | Cookie NAMES that must never get HttpOnly, even when httponly_cookies is on. The surgical exemption for a readable double-submit CSRF cookie, e.g. ["doneyet_csrf"]. Names match exactly (cookies are case-sensitive). |
strip | string list | vec!["Server".into(), "X-Powered-By".into()] | Response headers to strip (case-insensitive), e.g. ["Server", "X-Powered-By"]. |
[waf]
Pattern-based request rejection.
| Key | Type | Default | What it does |
|---|---|---|---|
mode | string | "off" | "off" (default) | "report" | "block". report evaluates rules and logs/counts matches but forwards the request anyway; block rejects a matching request with 403. |
sqli | boolean | true | Enable the built-in SQL-injection heuristic ruleset. |
xss | boolean | true | Enable the built-in cross-site-scripting heuristic ruleset. |
path_traversal | boolean | true | Enable the built-in path-traversal heuristic ruleset. |
inspect_path | boolean | true | Inspect the request path + query string (matched raw and percent-decoded). Default true. |
inspect_headers | boolean | false | Inspect request header values. Off by default: header bytes (cookies, tokens, opaque blobs) are noisy and prone to false positives. |
inspect_body | boolean | false | Inspect the request body (already capped by validation.max_body). Off by default. |
rules | list of tables | vec![] | Operator-defined deny patterns, evaluated alongside the enabled built-in rulesets. |
[access]
IP allow and deny lists.
| Key | Type | Default | What it does |
|---|---|---|---|
allow | string list | -- | CIDRs/IPs allowed in. Empty = allow all (subject to deny). |
deny | string list | -- | CIDRs/IPs always rejected (takes precedence over allow). |
[cors]
Cross-origin policy.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Answer CORS preflights and decorate responses. Off by default: a proxy that adds permissive CORS headers by surprise is a security hole, not a convenience. |
allow_origins | string list | vec![] | Allowed request origins, matched exactly (scheme + host + port), e.g. ["https://app.example.com"]. The single entry ["*"] allows any origin — but a wildcard cannot be combined with allow_credentials = true (the Fetch spec forbids it), so that combination is rejected at startup. |
allow_methods | string list | vec![] | Methods advertised in the preflight Access-Control-Allow-Methods. Empty = a sensible default set (GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD). |
allow_headers | string list | vec![] | Request headers advertised in Access-Control-Allow-Headers. Empty = reflect whatever the browser asks for in Access-Control-Request-Headers (the common, permissive default). |
expose_headers | string list | vec![] | Response headers the browser is allowed to read, advertised in Access-Control-Expose-Headers. Empty = none beyond the CORS-safelisted set. |
allow_credentials | boolean | false | Send Access-Control-Allow-Credentials: true so the browser may send cookies / HTTP auth. Requires explicit allow_origins (no "*"). |
max_age | string | "600s" | How long a browser may cache the preflight result, e.g. "600s", "1h". "0" omits the Access-Control-Max-Age header (the browser uses its own short default). |
[tls]
TLS termination with a supplied certificate.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | -- | Terminate TLS in EdgeGuard itself. Leave off when something upstream already does (a load balancer, a platform edge) and EdgeGuard only sees plaintext behind it. |
cert_path | string | -- | PEM certificate chain (leaf first). When ACME is enabled this is where the obtained certificate is written/read. |
key_path | string | -- | PEM private key (PKCS#8/PKCS#1/SEC1). |
acme | AcmeCfg | -- | Automatic certificate issuance. See [tls.acme]. |
[tls.acme]
Automatic certificates over ACME HTTP-01.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Obtain and renew a certificate automatically over ACME HTTP-01 instead of reading cert_path/key_path from disk. Requires port 80 to be reachable from the CA. |
domains | string list | vec![] | Domains to request a certificate for (the first is the primary CN). |
email | string | "" | Contact email for the ACME account (registration + expiry notices). |
directory_url | string | "https://acme-staging-v02.api.letsencrypt.org/directory" | ACME directory URL. Defaults to Let's Encrypt staging so a misconfiguration can't burn the strict production rate limits; switch to production explicitly. |
cache_dir | string | "./acme" | Directory for the cached ACME account key (so renewals reuse the same account). |
accept_tos | boolean | false | You must set this to true to signify acceptance of the ACME provider's Terms of Service; EdgeGuard refuses to register otherwise. |
[llm]
LLM gateway: metering, budgets, key vault, DLP.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Turn on the LLM gateway: token metering, cost attribution, budgets, the key vault and DLP. Off by default, and irrelevant unless the upstream is an LLM API. |
api_style | string | "openai" | Wire format. Only "openai" is understood today (the default). |
models | table | BTreeMap::new() | Per-model price book, keyed by the model string clients send. Prices are USD per 1,000,000 tokens. Example: [llm.models."gpt-4o"] input_per_1m = 2.5 / output_per_1m = 10.0. |
on_unpriced_model | string | "count" | What to do with a request whose model is not in [llm.models]: "count" (default — meter tokens, omit cost, forward the request) or "block" (reject 402 before it reaches the upstream, so an unpriced model is never served at a silent $0). "block" only bites when a price book is configured — a metering-only deployment (empty [llm.models]) never rejects. |
budgets | list of tables | [] | Hard token/cost budgets (gateway L1). Empty by default (no enforcement — L0 metering only). Each [[llm.budgets]] is a ceiling enforced fail-closed via reserve→reconcile. See [BudgetCfg]. |
store | string | "memory" | Budget store backend: "memory" (single replica / default) or "redis" (shared across replicas — required for a true fleet-wide cap). "local" is treated as "memory". |
redis_url | string | "" | Redis URL when store = "redis", e.g. redis://127.0.0.1:6379. Note: EDGEGUARD_REDIS_URL only overrides ratelimit.redis_url, not this key — set it here (or via pushed policy). |
redis_prefix | string | "edgeguard" | Key prefix for budget keys in Redis (namespacing a shared server). Defaults to edgeguard. |
fail_open | boolean | false | On a budget-store error, allow the request (true) or reject it 503 (false, the default — fail-closed, so an outage can't silently uncap spend). |
default_max_tokens | integer | 1024 | Completion tokens to assume when a request omits max_tokens, used only for the *reserve* estimate (the reservation is reconciled to actual usage afterward). Default 1024. |
team_header | string | "x-edgeguard-team" | Request header carrying the team / tag a request is attributed to, for the per-team budget scope and team chargeback. Case-insensitive; default x-edgeguard-team. A request without it falls into the shared _none team bucket. |
keys | list of tables | [] | BYO-key vault + egress governance (gateway L2). Empty by default (no vault). Each [[llm.keys]] maps a client-facing virtual key to a real provider key (injected upstream, never returned to the client) plus an optional per-key model egress allowlist. When any key is configured, every proxied request must present a known virtual key. See [KeyEntryCfg]. |
dlp | DlpCfg | DlpCfg::default() | Edge DLP — PII / secret detection + redaction (gateway L3). Off by default. See [DlpCfg]. |
telemetry | TelemetryCfg | TelemetryCfg::default() | OTLP span emission (gateway L4) — SDK-free tracing to an OTel-native store. Off by default. See [TelemetryCfg]. |
[[llm.budgets]]
Hard spend or token caps. Repeatable.
| Key | Type | Default | What it does |
|---|---|---|---|
name | string | "" | Identifier (also the metric/log label and part of the store key). Required, non-empty. |
scope | string | "global" | Keying dimension: "global", "key" (per authenticated principal), or "model". |
unit | string | "tokens" | "tokens" (prompt + completion) or "usd" (cost via the price book). |
limit | number | 0.0 | The ceiling, in unit: a token count, or — for unit = "usd" — dollars (e.g. 25.0). |
window | string | "24h" | Reset window, e.g. "1h", "24h", "30d". The budget resets at each window boundary. |
[[llm.keys]]
Virtual key to provider key mapping. Repeatable.
| Key | Type | Default | What it does |
|---|---|---|---|
virtual_key | string | -- | The secret the client presents (Authorization: Bearer <virtual_key>). Required. |
provider_key | string | -- | The real upstream provider secret injected on the way out. Required. Prefer sourcing this from a pushed control-plane policy / secret store rather than committing it. |
allowed_models | string list | -- | Allowed model names for this key (egress allowlist). Empty = unrestricted; non-empty = only these models may be requested (others get 403). |
label | string | -- | Optional label for logs/metrics/audit (never the secret). Defaults to a positional id. |
[llm.dlp]
Detect and block or redact sensitive strings.
| Key | Type | Default | What it does |
|---|---|---|---|
mode | string | "off" | off | report | block | redact. Default off. |
redact_style | string | "full" | How a span is rewritten in redact mode: full ([REDACTED:<cat>], default) | mask (keep last 4) | hash (stable opaque token). See [crate::dlp::RedactStyle]. |
scan_request | boolean | true | Scan the inbound request body (the prompt). Default true. |
scan_response | boolean | true | Scan the (buffered) response body and, in report mode, streamed frames. Default true. |
stream_redact | boolean | false | In redact mode, also rewrite *streamed* SSE frames (not just buffered bodies). Deterministic detectors only — NER never runs on the stream. Off by default: streaming redaction can only rewrite spans the carry buffer fully contains, so enable it deliberately. See [crate::dlp]. |
reversible | boolean | false | Reversible masking (redact mode only). When on, an inbound finding is replaced with a stable placeholder token (<edgeguard-<cat>-<n>>) instead of an irreversible [REDACTED] tag, and the placeholder→original map is kept for the request so the response is unmasked (buffered *and* streamed) back to the original value. The provider never sees the PII; the client gets its own data back — the round-trip an unmask keyed on shared state gets wrong. Off by default. When on, the response is unmasked rather than re-scanned/redacted (restore, not detect). |
detect_email | boolean | true | Built-in detectors. |
detect_credit_card | boolean | true | Detect card numbers. Pair with luhn_validate_credit_card to require a valid checksum, which removes most false positives from ordinary long digit strings. |
luhn_validate_credit_card | boolean | true | Require the Luhn checksum before flagging a digit run as a card (cuts false positives). Default true. |
detect_secrets | boolean | true | AWS keys, provider-style xx-… keys, and private-key blocks. |
detect_ssn | boolean | true | US SSN (NNN-NN-NNNN). Default true. |
detect_phone | boolean | false | Phone numbers. Off by default — false-positives on ordinary numeric runs. |
detect_iban | boolean | false | IBAN account numbers. Off by default — false-positives on uppercase+digit tokens. |
detect_high_entropy | boolean | false | High-entropy token sweep (catch-all). Off by default — can false-positive. |
detect_prompt_injection | boolean | false | Prompt-injection / jailbreak heuristics for agent traffic (a small, high-precision built-in deny set — "ignore previous instructions", "reveal your system prompt", etc.), reported under the prompt_injection category. Off by default (opt-in, report-first) since instructions to a model are legitimate traffic; enable and watch the counter before moving to block. |
entropy_min_len | integer | 24 | Minimum token length the entropy sweep considers. |
entropy_threshold | number | 4.0 | Per-character Shannon-entropy threshold (bits) for the entropy sweep. |
gazetteer_terms | string list | [] | Dictionary deny-list: literal terms matched case-insensitively (Aho-Corasick), reported under the gazetteer category. The fast, many-term path for known names / codenames / identifiers. |
custom_patterns | string list | [] | Extra regexes (linear-time regex syntax), all reported under the custom category. |
ner | NerCfg | NerCfg::default() | Optional ML NER family ([llm.dlp.ner]). Requires the ner cargo feature; catches person/address/org spans regex can't. See [NerCfg]. |
[llm.dlp.ner]
Optional ML entity detection for DLP. Requires the ner build feature.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Turn the NER family on. Requires the ner feature. |
model_path | string | "" | Path to the ONNX model file. |
tokenizer_path | string | "" | Path to the HuggingFace tokenizer.json. |
labels | string list | [] | Per-class label list in model id order (e.g. ["O","B-PER","I-PER","B-LOC", …]). Used to map argmax class ids back to entity labels. |
threshold | number | 0.5 | Confidence floor in [0.0, 1.0]; spans below it are dropped. Default 0.5. |
max_seq_len | integer | 256 | Max tokens fed to the model per scan (longer inputs are truncated). Default 256. |
[llm.models]
Per-model prices, USD per 1M tokens.
| Key | Type | Default | What it does |
|---|---|---|---|
input_per_1m | number | -- | USD per 1,000,000 prompt (input) tokens for this model, as billed by the provider. |
output_per_1m | number | -- | USD per 1,000,000 completion (output) tokens for this model. |
cached_per_1m | number | -- | USD per 1M cached prompt tokens. 0.0 = inherit input_per_1m. |
reasoning_per_1m | number | -- | USD per 1M reasoning tokens. 0.0 = inherit output_per_1m. |
[telemetry]
Logging and OpenTelemetry export.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Master switch. Default false. |
endpoint | string | "" | OTLP/HTTP traces endpoint, e.g. http://127.0.0.1:4318/v1/traces. Required when enabled. |
sample_rate | number | 1.0 | Fraction of LLM requests to emit a span for, 0.0–1.0 (deterministic per-trace sampling — the same trace always gets the same verdict). Default 1.0 (all). |
service_name | string | "edgeguard" | service.name resource attribute on emitted spans. Default edgeguard. |
capture_content | boolean | false | Capture the (DLP-redacted) prompt/response as input.value/output.value on the span. Off by default — content leaves the gateway only when this is explicitly enabled, and when an [llm.dlp] engine is configured the captured content is redacted before it is emitted. |
max_content_bytes | integer | 8192 | Cap on each captured content field in bytes (truncated past this). Default 8192. |
timeout_ms | integer | 2000 | Per-emit timeout for the background POST, in milliseconds. Default 2000. |
[alerts]
Outbound notification of budget events.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Master switch. Default false. |
webhook_url | string | "" | Slack incoming-webhook URL (or any endpoint accepting { "text": … }). Required when enabled. |
budget_consumed_threshold | number | 0.9 | Fire when a budget's consumed ratio (used/limit) reaches this (0.0–1.0+). Default 0.9. |
timeout_ms | integer | 2000 | Per-emit timeout for the background POST, in milliseconds. Default 2000. |
[control_plane]
Managed-plane enrolment. Optional.
| Key | Type | Default | What it does |
|---|---|---|---|
enabled | boolean | false | Enrol this instance with a managed control plane for pushed policy and quota. Off by default; EdgeGuard is fully functional without one. |
url | string | "" | Base URL of the control plane, e.g. https://cp.example. |
tenant_id | string | "" | This edge's tenant id at the control plane. |
edge_token | string | "" | Per-tenant edge token (Bearer). Prefer EDGEGUARD_CP_EDGE_TOKEN. |
poll_interval | string | "30s" | How often to poll for policy, e.g. "30s". |
report_interval | string | "60s" | How often to flush a metrics delta, e.g. "60s". |
forward_csp | boolean | true | Forward received CSP reports to the control plane (default true). |
enforce_quota | boolean | false | Enforce the configured quota as a hard stop: poll the control plane's /v3/edge/{id}/quota and, while the edge is over its quota, reject the edge's traffic with 429 (a Retry-After reset hint). Off by default — opt in to turn the rate signal into a hard cap. Prefer EDGEGUARD_CP_QUOTA_ENFORCE. |
quota_poll_interval | string | "30s" | How often to poll the quota verdict, e.g. "30s". A failed poll keeps the last verdict, so a control-plane blip neither over- nor under-enforces. |
Generated by scripts/build-config-reference.py from
src/config.rs. Editing this file by hand accomplishes nothing — the next
run overwrites it. Change the doc comment in the source instead.