ESC
Type to search...
S
Soli Docs

Server Hardening

Production-safe defaults for handling untrusted input at the request edge: trust-proxy gating for X-Forwarded-* headers, and a per-request body-size cap to prevent memory-exhaustion DoS.

Trust Proxy

Soli reads X-Forwarded-Proto and X-Forwarded-Host from incoming requests only when trust-proxy is enabled. These headers govern two security-sensitive decisions:

  • The Secure flag on the session cookie (set when the request scheme is https).
  • The host portion of *_url named-route helpers used for absolute URLs in emails and redirects.
Default: OFF

A request reaching the Soli process directly cannot influence either decision via these headers — the cookie Secure flag stays off and *_url falls back to the Host header. Enable trust-proxy only when your deployment terminates TLS at a trusted proxy hop (Caddy, nginx, ALB, etc.) and that proxy is configured to strip inbound X-Forwarded-* headers from clients before adding its own.

enable_trust_proxy() / disable_trust_proxy() / trust_proxy_enabled()

Toggle and inspect the trust-proxy gate. All three return Bool.

# config/application.sl
enable_trust_proxy

# Later, e.g. in a test harness running without a proxy:
disable_trust_proxy

# Inspect:
if trust_proxy_enabled
  println("X-Forwarded-* headers are honored")
end

You can also set the startup default from the environment — useful when the same image runs in different deployments:

# .env.production
SOLI_TRUST_PROXY=1

Truthy values: 1, true, yes (case-insensitive). The function calls still override the env-driven default at runtime.

Request Body Limit

Every non-GET/HEAD request is capped before its body is buffered into memory. Without this cap an attacker can stream an arbitrarily large body — or open many concurrent uploads — and exhaust worker memory before any handler runs.

The server short-circuits to 413 Payload Too Large in two ways: via the Content-Length header (no bytes read) or mid-stream once the running total crosses the limit (catches chunked uploads that don't declare a length).

Default: 8 MiB

Apps that accept larger uploads — document upload, image processing, etc. — should raise the cap explicitly. Prefer per-action checks inside the handler over a high global cap so abusive clients can't open many concurrent uploads on routes that shouldn't accept them.

set_max_body_size(bytes)

Sets the maximum buffered request body size, in bytes.

Parameters
  • bytes (Int) - New limit in bytes (must be non-negative)
# config/application.sl
set_max_body_size(32 * 1024 * 1024)  # 32 MiB cap for file uploads

# Returns Int — the value just set.

The startup default can also come from the environment:

# .env.production
SOLI_MAX_BODY_SIZE=33554432   # 32 MiB, in bytes

Non-numeric or negative values are ignored and the 8 MiB default stands. The function call still overrides at runtime.

max_body_size()

Returns the current limit in bytes.

println("Current cap: " + str(max_body_size) + " bytes")

Related: Security Headers

Production hardening also includes the response-side defaults — Content-Security-Policy, HSTS, X-Frame-Options, and friends — covered on the dedicated reference page.