Skip to main content

Configuration Reference

This page is the authority for the Impulse v0.6 configuration schema, allowed values, validation rules, and runtime semantics.

Use Configuration Defaults for the default inventory and Configuration Examples for complete deployment patterns.

For resilience, scoped rate-limit, and quota fields, see Resilience, Rate Limits, and Quota. Redis deployment, rollout, and incident guidance is in Distributed Quota Operations.

Scope​

This page documents the accepted YAML keys, defaults, validation constraints, and runtime meaning of Impulse v0.6 configuration. Unknown fields are rejected. For the complete default inventory, see Configuration Defaults. For deployment-shaped files, see Configuration Examples.

Impulse loads YAML with impulse --config /path/to/config.yaml. If --config is omitted, it attempts /etc/impulse/config.yaml.

Top-Level Configuration​

FieldTypeRequiredDefaultMeaning
versionintegerNo1Configuration schema version. Impulse v0.6 accepts only version 1.
listenobjectYes—Single listener definition. The key is required even when listeners is used.
listenersarray of objectsNo[]Effective listener set when non-empty; otherwise listen is used.
upstreammap of objectsYes—Named upstream pools. The map must contain at least one entry.
load_balancingobject or nullNonullAccepted and validated, but not applied as a v0.6 runtime fallback; configure each upstream instead.
upstream_tlsobjectNo{}Global backend TLS policy inherited by upstreams that omit tls. See TLS Configuration.
secretsobjectNo{}Literal and file-backed secret-provider configuration. See Authentication and Secrets.
logobjectNo{}Logging level and output configuration.
performanceobjectNo{}Timeouts, limits, worker settings, buffers, and backend DNS refresh.
observabilityobjectNo{}Metrics, tracing, Control API, and runtime-view endpoints.
resilienceobjectNo{}Admission, queueing, retry, circuit-breaker, brownout, and protocol policies.
securityobjectNo{}Process-security and privilege-drop settings.

Top-level listen is required by the schema. If listeners contains one or more entries, those entries are the effective listeners and the values inside listen are not validated or activated. Effective listener (address, port) pairs must be unique.

Per-upstream tls replaces the global upstream_tls policy for that upstream. The top-level load_balancing field is accepted and validated, but v0.6 does not apply it to upstreams. An upstream that omits its own load_balancing uses the per-upstream default, round-robin.

Minimal Complete Configuration​

version: 1
listen:
address: "0.0.0.0"
port: 9889
tls:
cert: "/etc/impulse/tls/server.crt"
key: "/etc/impulse/tls/server.key"
upstream:
app:
route:
path_prefix: "/"
backends:
- id: "app-1"
address: "https://app.internal.example:8443"

Listener Configuration​

The listen object and every listeners[] entry use the same schema. Each effective listener creates a native QUIC listener and its bootstrap listener.

FieldTypeRequiredDefaultMeaning
protocolstringNohttp3Listener protocol. The only accepted value is the case-sensitive string http3.
addressstringNo0.0.0.0Non-empty bind address.
portintegerNo9889Bind port in the range 1–65535.
tlsobjectNo{}Listener TLS identities and optional client authentication. A valid effective listener must define a complete TLS identity.

The bootstrap listener accepts HTTP/1.1 and HTTP/2 traffic and advertises the native QUIC listener with Alt-Svc. Both listener paths use the same routes, upstreams, load balancing, and backend health state.

Listener TLS​

FieldTypeRequiredDefaultMeaning
certstringConditionally""Default certificate PEM path. Must be paired with key.
keystringConditionally""Default private-key PEM path. Must be paired with cert.
certificatesarray of objectsNo[]Exact-SNI certificate identities. Required when the default cert/key pair is absent.
certificates[].server_namestringYes—Exact DNS hostname used for SNI selection. Wildcards and ports are rejected.
certificates[].certstringYes—Certificate PEM path for this identity.
certificates[].keystringYes—Private-key PEM path for this identity.
client_authobjectNo{}Downstream mutual-TLS policy.
client_auth.enabledbooleanNofalseEnables client-certificate verification.
client_auth.require_client_certbooleanNofalseRejects clients without a certificate. Requires enabled: true.
client_auth.ca_filestring or nullConditionallynullClient CA PEM path. Required when client authentication is enabled.

