Skip to content

Ingress Configuration

Ingress files are located in the config directory under CONFIG_ROOT/ingress.d/*.hcl.

An ingress configuration file defines the ingress rules for a particular bound address.

bind = {
interface = "127.0.0.1"
port = 8443
enable_http2 = true
tls = {
cert = "/path/to/certs/server.pem"
key = "/path/to/certs/server.key"
}
connection_filter = {
cidr = {
allow = []
deny = [
"10.0.0.0/8",
"192.168.0.0/16"
]
}
ip_family = {
ipv4 = true
ipv6 = false
}
on_no_peer_addr = "allow" # allow | deny
}
connection_rate_limiting_filter = {
max_connections_per_second = 10
window_seconds = 3
}
}

Type: string
Default: none

This is the interface to bind to.

Type: integer
Default: none

This is the port to bind to, on the specified interface.

Type: boolean
Default: false

Enable HTTP/2 on the ingress instance. This has ramifications for TLS configuration (TLS is required) and other settings where noted.

Snakeway supports filtering connections based on their source IP address.

Type: object
Default: none

The cidr block allows you to specify a list of CIDR blocks to allow or deny connections from.

Type: list(string)
Default: []

CIDR blocks to allow connections from. If empty, all connections are allowed.

Type: list(string)
Default: []

CIDR blocks to deny connections from. If empty, no connections are denied.

Type: object
Default: none

Type: boolean
Default: false

If true, IPv4 connections are allowed.

Type: boolean
Default: false

If true, IPv6 connections are allowed.

Type: string
Default: allow

Controls the behavior when a connection is made without a peer address. Default is permissive, i.e., any connection is allowed.

Rate Limiter (connection_rate_limiting_filter)

Section titled “Rate Limiter (connection_rate_limiting_filter)”

Snakeway supports connection rate limiting at the bind level.

This filter applies soft, time-windowed admission control to new incoming connections on a per-client IP basis.

Type: integer
Default: none

The maximum allowed average number of new connections per second, calculated over the configured time window.

Type: integer
Default: none

The duration of the time window, in seconds, used to measure the connection rate.

Shorter windows react faster but allow more burstiness.
Longer windows react more slowly but provide smoother enforcement.

Snakeway provides a built-in Admin API for observability and operational insight. These endpoints are available on the bind_admin address under the /admin/ path.

bind_admin = {
interface = "127.0.0.1"
port = 8440
tls = {
cert = "/path/to/certs/server.pem"
key = "/path/to/certs/server.key"
}
}

An ingress configuration file may define zero or more services:

services = [
{
load_balancing_strategy = "round_robin"
health_check = {
enable = false
failure_threshold = 3
unhealthy_cooldown_seconds = 10
}
circuit_breaker = {
enable_auto_recovery = false
failure_threshold = 3
open_duration_milliseconds = 10000
half_open_max_requests = 1
success_threshold = 2
count_http_5xx_as_failure = false
}
routes = [
{
path = "/api"
},
{
path = "/ws"
enable_websocket = true
ws_max_connections = 10000
}
]
upstreams = [
{
weight = 1
endpoint = { host = "127.0.0.1", port = 3443 }
},
{
weight = 1
endpoint = { host = "127.0.0.1", port = 3444 }
},
{
weight = 1
sock = "/tmp/snakeway-http-1.sock"
}
]
}
]

Type: string
Default: failover

Supported strategies:

  • failover: Always picks the first healthy upstream in the list.
  • round_robin: Distributes requests evenly across upstreams.
  • request_pressure: Picks the upstream with the lowest recent request pressure (heuristic-based, not transport-level).
  • random: Picks a random healthy upstream.
  • sticky_hash: Consistent hashing based on request characteristics.

The circuit breaker protects your services by aggressively stopping traffic to failing upstreams.

Type: boolean
Default: true

Type: integer
Default: 5

Number of consecutive failures (transport errors or 5xx) in the Closed state before tripping the circuit to Open.

Type: integer
Default: 10000 (10 seconds)

How long the circuit remains Open before transitioning to HalfOpen to allow probes.

Type: integer
Default: 1

How many simultaneous probe requests are allowed while in the HalfOpen state.

Type: integer
Default: 2

How many successful probes are required in HalfOpen to close the circuit again.

Type: boolean
Default: true

Whether HTTP 5xx responses from the upstream count as failures for the circuit breaker.

Type: string
Default: failover

Supported strategies:

  • failover: Always picks the first healthy upstream in the list.
  • round_robin: Distributes requests evenly across upstreams.
  • request_pressure: Picks the upstream with the lowest recent request pressure (heuristic-based, not transport-level).
  • random: Picks a random healthy upstream.
  • sticky_hash: Consistent hashing based on request characteristics.

Type: string
Required: true

The URL path prefix to match. Must:

  • start with /
  • be unique across all routes

Type: boolean
Default: false

Enables WebSocket upgrades for this route.

Type: integer
Optional

The maximum number of concurrent WebSocket connections allowed for this route.

Each service can have one or more upstream servers defined. Upstreams represent the backend servers that will handle the proxied requests.

Type: object
Required: false

The address of the upstream server: host, and port).

Example:

endpoint = { host = "10.0.0.1" port = 8080 }

The protocol is inferred from the bind block’s TLS settings (no settings mean HTTP, TLS means HTTPS).

Type: string
Required: false

The local filesystem path to a Unix domain socket (e.g., /run/snakeway-http-1.sock).

Type: integer
Default: 1

The weight of this upstream for load balancing strategies that support weighted distribution (i.e., round_robin). Higher weights receive proportionally more traffic. A weight of 10 will receive approximately 10 times more requests than a weight of 1.

An ingress configuration file may define zero or more static file policies.

static_files = [
{
routes = [
{
path = "/assets"
file_dir = "/var/www/html"
index = "index.html"
directory_listing = false
max_file_size = 10485760 // 10 MiB
compression = {
enable_gzip = false
small_file_threshold = 102400 // 100 KiB
min_gzip_size = 1024 // 1 KiB
enable_brotli = false
min_brotli_size = 4096
}
cache_policy = {
max_age_seconds = 60
public = true
immutable = false
}
}
]
}
]

Type: string
Required: true

The URL path prefix to match.

Type: string
Required: true

Absolute path to the directory on disk that will be served.

Constraints:

  • must be an absolute path
  • must exist
  • must be a directory
  • must not be /

Type: string
Optional

Filename to serve when a directory is requested.

Type: boolean
Default: false

Whether to enable directory listings when no index file is present.

Type: integer
Optional

Maximum file size in bytes. Default: 10485760 (10 MiB)

Static routes include optional configuration for performance and caching.

Type: object
Optional

Advanced configuration for static file handling.

  • small_file_threshold: (integer) Threshold for small file optimization in bytes. Default: 262144 (256 KiB)
  • min_gzip_size: (integer) Minimum size to enable gzip compression. Default: 1024 (1 KiB)
  • min_brotli_size: (integer) Minimum size to enable brotli compression. Default: 4096 (4 KiB)
  • enable_gzip: (boolean) Enable gzip compression. Default: true
  • enable_brotli: (boolean) Enable brotli compression. Default: true

Type: object
Optional

Configuration for the Cache-Control header.

  • max_age: (integer) max-age value in seconds. Default: 3600 (1 hour)
  • public: (boolean) Whether the cache is public. Default: true
  • immutable: (boolean) Whether to add the immutable directive. Default: false

Routing Priority

Both services and static routes use longest-prefix matching, meaning more specific routes take precedence over broader ones.