Documentation
Fast delivery in FlashLin v2
Static delivery, caching, compression, streaming limits and honest benchmark status.
The v2 delivery path uses bounded streaming, reusable upstream connections and
precompressed assets, plus an opt-in zero-copy sendfile(2) path for static
files. See Performance on the homepage for a controlled
comparison against Nginx and Apache — it shows a real, measured advantage on
large files, not a universal one across every workload or configuration.
Static pages and assets
- Uncached responses up to 8 MiB complete inside a single blocking-pool job using pooled 1 MiB/64 KiB buffers, not a large unpooled allocation. Larger transfers stream with a bounded 1 MiB per-reader buffer, not total connection memory.
server.sendfile(opt-in, Linux-only, default off) serves eligible plain-HTTP static GET/HEAD requests withsendfile(2)— zero-copy, kernel-to-socket, no userspace buffering at all.server.direct_static_io(opt-in, default off) skips the blocking-thread-pool handoff for files ≤16 KiB. Both fall back to the ordinary request path for anything outside their scope. See enabling these safely before turning either on.- Small cache entries share immutable byte buffers. The configured cache budget limits resident payload bytes, excluding metadata and in-flight responses.
- File metadata is checked before cache lookup. Changed files use new keys; old entries expire or are evicted. Metadata checks are intentional for freshness.
HEAD, conditional requests, and single byte ranges avoid unnecessary data transfer. Ranges support explicit, open-ended and suffix offsets plusIf-Range. Multiple ranges are ignored and receive the full representation.- Put
app.js.brand/orapp.js.gzbesideapp.js. FlashLin negotiates these when the compressed file is at least as new as the original, and honors q=0. The original file must exist; deploy source and sidecars together. - Dynamic compression handles buffered responses up to 1 MiB. It runs on blocking workers with at most min(CPU count, 8) jobs. When jobs are saturated, identity content is served. Streaming responses pass through without recompression.
- Fingerprint assets (for example
app.a17e9.js) before assigning a year-long immutable cache lifetime. Revalidate HTML withCache-Control: no-cache.
Proxy and application delivery
proxy_pass uses a shared connection pool (16 idle connections per origin,
60-second idle eviction). HTTP framing and chunk decoding are handled by Hyper.
Upstream responses stream with downstream backpressure; SSE is not fully buffered.
Requests are still buffered up to security.max_body_size, including proxy
uploads. Size this limit together with your concurrency limit.
Build with --features tls for HTTPS upstreams. Certificate verification uses
bundled WebPKI roots; custom private roots are not yet configurable. HTTP-only
builds reject HTTPS upstream configuration. Upstream connection establishment
has a 10-second limit; response headers and body idle waits use read_timeout.
Use either proxy_pass or a list:
[[routes]]
path = "/api"
proxy_upstreams = ["http://127.0.0.1:3000", "http://127.0.0.1:3001"]
php_enabled = false
Backends rotate round-robin. 502/503/504 results cause a 5-second passive cooldown; empty-body GET/HEAD and buffered QUERY requests may try up to three eligible backends. Writes and WebSocket upgrades are never automatically retried. This is passive failure detection, not a scheduled active health probe. If every backend is cooling down, one is probed for recovery.
Proxy URLs with a base path prepend it to the original request path. For example,
http://backend:3000/service plus /api/x forwards /service/api/x. The escaped
request URI and query are preserved; this is not full Nginx proxy_pass rewrite
compatibility. Configure application routing accordingly.
HTTP/1 WebSocket upgrades tunnel bidirectionally (up to 1,024 concurrent tunnels per process). Socket idle timeouts apply to downstream tunnel traffic too. HTTP/2 extended CONNECT is not implemented. Forwarded client IP/protocol headers are replaced from the actual connection; a configurable trusted-proxy chain is pending.
See QUERY and WebSocket setup for route examples, QUERY discovery/CORS, request-body limits and caching/replay behavior.
Operating the server
Start with the examples/performance.toml profile in the repository, and
measure under representative traffic. Paths remain relative to the working directory.
flashlin --check path/to/server.toml (or -t) validates before binding a port;
invalid or missing configuration stops startup. logging.level and logging.json
are honored. File log destinations/rotation remain pending.
read_timeout bounds HTTP/1 headers and request-body collection. HTTP/2 allows
128 concurrent streams per connection and caps header lists. keep_alive_timeout
and write_timeout bound pending socket reads/writes. TLS handshakes expire after
10 seconds. SIGTERM/Ctrl-C stops accepting and drains ordinary connections for up
to 30 seconds. Long-lived upgraded tunnels may end at process shutdown.
Accepted sockets enable TCP_NODELAY, and the timeout wrapper preserves vectored writes when the underlying transport supports them. These avoid unnecessary small-write delays and preserve Hyper's scatter/gather write path; their impact depends on workload and must be measured, not assumed.
/metrics is restricted to loopback clients. Scrape it using a local monitoring
agent; a .flashweb rule cannot grant remote access to this built-in endpoint.
Verification and ongoing hardening
The TCP regression test covers small-file cache hits, file-change freshness,
HEAD, range/suffix/416/If-Range, large streamed transfers, mounted-directory
redirects, precompressed and dynamic gzip, q=0, header forwarding, upstream pool
reuse, passive failover, early SSE delivery, WebSocket tunneling, slow headers,
and the sendfile fast path (GET/HEAD/conditional/keep-alive/fallback behavior).
Run cargo test --all-features and cargo test --no-default-features.
Use a release build for benchmarks. Record throughput, p50/p95/p99 latency, errors, peak memory and CPU under the same TLS, compression, cache state, files, hardware and concurrency for every server.
Automatic certificates and opt-in configuration/certificate reload are implemented; see operating guide. The offline tests cover cached ACME certificates and live keep-alive reload, not fresh public CA issuance.
Local loopback measurements are not production results — see Performance on the homepage for the current CPU-isolated Nginx/Apache/FlashLin comparison, and enabling the sendfile fast path safely before relying on it.
v2.0 is released; work continues on independent SNI certificate selection, fully streamed uploads, PHP-FPM pooling, active health probes, broader HTTP compliance/security testing, and real-domain ACME validation. None of these block using FlashLin today — they're the roadmap, not blockers.
