Skip to content

Static Files

Snakeway can serve static files directly from the filesystem, making it easy to host frontend assets, images, and other static content without needing a separate web server.

Static file serving is an optional feature. To enable it, compile Snakeway with the static_files feature:

Terminal window
cargo build --release --features static_files

To serve static files, add a route to the static_files block:

static_files = [
{
routes = [
{
path = "/"
file_dir = "/var/www/public"
index = "index.html"
}
]
}
]
OptionTypeRequiredDescription
pathstringYesThe URL path prefix to match
file_dirstringYesThe directory containing static files
indexstringNoThe name of the index file, e.g., index.html (no default)
directory_listingbooleanNoWhether list the contents of directory requests (default: false)
cache_policyobjectNoAdvanced cache policy configuration (see below)
compressionobjectNoAdvanced compression configuration (see below)

Each static route can have an optional cache_policy block.

OptionTypeDefaultDescription
max_age_secondsinteger3600How long a cached response is valid (e.g., 3600 seconds = 1 hour).
publicbooleantrueIndicates a cache can be shared across domains or with third-party services.
immutablebooleanfalseResponse won’t change unless its associated resource changes, allowing caches to return the same result without re-checking.

Each static route can have an optional compression block to customize compression behavior.

OptionTypeDefaultDescription
enable_brotlibooleantrueEnable Brotli compression for compressible content
enable_gzipbooleantrueEnable gzip compression (fallback when Brotli is unavailable)
min_brotli_sizeinteger4096Minimum file size in bytes to apply Brotli compression (4 KiB)
min_gzip_sizeinteger1024Minimum file size in bytes to apply gzip compression (1 KiB)
small_file_thresholdinteger262144Files smaller than this (in bytes) are read into memory and compressed; larger files are streamed (256 KiB)
max_file_sizeinteger10485760Maximum file size in bytes that will be served (10 MiB)

Example with custom compression settings:

static_files = [
{
routes = [
{
path = "/"
file_dir = "/var/www/public"
compression = {
enable_brotli = true
enable_gzip = true
min_brotli_size = 4096
min_gzip_size = 1024
}
}
]
}
]

Disable compression entirely for a route:

static_files = [
{
routes = [
{
path = "/raw"
file_dir = "/var/www/raw-assets"
compression = {
enable_brotli = false
enable_gzip = false
}
}
]
}
]

Increase file size limits for large assets:

static_files = [
{
routes = [
{
path = "/downloads"
file_dir = "/var/www/large-files"
compression = {
max_file_size = 104857600 # 100 MiB
small_file_threshold = 1048576 # 1 MiB - stream files larger than this
}
}
]
}
]

Serve a single-page application:

static_files = [
{
routes = [
{
path = "/"
file_dir = "/var/www/dist"
}
]
}
]

Serve static assets under a prefix:

static_files = [
{
routes = [
{
path = "/static"
file_dir = "/var/www/assets"
}
]
}
]

Mix static files with API proxy:

services = [
{
routes = [
{
path = "/api"
}
]
upstreams = [
{
endpoint = { host = "127.0.0.1", port = 8080 }
}
]
}
]
static_files = [
{
routes = [
{
path = "/"
file_dir = "/var/www/public"
}
]
}
]

Snakeway automatically detects and sets the correct Content-Type header based on file extensions.

Common types include:

ExtensionMIME Type
.htmltext/html
.csstext/css
.jsapplication/javascript
.jsonapplication/json
.pngimage/png
.jpg, .jpegimage/jpeg
.svgimage/svg+xml
.wasmapplication/wasm

Snakeway implements HTTP caching headers to reduce bandwidth and improve performance:

  • ETag: A weak ETag is generated from the file size and modification time
  • Last-Modified: The file’s modification timestamp is sent as an HTTP date

Clients can use conditional requests to avoid re-downloading unchanged files:

  • If-None-Match: If the client’s cached ETag matches, Snakeway returns 304 Not Modified
  • If-Modified-Since: If the file hasn’t changed since the given date, Snakeway returns 304 Not Modified

Snakeway automatically compresses responses for clients that support it, reducing transfer sizes significantly for text-based content.

Supported encodings (in order of preference):

  1. Brotli (br) - Best compression ratio, preferred when client supports it
  2. gzip - Fallback for clients that don’t support Brotli

Compression behavior (default settings):

  • Only compressible MIME types are compressed (text, JSON, JavaScript, XML, SVG, WASM, etc.)
  • Brotli is used for files ≥ 4 KiB (configurable via min_brotli_size)
  • gzip is used for files ≥ 1 KiB when Brotli is unavailable or not preferred by the client (configurable via min_gzip_size)
  • Compression can be disabled per-route using enable_brotli and enable_gzip options
  • Compression is skipped if the compressed size isn’t smaller than the original
  • The Vary: Accept-Encoding header is added for proper cache behavior

See Advanced Configuration (Per-Route) for customization options.

Example request/response:

GET /app.js HTTP/1.1
Accept-Encoding: gzip, deflate, br
HTTP/1.1 200 OK
Content-Type: application/javascript
Content-Encoding: br
Vary: Accept-Encoding
ETag: W/"1a2b3c-4d5e6f"
  • Small files (≤ 256 KiB by default): Read entirely into memory, compressed if applicable
  • Large files (> 256 KiB by default): Streamed directly from disk in 32 KiB chunks. Streaming responses are not compressed, since compression currently requires buffering the entire file in memory.

The threshold can be adjusted per-route using the small_file_threshold option.

Snakeway includes several security measures to protect against common attacks:

  • Path traversal protection: Requests containing .. or attempting to escape the file_dir are rejected with 403 Forbidden
  • File size limit: Files larger than 10 MiB (by default) are rejected to prevent memory exhaustion (configurable per-route).
  • Symlink resolution: Paths are canonicalized to prevent symlink-based escapes