Skip to content

Http

HTTP Server Configuration

Global configuration for HTTP endpoints (REST, monitoring, GraphQL) using named sockets. Channels bind to sockets by name; transport options are defined once per socket.

Inheritable settings (http {} → http.sockets.<name> {}):

  • concurrency-limit, content-encoding, protocols, shutdown
  • idle-connection-period, idle-connection-timeout

These settings are also inherited by:

  • http.sockets.<name> {} (named sockets)
  • monitoring.http {} (monitoring endpoint overrides)
  • channels.rest.http {} (REST API endpoint overrides)
  • channels.graphql {} (GraphQL API endpoint overrides)

By default, all endpoints use the @default socket (http.port/http.host). To put monitoring on a separate socket, define one under http.sockets.* and point monitoring.socket at it (example below).

Example: keep REST on @default (:8080), move monitoring to :9001

http.sockets.monitoring { port = 9001 }
monitoring.socket = "monitoring"

To override per-channel HTTP settings, use the channel’s http sub-section: monitoring.http { … } channels.rest.http { … }

Concurrency limiting using AIMD (Adaptive Increase Multiplicative Decrease). Protects against request overload by dynamically adjusting concurrent request permits. Inherited by named sockets (http.sockets.<name> {}) unless overridden. When requests timeout, permits are reduced by backoff-ratio. When requests succeed, permits are slowly increased. Auto-derived defaults (based on global concurrency + DB query permits): Let:

  • C = global concurrency
  • P = database channel query permits (queryMaxConnectionPermits, defaults to database.channel-pool-size)

Defaults:

  • min-limit: max(10, C)
  • max-limit: max(min-limit, P * 2)
  • initial-limit: clamp(P, min-limit, max-limit)
  • queue-length: max-limit

Rationale:

  • DB permits already throttle query throughput, so HTTP limits should prevent unbounded waiting herd
  • Bounds scale with database capacity (P) rather than CPU-only heuristics
  • AIMD backs off automatically if requests start timing out

Examples (assumes default P = database.channel-pool-size = C):

concurrencyminmaxinitialqueue
810161016
1616321632
505010050100
100100200100200
200200400200400

Setting an env var overrides auto; not setting it keeps auto behavior.

Multiplier for permit reduction on timeout (0.5-1.0). Lower values = more aggressive backoff. Default: 0.75

PropertyValue
Default0.75
OverrideSCRIBE_HTTP_CONCURRENCY_BACKOFF_RATIO (optional)
http.concurrency-limit.backoff-ratio = 0.75
http.concurrency-limit.backoff-ratio = ${?SCRIBE_HTTP_CONCURRENCY_BACKOFF_RATIO}

Starting permit count.

Auto: queryMaxConnectionPermits (clamped to [min, max])

PropertyValue
OverrideSCRIBE_HTTP_CONCURRENCY_INITIAL (optional)
http.concurrency-limit.initial-limit = ${?SCRIBE_HTTP_CONCURRENCY_INITIAL}

Maximum permits (ceiling during increase).

Auto: max(min-limit, queryMaxConnectionPermits * 2)

PropertyValue
OverrideSCRIBE_HTTP_CONCURRENCY_MAX (optional)
http.concurrency-limit.max-limit = ${?SCRIBE_HTTP_CONCURRENCY_MAX}

Minimum permits (floor during backoff).

Auto: max(10, concurrency)

PropertyValue
OverrideSCRIBE_HTTP_CONCURRENCY_MIN (optional)
http.concurrency-limit.min-limit = ${?SCRIBE_HTTP_CONCURRENCY_MIN}

Requests to queue when at max permits (0 = no queueing).

Auto: max-limit

PropertyValue
OverrideSCRIBE_HTTP_CONCURRENCY_QUEUE_LENGTH (optional)
http.concurrency-limit.queue-length = ${?SCRIBE_HTTP_CONCURRENCY_QUEUE_LENGTH}

Maximum time to wait in queue before rejecting with 503.

Default: 1s

PropertyValue
Default1s
OverrideSCRIBE_HTTP_CONCURRENCY_QUEUE_TIMEOUT (optional)
http.concurrency-limit.queue-timeout = 1s
http.concurrency-limit.queue-timeout = ${?SCRIBE_HTTP_CONCURRENCY_QUEUE_TIMEOUT}

Request timeout; exceeding this triggers AIMD backoff. Helidon default is 5s; we use 2s for responsive backpressure. Set higher (e.g., 5s-10s) for slow endpoints, lower for fast APIs.

