rws
Website: rws8.tech
An HTTP web framework, reverse proxy, and server for Rust — HTTP/1.1 · HTTP/2 · HTTP/3/QUIC · TLS · No third-party HTTP dependencies.
| Mode | Setup | Code required |
|---|---|---|
| Static file server | cargo install rust-web-server && rws |
None |
| Config-driven proxy | rws.config.toml with [[route]] / [[upstream]] |
None |
| Library crate | cargo add rust-web-server |
Yes |
Quick start — library
# Cargo.toml
[]
= "17"
= { = "1", = ["rt-multi-thread", "macros"] }
use *;
async
See DEVELOPER for 59 use-case examples covering JSON, auth, WebSocket, SSE, middleware, ORM, MCP, and more.
Quick start — static file server
Starts on http://127.0.0.1:7878. Place files in the working directory and open the URL.
With HTTPS + HTTP/2 + HTTP/3
Generate a self-signed cert for local development:
HTTP/2 and HTTP/3 are negotiated automatically — no extra configuration needed. See CONFIGURE for all options.
Quick start — config-driven proxy
Drop rws.config.toml in the working directory and run rws — no code required:
[[]]
= "api"
= ["10.0.0.10:8080", "10.0.0.11:8080"]
[]
= "/healthz"
= 10
= 2000
= 2
= 3
[[]]
[]
= "api.example.com"
= "/v1/*"
[]
= "proxy"
= "api"
[]
= { = 500, = 60 }
= { = "bearer", = "API_TOKEN" }
[[]]
[]
= "/*"
[]
= "respond"
= 404
= "Not Found"
See spec/PROXY_SERVER_CONFIG.md for the full annotated config reference.
What's in the box
Protocol & transport
- HTTP/3 over QUIC (UDP) + HTTP/2 + HTTP/1.1 on the same port via ALPN
- TLS via rustls — aws-lc-rs crypto, no OpenSSL
- Automatic TLS (ACME) — Let's Encrypt provisioning + background renewal (
acmefeature) - mTLS — set
RWS_CONFIG_TLS_CLIENT_CA_FILE; client cert required on HTTPS and QUIC - Virtual hosting / SNI — per-domain TLS certs;
Router::with_host()for per-host routing - WebSocket (RFC 6455) — handshake, frame codec, SHA-1 + base64 built in, no extra dep
- Server-Sent Events —
Ssebuilder with correct headers; ideal for AI token streaming - Outbound HTTP client —
Client(sync) andAsyncClient(async,http2feature); HTTPS via rustls
Routing & app building
routes!macro +App::with_state(S)— typed shared state (Arc<S>) across handlersRouterwith:param/*wildcardpath matching;PathParams::get("name")- Async handlers via
App::with_async_state(S)(http2feature) - Middleware pipeline —
app.wrap(layer)stacks composableMiddlewarelayers - Typed extractors —
Body,BodyText,Query,RequestHeaders;#[derive(FromRequest)] - Request validation —
#[derive(Validate)]withlength,range,email,url; returns422 - Typed errors —
AppErrorenum (400–500);IntoResponsetrait for custom error types - Cookie jar —
CookieJarparses;SetCookiebuilder writes all RFC 6265 attributes - Sessions —
SessionStorein-memory TTL sessions;DbSessionStorepersistent sessions backed by the model layer (survives restarts, multi-instance);RedisSessionStoreRedis-backed sessions with automatic TTL expiry; cookie helpers included - JSON —
Json<T>extractor + responder viaserde_json(serdefeature) - HTML templates — Tera engine (Jinja2 syntax);
template::render()one-liner (terafeature) - Dependency injection —
Containerkeyed byTypeId; concrete types anddyn Trait - In-process test client —
TestClient::new(app)dispatches without a TCP socket
Proxy & gateway
- Config-driven proxy —
rws.config.tomlwith[[route]]/[[upstream]]; per-route middleware - Reverse proxy middleware —
ReverseProxy; round-robin;502when all backends fail; built-inConnPoolreuses keep-alive TCP streams; SSE, chunked AI streams, and large downloads are streamed without buffering viaResponse::stream_pipe - HTTP/2 reverse proxy —
H2ReverseProxy(h2://,h2s://,https://);GrpcProxywraps it forContent-Type: application/grpc*(grpc://,grpcs://); TLS upstreams via rustls + ALPNh2 - L4 TCP proxy —
TcpProxybidirectional relay, any TCP protocol (databases, legacy HTTP) - UDP proxy —
UdpProxydatagram proxy; DNS / syslog style - WebSocket proxy —
WsProxyperforms the HTTP upgrade and relays frames bidirectionally;wss://backends connect over TLS via rustls - Health checks — per-upstream background checker; live backend list via
Arc<RwLock<Vec<String>>> - Canary / traffic splitting —
CanaryLayerdistributes requests by weight, lock-free - Circuit breaker — Closed → Open → HalfOpen;
RetryLayerretries on 502/503/504 - Service discovery —
Static,EnvPrefix,File,Dnssources; background refresh thread - Kubernetes Ingress —
KubernetesIngressWatcherpolls K8s API; routes to cluster services
Security
- Per-IP rate limiting — sliding-window
RateLimiter+RateLimitLayer; hot-reloadable - CORS — configurable origins, methods, headers; updated live via
SIGHUP - Auth —
BasicAuthLayer(HTTP Basic),JwtLayer(HS256 Bearer) (authfeature) - IP filter —
IpFilter::allow([...])/deny([...]); exact IPv4 and CIDR ranges - CSRF — double-submit cookie,
SameSite=Strict, constant-time compare (csrffeature) - Password hashing — Argon2id + CSPRNG token generation (
cryptofeature) - OAuth2 / OIDC SSO — authorization-code + PKCE flow; RS256/ES256 JWT via JWKS;
OidcAuthmiddleware; presets for Google, Microsoft, GitHub, Okta, Auth0, Keycloak;from_env();ssofeature - Request / response rewriting —
RewriteLayerrewrites headers, URI, status, body bytes
Observability & ops
- Prometheus metrics —
GET /metrics;MetricsLayeradds per-route counters + histograms - OpenTelemetry tracing —
OtelLayer; W3Ctraceparent; stdout or OTLP (Jaeger, Tempo) - Access log — Combined Log Format or
RWS_CONFIG_LOG_FORMAT=json - Hot config reload —
SIGHUPorPOST /admin/config/reload; no restart required - Graceful shutdown — SIGTERM drains connections;
/readyzreturns503during drain - Background scheduler — fixed-rate, fixed-delay, 6-field cron; one thread per task
- Kubernetes-ready —
/healthz,/readyz,/metrics;0.0.0.0default bind; Dockerfile included - Compression — automatic gzip for text types; chunked streaming for files > 8 MB
AI & MCP
- MCP server —
McpServerserves tools, resources, and prompts over MCP Streamable HTTP (POST /mcp); bearer token auth; connects to Claude, Cursor, and other MCP clients - 8 built-in rws tools —
server_config,feature_flags,server_metrics,rate_limit_config,check_rate_limit,cors_config,list_static_files,reload_config - SSE streaming —
Ssebuilder makes forwarding AI token streams to the browser trivial - Response caching —
CacheLayerTTL cache; vary-by-header;Cache-Controlopt-out
Database / ORM
#[derive(Model)]— maps structs to tables; asyncRepository<T, i64>for zero-boilerplate CRUD (all methods.await)QueryBuilder<T>—.where_eq(),.order_by(),.limit(),.fetch_all().await,.count().await- Migrations —
pool.migrate("migrations/").awaitruns*.sqlfiles in lexicographic order, idempotent - Relations —
HasMany<T>,HasOne<O>,BelongsTo<O>; explicit async load, no hidden N+1 - Backends — SQLite (
model-sqlite), PostgreSQL (model-postgres), MySQL (model-mysql); all implyhttp2(tokio runtime) - Backed by
sqlx— async-native driver;DbPoolis a cheap-to-cloneArc-wrappedsqlx::Pool - In-memory SQLite —
DbPool::memory().awaitfor isolated per-test databases
Optional features
| Feature | What it adds |
|---|---|
http-client |
HTTPS for outbound Client — adds rustls + webpki-roots |
serde |
Json<T> extractor and responder via serde_json |
auth |
BasicAuthLayer (HTTP Basic) and JwtLayer (HS256) |
macros |
#[get], #[post], …, #[derive(FromRequest)], #[derive(Validate)], #[derive(Config)] |
acme |
Automatic TLS via Let's Encrypt (ACME RFC 8555); implies http2 |
tera |
Tera HTML template engine (Jinja2/Django syntax) |
model-sqlite |
Async ORM backed by SQLite (via sqlx); implies http2 |
model-postgres |
Async ORM backed by PostgreSQL (via sqlx); implies http2 |
model-mysql |
Async ORM backed by MySQL (via sqlx); implies http2 |
crypto |
Argon2id password hashing + CSPRNG token generation |
csrf |
Double-submit cookie CSRF protection |
sso |
OAuth2/OIDC SSO — OidcAuth middleware, RS256/ES256 JWT via JWKS, PKCE, provider presets (Google · Microsoft · GitHub · Okta · Auth0 · Keycloak) |
mailer |
SMTP email — Mailer::from_env() + Email::builder(); plain, STARTTLS, and SMTPS; multipart text+HTML; AUTH PLAIN; no third-party mail library (STARTTLS/SMTPS additionally require http-client or http2) |
[]
= { = "17", = ["serde", "auth", "macros"] }
Build from source
| Build | Flags | Approx. size |
|---|---|---|
| HTTP/3 + HTTP/2 + HTTP/1.1 + TLS | (default) | ~12 MB |
| HTTP/2 + HTTP/1.1 + TLS | --no-default-features --features http2 |
~8 MB |
| HTTP/1.1 only, no TLS | --no-default-features --features http1 |
~3 MB |
Binary is at target/release/rws. MSRV is 1.75.
Further reading
- CONFIGURE — all configuration options (env vars, config file, CLI flags)
- DEVELOPER — building blocks reference and 58 use-case examples
- FAQ — common problems and solutions
- spec/PROXY_SERVER_CONFIG.md — annotated proxy config reference
- spec/AI_ADOPTION.md — AI adoption strategy
- docs.rs/rust-web-server — API reference
License
MIT