Certificate and key files must be readable PEM files no larger than 1 MiB. Normalized SNI names must be unique. Certificate selection uses an exact SNI match first, then the default cert/key pair, then the first certificates[] entry. An unmatched or absent SNI therefore uses the default identity. Certificate reload affects new handshakes, not established connections.

Downstream SNI normalization, SAN coverage, optional and required client-auth behavior, and atomic reload semantics are documented in TLS Configuration.

listen:
protocol: http3
address: "0.0.0.0"
port: 9889
tls:
certificates:
- server_name: "api.example.com"
cert: "/etc/impulse/tls/api.crt"
key: "/etc/impulse/tls/api.key"

Upstream TLS​

The top-level upstream_tls policy applies to each upstream that omits its own tls object. A present upstream.<name>.tls object replaces the complete global policy rather than merging with it. These settings affect only https:// backends.

FieldTypeRequiredDefaultMeaning
verify_certificatesbooleanNotrueVerifies the backend certificate chain and identity.
strict_snibooleanNotrueSends the backend hostname as SNI; disabling it does not disable certificate verification.
ca_filestring or nullNonullPEM CA bundle added to the built-in WebPKI roots.
ca_dirstring or nullNonullDirectory of .pem, .crt, or .cer CA files added to the built-in roots.
client_certificatestring or nullConditionallynullPEM client-certificate chain path; mutually exclusive with client_certificate_ref.
client_certificate_refobject or nullConditionallynullSecret reference for the client-certificate chain.
client_keystring or nullConditionallynullPEM client-key path; mutually exclusive with client_key_ref.
client_key_refobject or nullConditionallynullSecret reference for the client key.

Client certificate and key sources must form a complete pair and require at least one HTTPS backend. Inline paths and references may be mixed across the pair, but a field and its _ref counterpart cannot both be set. CA material, client identities, verification semantics, examples, and activation behavior are documented in TLS Configuration.

upstream:
private_api:
route:
path_prefix: "/"
tls:
verify_certificates: true
strict_sni: true
ca_file: "/etc/impulse/tls/backend-ca.pem"
client_certificate_ref:
ref: "file://private-api/client-chain.pem"
client_key_ref:
ref: "file://private-api/client-key.pem"
backends:
- id: "private-api-1"
address: "https://private-api.internal.example:8443"

Routing and Upstreams​

The top-level upstream map defines routes, backend pools, per-upstream policies, and load balancing. Each entry requires a route and a non-empty backends array. Per-upstream load balancing defaults to round-robin.

Exact host, path, method, wildcard, precedence, backend, health-check, request-key, strategy-alias, and weight semantics are consolidated in Routing and Upstreams. Use Load Balancing for strategy-selection guidance.

Authentication and Secrets​

Downstream request authentication is configured per upstream under upstream.<name>.auth. It supports API keys, local JWT verification with static or JWKS keys, and HTTP or OIDC-introspection external authorization. The top-level secrets object configures file-backed secret resolution used by supported *_ref fields.

Exact fields, defaults, validation rules, failure behavior, examples, and reload semantics are consolidated in Authentication and Secrets. Control API authentication is a separate admin-plane policy; its endpoint and role contract is documented in the Control API Reference.

Logging Configuration​

Controls logging output, verbosity, and destination.

Properties​

FieldTypeRequiredDefaultMeaning
levelstringNoinfoLog level
formatstringNoplainOutput format: plain (human-readable) or json (structured)
file.enabledboolNofalseWrite logs to a file instead of stderr
file.pathstringNo/var/log/impulse/impulse.logLog file path (used when file.enabled is true)

Log Levels​

Log levels in order of increasing verbosity:

  • off: No logging output
  • error: Error messages only
  • warn: Warnings and errors
  • info: Informational messages, warnings, and errors
  • debug: Debug information
  • trace: Trace-level debugging

Examples​

# stderr only (default)
log:
level: info
format: plain