PropertyValue
Default2s
OverrideSCRIBE_HTTP_CONCURRENCY_TIMEOUT (optional)
http.concurrency-limit.timeout = 2s
http.concurrency-limit.timeout = ${?SCRIBE_HTTP_CONCURRENCY_TIMEOUT}

Connection limits.

Inherited by named sockets (http.sockets.<name> {}) unless overridden.

http.connection-limits.max-concurrent-requests

Section titled “http.connection-limits.max-concurrent-requests”

Maximum concurrent HTTP requests across all connections. Unset or null = unlimited. Use -1 in env vars for unlimited.

Default: unlimited

Priority: SCRIBE_HTTP_MAX_CONCURRENT_REQUESTS > config

PropertyValue
Default500
OverrideSCRIBE_HTTP_MAX_CONCURRENT_REQUESTS (optional)
http.connection-limits.max-concurrent-requests = ${?SCRIBE_HTTP_MAX_CONCURRENT_REQUESTS}

http.connection-limits.max-tcp-connections

Section titled “http.connection-limits.max-tcp-connections”

Maximum concurrent TCP connections.

Unset or null = unlimited. Use -1 in env vars for unlimited.

Default: unlimited

Priority: SCRIBE_HTTP_MAX_TCP_CONNECTIONS > config

PropertyValue
Default1000
OverrideSCRIBE_HTTP_MAX_TCP_CONNECTIONS (optional)
http.connection-limits.max-tcp-connections = ${?SCRIBE_HTTP_MAX_TCP_CONNECTIONS}

Content encoding configuration.

Inherited by named sockets (http.sockets.<name> {}) unless overridden.

Why: gzip reduces bandwidth at the cost of CPU. Disable for endpoints where

compression hurts more than it helps (e.g., Prometheus /metrics).

Gzip compression for response bodies.

Enable gzip compression.

Priority: SCRIBE_HTTP_GZIP_ENABLED > config

PropertyValue
Defaulttrue
OverrideSCRIBE_HTTP_GZIP_ENABLED (optional)
http.content-encoding.gzip.enabled = true
http.content-encoding.gzip.enabled = ${?SCRIBE_HTTP_GZIP_ENABLED}

CORS (Cross-Origin Resource Sharing) configuration.

Inherited by named sockets (http.sockets.<name>.cors {}) unless overridden. CORS applies to ALL routes on the socket. If you want monitoring endpoints to remain non-CORS, run monitoring on a separate socket. List settings accept arrays or comma-separated strings (for env vars):

allow-origins = ["https://a.com", "https://b.com"]
SCRIBE_HTTP_CORS_ALLOW_ORIGINS = "https://a.com,https://b.com"

Allow credentials (cookies, Authorization header).

Cannot be true when allow-origins contains ”*”.

Default: false

Priority: SCRIBE_HTTP_CORS_ALLOW_CREDENTIALS > config

PropertyValue
Defaultfalse
OverrideSCRIBE_HTTP_CORS_ALLOW_CREDENTIALS (optional)
http.cors.allow-credentials = false
http.cors.allow-credentials = ${?SCRIBE_HTTP_CORS_ALLOW_CREDENTIALS}

Headers the client may send. Grouped: content, auth, conditional, preferences, correlation, W3C tracing.

Priority: SCRIBE_HTTP_CORS_ALLOW_HEADERS > config

allow-headers = [
# Content negotiation
"Accept", "Content-Type",
# Authentication
"Authorization",
# Conditional requests (RFC 7232)
"If-Match", "If-Modified-Since", "If-None-Match", "If-Unmodified-Since",
# Preferences (RFC 7240)
"Prefer",
# Request correlation
"Correlation-Id", "Request-Id",
# W3C Trace Context
"baggage", "traceparent", "tracestate"
]
PropertyValue
OverrideSCRIBE_HTTP_CORS_ALLOW_HEADERS (optional)
http.cors.allow-headers = ${?SCRIBE_HTTP_CORS_ALLOW_HEADERS}

Allowed HTTP methods.

Default: GET, POST, PUT, DELETE, PATCH, OPTIONS

Priority: SCRIBE_HTTP_CORS_ALLOW_METHODS > config

allow-methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
PropertyValue
OverrideSCRIBE_HTTP_CORS_ALLOW_METHODS (optional)
http.cors.allow-methods = ${?SCRIBE_HTTP_CORS_ALLOW_METHODS}

