Skip to main content

Snakeway v0.15.0

Highlights

WASM devices

Snakeway now supports extending the proxy with WASM devices: custom traffic logic written in any language that compiles to a WebAssembly component.

Devices run in a sandboxed Wasmtime runtime (component model, snakeway:device@0.4.0) with access to request and response context, a host API for logging and metrics, and a typed configuration map. A bug in a device cannot crash the proxy, and each device runs in a memory-limited sandbox.

Devices are declared in a device file under device.d/:

wasm_devices = [
{
name = "my-device"
enable = true
path = "/etc/snakeway/devices/my_device.wasm"
fail_policy = "open" # "open" or "closed" on trap, timeout, or load error
timeout_ms = 5 # per-hook epoch deadline
body_buffer_max = 0 # 0 = streaming; > 0 buffers up to N bytes
hooks = ["on_request"]

config = {
api_key = "secret-value"
}
}
]

Hooks can inspect and modify request and response headers and bodies.

A reference JWT auth device ships alongside the runtime as a worked example, and it models secure identity handling for anyone adapting it. It rejects tokens that are missing required claims or signed with a secret that is too short, and it returns a generic error rather than revealing which check failed. It also strips client-supplied identity headers such as x-user-id and x-tenant-id before a request is forwarded, so a caller cannot spoof identity, including on public paths that bypass authentication.

caution

The WIT interface (snakeway:device@0.4.0) may change in future releases.

Engine-wide resource limits for the shared WASM runtime are set with the optional wasm block in server. max_concurrent_executions caps how many device hooks run at once, and max_memory_bytes caps the memory a single execution may use. Both default to Snakeway's previous built-in values, so existing configurations are unaffected. See the Server block for the field reference.

See Authoring WASM Devices for the full guide.

HTTP/2 server tuning

Listeners with enable_http2 = true accept an optional http2 block that tunes the HTTP/2 server parameters advertised to clients. Every field is optional and falls back to its default when unset.

bind = {
interface = "0.0.0.0"
port = 443
enable_http2 = true

http2 = {
max_concurrent_streams = 100
max_header_list_size = 65536
initial_window_size = 65535
initial_connection_window_size = 1048576
}
}

See HTTP/2 settings for the field reference.

Upstream connection tuning and reuse fix

This release remediates an upstream connection reuse issue and adds explicit control over upstream connection behavior through the new upstream block (see Breaking Changes for the relocation of existing fields).

Two new timeout settings are available:

  • connection_timeout_seconds bounds how long a connect (TCP plus the TLS handshake) may take before failing.
  • read_timeout_seconds bounds a stalled or wedged origin without breaking slow-but-progressing or streaming responses; the timer resets on every read and is not applied to websocket upgrades.

Both are optional and disabled when omitted, preserving v0.14.0 behavior.

upstream {
connection_pool_size = 256
connection_timeout_seconds = 10
read_timeout_seconds = 60
}

See the Server block for the full field reference.

Inspecting effective configuration

snakeway config dump gained a populated-spec representation. Run snakeway config dump --repr populated-spec to print your configuration with every optional block and field filled in with its default value. This shows the effective settings the proxy will apply without starting it, which is useful for confirming what a partial config actually resolves to.

The output format is selectable with --format hcl, --format json, or --format yaml.

snakeway config dump --repr populated-spec --format hcl

Breaking Changes

Upstream tuning consolidated into a single upstream block

Upstream connection settings are now grouped under one upstream block inside server. Two settings that lived elsewhere in v0.14.0 have moved into it:

  • The top-level upstream_source_addresses block is now upstream.source_addresses.
  • The performance.upstream_connection_pool_size field is now upstream.connection_pool_size.

The upstream block also introduces connection_timeout_seconds and read_timeout_seconds, which did not exist in v0.14.0.

Before (v0.14.0):

server {
performance {
work_stealing = true
upstream_connection_pool_size = 128
}

upstream_source_addresses {
ipv4 = ["10.0.1.5"]
ipv6 = ["fd00::1"]
}
}

After (v0.15.0):

server {
performance {
work_stealing = true
}

upstream {
connection_pool_size = 128
connection_timeout_seconds = 10 # new, omit to disable, but you probably want this
read_timeout_seconds = 60 # new, omit to disable, but you probably want this

source_addresses {
ipv4 = ["10.0.1.5"]
ipv6 = ["fd00::1"]
}
}
}

A config that still uses upstream_source_addresses or performance.upstream_connection_pool_size is rejected at load time, and the proxy refuses to start until it is updated.

What to do: move upstream_connection_pool_size out of performance into the new upstream block as connection_pool_size, and move the upstream_source_addresses block under upstream as source_addresses. No values need to change.

Upgrade Notes

Run snakeway config check before upgrading. If your v0.14.0 config sets upstream_source_addresses or performance.upstream_connection_pool_size, relocate them into the new upstream block as described above. The new upstream.connection_timeout_seconds and upstream.read_timeout_seconds fields are optional. Omit them to preserve the previous behavior of no upstream timeouts.

Internals / Developer

These changes do not affect configuration or runtime behavior. They are noted for contributors and anyone tracking the project internals.

confval matured into a standalone library

Reusable validation and conversion logic moved out of the application crates and into the confval configuration library.

  • A new keyword pipeline module adds KeywordSet for validating keyword fields, now used across the device and ingress specifications.
  • A new narrow pipeline module centralizes numeric and duration conversions that were previously scattered helper functions.
  • The derive macro gained support for #[confval(nested, default)] on non-optional nested fields. The attribute is now rejected on optional fields, enforced by a compile-fail test.
  • New reuse helpers parse_cidr_list and require_existing_file (the latter with remediation help) replace duplicated validation across CIDR and filesystem checks.

confval and confval-derive also received READMEs, TOML and HCL usage examples, and an enhanced prelude. The crates were published as confval 0.3.1 and confval-derive 0.1.1. A just doc task was added for building API documentation.