# Write to file
log:
level: info
format: plain
file:
enabled: true
path: /var/log/impulse/impulse.log

# Structured JSON logs (recommended for log pipelines)
log:
level: info
format: json

# Development — debug to stderr
log:
level: debug # debug level
format: plain

# Troubleshooting — trace to file
log:
level: trace # trace level
format: json
file:
enabled: true
path: /tmp/impulse-trace.log

Operational Implications​

  • log.level reloads live, but log sink shape such as file output and format remains startup-owned.
  • json is the safer default for production log pipelines.
  • file logging adds local disk-management responsibility; stderr or journald avoids that at the cost of external collection requirements.

Common Mistakes​

  • enabling file logging without rotation
  • using trace-level logging for sustained production traffic
  • assuming format changes apply through live runtime activation

Performance Configuration​

Controls resource limits, tuning knobs, and connection-flood protection. All fields are optional and fall back to sane defaults.

Properties​

FieldTypeRequiredDefaultMeaning
worker_threadsintegerNo1Number of polling worker threads
control_plane_threadsintegerNo2Tokio worker threads for the control-plane runtime (startup, health checks, metrics, and other async control tasks)
reuseportboolNotrueEnable SO_REUSEPORT; required when worker_threads > 1
pin_workersboolNofalsePin each worker thread to a dedicated CPU core
packet_shards_per_workerintegerNo1Packet-processing shards per bound UDP worker socket; 1 preserves single-loop behavior, values >1 enable parallel shard workers
packet_shard_queue_capacityintegerNo2048Capacity of the bounded ingress queue per shard
packet_shard_queue_max_bytesintegerNo67108864Memory-aware cap (bytes) for queued datagram bytes per ingress shard dispatch queue
global_inflight_limitintegerNo4096Maximum concurrent in-flight requests across all upstreams
per_upstream_inflight_limitintegerNo1024Maximum concurrent in-flight requests per upstream pool
per_backend_inflight_limitintegerNo64Maximum concurrent in-flight requests per backend
inflight_acquire_wait_msintegerNo0Optional micro-wait (ms) before shedding on global/upstream inflight permit acquisition; 0 sheds immediately
backend_timeout_msintegerNo2000Initial backend response timeout (ms)
backend_connect_timeout_msintegerNo500Backend TCP/TLS handshake timeout (ms); must be ≤ backend_timeout_ms
backend_body_idle_timeout_msintegerNo2000Idle timeout while streaming response body (ms); must be ≥ backend_timeout_ms
backend_body_total_timeout_msintegerNo30000Maximum wait for first upstream body bytes (ms); after body progress, idle timeout governs chunk pacing
backend_total_request_timeout_msintegerNo35000Hard deadline for an entire request round-trip (ms); must be ≥ backend_body_total_timeout_ms
shutdown_drain_timeout_msintegerNo5000Graceful-shutdown drain timeout in ms; active connections are force-closed once this deadline is reached
udp_recv_buffer_bytesintegerNo8388608UDP socket receive buffer size (bytes)
udp_send_buffer_bytesintegerNo8388608UDP socket send buffer size (bytes)
h2_pool_max_idle_per_backendintegerNo256Maximum idle HTTP/2 connections kept open per backend
h2_pool_idle_timeout_msintegerNo90000How long an idle H2 connection is kept before being closed (ms)
backend_dns_refresh_enabledboolNofalseEnable periodic DNS refresh for hostname-based upstream backends
backend_dns_refresh_interval_msintegerNo30000Control-plane DNS refresh interval for hostname-based upstream backends (ms)
new_connections_per_secintegerNo2000Steady-state rate at which new QUIC connections are accepted (token-bucket refill, connections/sec)
new_connections_burstintegerNo500Burst capacity above the steady-state rate; the bucket starts full so the first burst of legitimate connections always succeeds
max_active_connectionsintegerNo20000Hard cap on active QUIC connections per worker; unknown Initial packets are dropped once this cap is reached
quic_max_idle_timeout_msintegerNo5000QUIC idle timeout in ms; connection is closed after this period of inactivity
quic_initial_max_dataintegerNo10000000Connection-level QUIC flow control window in bytes
quic_initial_max_stream_dataintegerNo1000000Per-stream QUIC flow control window in bytes; must be ≤ quic_initial_max_data
quic_initial_max_streams_bidiintegerNo100Maximum concurrent bidirectional QUIC streams per connection
quic_initial_max_streams_uniintegerNo100Maximum concurrent unidirectional QUIC streams per connection
max_response_body_bytesintegerNo104857600Hard cap on upstream response body bytes per stream; streams exceeding this return 503 (upstream response body too large)
max_request_body_bytesintegerNo1000000Hard cap on request body bytes per stream; requests exceeding this are rejected with 413. Must be ≤ quic_initial_max_stream_data
request_buffer_global_cap_bytesintegerNo67108864Global cap (bytes) for data buffered in request backpressure queues across a worker
unknown_length_response_prebuffer_bytesintegerNo2097152Max bytes buffered for unknown-length upstream responses before headers are emitted; responses exceeding this are terminated with an overload response
client_body_idle_timeout_msintegerNo10000Idle timeout (ms) for request-body upload progress; the stream is failed if no body bytes arrive within this period

Connection Flood Protection​

new_connections_per_sec and new_connections_burst implement a token-bucket rate limiter on new QUIC connection accepts. The bucket starts full and permits the configured initial burst. The limit does not affect packets for existing connections; it gates only unknown Initial packets that create connection state.

max_active_connections separately limits total connection state, including when the token bucket permits a temporary burst.

performance:
new_connections_per_sec: 2000 # refill rate: 2 k new conns/sec
new_connections_burst: 500 # allow a burst of up to 500 above the rate
max_active_connections: 20000 # hard ceiling for concurrently tracked connections

Lower values throttle connection floods more aggressively but can reject legitimate concurrent handshakes.

Examples​

# Single-worker, conservative limits
performance:
worker_threads: 1
global_inflight_limit: 1024
new_connections_per_sec: 500
new_connections_burst: 100

# High-throughput multi-worker setup
performance:
worker_threads: 8
reuseport: true
pin_workers: true
global_inflight_limit: 16384
per_upstream_inflight_limit: 4096
per_backend_inflight_limit: 256
new_connections_per_sec: 10000
new_connections_burst: 2000

Operational Implications​

  • worker_threads, reuseport, and shard settings shape how ingress work spreads across cores.
  • inflight limits, timeouts, and body caps define overload behavior as much as raw performance.
  • DNS refresh and connection-pool settings affect how quickly backend changes are observed.

Common Mistakes​

  • raising inflight limits without validating backend capacity and timeout posture
  • setting very high body caps without thinking about memory pressure
  • enabling aggressive multi-worker tuning before baseline observability is in place

Resilience Configuration​

resilience contains local overload protection, retry/hedge behavior, scoped rate limits, distributed quota, protocol policy, and the worker watchdog.

FieldTypeRequiredDefaultMeaning
adaptive_admissionobjectNoobject defaultsDynamic local inflight ceiling.
route_queueobjectNoobject defaultsPer-upstream and global concurrent admission caps.
scoped_rate_limitsarrayNo[]Per-instance token-bucket rules.
quotaobjectNoobject defaultsIn-memory or Redis-backed quota contracts.
protocolobjectNoobject defaultsRequest-shape, early-data, and CONNECT policy.
circuit_breakerobjectNoobject defaultsPer-backend failure isolation.
hedgingobjectNoobject defaultsDelayed speculative requests.
retry_budgetobjectNoobject defaultsRetry-amplification limits.
brownoutobjectNoobject defaultsPressure-triggered non-core shedding.
watchdogobjectNoobject defaultsWorker-health and restart policy.

The exact fields, defaults, constraints, retry behavior, selector matrix, quota failure semantics, and complete example are in Resilience, Rate Limits, and Quota. Redis deployment and incident guidance is intentionally separate in Distributed Quota Operations.

Observability and Control​

observability configures the metrics listener, the HTTPS Control API, OpenTelemetry tracing, and route-decision transparency. security.privileges configures the post-bind Unix privilege drop.

