Skip to content

About

A web server and reverse proxy with automatic HTTPS from Let's Encrypt, HTTP/3, load balancing, and auth — configured in one TOML file. When you outgrow configuration, the same engine is a Rust library.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

2,256 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rws

CI Crates.io docs.rs License: MIT MSRV: 1.88

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

brew install bohdaq/tap/rws          # macOS / Linux — or: cargo binstall rust-web-server
docker run -p 7878:7878 -v "$PWD:/srv" bohdaq/rws

Prebuilt binaries for Linux (static, any distro), macOS, and Windows are on GitHub Releases.


Serve a folder

cd my-site && rws

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
port               = 443
http_redirect_port = 80

[acme]
domains = ["example.com", "www.example.com"]
email   = "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

[[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" }

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


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
[dependencies]
rust-web-server = "18"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use rust_web_server::prelude::*;

fn hello(_: &Request, _: &PathParams, _: &ConnectionInfo, _: &()) -> 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(),
    );
}

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/h3 crates, and TLS uses rustls — 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/):

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

git clone https://github.com/bohdaq/rust-web-server.git
cd rust-web-server
cargo build --release      # target/release/rws; MSRV 1.88

--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

About

A web server and reverse proxy with automatic HTTPS from Let's Encrypt, HTTP/3, load balancing, and auth — configured in one TOML file. When you outgrow configuration, the same engine is a Rust library.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages