Product overview
One server between the network and your application.
Webship is a self-hosted Rust edge and static web server. One runtime terminates modern protocols, applies edge policy, serves files, and proxies application requests.
Modern transport
Accept HTTP/1.1, HTTP/2, and HTTP/3, with TLS 1.3 and an optional WebTransport endpoint.
Static and proxied delivery
Serve static files with validators and precompressed sidecars, or proxy application traffic through bounded upstream pools.
Secure defaults
Begin with the WAF, DDoS controls, bot challenge, response security headers, API Shield, and dot-file protection enabled.
Observable operations
Use authenticated statistics, Prometheus metrics, request IDs, graceful reloads, and the optional MCP control plane.
Quick start
From release binary to healthy listener.
Start on loopback, validate everything before binding, and verify the built-in health response before adding public traffic.
Prepare files
Place the release binary, its TOML configuration, the static root, and any configured TLS certificate and key files on the host.
Validate and inspect
Run both configuration commands. Fix the first error and inspect the redacted effective result before startup.
Start privately
Start Webship with the selected TOML file. Add a complete certificate pair or automatic TLS when the site is ready for secure public traffic.
Verify the runtime
Call GET /health locally. Then test static paths, TLS, proxy routes, security rules, and authenticated monitoring.
listen = "127.0.0.1:4433"
workers = 4
root = "./public"/usr/local/bin/webship --check-config --config /etc/webship/production.toml
/usr/local/bin/webship --print-effective-config --config /etc/webship/production.toml/usr/local/bin/webship --config /etc/webship/production.toml
curl --http3-only --insecure https://127.0.0.1:4433/healthQuick Start Guide for AI Agents
Connect an AI agent to Webship in five lines.
Connect Claude Code, OpenAI, DeepSeek, or any compatible MCP client through a private SSH tunnel. The agent receives an authenticated operations surface without sharing the public listener or exposing control credentials to internet traffic.
{
"mcpServers": {
"webship": { "url": "https://localhost:19443/mcp",
"headers": { "Authorization": "Bearer <token>" } }
} }Static delivery
Serve a directory with protocol-aware defaults.
Set a root globally or per site. TLS sites default to HTTP/3 only; cleartext sites default to HTTP/1.1 and H2C. Override HTTP/1.1, HTTP/2, and HTTP/3 independently for each site.
[[sites]]
domain = "app.example.com"
root = "/srv/app"
listen = "0.0.0.0:443"
[sites.protocols]
h1 = true
h2 = true
h3 = trueThe built-in router supports GET and HEAD, byte ranges, conditional requests, validators, and .br, .zst, and .gz sidecars. Dot-file paths are refused by default; .well-known remains available.
Application traffic
Route requests to one or more upstreams.
Enable reverse proxying, match a host and path, then define a final unconditional policy. Webship supports bounded pools, health checks, load balancing, circuit breakers, safe bodyless retries, WebSockets, and caching.
[reverse_proxy]
enabled = true
[[reverse_proxy.routes]]
domain = "app.example.com"
path_prefix = "/api"
strip_path_prefix = true
upstreams = ["127.0.0.1:8080", "127.0.0.1:8081"]
[[reverse_proxy.policies]]
name = "default"
hosts = []
path_prefixes = ["/"]
methods = []
max_body_bytes = 1048576
total_timeout_ms = 30000TLS and HTTP/3
Use manual certificates or let Webship manage them.
Webship 1.4.0 accepts TLS 1.3 and lets every site select its certificate mode independently. HTTP/3 uses the matching UDP listener; enable HTTP/1.1 or HTTP/2 when the same TLS site also needs TCP compatibility.
listen = "0.0.0.0:443"
[automatic_tls]
enabled = true
directory_url = "https://acme-v02.api.letsencrypt.org/directory"
cache_dir = "/var/lib/webship/acme"
contacts = ["mailto:ops@example.com"]
accept_terms_of_service = true
[[sites]]
domain = "app.example.com"
root = "/srv/app"
certificate_mode = "per_site" # default public ACME certificate
[[sites]]
domain = "legacy.example.com"
root = "/srv/legacy"
certificate_mode = "shared" # legacy public multi-SAN certificateWebship 1.4.0 certificate architecture
Choose certificate trust and scale independently for every site.
Webship 1.4.0 moves certificate_mode onto each [[sites]] entry. Public per-site ACME, public DNS-01 fleet shards, the embedded private CA, the legacy shared certificate, and manual certificate files can coexist in one self-contained process.
per_site — public certificate
The default. Order one browser-trusted public ACME certificate for the site's exact name with TLS-ALPN-01.
fleet — public DNS-01 shards
Use public DNS-01 issuance for many third- and fourth-level names under explicit registered domains. Names remain in stable, batched certificate shards.
embedded — private CA
Issue a separate certificate in-process from Webship's private CA. No public ACME account, DNS challenge, registrar integration, or inbound port 443 is required.
shared — legacy multi-SAN
Keep the legacy public multi-SAN group for deployments that require it. This is not the default and remains subject to public-CA identifier limits.
[automatic_tls]
enabled = true
directory_url = "https://acme-v02.api.letsencrypt.org/directory"
cache_dir = "/var/lib/webship/acme"
contacts = ["mailto:ops@example.com"]
accept_terms_of_service = true
[automatic_tls.fleet]
shard_size = 64
batch_window_ms = 300000
weekly_certificate_limit = 50
emergency_certificate_reserve = 5
registered_domains = ["example.com"]
[automatic_tls.fleet.dns]
listen = "0.0.0.0:53"
nameservers = ["ns1.example.net"]
addresses = ["192.0.2.10"]
propagation_timeout_ms = 120000
resolver_url = "https://dns.google/resolve"
challenge_ttl_seconds = 900
[[sites]]
domain = "app.example.com"
root = "/srv/app"
certificate_mode = "fleet"
[[sites]]
domain = "media.app.example.com"
root = "/srv/media"
certificate_mode = "fleet"[automatic_tls]
enabled = true
cache_dir = "/var/lib/webship/acme"
[acme_ca]
state_dir = "/var/lib/webship/acme-ca"
leaf_validity_days = 90
[[sites]]
domain = "internal.example.com"
root = "/srv/internal"
certificate_mode = "embedded"Edge policy
Keep the secure baseline intact.
Webship enables its main protection layers by default. Tune limits for your workload and validate after every rule or header-policy change.
[ddos]
enabled = true
mode = "normal"
requests_per_minute = 600
burst = 100
block_seconds = 300
[security.response_headers]
enabled = true
nosniff = true
frame_deny = true
referrer_no_referrer = true
hsts = "max-age=31536000; includeSubDomains"
content_security_policy = "default-src 'self'; frame-ancestors 'none'"Use normal mode for regular traffic, under_attack for stricter active-attack handling, and lockdown when only probes and explicitly permitted paths should remain available.
Private diagnostics
Inspect the edge without exposing the control plane.
Statistics and Prometheus metrics run on a separate authenticated listener. Instrumentation must be enabled whenever either endpoint is active.
[observability]
instrumentation = true
stats = true
metrics = true
listen = "127.0.0.1:9090"
token = "replace-with-at-least-32-random-printable-ascii-characters"Safe operations
Reload deliberately. Keep rollback close.
Configuration reload
Send SIGHUP after editing a file-backed configuration. Webship validates the replacement before installing it and retains the running configuration when validation fails.
Upgrade and rollback
Install the new binary beside the previous version, validate the production configuration with it, then verify health, TLS, proxying, and metrics. Keep the previous binary until every gate passes.
kill -HUP "$(pidof webship)"
/usr/local/bin/webship update --config /etc/webship/production.toml
sudo systemctl daemon-reload
sudo systemctl enable --now webship
sudo systemctl status webshipProfile-guided optimization
Collect target-native profiles without confusing training and production.
Every Webship 1.4.0 target has a separate instrumented CLI for collecting target-native LLVM profile data under your representative traffic. Use the exact version and target triple, exercise the routes and protocols that matter, and stop the process gracefully so it can flush every .profraw file.
Select the exact target
Download the PGO training CLI whose release version and Rust target triple exactly match the runtime you intend to optimize. Verify its published SHA-256 first.
Capture representative traffic
Set LLVM_PROFILE_FILE to a writable directory, start the training CLI with a validated copy of the real configuration, replay representative direct and reverse-proxy traffic, then stop Webship gracefully.
Merge raw profiles
Use llvm-profdata from the compiler generation recorded for the release. Merge every emitted .profraw file into one sparse webship.profdata file.
Rebuild and gate
Apply the merged profile only to the exact source, compiler, crypto provider, feature set, and target that generated it. Run correctness and performance gates before promotion.
mkdir -p ./profiles
export LLVM_PROFILE_FILE="$PWD/profiles/webship-%p-%m.profraw"
./webship-pgo-training-1.4.0-<target> --config ./webship.tomlNew-Item -ItemType Directory -Force ./profiles
$env:LLVM_PROFILE_FILE = "$PWD/profiles/webship-%p-%m.profraw"
.\webship-pgo-training-1.4.0-<target>.exe --config .\webship.tomlllvm-profdata merge -sparse ./profiles/*.profraw -o ./webship.profdataCommand-line reference
Small surface, explicit startup.
webship [OPTIONS] | webship update [OPTIONS]
-c, --config PATH- Select the TOML file. If it does not exist, Webship creates it with a private localhost TLS identity.
--check-config- Validate the complete configuration and exit without starting listeners.
--print-effective-config- Print the merged effective configuration with secrets removed.
update- Verify the signed community manifest, select this exact platform target, and install a newer version when one exists.
--help / --version- Print command help or the installed Webship version.
Common failure modes
Start with configuration, then move outward.
- Run --check-config and correct the first reported error; unknown TOML fields are rejected.
- Confirm the configured TCP and UDP ports are available and allowed by the firewall.
- Confirm the certificate and key exist, are readable by the service account, and form a matching pair.
- For automatic TLS, confirm every configured domain resolves to the Webship host.
- Call /health on the local application listener before testing through DNS or an external load path.
- Enable authenticated observability temporarily when runtime evidence is required.