rws
A single-binary web server and reverse proxy, written in Rust. Automatic HTTPS from Let's Encrypt, HTTP/3, load balancing with health checks, auth and rate limiting — configured in one TOML file, no code required. When you outgrow configuration, the same engine is a Rust library.
Website: rws8.tech
Prebuilt binaries for Linux (static, any distro), macOS, and Windows are on GitHub Releases.
Serve a folder
&&
Serves the current directory on http://localhost:7878 — index.html, directory listings, ETags and browser caching (304 revalidation), gzip, byte ranges (video seeking, resumable downloads), and an optional SPA fallback for client-side routers. rws --help lists every option.
Automatic HTTPS
# rws.config.toml
= 443
= 80
[]
= ["example.com", "www.example.com"]
= "you@example.com"
rws gets certificates from Let's Encrypt on first start, serves HTTPS with HTTP/2 and HTTP/3, redirects HTTP to HTTPS, and renews in the background with zero-downtime reloads. Retries until DNS is ready, IPv4 and IPv6, private ACME CAs supported. → Automatic HTTPS
Reverse proxy
[[]]
= "app"
= ["10.0.0.10:8080", "10.0.0.11:8080"]
= "least_connections"
[]
= "/healthz"
[[]]
[]
= "api.example.com"
= "/v1/*"
[]
= "proxy"
= "app"
[]
= { = 500, = 60 }
= { = "bearer", = "API_TOKEN" }
Load balancing (round-robin, least-connections, random, IP hash), active health checks, bearer / JWT / basic auth, rate limits, caching, IP allow/deny lists, header and URL rewrites, per-route timeouts and body limits — plus TCP, UDP, WebSocket, and gRPC proxying. Misconfigured auth fails closed. Circuit breakers, canary splits, forward auth, and service discovery are available from the library. Combine with [acme] for HTTPS in front of your apps. → Config-driven proxy · full config reference
Kubernetes Gateway API
Built with the gateway-api feature, rws is a Gateway API controller and data plane in one binary: HTTPRoute, GRPCRoute, TLSRoute, TCPRoute and UDPRoute, conformant with Gateway API v1.6.3 (all five Gateway profiles, every standard-channel extended feature), installed with the Helm chart (gatewayAPI.enabled=true). See Kubernetes Gateway API.
Need custom logic? It's also a Rust library
The server above is the rust-web-server crate. Use it directly when you need routes, middleware, or an MCP server in code:
# Cargo.toml
[]
= "18"
= { = "1", = ["rt-multi-thread", "macros"] }
use *;
async
Routing with path parameters, typed extractors, one Middleware trait for everything (auth, rate limiting, caching, tracing, the reverse proxy itself), WebSocket, SSE, an MCP server, an async ORM, background jobs, object storage, a mailer, and OAuth/OIDC/SAML login — all features, building apps.
Why rws
- One binary, one file. Static site, HTTPS, reverse proxy, and gateway features in a single executable configured by one
rws.config.toml— no separate certbot, cron job, or proxy process. - No hyper, no Tower, no Axum. HTTP/1.1 parsing, routing, middleware, WebSocket, SSE, CORS, range requests, JWT, and the ACME client are implemented in this crate. The HTTP/2 server is rws's own too (checked with h2spec and fuzzing); HTTP/3 uses the widely deployed
quinn/h3crates, and TLS usesrustls— no OpenSSL. - Config and code share one engine. Everything the TOML file does is a type you can use from Rust, so moving from configuration to code doesn't mean switching tools.
- Tested against the real world. CI fuzzes every parser that sees untrusted input, checks HTTP/2 conformance with h2spec, and runs the ACME flow end to end against Let's Encrypt's test CA on every push. Report vulnerabilities privately — see SECURITY.md.
- Fast. Up to 5× faster than Caddy, and less CPU per request than nginx in every scenario of the published benchmark (results vary by hardware) — see Performance.
- SemVer. Breaking changes only in a major version — see the CHANGELOG.
Performance
Requests per second (p99 latency), on one 4-CPU GitHub Actions runner with
the load generator on the same machine: oha, 64 keep-alive connections,
20 s per scenario, no compression, access logs off; nginx with
open_file_cache.
| Scenario | rws | Caddy 2.11 | nginx |
|---|---|---|---|
| Static file, 1 KiB | 96,670 (1.7 ms) | 18,592 (13.5 ms) | 81,161 (3.1 ms) |
| Static file, 1 MiB | 9,511 (14.0 ms) | 2,398 (124 ms) | 9,767 (14.1 ms) |
| Reverse proxy, 1 KiB | 34,260 (3.9 ms) | 13,402 (14.2 ms) | 33,942 (4.5 ms) |
| HTTP/2, 1 KiB | 66,141 (2.4 ms) | 13,604 (14.2 ms) | 51,416 (4.5 ms) |
| 1 MiB over HTTPS | 1,602 (49 ms) | 1,460 (108 ms) | 1,311 (101 ms) |
| CPU per request (1 KiB / 1 MiB / proxy / HTTP/2 / 1 MiB HTTPS) | 16.9 / 210 / 44.6 / 27.4 / 924 µs | 154 / 1,195 / 191 / 216 / 1,484 µs | 25.1 / 216 / 47.1 / 37.9 / 1,640 µs |
| Peak memory | 34–66 MiB | 66–109 MiB | 23–42 MiB |
rws is 2.6–5.2× faster than Caddy (1.1× for large files over HTTPS) and has the lowest p99 of the three in
every scenario. It needs less CPU per request than nginx in every scenario:
small files −33%, large files −3%, proxying −5%, HTTP/2 −28%, HTTPS −23%,
large files over HTTPS −44%, access-logged traffic −29%, gzip a hundredth —
and serves more requests per second in all but large plain files (−3%).
That's on the AMD EPYC runners; on the fastest (Intel) runner type nginx
keeps a few percent on plain-HTTP throughput, which the opt-in
RWS_CONFIG_RUNTIME=per-core narrows. Release builds use the mimalloc
allocator: less CPU, but more memory than nginx (build without the
mimalloc feature for ~9 MiB) — see the
benchmarks page. Shared CI runners are noisy, so
compare servers within a run, not across runs. Reproduce it with
bench/run.sh or the manual
Benchmark workflow.
Documentation
Everything is on rws8.tech (source: docs/):
- Quick start · Installation and feature flags · All features
- Configuration — environment variables,
rws.config.toml, CLI flags - Building apps — routing, state, extractors, middleware, templates, the ORM
- Proxy · MCP server · Deployment
- Architecture · Troubleshooting · Migrating to 18.0
- API reference: docs.rs/rust-web-server · Changes: CHANGELOG.md
Building apps with AI
rws is easy for coding assistants to get right: one routing pattern, one
Middleware trait for everything, and no hyper/Tower/Axum types to confuse
with this crate's own. Point your assistant at:
- llms.txt — an index of the docs with a one-line summary per page;
raw:
https://raw.githubusercontent.com/bohdaq/rust-web-server/main/llms.txt - llms-full.txt — every docs page in one file, for pasting into a chat or system prompt
- CLAUDE.md — architecture and conventions; Claude Code reads it automatically inside this repo
I'm building on the rust-web-server (rws) crate. Read
https://raw.githubusercontent.com/bohdaq/rust-web-server/main/llms-full.txt
then build a REST API with GET/POST /todos backed by SQLite (model-sqlite),
JWT auth on POST (auth), and per-IP rate limiting on every route.
To make your app a tool that Claude, Cursor and other MCP clients can call, see the MCP server.
Build from source
--no-default-features --features http2 drops HTTP/3; --features http1
builds a plain HTTP/1.1 server with no TLS and no async runtime. Contributor
guide: DEVELOPER.md.
Contributing
Issues labelled good first issue are a good place to start; questions go to Discussions. See CONTRIBUTING.md for how to build, test and send a change.
License
MIT