The web server that gets
its own certificates
and routes your apps
Static files, automatic Let's Encrypt certificates, HTTP/3 and a load balancing reverse proxy, configured in one TOML file. When you need code, the same engine is a Rust crate.
brew install bohdaq/tap/rwsmacOS and Linux, x86_64 and arm64.
cargo binstall rust-web-serverPrebuilt binary through cargo binstall; works on Windows too.
docker run -p 7878:7878 -v "$PWD:/srv" bohdaq/rwslinux/amd64 and linux/arm64, also on ghcr.io/bohdaq/rws.
sudo apt install rws # or: sudo dnf install rwsAfter adding the repository; installs and starts the rws service. Add the repository.
Gateway API v1.6.3 conformant · h2spec 146 of 146 · MIT licensed
Three jobs, three short configs
cd my-site && rwsServes the folder on port 7878 with directory listings, ETags, byte ranges and compression.
port = 443
http_redirect_port = 80
[acme]
domains = ["example.com", "www.example.com"]
email = "you@example.com"Gets certificates from Let's Encrypt on first start, serves HTTP/2 and HTTP/3, redirects HTTP and renews in the background.
[[upstream]]
name = "app"
backends = ["10.0.0.10:8080", "10.0.0.11:8080"]
strategy = "least_connections"
[upstream.health_check]
path = "/healthz"
[[route]]
[route.match]
host = "api.example.com"
path = "/v1/*"
[route.action]
type = "proxy"
upstream = "app"
[route.middleware]
rate_limit = { max_requests = 500, window_secs = 60 }
auth = { type = "bearer", token_env = "API_TOKEN" }Balances two backends by open connections, checks their health and puts a rate limit and a token in front.
One binary serves your files, gets your certificates and routes your traffic. One file tells it how.
What's in the box
One process instead of four
Static files, certificates, redirects and the proxy run in one binary; no certbot, cron job or sidecar.
Certificates that look after themselves
Ordered on first start, renewed at two thirds of their lifetime, reloaded without dropping connections. HTTP-01, TLS-ALPN-01 and DNS-01.
Traffic you can steer
Round robin, least connections, IP hash, weights, health checks, retries, circuit breakers, sticky sessions and canary splits.
Protection on by config
Bearer, JWT and basic auth that fail closed, rate limits, IP allow and deny lists, request size limits.
Answers you can measure
Prometheus metrics with native histograms, OpenTelemetry traces and metrics, JSON access logs.
Kubernetes without another controller
Built with gateway-api, rws is the Gateway API controller and data plane: HTTP, gRPC, TLS, TCP and UDP routes, installed with the Helm chart.
How it works
- 1
Install one binary
Homebrew, Cargo, Docker, apt or dnf. Static builds for Linux, plus macOS and Windows.
- 2
Write one file
Put what you need in
rws.config.toml.rws --checkvalidates it before anything starts. - 3
Run rws
It serves and gets certificates, and reloads on
SIGHUP, or by itself when the file changes withwatch = true.
Fast where it counts
Same 4 CPU runner, same load: HTTP/1.1, 64 connections, 20 seconds per scenario.
96,670req/s
1 KiB static file. nginx: 81,161. Caddy: 18,592.
16.9µs
CPU per static request. nginx: 25.1 µs.
1.9×
Gateway API throughput of the next gateway: 38,501 vs 20,225 req/s (kgateway).
Built in the open
- h2spec: 146 of 146 HTTP/2 conformance tests
- Gateway API v1.6.3: all five Gateway profiles, core and extended
- ACME tested end to end against Pebble, Let's Encrypt's test CA
- Every parser of untrusted input is fuzzed
- Releases carry build attestations and a cosign signature
- MSRV pinned at Rust 1.99, MIT licensed
When config isn't enough, it's a crate
The same engine is rust-web-server on crates.io: routes with typed extractors, one Middleware trait, an MCP server, OAuth, OIDC and SAML, an async ORM and background jobs, without hyper, Tower or Axum underneath.
use rust_web_server::prelude::*;
fn hello(_req: &Request, _params: &PathParams, _conn: &ConnectionInfo, _state: &()) -> Response {
Response::text(STATUS_CODE_REASON_PHRASE.n200_ok, "Hello, world!")
}
#[tokio::main]
async fn main() {
let app = routes! {
App::with_state(()),
GET "/hello" => hello,
};
let (listener, pool) = Server::setup().unwrap();
tokio::join!(
Server::run_tls(listener, pool, app.clone()),
Server::run_quic(app),
Server::run_redirect(),
);
}Questions
How is rws different from nginx or Caddy?
One binary covers static files, certificates, the reverse proxy and a Kubernetes gateway, configured in TOML. When config runs out, the same engine is a Rust library, so you don't switch tools.
Is it ready for production?
It runs the HTTP/2 conformance suite, the Gateway API suite and ACME against Pebble on every change, and fuzzes its parsers. It is a younger project than nginx; read the changelog and pin a version.
Does it run on Windows?
Yes. There are prebuilt binaries for Windows, Linux (static, any distribution) and macOS, and it can run as a Windows service.
What does it cost?
Nothing. rws is MIT licensed.
How do I upgrade?
Replace the binary and restart, or reload. Breaking changes are listed in the changelog with a migration guide per major version.
Does it support HTTP/3?
Yes, over QUIC on the same port as HTTPS, alongside HTTP/2 and HTTP/1.1.
Can I run it on Kubernetes?
Yes, as a plain Deployment or as a Gateway API controller with the Helm chart.
Can my AI coding agent use these docs?
Yes. llms.txt and llms-full.txt cover every page, and an agent skill pack lives at /agents/.
What if I outgrow the config file?
Use the rust-web-server crate: the config file's features are library types you can compose in code.
How do I remove it?
Delete the binary and the config file. rws keeps nothing else, except certificates under .rws/acme/ if you used ACME.
Run it in one minute
brew install bohdaq/tap/rwsmacOS and Linux, x86_64 and arm64.
cargo binstall rust-web-serverPrebuilt binary through cargo binstall; works on Windows too.
docker run -p 7878:7878 -v "$PWD:/srv" bohdaq/rwslinux/amd64 and linux/arm64, also on ghcr.io/bohdaq/rws.
sudo apt install rws # or: sudo dnf install rwsAfter adding the repository; installs and starts the rws service. Add the repository.
MIT licensed. One binary. Remove it by deleting one file.