Configuration Reference¶
Illustrative mutation fragments
The management mutations on this page are non-standalone fragments. Before adapting them, follow this site's Example Quality Contract and complete Quickstart lifecycle. Do not treat HTTP success or management readback alone as runtime proof.
The public contract reference for the serviceArguments object (and its
endpoints[] and mtls_* sub-objects) used to create an AI Gateway load-balancer rule via
POST /netlox/v1/config/loadbalancer. The tables follow the current API schema together with the
server's engine-coherence and topology validation. Invalid combinations fail before a rule is
created; a client must not assume that every individually valid field can be combined.
A load-balancer create body has three top-level keys:
{
"serviceArguments": {
"externalIP": "192.0.2.10",
"port": 8080,
"protocol": "tcp",
"mode": 4
},
"endpoints": [
{ "endpointIP": "198.51.100.11", "targetPort": 8000, "weight": 1 }
],
"secondaryIPs": []
}
serviceArguments carries the VIP, the L4/L7 behaviour, and every AI-routing knob. endpoints
carries the backend pool. This page documents both.
Prerequisite for AI routing
All AI routing behaviour (model-name pools, CHWBL, KV-cache routing, P/D disaggregation,
SSE) requires mode: 4 (fullproxy). Set mode: 4 on every AI rule.
How to read the tables
Type uses the schema's own format (e.g. int32, int64, uint32). A Default of
— means the field is optional with no server-applied default (unset = feature off /
backward-compatible). Enum values are listed as value-meaning.
1. Core service fields¶
The VIP, ports, protocol, mode, security, selection algorithm, and L7 host/path matching. These apply to every rule, AI or not.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
externalIP |
string | — | any IPv4/IPv6 | The VIP (virtual IP) clients connect to. Nullable. |
privateIP |
string | — | any IP | Private (NAT'd) address for external access. |
port |
integer | — | 1–65535 | (Min) service port. Nullable. |
portMax |
integer | — | ≥ port |
Max port of a range. Omit for a single port. |
protocol |
string | — | tcp, udp, sctp, icmp |
L4 protocol. AI/L7 rules use tcp. |
sel |
integer | 0 |
0–10 (see §2) |
Load-balance algorithm. 8=CHWBL, 9=gpuaware, 10=wrr-hash. |
mode |
int32 | 0 |
0–5 (see §2) |
NAT/proxy mode. 4=fullproxy is the AI prerequisite. |
security |
int32 | 0 |
0–2 (see §8) |
TLS mode: 0=plain HTTP, 1=frontend TLS termination with an HTTP backend, 2=frontend TLS termination plus TLS re-encryption to the backend. |
host |
string | — | hostname / FQDN | L7 Ingress host to match (SNI / Host header). |
path_prefix |
string | — | URL path (e.g. /v1/chat) |
L7 path prefix. Empty = hostname-only matching. |
path_match_mode |
string | disabled |
disabled, prefix, exact |
disabled=host-only (compat), prefix=longest-prefix, exact=exact path. |
name |
string | — | free text | Human-readable service name. |
bgp |
boolean | false |
true/false |
Advertise the VIP over BGP. |
monitor |
boolean | false |
true/false |
Enable endpoint health monitoring. |
managed |
boolean | false |
true/false |
Rule is externally managed (e.g. by an operator). |
snat |
boolean | false |
true/false |
Mark as an SNAT rule. |
egress |
boolean | false |
true/false |
Mark as an egress rule. |
proxyprotocolv2 |
boolean | false |
true/false |
Emit PROXY protocol v2 to backends. |
sockMapMode |
string | off |
off, request, response, both |
Experimental directional sockmap relay acceleration. Non-off requires plaintext IPv4 TCP fullproxy, daemon --sockmapsupport, and no sse_mode, P/D, api_key_auth declaration, or attached L7 policy. HTTP/2/h2c is never accelerated. See Sockmap Acceleration. |
oper |
int32 | 0 |
0-create, 1-attachEP, 2-detachEP |
Endpoint-specific operation for incremental EP edits. |
block |
uint32 | — | any | Block-number grouping for this LB entry. |
id |
string | minted | UUIDv4 if absent | Stable opaque rule identifier (Octavia). |
adminStateUp |
boolean | true |
true/false |
Lifecycle flag; false pauses the rule. |
projectId |
string | — | opaque | Tenant/project id. Not a tenant-isolation boundary. |
connectionLimit |
uint32 | 0 (unlimited) |
≥0 | Per-rule concurrent-connection ceiling, counted across all of the rule's endpoints. Enforced by the conntrack selector on DNAT-mode rules: at the ceiling, further SYNs are dropped without a reset, and a slot frees when a connection is torn down. A mode: 4 fullproxy rule is not gated by this field, and HTTP/2 streams are not counted as connections; bound fullproxy connections with LLB_PD_MAX_TOTAL_INFLIGHT and see Admission Flow Control. POST stores it, PATCH overlays it when present (an explicit 0 clears it), null is rejected. |
cb_enable |
boolean | false |
true/false |
Enable the fullproxy per-endpoint circuit breaker. The default connect-failure threshold is five with a 30-second open period. Origin-5xx demotion uses a separate threshold; P/D rules can enable breaker behavior automatically. |
vip_qos_policy_id |
string | empty | existing /config/policy identifier |
Associate a pre-created policy with the LB rule. Empty is a no-op; an unknown identifier makes creation fail. The policy must be created first. |
annotations |
object (string→string) | — | opaque map | Round-trips arbitrary Octavia fields verbatim; never interpreted. |
2. Selection algorithm (sel) and mode (mode) enums¶
sel — load-balance algorithm (default 0)¶
| Value | Name | Meaning |
|---|---|---|
0 |
rr | Round-robin (default). |
1 |
hash | Flow hash. |
2 |
priority / wrr | Weighted round-robin by endpoint weight. |
3 |
persist | Session persistence (see session_header_name, §7). |
4 |
lc | Least connections. |
5 |
n2 | Reserved selection variant. |
6 |
n3 | Reserved selection variant. |
7 |
reserved | Reserved (do not use). |
8 |
chwbl | Consistent-hash-with-bounded-load — the AI prefix-cache router (see §5). |
9 |
gpuaware | Plain fullproxy uses prefix/conversation affinity and healthy-endpoint fallback. A P/D capacity scorer exists, but its activation is release-blocked because the current gate checks a mutable endpoint cursor instead of the configured selector. |
10 |
wrr-hash | Weighted CHWBL hashing; endpoint weights apply, while stored chwbl_* tuning values are not currently propagated (§5). |
mode — NAT / proxy mode (default 0)¶
| Value | Name | Meaning |
|---|---|---|
0 |
DNAT | Destination NAT (default). |
1 |
onearm | One-arm. |
2 |
fullnat | Full NAT. |
3 |
dsr | Direct server return. |
4 |
fullproxy | L7 full proxy — required for all AI routing. |
5 |
hostonearm | Host one-arm. |
3. AI model routing, tracing & streaming¶
model_name selects the backend pool for a request; the SSE knobs govern streaming lifecycle.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
model_name |
string | — (""=wildcard) |
any model id | Endpoint-pool selection key (e.g. llama-70b). Empty string = wildcard pool (matches any). |
backend_protocol |
string | http1 |
http1, http2, both |
ALPN negotiation. http1=HTTP/1.1 only (safest), http2=HTTP/2 only, both=either. |
trace_type |
string | — | e.g. v1, anthropic, default |
Tracing catalog for deep body inspection/parser invocation. Field only — no dedicated endpoint. |
sse_mode |
boolean | false |
true/false |
Enable SSE streaming: suppresses idle-timeout while a text/event-stream response is active. Required for OpenAI-compatible streaming. |
max_stream_duration_sec |
int32 | 0 |
≥0 | Absolute wall-clock cap (seconds) for an SSE stream. 0 = system hard cap of 86400 (24h). Set e.g. 300 to bound runaway streams. |
backend_keepalive_interval_sec |
int32 | 0 |
≥0 | Sets SO_KEEPALIVE+TCP_KEEPIDLE on the backend socket (seconds). 0 = disabled. Recommended 60 to survive cloud NAT during long SSE streams. |
SSE lifecycle and admission controls are enforced
SSE lifecycle handling is part of the fullproxy stream path and does not activate
authentication. api_key_auth independently selects omitted, disabled, required, jwt,
or apikey-or-jwt. A required API-key policy uses the PostgreSQL store configured by
--aikey-db-*; if it cannot evaluate the key, it fails closed with 503. Prove missing or
unknown key 401, store failure 503, and backend receipt delta 0 separately.
Capacity admission gate (fc_*)¶
These fields configure the capacity admission gate of an AI-gateway service (mode: 4 with
sse_mode, pd_disagg_mode, or an api_key_auth policy other than omitted or disabled). Every
one is optional. 0 (or
inherit) on a rule declares nothing, and the value then comes from the process environment
variable in the last column, else the product default. Every field is changeable at runtime by a
replace POST; explicit JSON null is refused. The full behavior is in
Admission Flow Control.
| Field | Type | Range / Enum | Process default | Notes |
|---|---|---|---|---|
fc_mode |
string | off, observe, enforce, inherit |
LLB_FC_MODE |
enforce refuses or queues a request over a ceiling; observe counts and admits; off bypasses the gate. Read back only when declared; the mode in force is fc_effective.mode. |
fc_max_outstanding |
int | 0–100000 |
LLB_FC_MAX_OUTSTANDING |
Pool-wide ceiling on executing requests. |
fc_ep_max_inflight |
int | 0–100000 |
LLB_FC_EP_MAX_INFLIGHT |
Per-endpoint ceiling, normal (non-P/D) role. |
fc_prefill_max_inflight |
int | 0–100000 |
LLB_FC_PREFILL_MAX_INFLIGHT, else LLB_PD_MAX_INFLIGHT_PER_EP |
Per-endpoint ceiling on prefill legs. |
fc_decode_max_inflight |
int | 0–100000 |
LLB_FC_DECODE_MAX_INFLIGHT |
Per-endpoint ceiling on decode legs. |
fc_max_queue_depth |
int | 0–65536 |
LLB_FC_MAX_QUEUE_DEPTH |
Requests that may wait. Depth × 1 MiB is the memory bound when full. HTTP/2 streams never wait. |
fc_max_queue_wait_ms |
int | 0–3600000 |
LLB_FC_MAX_QUEUE_WAIT_MS |
Longest wait before 504 admission_queue_timeout. Required, greater than 0, whenever a depth is set. |
fc_adaptive |
string | on, off, inherit |
LLB_FC_ADAPTIVE |
Let the service ceiling tighten on engine backpressure and climb back on fresh, clear signals. Stale telemetry never widens it. |
fc_ttft_target_ms |
int | 0–3600000 |
LLB_FC_TTFT_TARGET_MS |
With fc_adaptive on: a streamed time to first token above this is backpressure. 0 leaves it out. |
fc_telemetry_stale_ms |
int | 0–3600000 |
LLB_FC_TELEMETRY_STALE_MS, else 30000 |
How long a scraped queue depth or first-token average is trusted. |
fc_warmup_ms |
int | 0–3600000 |
LLB_FC_WARMUP_MS, else no ramp |
An endpoint back in service ramps its per-endpoint ceilings from a quarter to all over this window. |
fc_tenant_max_share_pct |
int | 0–100 |
LLB_FC_TENANT_MAX_SHARE_PCT, else no share |
The most of the ceiling in force and of the queue one tenant may hold. 100 is no share. Inert without fc_max_outstanding. |
fc_expose_headers |
string | on, off, inherit |
LLB_FC_EXPOSE_HEADERS |
Put the three X-Loxilb-Admission-* headers on admitted responses. Refused 400 with sockMapMode both or response. |
fc_effective |
object | read-only | — | The gate's resolved state on the rule's pool: values in force, live inflight and queued, adaptive state, and source (rule, env, or default) per value. Present on GET; ignored on input. |
Half-close hold (half_close_mode)¶
What a FullProxy service does with a client that half-closes (shuts down its write side) after sending its request.
| Field | Type | Enum | Default | Notes |
|---|---|---|---|---|
half_close_mode |
string | off, hold, hold+parked, inherit |
inherit (process default off) |
off cuts the client at its FIN. hold keeps it open until the answer is out, where the gateway relays the answer itself (a plaintext connection the kernel was never given to carry); the client is then closed once its answers are written, once the backend ends the answer's connection, when no answer byte has reached it for the hold bound, or on release. With sockMapMode other than off, a client whose FIN arrives before its connection is accelerated is not accelerated, so it can be held. hold+parked is refused 400 until it is available. hold is refused 400 unless the service is mode: 4 fullproxy, without TLS (security 1 or 2 are never held) and without pd_disagg_mode. Read back only when declared. |
The process-wide hold settings apply to every service whose mode is hold:
| Operation | Purpose |
|---|---|
GET /config/halfclose |
allow (whether new holds may be taken) and capSeconds (the idle bound on a hold, 1–3600). Until set, the defaults are in force: allowed, 240 seconds. |
POST /config/halfclose |
Set either field; an omitted field keeps its value, and a body with neither or with an unknown field is refused 400. allow: false blocks new holds only: clients already held stay held until their answers are out or the bound ends them. A new bound applies to every hold, those already held included. Kept across a restart and in a configuration snapshot. |
POST /config/halfclose/release |
Close every held client on every service within a second, as it would have been closed without the hold. An answer still on its way is lost. Nothing is stored: block new holds first to stop them. |
The bound's clock starts once the request has reached the backend and restarts with every write of
the answer. The loxilb_proxy_halfclose_* families report held clients, refused and expired holds
and the settings in force; see the generated Metrics reference.
4. KV-cache exact routing¶
Tier 1.5 block-hash routing between the trie (Tier 1) and min-load (Tier 2) tiers. The KV-hash contract is all-or-nothing: every knob below must match the serving engine exactly or hash overlap silently drops to zero. See KV-Cache Routing.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
kvExactMode |
int64 | 0 |
0–3 |
0=off; 1=P/D-coupled KV-exact routing and requires pd_disagg_mode: true; 2=reserved and not implemented; 3=single-role KV-exact routing and requires mode: 4 with P/D disabled. The transport is selected by kvEngineType, not by this number. |
kvBlockSize |
int64 | 16 |
≥1 | Token block size for hash computation. Must match vLLM --block-size, SGLang --page-size, or TensorRT-LLM tokens_per_block. TensorRT-LLM commonly uses 32 while this field defaults to 16, so verify it explicitly. |
kvHashAlgo |
string | derived | sha256_cbor, xxhash_cbor, sha256_sglang, blockhash_trtllm |
Prefer omission: the gateway derives the coherent engine default (vllm→sha256_cbor, sglang→sha256_sglang, trtllm→blockhash_trtllm). Explicit engine/algo mismatches and every explicit value for llama.cpp are rejected. |
kvZmqPort |
int64 | 5557 |
1–65535 |
Base ZMQ publisher port for vLLM/SGLang. Mode 1 subscribes prefill endpoints; mode 3 subscribes all endpoints. A meaningful non-default value is rejected for TensorRT-LLM and llama.cpp. |
kvWarmupSec |
int64 | 30 |
≥0 | Accepted but currently inert on all paths. Intended as a Tier 1.5 warmup delay after subscriber connect, but the timer is never armed in the shipped data path — Tier 1.5 activates without waiting. Do not design procedures around it. |
kvEngineType |
string | vllm |
vllm, sglang, trtllm, llamacpp |
Typed serving engine. Immutable after create; delete and recreate the rule to change it. Engine selection enables validation but does not imply feature parity. |
kvDpRankCount |
int32 | 1 |
1–8 |
SGLang data-parallel rank count. Rank N publishes at kvZmqPort+N; all ranks union into one per-endpoint inventory. Values above 1 are rejected for TensorRT-LLM and llama.cpp. |
kvExactApiMode |
string | profile surfaces or legacy both when omitted |
completions, chat, both |
REST-only scalar declaration. Requires kvExactMode: 1 or 3; immutable after create. With a bound profile, an explicit value must be a subset of supportedApis. |
kvModelProfile |
string | profile-less legacy mode when omitted | one published profile ID | REST-only scalar binding. Requires kvExactMode: 1 or 3; strict admission validates aliases and artifacts. Normally immutable; the sole exception is attaching a profile to a profile-less KV-exact rule. |
pdBootstrapPort |
int32 | 0 |
0–65535 |
SGLang P/D bootstrap port on each prefill endpoint. 0 uses SGLang's default 8998. A nonzero value requires pd_disagg_mode: true and kvEngineType: sglang; all other shapes are rejected. |
Strict profile configuration is REST-only
Current loxicmd create lb has no flags for kvExactApiMode or kvModelProfile. Discover
published profiles through REST, create the strict rule through REST, then verify the
dedicated kvexactstatus read model. See
Model Profiles and KV-Exact Readiness.
Engine and field coherence¶
| Engine | Supported routing shapes | Event transport | Required coherence / rejected fields |
|---|---|---|---|
vllm |
Plain L7 LB; single-role mode 3; sequential P/D with optional mode 1 | ZMQ | Use a vLLM hash algorithm and match block size and hash seed. pdBootstrapPort is rejected. |
sglang |
Plain L7 LB; single-role mode 3; concurrent P/D; optional P/D-coupled mode 1 | ZMQ, including per-rank ports | Omit kvHashAlgo or use only sha256_sglang. pdBootstrapPort is valid only for SGLang P/D. |
trtllm |
Plain L7 LB; single-role mode 3; sequential P/D with mode 1 | HTTP polling on each endpoint's serving port | The gateway must be the sole consumer of /kv_cache_events. Meaningful ZMQ and rank settings are rejected; match kvBlockSize to tokens_per_block. |
llamacpp |
Plain L7 LB with CHWBL or session affinity | None | KV-exact and P/D are unsupported. Explicit hash settings and meaningful KV transport, rank, or block-size overrides are rejected. |
Fail closed on incoherent engine settings
Treat a create-time rejection as a configuration defect; do not work around it by changing the engine name or disabling certificate verification. The validation prevents accepted-but-unused fields and silent hash mismatches.
vLLM hash-contract triad
All three legs must match the vLLM launch flags or hash overlap is 0%: NONE_HASH seed
(PYTHONHASHSEED == LLB_KV_NONE_HASH_SEED), hash algo (set vLLM
--prefix-caching-hash-algo=sha256_cbor — its default sha256 is non-portable), and block
size (--block-size == kvBlockSize). vLLM must also set
VLLM_KV_EVENTS_USE_INT_BLOCK_HASHES=1. Current Gateway main also requires a nonempty
Gateway seed of at most 23 bytes and returns HTTP 412 before mutation otherwise. Query the
REST-only GET /status/capabilities surface and require kv_exact_vllm.ready=true before
presenting or submitting the rule.
5. CHWBL / WRR-HASH tuning knobs¶
The REST model accepts and returns these fields for sel: 8 (CHWBL) and
sel: 10 (wrr-hash), but the current FullProxy programming path does not
propagate them to the data plane. Runtime selection instead uses a mean-load
factor of 175, replication 256, prefix flags 0, and cache-salt enforcement
off. Treat API read-back as stored configuration, not proof of enforcement. See
LLM Routing.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
chwbl_prefix_hash_level |
integer | 1 |
1, 2, 3 |
Stored/read back; current runtime infers prefix scope from request content. |
chwbl_prefix_hash_flags |
integer | 0 |
0–255 (bitflags) |
Stored/read back; current runtime programs flags 0. |
chwbl_mean_load_factor |
integer | 125 (schema) |
100–300 |
Stored/read back; current runtime uses 175 (1.75×) regardless of this value. |
chwbl_replication |
integer | 100 |
1–1024 |
Stored/read back; current runtime uses 256 virtual nodes. |
chwbl_enable_cache_salt |
boolean | false |
true/false |
Stored/read back; current runtime does not enforce cache salt. Do not use this field as a tenant-isolation boundary. |
6. Prefill / Decode (P/D) disaggregation¶
P/D requires mode: 4 plus at least one prefill endpoint (ep_role: 1) and one decode endpoint
(ep_role: 2). vLLM and TensorRT-LLM use sequential engine-specific flows. SGLang uses concurrent
dual dispatch and may use pdBootstrapPort; base SGLang P/D does not require kvExactMode.
Use kvExactMode: 1 only when adding the P/D-coupled KV-exact tier. Mode 3 is single-role and is
rejected when P/D is enabled. See P/D Disaggregation.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
pd_disagg_mode |
boolean | false |
true/false |
Enable prefill/decode disaggregation (the two-phase flow). |
pd_cache_aware_mode |
boolean | false |
true/false |
Cache-aware endpoint selection (session stickiness + radix-trie prefix match + min-load). Requires pd_disagg_mode: true. |
pd_session_ttl_sec |
int32 | 0 |
≥0 | Tier-0 P/D session-stickiness TTL (seconds). Runtime 0 selects the 300-second default; it does not disable expiry. This applies to P/D session lookup independently of pd_cache_aware_mode; that field controls the optional radix-trie tier. |
pd_prefill_timeout_sec |
int32 | 0 |
0–3600 |
Longest wait (seconds) for the prefill stage of a P/D request before the Gateway answers 504 pd_prefill_timeout. 0 uses the process default: 30 seconds, or LLB_PD_PREFILL_TIMEOUT_SEC when set. A positive value overrides the default for this rule only and can be changed on a live rule by a replace POST. A nonzero value requires pd_disagg_mode: true; JSON null is rejected and PATCH does not accept the field. |
pd_cache_threshold |
int32 | 20 |
0–100 |
Cache-match threshold. Runtime 0 selects 20; lower nonzero values are more aggressive. |
pd_balance_abs_threshold |
int32 | 3 |
0–255 effective |
Load-imbalance threshold. Runtime 0 selects 3; the value is passed through an 8-bit field. If (max−min) active connections exceeds it, cache affinity is bypassed. |
7. Session affinity¶
session_header_name drives persistence when sel: 3 (persist). If empty with sel: 3, the
gateway falls back to IP-based persistence.
| Field | Type | Default | Notes |
|---|---|---|---|
session_header_name |
string | — | Session-key source (see supported forms below). |
Supported session_header_name forms
| Form | Example | Extracts |
|---|---|---|
| Regular header | X-Session-ID, mcp-session-id, authorization |
Full header value. |
| Cookie | cookie:JSESSIONID, cookie:PHPSESSID, cookie:ASP.NET_SessionId, cookie:connect.sid |
The named cookie's value; other cookies ignored. |
| Query parameter | query:sessionid, query:token, query:jsessionid |
The named ?param=value; other params ignored. |
| Basic auth | basic-auth |
Username from an Authorization: Basic header. |
8. TLS / mTLS¶
security sets the TLS posture; mtls_frontend is the inline sub-object for client-certificate
verification, and the backend leg is verified and authenticated by certificate ID. Additional
TLS-tuning fields follow. See Frontend mTLS and
Backend TLS Verification and Client Certificates.
security enum (default 0)¶
| Value | Name | Meaning |
|---|---|---|
0 |
plain | Plain HTTP on both legs (default). |
1 |
https | TLS terminates at the gateway; the backend leg is plain HTTP. |
2 |
e2ehttps | TLS terminates at the gateway and the gateway establishes a separate TLS connection to the backend. |
Mode 2 is not TLS passthrough
The gateway terminates and re-encrypts TLS, so it can inspect HTTP traffic. Values outside
0, 1, and 2 fail request validation and the rule is not created. For production backend TLS, set
mtls_backend.verify_server_cert: true together with backend_ca_cert_id rather than accepting any
backend certificate.
mtls_frontend (object)¶
Client-certificate verification. Only valid with security: 1 or security: 2 and mode: 4.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
client_cert_mode |
string | disabled |
disabled, optional, required |
disabled=no verification, optional=accept with/without cert, required=reject without a valid cert. |
client_ca_path |
string | — | filesystem path (PEM) | Absolute path to a mounted client CA bundle. Prefer a read-only secret mount. |
client_ca_cert_data |
string | — | base64 PEM | Inline CA data — alternative to client_ca_path (e.g. for Kubernetes secrets). |
require_client_cn |
boolean | false |
true/false |
Require a specific CN pattern in the client cert. |
client_cn_pattern |
string | — | e.g. client.example.test |
Required CN pattern (wildcards supported). Only used if require_client_cn: true. |
client_crl_path |
string | — | filesystem path (PEM) | Absolute path to a mounted static CRL; a revoked client leaf certificate is rejected. Keep it current. |
mtls_backend (object) and backend TLS by certificate ID¶
Backend server verification and the client certificate the gateway presents. Only valid with
security: 2 and mode: 4, on a gateway whose backend_tls_verify capability is ready;
otherwise the rule is refused (400, or 412 when the build lacks client-certificate support).
Certificate material is uploaded to /config/cert and named by ID. See
Backend TLS Verification and Client Certificates.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
mtls_backend.verify_server_cert |
boolean | false |
true/false |
true verifies every endpoint's certificate against backend_ca_cert_id and requires the certificate to name the endpoint. Refused without backend_ca_cert_id. false accepts any backend certificate. Set true in production. |
backend_ca_cert_id |
string | — | certId of a usage: ca entry |
The CA bundle endpoint certificates must chain to. Required with verify_server_cert: true and refused without it. There is no default trust store. |
backend_client_cert_id |
string | — | certId of a usage: client entry |
The certificate and key the gateway presents to endpoints. Empty = no client certificate is presented. |
backend_tls_server_name |
string | — | DNS host name | Sent as SNI to every endpoint; with verification on, required among the DNS names of the endpoint's certificate. Empty = no SNI, and the endpoint's IP address must be in its certificate. An address is refused. |
backend_tls_effective |
object | — | read-only | The policy the listener has installed, read from the data plane on GET: status (applied, pending, failed, unsupported), verify, ca, client_cert, client_cert_id, server_name, generation. Ignored on input. |
mtls_backend.backend_ca_path, client_cert_path, client_key_path, client_cert_data and
client_key_data are retired: a request that carries one is refused with 400, and no read
returns them.
Additional TLS-tuning fields¶
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
alpn_protocols |
array[string] | — | e.g. ["h2","http/1.1"] |
ALPN list advertised on listener + pool. Maps to backend_protocol. Empty preserves the backend_protocol-driven value. |
tls_ciphers |
string | — | OpenSSL cipher string, at most 255 bytes | The one string is applied to both the TLS 1.3 ciphersuites and the TLS 1.2 cipher list, and both must take it: name at least one of each, for example TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES256-GCM-SHA384. A string the TLS library does not take is refused with 400 naming tls_ciphers, on a FullProxy rule with security 1 or 2. Empty = built-in defaults. |
tls_versions |
array[string] | — | e.g. ["TLSv1.2","TLSv1.3"] |
Collapsed to a min/max version range. Empty = TLS1.2–1.3. |
hsts_max_age |
uint32 | 0 |
≥0 | Strict-Transport-Security max-age (seconds), injected on HTTPS listeners. 0 = no HSTS. |
hsts_include_subdomains |
boolean | false |
true/false |
Append ; includeSubDomains. Only meaningful when hsts_max_age > 0. |
hsts_preload |
boolean | false |
true/false |
Append ; preload. Only meaningful when hsts_max_age > 0. |
A rule read (GET) reports these fields, the member timeouts (timeoutMemberConnect,
timeoutMemberData, timeoutTcpInspect) and mtls_frontend.client_crl_path as the rule stores
them, so a rule that is read and posted back keeps them.
9. Endpoints (endpoints[])¶
The backend pool. endpointIP, weight, and targetPort are required; the rest are
additive.
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
endpointIP |
string | — (required) | any IP | Backend server IP. |
weight |
integer | — (required) | ≥1 | Load-balancing weight (used by sel: 2/10). |
targetPort |
integer | — (required) | 1–65535 | Backend service port. |
ep_role |
int32 | 0 |
0-normal, 1-prefill, 2-decode |
P/D role. Only used when pd_disagg_mode: true. |
nixl_port |
int32 | 0 |
port / 0 |
NIXL side-channel port for KV transfer. 0 = use targetPort. Only meaningful with pd_disagg_mode: true. |
backup |
boolean | false |
true/false |
Standby member — carries traffic only when all primaries are down. |
subnetId |
string | — | opaque | Octavia member subnet id; stored verbatim, not interpreted. |
monitorAddress |
string | — | any IP | Health-probe target address (instead of the traffic IP). |
httpMethod |
string | GET |
e.g. GET, HEAD |
HTTP(S) health-monitor method. |
urlPath |
string | — | e.g. /healthz |
HM request path. Empty falls back to probereq or /. |
expectedCodes |
string | 200 |
200, 200,202, 200-204 |
Octavia expected HM response codes (single, list, or range). |
httpVersion |
string | — | 1.0, 1.1 |
HM HTTP version; 1.1 sends a Host header. |
domainName |
string | — | FQDN | TLS SNI + Host header for HTTPS monitors. |
state |
string | — | (read-only) | Endpoint state (returned on GET). |
counter |
string | — | (read-only) | Endpoint traffic counters (returned on GET). |
10. Health & probe fields¶
Applies to the rule as a whole (endpoint-level HM fields are in §9).
| Field | Type | Default | Allowed / Enum | Notes |
|---|---|---|---|---|
probetype |
string | — | tcp, udp, sctp, http, https, ping, none |
Health-probe type for endpoints in this rule. |
probeport |
uint16 | — | 1–65535 | Probe port (for tcp/udp/sctp probes). |
probereq |
string | — | free text | Probe request string (e.g. HTTP path/body). |
proberesp |
string | — | free text | Expected probe response string. |
probeTimeout |
uint32 | — | seconds | Probe timer. |
probeRetries |
int32 | — | ≥0 | Probe retry count before marking an endpoint down. |
inactiveTimeOut |
int32 | — | seconds | Connection inactivity timeout. |
timeoutMemberConnect |
uint32 | 0 (=500ms) |
milliseconds | Backend connect timeout (Octavia unit). 0/absent preserves the 500 ms default (NOT Octavia's 5000 ms). L7-proxy peer only. |
timeoutMemberData |
uint32 | 0 |
milliseconds | Member-side relay idle timeout. 0/absent preserves the client-idle value. |
timeoutTcpInspect |
uint32 | 0 |
milliseconds | Header-accumulation deadline (slowloris protection). 0/absent uses a bounded default. Octavia-only. |
httpchk is not a field
Health checking uses probetype / probereq / proberesp (rule-level) or the endpoint HM
fields in §9. There is no httpchk field.
11. Worked example — full KV-exact P/D rule¶
A complete POST body: a fullproxy VIP at 192.0.2.254:8080 doing KV-exact routing
(kvExactMode: 1) over a 3-prefill / 3-decode pool. This mirrors the vllm-kvcache-routing-cpu
scenario.
curl -s -X POST http://192.0.2.254:11111/netlox/v1/config/loadbalancer \
-H 'Content-Type: application/json' -d '{
"serviceArguments": {
"externalIP": "192.0.2.254",
"port": 8080,
"protocol": "tcp",
"sel": 0,
"mode": 4,
"security": 0,
"host": "192.0.2.254",
"pd_disagg_mode": true,
"probeRetries": 1,
"kvExactMode": 1,
"kvBlockSize": 16,
"kvHashAlgo": "sha256_cbor",
"kvZmqPort": 5557,
"kvWarmupSec": 30,
"kvEngineType": "vllm"
},
"endpoints": [
{ "endpointIP": "198.51.100.11", "targetPort": 80, "weight": 1, "ep_role": 1 },
{ "endpointIP": "198.51.100.12", "targetPort": 80, "weight": 1, "ep_role": 2 },
{ "endpointIP": "198.51.100.13", "targetPort": 80, "weight": 1, "ep_role": 1 },
{ "endpointIP": "198.51.100.14", "targetPort": 80, "weight": 1, "ep_role": 2 },
{ "endpointIP": "198.51.100.15", "targetPort": 80, "weight": 1, "ep_role": 1 },
{ "endpointIP": "198.51.100.16", "targetPort": 80, "weight": 1, "ep_role": 2 }
]
}'
loxicmd create lb 192.0.2.10 --tcp=8080:80 --endpoints=198.51.100.11:1,198.51.100.12:1,198.51.100.13:1,198.51.100.14:1,198.51.100.15:1,198.51.100.16:1 --mode=fullproxy --host=192.0.2.10 --pd-disagg --proberetries=1 --kv-exact-mode=1 --kv-block-size=16 --kv-hash-algo=sha256_cbor --kv-zmq-port=5557 --kv-warmup=30 --kv-engine-type=vllm --ep-role=prefill,decode,prefill,decode,prefill,decode
A CHWBL prefix-cache variant (no P/D) swaps serviceArguments for the
following minimal shape. The current runtime uses the fixed CHWBL values
described in section 5; adding stored chwbl_* fields does not change them.
{
"externalIP": "192.0.2.254", "port": 8080, "protocol": "tcp",
"mode": 4, "security": 0, "host": "192.0.2.254",
"sel": 8,
"model_name": "llama-70b",
"backend_protocol": "http1",
"sse_mode": true,
"backend_keepalive_interval_sec": 60
}
Verify¶
Confirm the rule landed and inspect its state:
See also¶
- Reference: Configuration index — field-name → page lookup.
- LLM Routing — CHWBL / GPU-aware routing in depth.
- KV-Cache Routing — the hash-contract triad and SGLang.
- P/D Disaggregation — prefill/decode flow and
ep_role. - SSE & Quota — streaming lifecycle knobs.
- Frontend mTLS —
mtls_frontendin practice. - Backend TLS Verification and Client Certificates — verifying backends and presenting a client certificate.