Skip to main content

Crate flexd

Crate flexd 

Source
Expand description

§flexd

A hardened web server and reverse proxy, written in Rust.

flexd owns the external port and does strict parsing, connection limiting, and static file serving in front of your application backend. Configuration is a single TOML file, nginx-shaped but typed and validated at startup.

§Features

  • HTTP/1.1, HTTP/2, HTTP/3 — h2 via hyper, h3 via quinn/QUIC
  • TLS — rustls only (no OpenSSL); TLS 1.2/1.3, static certs or ACME
  • ACME — automatic issuance and renewal (Let’s Encrypt or any RFC 8555 CA), http-01 and tls-alpn-01 challenges, EAB support, custom CA roots for private PKI, certs persisted with mode 0600
  • Reverse proxy — weighted round-robin upstreams, header normalization before proxying, configurable trusted-proxy headers
  • Static file serving — with path traversal protection
  • Rewrites and redirects — regex rewrite rules, exact/prefix location matching
  • A/B traffic splitting — weighted groups, optional sticky assignment
  • TCP stream proxying — raw TCP forwarding with optional TLS termination
  • GeoIP — MaxMind database lookups
  • Hardening built in:
    • strict host-header policy (reject unknown Host: by default)
    • ambiguous request framing rejected (request smuggling defense)
    • control characters in headers rejected
    • header count/size and body size limits
    • HTTP/2 reset-flood rate limiting
    • decompression ratio/size bombs capped
    • slow-loris defense via minimum read rate and idle timeouts
    • upstream targets resolving to loopback/private ranges require explicit allowlisting (SSRF defense)
    • privilege drop (user = "...") after binding low ports

§Install

cargo install flexd

§Quick start

# Write a config (see flexd.conf.example in this repository)
flexd --config flexd.conf --test   # validate config and exit
flexd --config flexd.conf          # run

A minimal static-site config:

[global]
worker_processes = "auto"
error_log = "./logs/error.log"

[[http]]
server_name = ["localhost"]
root = "./public"
host_header_policy = "any"

[[http.listen]]
port = 8080
protocol = "tcp"

[[http.locations]]
pattern = "/"
match_type = "prefix"

[http.locations.handler]
type = "static"
root = "./public"

Add a reverse-proxied backend:

[[http.locations]]
pattern = "/api/"
match_type = "prefix"

[http.locations.handler]
type = "proxy"

[http.locations.handler.upstream]
name = "backend"

[[http.locations.handler.upstream.servers]]
address = "127.0.0.1:3000"

HTTPS with automatic certificates:

[http.ssl.acme]
enabled = true
email = "admin@example.com"
domains = ["example.com"]
agree_tos = true

See flexd.conf.example for the full annotated configuration surface, including HTTP/3, stream proxying, A/B splits, and ACME EAB/private-CA options.

§Logging

flexd uses tracing; set RUST_LOG to control verbosity:

RUST_LOG=debug flexd --config flexd.conf

Access and error logs are written to the paths configured per-server (access_log, error_log).

§License

AGPL-3.0-only. See LICENSE.

§Library overview

The flexd binary is a thin main wrapper; everything it does lives in this library so the request pipeline can be unit- and integration-tested without binding a socket. The public surface is organized as follows.

§Lifecycle

  • config — the typed configuration schema. config::Config::load parses TOML (or JSON) and runs config::Config::validate, which rejects an unsafe or contradictory configuration before any socket is bound.
  • serverserver::Server owns the accept loops for every listener (TCP, TLS, and QUIC/HTTP3), connection accounting, graceful shutdown, and the background certificate-renewal task.
  • handlerhandler::HandlerService is the per-block request pipeline shared by all three protocol entry points: security checks, routing, rewrites, GeoIP, static serving, and proxying.

§Routing and proxying

  • balance — weighted load balancing (round-robin, least-conn, ip-hash) with deterministic connect-failure failover.
  • proxy — the pooled upstream HTTP client.
  • resolver — a DNS resolver that vets every answer against the SSRF allowlist before a connection is made (DNS-rebinding defense).
  • rewrite — regex rewrite and redirect rules.
  • absplit — weighted A/B traffic splitting with optional sticky sessions.
  • static_file — path-traversal-safe static file serving.
  • geoip — MaxMind GeoIP lookups.

§TLS and certificates

  • tls — rustls acceptor and QUIC config construction.
  • acme — automatic certificate issuance and renewal (RFC 8555).

§Hardening (security)

The security modules implement the request-handling invariants that make flexd safe to expose directly to the internet — host-header policy, header and framing validation, SSRF filtering of upstream targets, connection and memory limits, HTTP/2 reset-flood rate limiting, and privilege dropping. Each item references the numbered contract invariant it enforces.

§A note on “Invariant N” references

Doc comments throughout the crate cite numbered invariants (e.g. “Invariant 41”) and contract criteria (e.g. “C53”). These refer to the project’s security contract — the enumerated properties the server is required to uphold. The numbers are stable identifiers for those requirements, not line numbers or error codes.

Modules§

absplit
Weighted A/B traffic splitting with optional sticky session assignment. Weighted A/B traffic splitting.
acme
Automatic TLS certificate issuance and renewal via ACME (RFC 8555). ACME (RFC 8555) certificate lifecycle for flexd.
balance
Upstream load balancing strategies and connect-failure failover. Upstream load balancing and connect-failure failover.
config
Typed configuration schema, parsing, and startup validation. Configuration schema, parsing, and startup validation.
geoip
MaxMind GeoIP database lookups for request geolocation. GeoIP lookups backed by a MaxMind database.
handler
The per-block request pipeline shared by HTTP/1, HTTP/2, and HTTP/3.
logging
Combined-format access logging with control-character stripping. Access logging in the Common/Combined Log Format.
proxy
Pooled upstream HTTP client used by the reverse proxy. The pooled upstream HTTP client used by the reverse proxy.
resolver
SSRF- and rebinding-aware DNS resolver for hostname upstreams. SSRF- and rebinding-aware DNS resolution for hostname upstreams.
rewrite
Regex-based rewrite and redirect rules. Regex-based path rewriting and redirects.
security
Request-handling hardening: the building blocks of flexd’s security model.
server
Accept loops, connection accounting, and lifecycle management.
static_file
Path-traversal-safe static file serving. Path-traversal-safe static file serving.
tls
rustls / QUIC TLS configuration construction. TLS and QUIC configuration construction.