# Installation

> How to install rust-web-server as a library crate, as a standalone binary, or from source — including feature flags and MSRV.

Source: https://rws8.tech/docs/getting-started/installation/ · Last updated 2026-11-10

## Requirements

**Minimum Supported Rust Version (MSRV): 1.99**

Install or update Rust via [rustup](https://rustup.rs/):

```bash
rustup update stable
rustc --version   # should print 1.99.0 or newer
```

## As a library crate

Add `rust-web-server` to your `Cargo.toml`:

```bash
cargo add rust-web-server
```

Or pin the major version manually:

```toml
[dependencies]
rust-web-server = "18"
```

The default feature set (`http3`) pulls in HTTP/3, HTTP/2, TLS, and a tokio async runtime. If you need a lighter build, opt out and select a lower feature tier (see the feature flags table below).

### Prelude

A single glob import covers the types you need in almost every handler:

```rust
use rust_web_server::prelude::*;
// Re-exports: App, Server, ConnectionInfo, Request, Response,
//             STATUS_CODE_REASON_PHRASE, Range, MimeType,
//             PathParams, New, routes!
```

## As a standalone binary

Every release ships prebuilt binaries, so no Rust toolchain is needed:

| Method | Command | Platforms |
|---|---|---|
| Install script | `curl -fsSL https://rws8.tech/install.sh \| sh` (`sh -s -- --version 18.8.3 --dir ~/bin` to pin a release or a directory) — downloads the release archive, checks its `.sha256` and installs to `/usr/local/bin`, else `~/.local/bin` (since 18.8.4) | Linux (x86_64, arm64), macOS (Apple Silicon, Intel) |
| Homebrew | `brew install bohdaq/tap/rws` | macOS (Apple Silicon, Intel), Linux (x86_64, arm64) |
| cargo-binstall | `cargo binstall rust-web-server` | everything below, without compiling |
| apt / dnf | `sudo apt install rws`, `sudo dnf install rws` after adding the repository — [systemd: install from a package](/deployment/systemd/#install-from-a-package); installs and starts the `rws` service (since 18.2.0) | Debian, Ubuntu, Fedora, RHEL and derivatives (x86_64, arm64) |
| Docker | `docker run -p 7878:7878 -v "$PWD:/srv" bohdaq/rws` (also `ghcr.io/bohdaq/rws`) | linux/amd64, linux/arm64 |
| Download | [GitHub Releases](https://github.com/bohdaq/rust-web-server/releases/latest) | `x86_64`/`aarch64-unknown-linux-musl`, `x86_64`/`aarch64-apple-darwin`, `x86_64-pc-windows-msvc` |
| From source | `cargo install rust-web-server` | anywhere Rust 1.99+ runs |

On Windows, `rws.exe` also runs as a Windows service — see [Windows](/deployment/windows/).

Linux binaries are statically linked against musl, so they run on any distribution regardless of glibc version. Each archive has a matching `.sha256` file.

```bash
rws --version
rws --help      # every option, with its environment-variable equivalent
```

Run it in any directory that contains static files and it will serve them on `http://localhost:7878` with no configuration file needed.

### Verifying a release

From 18.0.0, releases can be checked end to end:

```bash
# The archive was built by this repository's release workflow
gh attestation verify rws-18.0.0-x86_64-unknown-linux-musl.tar.gz --repo bohdaq/rust-web-server

# The image too — attestation, or the keyless cosign signature
gh attestation verify oci://ghcr.io/bohdaq/rws:18.0.0 --repo bohdaq/rust-web-server
cosign verify ghcr.io/bohdaq/rws:18.0.0 \
  --certificate-identity-regexp 'https://github.com/bohdaq/rust-web-server/.github/workflows/release.yml@.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

# Known vulnerabilities in the dependencies compiled into a binary
# (built with cargo-auditable, so the list travels with it)
cargo audit bin ./rws
```

Each release also has a CycloneDX SBOM (`rws-<version>.cdx.json`) of the
binary's dependency tree. CI checks every change with `cargo audit` and
`cargo deny` (advisories; permissive licenses only; crates.io sources only —
`deny.toml`).

## Build from source

```bash
git clone https://github.com/bohdaq/rust-web-server.git
cd rust-web-server
cargo build --release
# binary is at: target/release/rws
```

To build a specific feature tier from source:

```bash
# HTTP/2 + TLS only (no QUIC)
cargo build --release --no-default-features --features http2

# HTTP/1.1 only — no TLS, no async runtime, smallest binary
cargo build --release --no-default-features --features http1
```

## Feature flags

### Presets

Since 18.32.0 four presets turn on common sets of the features below. They
only enable other features, so they combine with each other and with single
features:

```toml
[dependencies]
rust-web-server = { version = "18.32", features = ["api"] }
# HTTP/2 + TLS without QUIC: default-features = false, features = ["api"]
```

| Preset | For | Features |
|---|---|---|
| `web` | Server-rendered apps | `http2`, `serde`, `macros`, `tera`, `auth`, `crypto` (password hashing, signed and encrypted cookies), `csrf`, `model-sqlite`, `jobs`, `mailer`, `storage-local` |
| `api` | JSON APIs | `http2`, `serde`, `macros`, `openapi`, `auth`, `auth-asymmetric`, `model-sqlite`, `jobs` |
| `proxy` | The reverse proxy / edge server | `http3`, `brotli`, `zstd`, `acme`, `auth`, `auth-asymmetric`, `sso`, `rewrite-regex`, `secrets` |
| `full` | Everything that builds with Rust and a C compiler alone | every feature except `fips` (needs CMake and Go), `pkcs11` (only useful with an HSM), `http1` (the synchronous server, an alternative to `http2`) and `mimalloc` (the `rws` binary's allocator) |

Sessions, routing, middleware, MCP, WebSocket and SSE need no feature. Add
`model-postgres` or `model-mysql` beside a preset for another database.

**Build times.** A clean debug `cargo build --lib` of rust-web-server, each
preset on top of the default features (`http3`, `brotli`, `zstd`), measured
2026-11-04 on a 4-core Linux container (rustc 1.97) with other builds
sharing the CPU — read them as relative:

| Features | Clean build | `target/` size |
|---|---|---|
| default | 49 s | 1.1 GB |
| `proxy` | 52 s | 1.4 GB |
| `web` | 59 s | 1.8 GB |
| `api` | 62 s | 1.6 GB |
| `full` | 1 min 47 s | 3.9 GB |

Rebuilds after a change to your own code only recompile your crate.

### On docs.rs

[docs.rs](https://docs.rs/rust-web-server) documents the crate with `full`,
`http1` and `pkcs11` — every item, each labelled with the features it needs
(for example *Available on crate feature `sso` only*). `fips` and `mimalloc`
add no items.

### All features

`fips` (since 18.23.0) builds TLS on aws-lc's FIPS 140-3 validated module
and needs CMake and Go; see [FIPS 140-3](/features/https-tls/#fips-140-3).
`pkcs11` (since 18.23.0) lets `tls_key_file` name a key on an HSM or cloud
KMS; see [PKCS#11](/features/https-tls/#keys-in-an-hsm-or-cloud-kms-pkcs11).


| Feature | What it adds | Required deps |
|---|---|---|
| `http1` | Synchronous thread-pool server, no async runtime, no TLS | `ctrlc`, `libc` |
| `http2` | tokio runtime, TLS via rustls (aws-lc-rs), HTTP/2 via ALPN | `h2`, `rustls`, `tokio`, `tokio-rustls`, … |
| `http3` *(default)* | QUIC transport and HTTP/3 on top of `http2` | `quinn`, `h3`, `h3-quinn` |
| `geo` *(default)* | The country table of the admin UI's Traffic page (DB-IP Lite, CC BY 4.0, ~700 KB), since 18.31.0 | `flate2` |
| `http-client` | HTTPS support in the outbound `Client` | `rustls`, `webpki-roots` |
| `serde` | JSON serialization/deserialization via serde | `serde`, `serde_json` |
| `auth` | `BasicAuthLayer`, `JwtLayer` (HS256), `ForwardAuthLayer`, JWT helpers | `hmac`, `sha2` |
| `auth-asymmetric` | RS256 / ES256 in `JwtLayer` (in-crate RSA verification) | `auth`, `p256`, `rand_core` |
| `macros` | `#[derive(Model)]`, `#[derive(FromRequest)]`, `#[derive(Validate)]`, `#[derive(Config)]`, `#[get]`/`#[post]`/… route attributes | `rws-macros` |
| `acme` | Automatic TLS certificate provisioning (ACME/Let's Encrypt) | `http2`, `rcgen`, `aws-lc-rs`, … |
| `mimalloc` | The `rws` binary allocates with mimalloc v3 (about 5% less CPU per request than glibc's allocator; more memory under load); release binaries and images have it. The library never sets a global allocator | `mimalloc` |
| `tera` | Tera template engine integration | `tera`, `serde`, `serde_json` |
| `model-sqlite` | Async ORM backend for SQLite | `http2`, `sqlx` (sqlite) |
| `model-postgres` | Async ORM backend for PostgreSQL | `http2`, `sqlx` (postgres) |
| `model-mysql` | Async ORM backend for MySQL / MariaDB | `http2`, `sqlx` (mysql) |
| `crypto` | Argon2id password hashing, signed (HMAC) and encrypted (AES-GCM) cookies | `argon2`, `rand_core`, `hmac`, `sha2`, `aes-gcm` |
| `csrf` | CSRF token generation and validation | `rand_core` |
| `mailer` | SMTP client (STARTTLS/SMTPS also need `http-client` or `http2`) | — |
| `sso` | OAuth 2.0 / OIDC client (RS256/ES256 `id_token` verification, outbound HTTPS) | `p256`, `sha2`, `rand_core`, `serde`, `serde_json`, `http-client` |
| `sso-server` | `AuthServer`: rws as an OAuth 2.0 authorization server (HS256 tokens) | `sso`, `auth` |
| `sso-saml` | `SamlSp`: SAML 2.0 Service Provider | `sso` |
| `jobs` | In-memory `JobQueue` (`PersistentJobQueue` also needs a `model-*` feature) | — |
| `storage-local` | `LocalStorage` | — |
| `storage-s3` | `S3Storage` (AWS SigV4, no SDK) | `hmac`, `sha2`, `http-client` |
| `storage-azure` | `AzureBlobStorage` (Shared Key / Managed Identity, no SDK) | `hmac`, `sha2`, `http-client` |
| `storage-gcs` | `GcsStorage` (service-account JWTs, metadata server, no SDK) | `http-client`, `aws-lc-rs` |
| `brotli` *(default)* | `br` content coding | `brotli` |
| `zstd` *(default)* | `zstd` content coding | `zstd` (C libzstd, built with the crate) |
| `tower` | Tower layers as middleware, Tower services as apps, an app as a Tower service | `http2`, `tower-service`, `tower-layer`, `http-body` |
| `gateway-api` | Kubernetes Gateway API controller | `http2`, `serde`, `kube`, `k8s-openapi` |
| `k8s` | The Kubernetes API from an app (ConfigMaps, Secrets, discovery, leader election) and operators (controllers, webhooks, CRD/RBAC manifests, test clusters) | `http2`, `serde`, `kube`, `k8s-openapi`, `schemars` |
| `wasm-plugins` | `WasmLayer`: middleware as WebAssembly modules | `wasmtime` |
| `fips` | TLS on aws-lc's FIPS 140-3 module (needs CMake and Go) | `http2` |
| `pkcs11` | TLS private keys on an HSM or cloud KMS | `http2`, `cryptoki` |
| `openapi` | `GET /openapi.json` + `GET /docs` from registered routes | — |
| `webhook` | `verify_webhook_signature` (GitHub, Shopify, Stripe) | `hmac`, `sha2` |
| `rewrite-regex` | `RewriteLayer::request_uri_regex_rewrite` | `regex` |
| `secrets` | `secrets::resolve()` for `vault://`, `aws-sm://`, `azkv://` references | `hmac`, `sha2`, `http-client` |

:::note[Combining features]
Features compose freely. For example, to build HTTP/2 + TLS + JSON + SQLite:

```toml
rust-web-server = { version = "18", default-features = false, features = ["http2", "serde", "model-sqlite"] }
```
:::

## Approximate binary sizes

These measurements are for a release build (`cargo build --release`) of the `rws` binary with only the core transport feature active. Enabling additional features (`serde`, `tera`, ORM backends, etc.) increases the size.

| Feature tier | Approx. binary size |
|---|---|
| `http1` | ~3 MB |
| `http2` | ~8 MB |
| `http3` (default) | ~12 MB |

:::note[No OpenSSL]
TLS uses `rustls` with the `aws-lc-rs` crypto backend. There is no dependency on a system OpenSSL installation. Binaries are fully static with respect to TLS and are compatible with FIPS-validated environments.
:::

## What's built in, and what isn't

HTTP/1.1 parsing, CORS, MIME types, range requests, WebSocket, SSE, and routing are implemented inside this crate. The transitive dependency tree has no `hyper`, `tower`, or `actix-net`.

The HTTP/2 server is rws's own (`h2_server`: framing, HPACK, flow control — conformance-checked with h2spec and fuzzed); the `h2` crate remains a dependency as the HTTP/2 *client* of `H2ReverseProxy`/`GrpcProxy`. HTTP/3 and QUIC use `h3` and `quinn`, and TLS uses `rustls`. `tokio-util` appears transitively in the default build through `h2`.
