Skip to main content

upstream

upstream

Proxies the request to one of the configured backend targets over HTTP and writes the backend's status, headers, and body into context.response. It is the workhorse node of most pipelines, usually placed after any auth/traffic-control nodes and before the client node.

Configuration

KeyTypeDefaultDescription
targetsarray of {host, port}requiredThe backend pool. Entries missing host or port are skipped; if no valid target remains, config load fails.
load_balancingstringround_robinOne of round_robin, least_connections, ip_hash. Hyphenated and short spellings (round-robin, least-conn) are accepted, as is the legacy key name load_balancer (saved by earlier UI builds).
timeout_msinteger60000Whole-call deadline (connect + request + response body) per proxied request; exceeding it emits UPSTREAM_TIMEOUT through the error port.
tlsboolfalseConnect to the upstream over TLS — https for the buffered path, wss for a WebSocket upgrade.
ssl_verifybooltrueVerify the upstream's TLS certificate against the system's native root store. Only meaningful when tls is set; set false for self-signed backends.
type: upstream
config:
targets:
- host: backend-1
port: 8443
- host: backend-2
port: 8443
load_balancing: least_connections
tls: true # https / wss to the upstream
ssl_verify: true

Config load fails if targets yields an empty pool, if load_balancing is not a string, or if it names an unknown strategy — values like random are rejected with Unknown load_balancing 'random' — supported: round_robin, least_connections, ip_hash.

Mutual TLS to the upstream

When tls: true, the node can present a client certificate and/or trust a private CA:

KeyTypeDescription
client_cert_pathstringPEM client certificate (chain) presented to the upstream. Requires client_key_path.
client_key_pathstringPEM private key for client_cert_path. Requires client_cert_path.
ca_cert_pathstringPEM CA bundle used to verify the upstream. Replaces the system trust store for this upstream. Incompatible with ssl_verify: false.

Files are loaded and validated when the policy compiles: unreadable files, cert/key mismatches, or contradictory combinations reject the policy. Rotating certificates means touching gateway.yaml (hot-reload recompiles the policy) or restarting the gateway. ssl_verify: false together with a client certificate is allowed: the certificate is presented, the upstream's own certificate is not verified.

type: upstream
config:
tls: true
targets:
- host: payments.internal
port: 8443
client_cert_path: /etc/featherbit/certs/gateway-client.crt
client_key_path: /etc/featherbit/certs/gateway-client.key
ca_cert_path: /etc/featherbit/certs/private-ca.crt

Both HTTPS proxying and wss WebSocket relays present the certificate.

Load balancing

  • round_robin (default) — cycles through targets in order via a monotonic counter.
  • least_connections — picks the target with the fewest in-flight requests. Each target's in-flight count is incremented when a request is dispatched and decremented when it completes, including on error paths.
  • ip_hash — hashes the client IP from context.request.remote_addr (the ephemeral port is stripped first), so all connections from one client stick to the same target.

Behavior

The plugin builds an HTTP request to http://<host>:<port><path>, forwarding the request method, all request headers (the Host header is overridden with the upstream target's host:port), and the buffered request body. On success it populates context.response with the upstream's status code, headers, and body, and exits through the success port. The upstream's status is passed through as-is — a backend 500 is still a success-port outcome.

Failures return the Context along with an error so the graph engine routes through the error port; the error is appended to context.errors:

CodeWhen
UPSTREAM_REQUEST_BUILD_ERRORThe outbound request could not be constructed (e.g. invalid header values).
UPSTREAM_CONNECTION_ERRORConnecting to or exchanging with the target failed.
UPSTREAM_BODY_READ_ERRORReading the upstream response body failed.

The plugin does not read or write context.message.

Each proxied call runs under the timeout_ms deadline; exceeding it fails the node with error code UPSTREAM_TIMEOUT through the error port.