rws
Static file web server and HTTP toolkit written in Rust. Supports HTTP/3, HTTP/2, and HTTP/1.1. HTTP/3 and HTTP/2 require a TLS certificate; without one the server falls back to plain HTTP/1.1 automatically.
Use it as a ready-to-run binary or pull it in as a library crate to get battle-tested building blocks — request/response parsing, routing, headers, MIME detection, body parsing, JSON, logging — without taking on a full async framework.
Install
This installs the rws binary with HTTP/3, HTTP/2, and TLS support included.
Run
Plain HTTP/1.1
Starts on http://127.0.0.1:7878 by default. Place your files in the working directory and open the URL in a browser.
HTTPS + HTTP/2 + HTTP/3
Generate a self-signed certificate for local development:
Start the server with the certificate:
Open https://127.0.0.1:7878 in a browser. The server listens on the same port for both TCP (HTTP/1.1 and HTTP/2 via ALPN) and UDP (HTTP/3 via QUIC). HTTP/2 and HTTP/3 are negotiated automatically — no extra configuration needed.
For a public domain, obtain a certificate from Let's Encrypt.
Custom address and port
See CONFIGURE for all configuration options (env vars, config file, command-line flags).
Build from source
The binary is at target/release/rws.
To build with HTTP/2 only (no QUIC/HTTP/3):
To build HTTP/1.1 only (smallest binary, no TLS):
Features
- HTTP/3 over QUIC (UDP) — negotiated via
Alt-Svc - HTTP/2 with ALPN negotiation alongside HTTP/1.1 on the same TCP port
- TLS via rustls (aws-lc-rs backend, no OpenSSL)
- HTTP/1.1 keep-alive — persistent connections;
Connection: closeor idle timeout ends the session - Response compression — automatic gzip for text types when client sends
Accept-Encoding: gzip - Large file streaming — chunked transfer for files > 8 MB; no full-file buffering
- HTTP → HTTPS redirect — set
RWS_CONFIG_HTTP_REDIRECT_PORTto redirect a plain-HTTP port - Cookie handling —
CookieJarparses theCookieheader;SetCookiebuilder createsSet-Cookievalues - CORS — allowed for all origins by default, fully configurable
- HTTP Range Requests — partial file serving and multi-range responses
- HTTP Client Hints
- ETag and 304 Not Modified — conditional requests skip body transfer on cache hit
- Security headers —
Strict-Transport-Security(HTTPS only),Content-Security-Policy(configurable viaRWS_CONFIG_CSP),Referrer-Policy,Permissions-Policy,X-Content-Type-Options,X-Frame-Options - WebAssembly MIME type —
.wasmfiles served asapplication/wasm - Combined Log Format (CLF) — access log compatible with GoAccess and AWStats; set
RWS_CONFIG_LOG_FORMAT=jsonfor structured JSON logs - Graceful shutdown — Ctrl+C and SIGTERM stop the server cleanly (async/TLS paths);
/readyzreturns503during drain - Kubernetes-ready — health probes (
GET /healthzliveness,GET /readyzreadiness), Prometheus metrics (GET /metrics),0.0.0.0default bind, Dockerfile included - Dynamic routing — standalone
Routerwith:paramand*wildcardpath matching - Typed errors —
IntoResponsetrait and built-inAppErrormapping to HTTP status codes - In-process test client —
TestClientdispatches requests without a TCP socket - 30-second read timeout per request on plain HTTP/1.1 connections
- Symlink resolution
.htmlextension inference —/pageservespage.html;/dirservesdir/index.html- Custom 404 page — place a
404.htmlin the working directory to override the default
Use as a library
Add the crate to Cargo.toml:
[]
= "17"
Implement a controller and plug it into the server in a few lines:
use Controller;
use ;
use ;
use Range;
use MimeType;
use ConnectionInfo;
;
See DEVELOPER for the full building blocks reference and 12 use case examples covering JSON responses, query parameters, form and file upload parsing, redirects, error responses, MIME detection, and access logging.
Further reading
- CONFIGURE — all configuration options
- FAQ — common problems and solutions
- DEVELOPER — building blocks, use cases, building, and testing
- src/README.md — module-level documentation
License
MIT