Allowed origins. Accepts:

  • Explicit origins: [“https://example.com”, “https://app.example.com”]
  • Magic values (single value, mutually exclusive, cannot mix with explicit):
    • “same-origin” - only allow if Origin header matches socket’s scheme://host:port
    • “host” - always respond with socket’s scheme://host:port as allowed origin

(useful behind reverse proxy; browser enforces match)

  • “origin” - reflect the Origin header value (dangerous, allows any origin)
  • ”*” - wildcard, allow all origins (cannot use with credentials)

Default: [“same-origin”] (when enabled)

Priority: SCRIBE_HTTP_CORS_ALLOW_ORIGINS > config

allow-origins = ["https://example.com"]
PropertyValue
OverrideSCRIBE_HTTP_CORS_ALLOW_ORIGINS (optional)
http.cors.allow-origins = ${?SCRIBE_HTTP_CORS_ALLOW_ORIGINS}

Enable CORS for this socket.

Default: false

Priority: SCRIBE_HTTP_CORS_ENABLED > config

PropertyValue
Defaultfalse
OverrideSCRIBE_HTTP_CORS_ENABLED (optional)
http.cors.enabled = false
http.cors.enabled = ${?SCRIBE_HTTP_CORS_ENABLED}

Headers the client may read from responses. Grouped: caching, standard HTTP, errors, preferences, correlation/telemetry.

Priority: SCRIBE_HTTP_CORS_EXPOSE_HEADERS > config

expose-headers = [
# Caching (RFC 7234)
"Cache-Control", "ETag", "Last-Modified", "Vary",
# Standard HTTP
"Date", "Location", "Retry-After",
# Error headers
"Error-Code", "Error-Id", "Error-Kind",
# Preferences (RFC 7240)
"Preference-Applied",
# Correlation / Telemetry
"Correlation-Id", "Request-Id", "Span-Id", "Trace-Id"
]
PropertyValue
OverrideSCRIBE_HTTP_CORS_EXPOSE_HEADERS (optional)
http.cors.expose-headers = ${?SCRIBE_HTTP_CORS_EXPOSE_HEADERS}

How long preflight results can be cached (seconds).

Default: 1 hour

Priority: SCRIBE_HTTP_CORS_MAX_AGE > config

PropertyValue
Default1h
OverrideSCRIBE_HTTP_CORS_MAX_AGE (optional)
http.cors.max-age = 1h
http.cors.max-age = ${?SCRIBE_HTTP_CORS_MAX_AGE}

Host to bind to for the default socket.

host = auto resolves based on app.mode:
  • dev/test/local: localhost
  • production: 0.0.0.0

To bind all interfaces explicitly, set host = “0.0.0.0”.

Priority: SCRIBE_HTTP_HOST > config

PropertyValue
Defaultauto
OverrideSCRIBE_HTTP_HOST (optional)
http.host = auto
http.host = ${?SCRIBE_HTTP_HOST}

Idle connection management.

Inherited by named sockets (http.sockets.<name> {}) unless overridden.

Why: closes idle keep-alive connections to free server resources.

How:

  • idle-connection-period: scan interval
  • idle-connection-timeout: close connections idle longer than this
PropertyValue
Default2m
http.idle-connection-period = 2m

PropertyValue
Default5m
http.idle-connection-timeout = 5m

@default socket binding - primary HTTP endpoint Port for the default HTTP socket.

Priority: SCRIBE_HTTP_PORT > config

PropertyValue
Default8080
OverrideSCRIBE_HTTP_PORT (optional)
http.port = 8080
http.port = ${?SCRIBE_HTTP_PORT}

HTTP protocol configuration.

Inherited by named sockets (http.sockets.<name> {}) unless overridden. HTTP/1.1 and HTTP/2 can be enabled at the same time. When both are enabled, the server negotiates HTTP/2 when supported (typically via TLS ALPN) and falls back to HTTP/1.1 otherwise.

HTTP/1.1 settings.

PropertyValue
Defaulttrue
http.protocols.http-1-1.enabled = true

Maximum total headers size (bytes).

PropertyValue
Default16384
http.protocols.http-1-1.max-headers-size = 16384

http.protocols.http-1-1.max-prologue-length

Section titled “http.protocols.http-1-1.max-prologue-length”

Maximum request line + headers length (bytes).

PropertyValue
Default8192
http.protocols.http-1-1.max-prologue-length = 8192

HTTP/2 settings.

HTTP/2 is disabled by default.

Priority: SCRIBE_HTTP2_ENABLED > config

PropertyValue
Defaultfalse
OverrideSCRIBE_HTTP2_ENABLED (optional)
http.protocols.http-2.enabled = false
http.protocols.http-2.enabled = ${?SCRIBE_HTTP2_ENABLED}

Initial flow control window size (bytes).

PropertyValue
Default65535
http.protocols.http-2.initial-window-size = 65535

http.protocols.http-2.max-concurrent-streams

Section titled “http.protocols.http-2.max-concurrent-streams”

Maximum concurrent streams per connection.

PropertyValue
Default100
http.protocols.http-2.max-concurrent-streams = 100

Maximum frame size (bytes).

PropertyValue
Default16384
http.protocols.http-2.max-frame-size = 16384

Request size limits.

Inherited by named sockets (http.sockets.<name> {}) unless overridden.

Maximum entity size to buffer in memory (bytes). Larger entities are streamed to disk. Must fit in int (max 2GiB). Use HOCON memory-size syntax: “128KiB”, “1MiB”.

Default: 128KiB

Priority: SCRIBE_HTTP_MAX_IN_MEMORY_ENTITY > config

PropertyValue
Default128KiB
OverrideSCRIBE_HTTP_MAX_IN_MEMORY_ENTITY (optional)
http.request-limits.max-in-memory-entity = 128KiB
http.request-limits.max-in-memory-entity = ${?SCRIBE_HTTP_MAX_IN_MEMORY_ENTITY}

Maximum request payload size (bytes). Use HOCON memory-size syntax: “10MiB”, “100KiB”, “1GiB”. Unset or null = unlimited. Use -1 in env vars for unlimited.

Default: unlimited

Priority: SCRIBE_HTTP_MAX_PAYLOAD_SIZE > config

PropertyValue
Default10MiB
OverrideSCRIBE_HTTP_MAX_PAYLOAD_SIZE (optional)
http.request-limits.max-payload-size = ${?SCRIBE_HTTP_MAX_PAYLOAD_SIZE}

Proxy header support for load balancer deployments. Enables extraction of original client IP from Forwarded/X-Forwarded-* headers. Named sockets inherit these settings unless overridden.

Enable proxy header discovery.

Default: false

Priority: SCRIBE_HTTP_PROXY_ENABLED > config

PropertyValue
Defaultfalse
OverrideSCRIBE_HTTP_PROXY_ENABLED (optional)
http.requested-uri-discovery.enabled = false
http.requested-uri-discovery.enabled = ${?SCRIBE_HTTP_PROXY_ENABLED}

http.requested-uri-discovery.trusted-proxies

Section titled “http.requested-uri-discovery.trusted-proxies”

Trusted proxy addresses. REQUIRED when enabled to prevent IP spoofing. Proxies are matched by their connection peer IP address. Accepts array or comma-separated string (for env vars).

http.requested-uri-discovery.trusted-proxies.exact

Section titled “http.requested-uri-discovery.trusted-proxies.exact”

Exact IP addresses or CIDR ranges.

Use this for IP-based matching (recommended).

Default: none (required when discovery enabled)

Example: [“10.0.0.0/8”, “192.168.1.100”]

Priority: SCRIBE_HTTP_PROXY_EXACT > config

exact = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
PropertyValue
OverrideSCRIBE_HTTP_PROXY_EXACT (optional)
http.requested-uri-discovery.trusted-proxies.exact = ${?SCRIBE_HTTP_PROXY_EXACT}

http.requested-uri-discovery.trusted-proxies.pattern

Section titled “http.requested-uri-discovery.trusted-proxies.pattern”

Regex patterns matched against the peer IP string. For advanced matching; prefer ‘exact’ with CIDRs for IP ranges.

Default: none

Example: [“^10\..*”, “192\.168\.1\.\d+”]

Priority: SCRIBE_HTTP_PROXY_PATTERN > config

pattern = ["^10\\..*"]
PropertyValue
OverrideSCRIBE_HTTP_PROXY_PATTERN (optional)
http.requested-uri-discovery.trusted-proxies.pattern = ${?SCRIBE_HTTP_PROXY_PATTERN}

Discovery types: FORWARDED (RFC 7239), X_FORWARDED (X-Forwarded-*) Accepts array or comma-separated string (for env vars).

Default: [“FORWARDED”, “X_FORWARDED”] (both enabled)

Priority: SCRIBE_HTTP_PROXY_TYPES > config

PropertyValue
Default["FORWARDED", "X_FORWARDED"]
OverrideSCRIBE_HTTP_PROXY_TYPES (optional)
http.requested-uri-discovery.types = ["FORWARDED", "X_FORWARDED"]
http.requested-uri-discovery.types = ${?SCRIBE_HTTP_PROXY_TYPES}

Graceful shutdown configuration.

Inherited by named sockets (http.sockets.<name> {}) unless overridden.

Time to drain active connections before force close.

Priority: SCRIBE_HTTP_SHUTDOWN_GRACE_PERIOD > config

PropertyValue
Default30s
OverrideSCRIBE_HTTP_SHUTDOWN_GRACE_PERIOD (optional)
http.shutdown.grace-period = 30s
http.shutdown.grace-period = ${?SCRIBE_HTTP_SHUTDOWN_GRACE_PERIOD}

Named sockets (optional, inherit from http )


SSL/TLS for the HTTP server. Uses same PEM-based format as ldap.ssl. Named sockets inherit these settings unless overridden.

CA certificate (PEM) for client cert verification (mTLS). Required when client-auth is OPTIONAL or REQUIRED.

Default: none

Priority: SCRIBE_HTTP_SSL_CA > config

PropertyValue
Default"/path/to/ca.pem"
OverrideSCRIBE_HTTP_SSL_CA (optional)
http.ssl.ca = ${?SCRIBE_HTTP_SSL_CA}

Server certificate (PEM) - required when enabled.

Default: none (required when enabled=true)

Priority: SCRIBE_HTTP_SSL_CERT > config

PropertyValue
Default"/path/to/server.pem"
OverrideSCRIBE_HTTP_SSL_CERT (optional)
http.ssl.cert = ${?SCRIBE_HTTP_SSL_CERT}

Cipher suites to enable. Accepts array or comma-separated string (for env vars).

Default:

TLS 1.3: TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256, TLS_CHACHA20_POLY1305_SHA256

TLS 1.2: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, …

See: https://docs.oracle.com/en/java/javase/21/security/java-security-standard-algorithm-names.html

Example: [“TLS_AES_256_GCM_SHA384”] or “TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256”

Priority: SCRIBE_HTTP_SSL_CIPHER_SUITES > config

cipher-suites = ["TLS_AES_256_GCM_SHA384", "TLS_AES_128_GCM_SHA256"]
PropertyValue
OverrideSCRIBE_HTTP_SSL_CIPHER_SUITES (optional)
http.ssl.cipher-suites = ${?SCRIBE_HTTP_SSL_CIPHER_SUITES}

Client certificate mode for mTLS: NONE - don’t request client certs (default) OPTIONAL - request but proceed without REQUIRED - require valid client cert

Default: NONE

Priority: SCRIBE_HTTP_SSL_CLIENT_AUTH > config

PropertyValue
Default"NONE"
OverrideSCRIBE_HTTP_SSL_CLIENT_AUTH (optional)
http.ssl.client-auth = "NONE"
http.ssl.client-auth = ${?SCRIBE_HTTP_SSL_CLIENT_AUTH}

Enable HTTPS for this socket.

Default: false

Priority: SCRIBE_HTTP_SSL_ENABLED > config

PropertyValue
Defaultfalse
OverrideSCRIBE_HTTP_SSL_ENABLED (optional)
http.ssl.enabled = false
http.ssl.enabled = ${?SCRIBE_HTTP_SSL_ENABLED}

Private key (PEM) - required when enabled.

Default: none (required when enabled=true)

Priority: SCRIBE_HTTP_SSL_KEY > config

PropertyValue
Default"/path/to/server.key"
OverrideSCRIBE_HTTP_SSL_KEY (optional)
http.ssl.key = ${?SCRIBE_HTTP_SSL_KEY}

Maximum depth for client certificate chain validation.

Default: 10

Priority: SCRIBE_HTTP_SSL_MAX_CERT_CHAIN_LENGTH > config

PropertyValue
Default10
OverrideSCRIBE_HTTP_SSL_MAX_CERT_CHAIN_LENGTH (optional)
http.ssl.max-cert-chain-length = 10
http.ssl.max-cert-chain-length = ${?SCRIBE_HTTP_SSL_MAX_CERT_CHAIN_LENGTH}

Private key password (if encrypted).

Default: none (unencrypted key)

Priority: SCRIBE_HTTP_SSL_PASSWORD > config

PropertyValue
OverrideSCRIBE_HTTP_SSL_PASSWORD (optional)
http.ssl.password = ${?SCRIBE_HTTP_SSL_PASSWORD}

TLS protocols to enable. Accepts array or comma-separated string (for env vars).

Default: TLSv1.3, TLSv1.2

Example: [“TLSv1.3”, “TLSv1.2”] or “TLSv1.3,TLSv1.2”

Priority: SCRIBE_HTTP_SSL_PROTOCOLS > config

protocols = ["TLSv1.3", "TLSv1.2"]
PropertyValue
OverrideSCRIBE_HTTP_SSL_PROTOCOLS (optional)
http.ssl.protocols = ${?SCRIBE_HTTP_SSL_PROTOCOLS}