FieldTypeRequiredDefaultMeaning
observability.metricsobjectNoobject defaultsPrometheus endpoint bind, path, connection limits, and remote-mTLS opt-in.
observability.control_apiobjectNoobject defaultsAdministrative listener, paths, TLS client auth, bearer auth, RBAC, source policy, audit, and limits.
observability.tracingobjectNoobject defaultsOTLP endpoint, service name, and sample ratio.
observability.routingobjectNoobject defaultsRoute-decision logging and transparency controls.
security.privilegesobjectNoobject defaultsPost-bind process user and group.

The exact fields, defaults, constraints, complete security policy, and privilege-dropping behavior are in Observability and Control Configuration. HTTP endpoint methods, payloads, responses, and status codes remain in the Control API Reference; metric names and labels remain in the Metrics Reference.

Routing Transparency​

observability.routing enables explicit route-decision logging.

FieldTypeRequiredDefaultMeaning
enabledbooleanNofalseEmit route-decision transparency logs
include_reasonbooleanNotrueInclude deterministic tie-break reason in route-decision logs
expose_headerbooleanNofalseReserved toggle for downstream route-decision response headers
header_namestringNo"x-impulse-route-decision"Reserved header name; must be non-empty when expose_header=true

Watchdog Restart Hook​

Use structured command execution:

  • resilience.watchdog.restart_command: array, where index 0 is executable and remaining entries are arguments.

Legacy resilience.watchdog.restart_hook is deprecated and rejected by validation.

Common Mistakes​

  • exposing the Control API on 0.0.0.0 for convenience
  • assuming health and readiness endpoints are enough protection for admin-plane exposure
  • using the legacy reload shortcut when staged validate/preview/activate flows are the safer operational path

Configuration Validation​

Impulse validates configuration at startup and reports errors before attempting to start the server.

Common Validation Errors​

  1. Missing required fields

    • Neither listen.tls.cert/key nor listen.tls.certificates specified
    • Backend address or ID missing
    • Route configuration empty
  2. Invalid file paths

    • TLS certificate file not found or not readable
    • TLS key file not found or not readable
    • Incorrect file permissions
  3. Invalid values

    • Port number out of range (1-65535)
    • Invalid backend address format (accepted: host:port, https://host:port, http://host:port, or bare host; scheme-default port is inferred when omitted)
    • Backend weight outside 1–1000
  4. Configuration conflicts

    • Duplicate effective listener (address, port) values
    • Duplicate normalized route matchers
    • Duplicate normalized backend origins
    • Brownout recover_inflight_percent ≥ trigger_inflight_percent
    • adaptive_admission.min_limit set to 0
    • retry_budget.ratio_percent > 100
    • hedging.enabled with delay_ms = 0

Testing Configuration​

There is no validation-only CLI flag. Running Impulse with a valid configuration continues into runtime initialization, binds the configured listeners, and keeps the process running. It does not exit after validation.

Use one of these workflows instead:

  1. Controlled startup: copy the candidate config to an isolated host or change every listener and observability bind to non-production addresses and ports. Start Impulse in the foreground, wait for its listening/ready log, then stop it with Ctrl-C.
  2. Staged Control API: on a running instance, submit the same candidate to POST /admin/runtime/validate, then /preview, and finally /activate only after reviewing the returned plan and rejected changes. Validate and preview do not replace the active runtime; activate does.

Controlled-startup example:

impulse --config /etc/impulse/config-validation.yaml

An unreadable or invalid explicitly supplied configuration produces a fatal startup error and exits with status 1. A valid configuration has no automatic success exit status because the server remains running; reaching the listening/ready state is the success signal. Stop the isolated process after that signal. A later bind or runtime-initialization failure is also a failed startup, even if schema validation succeeded. If --config is omitted and the default /etc/impulse/config.yaml does not exist, Impulse exits with status 2.

For the staged workflow, do not treat HTTP status alone as the validation result: /admin/runtime/validate can return 200 with rejected changes. Inspect candidate_status and rejected_changes before previewing or activating. See the Control API Reference for request and response details.

Complete Examples​

Use Configuration Examples for complete deployment files and Routing and Upstreams for the canonical routed backend-pool example.