KingIronMan2011/WebServer

★ 0Forks 0RustGitHub ↗Compare

Project website ↗

README

Webserver

Ein in Rust geschriebener Webserver und Reverse Proxy mit einer schlanken TOML-Konfiguration. Das Projekt bündelt Static-File-Serving, TLS, Load-Balancing, Observability und moderne HTTP-Protokolle in einem Binary.

Lizenz: MIT

Aktueller Stand: v1.1.2. Die stabilen Verträge und Hinweise für produktive Upgrades stehen in docs/UPGRADING.md.

Inhalt

Schnellstart

Für die lokale Entwicklung genügt eine aktuelle Rust-Toolchain:

cargo run -- init
cargo run -- check
cargo run -- run

init legt eine globale Konfiguration, eine erste Site-Datei und ein Startdokument an. check validiert die Konfiguration ohne einen Port zu öffnen. run startet den Server.

Die Standardstruktur ist:

webserver.toml              # globale Server- und TLS-Einstellungen
sites/
  example.com.conf          # eine virtuelle Site je Datei
public/                     # statische Inhalte

Installation auf Debian und Ubuntu

Das signierte APT-Repository stellt derzeit amd64-Pakete bereit:

sudo apt update
sudo apt install -y ca-certificates curl

curl -fsSL https://repo.kingironman.dev/webserver-archive-keyring.gpg \
  | sudo tee /usr/share/keyrings/webserver-archive-keyring.gpg >/dev/null

echo 'deb [signed-by=/usr/share/keyrings/webserver-archive-keyring.gpg] https://repo.kingironman.dev stable main' \
  | sudo tee /etc/apt/sources.list.d/webserver.list >/dev/null

sudo apt update
sudo apt install webserver
sudo systemctl enable --now webserver

Danach liegen Konfiguration und Inhalte unter /etc/webserver/ beziehungsweise /var/www/webserver/. Der Dienst läuft als www-data und nutzt systemd Hardening sowie CAP_NET_BIND_SERVICE für Ports unter 1024.

Betrieb

Aufgabe Befehl
Konfiguration prüfen webserver check --config /etc/webserver/webserver.toml
Dienst starten sudo systemctl start webserver
Routen neu laden sudo systemctl reload webserver
Logs verfolgen sudo journalctl -u webserver -f

Ein Reload (SIGHUP) übernimmt Routen- und Serveränderungen, sofern die neue Konfiguration gültig ist. Änderungen an TLS-Listenern oder Zertifikaten benötigen einen Neustart.

Zero-Downtime-Binary-Upgrade unter Linux

Der Server verwendet auf Linux SO_REUSEPORT. Eine Ersatz-Binary bindet die HTTP-, HTTPS- und QUIC-Ports zuerst; die bisherige Generation nimmt danach keine neuen Verbindungen mehr an und beendet laufende Requests sauber.

sudo install -m 755 ./target/release/webserver /usr/local/bin/webserver.new
sudo mv -f /usr/local/bin/webserver.new /usr/local/bin/webserver
sudo systemctl kill -s USR2 webserver.service

Falls die Ersatz-Binary unmittelbar fehlschlägt, läuft die bisherige Generation weiter.

Konfiguration

Die globale Datei enthält Listener, Limits, Metriken und TLS. Jede Datei im Verzeichnis sites/ beschreibt genau einen virtuellen Host. Bei mehreren passenden Routen gewinnt das längste path_prefix.

# /etc/webserver/webserver.toml
[server]
bind = "0.0.0.0:80"
upstream_timeout_secs = 30
max_header_bytes = 32768
max_body_bytes = 10485760
max_connections = 1024
# rate_limit_per_minute = 120
# allow_ips = ["192.0.2.0/24"]
# deny_ips = ["198.51.100.10/32"]
# trusted_proxies = ["127.0.0.1/32", "::1/128"]
# metrics_path = "/metrics"

[tls]
enabled = true
bind = "0.0.0.0:443"
http3 = true
email = "[email protected]"
certificate_cache = "/etc/webserver/certificates/acme"
# /etc/webserver/sites/example.com.conf
host = "example.com"

[[routes]]
path_prefix = "/"
kind = "static"
root = "/var/www/webserver/example.com"
index_file = "index.html"

[[routes]]
path_prefix = "/api"
kind = "proxy"
upstream = "http://127.0.0.1:3000"

Statische Dateien und Redirects

Static Files werden gestreamt und unterstützen Range Requests, ETag, Last-Modified, Conditional Requests, gzip und Brotli. Response-Header, Fehlerseiten und Redirects sind pro Route konfigurierbar:

[[routes]]
path_prefix = "/assets"
kind = "static"
root = "/var/www/webserver/assets"
response_headers = { cache-control = "public, max-age=3600", x-content-type-options = "nosniff" }
error_pages = { "404" = "/var/www/webserver/errors/not-found.html" }

[[routes]]
path_prefix = "/old"
kind = "redirect"
location = "https://example.com/new"
status = 308

TLS und HTTP/3

Mit aktiviertem TLS leitet Port 80 reguläre Anfragen auf HTTPS um und bedient nur ACME-HTTP-01-Challenges direkt. HTTP/2 wird auf dem TLS-Listener angeboten. http3 = true startet zusätzlich QUIC auf UDP/443 und fügt HTTPS-Antworten automatisch Alt-Svc hinzu, damit Browser auf HTTP/3 wechseln können.

Für einen abweichenden UDP-Port:

[tls]
enabled = true
bind = "0.0.0.0:443"
http3 = true
quic_bind = "0.0.0.0:8443"

Neben automatisch verwalteten Let's-Encrypt-Zertifikaten werden lokale PEM-Zertifikate und interne CAs unterstützt:

[[tls.certificates]]
hosts = ["internal.example.com"]
certificate = "/etc/webserver/certificates/local/internal.fullchain.pem"
private_key = "/etc/webserver/certificates/local/internal.key.pem"

Für Wildcard-Zertifikate kann DNS-01 über den separat installierten lego-Client verwendet werden:

[tls.dns_challenge]
command = "/usr/bin/lego"

[[tls.dns_challenge.providers]]
provider = "cloudflare"
domains = ["example.com", "*.example.com"]
credentials_file = "/etc/webserver/dns/cloudflare.env"

Private Schlüssel und DNS-Zugangsdaten müssen für andere Benutzer unlesbar sein; auf Linux ist für die Credentials-Datei üblicherweise 0600 passend.

Upstreams und Discovery

Proxy-Routen unterstützen mehrere Upstreams, Round Robin, gewichtetes Round Robin, Least Connections, aktive und passive Health Checks, Retries mit Backoff und Limits je Upstream.

[[routes]]
path_prefix = "/api"
kind = "proxy"
load_balancing = "least_connections"
upstreams = [
  { url = "http://127.0.0.1:3000", weight = 3 },
  { url = "http://127.0.0.1:3001", weight = 1 },
]
retries = 2
retry_backoff_ms = 100
max_connections_per_upstream = 100

[routes.health_check]
path = "/health"
interval_secs = 10
timeout_secs = 3

Discovery kann statische Upstreams ergänzen oder vollständig ersetzen.

# DNS
[routes.dns_discovery]
host = "api.internal.example"
port = 3000

# Docker: benötigt nur lesenden Zugriff auf den Docker-Socket.
[routes.docker_discovery]
labels = { "webserver.discovery" = "api" }
port = 3000
socket = "/var/run/docker.sock"
refresh_secs = 30

# Kubernetes-Service-DNS, auch für Headless Services.
[routes.kubernetes_discovery]
service = "api"
namespace = "production"
port = 3000
cluster_domain = "cluster.local"

Sicherheit und Observability

  • Limits für Header, Body, Requests pro IP und gleichzeitige Verbindungen
  • Allow-/Deny-Netze und vertrauenswürdige Proxy-Netze für X-Forwarded-For
  • CORS- sowie beliebige Response-Header-Regeln
  • JSON-Logs mit WEBSERVER_LOG_FORMAT=json
  • Prometheus-Endpunkt über server.metrics_path
  • OpenTelemetry über die üblichen OTEL_EXPORTER_OTLP_*-Umgebungsvariablen
  • Embedded Standardfehlerseiten für gängige 4xx- und 5xx-Statuscodes

Metriken sollten ausschließlich über ein privates Netzwerk oder einen vertrauenswürdigen vorgeschalteten Proxy verfügbar sein.

CLI

Neben init, check und run kann die CLI Sites und Routen verwalten:

webserver site-add --host example.test
webserver route-add --host example.test --path / --static ./public
webserver route-add --host example.test --path /api --upstream http://127.0.0.1:3000
webserver route-remove --host example.test --path /api
webserver completion bash

Stabile Verträge

Ab v1.0 gelten die folgenden Kompatibilitätsregeln:

  • TOML-Felder, CLI-Befehle und ihre dokumentierten Optionen bleiben innerhalb einer Hauptversion kompatibel. Neue optionale Felder oder Endpunkte sind zulässig; Umbenennungen, Entfernungen oder Bedeutungsänderungen erfordern eine neue Hauptversion.
  • Die Verwaltungs-API verwendet den Pfadpräfix /api/v1; jede Antwort enthält X-Webserver-Api-Version: 1. Der maschinenlesbare Vertrag ist unter /api/v1/openapi.json verfügbar.
  • Browser-Sitzungen verwenden ausschließlich das HttpOnly- Secure-Cookie __Host-webserver_admin. Automatisierung kann einen Bearer-Session-Token verwenden. Zugangsdaten und private Schlüssel werden niemals von API-Endpunkten ausgegeben.
  • Die Dashboard-Dateien sind ein Build-Artefakt unter dashboard/; der Release- und Debian-Paketbau liefert dessen dist mit aus.

Die vollständige API-, Konfigurations- und Upgrade-Referenz steht in docs/UPGRADING.md.

Upgrades

Vor jedem produktiven Upgrade müssen Konfiguration und Verwaltungsdatenbank gesichert werden. Die Schritt-für-Schritt-Anleitung, Downgrade-Regeln und Rollback-Abläufe stehen in docs/UPGRADING.md.

Entwicklung

cargo fmt --check
cargo test --locked
cargo clippy --locked -- -D warnings
cargo build --locked --release

Für eine lokale Paketinstallation auf systemd-basierten Linux-Systemen:

sudo packaging/install.sh ./target/release/webserver

Roadmap

V1.0 ist abgeschlossen. Weiterführende Vorhaben werden in TODO.md gepflegt.

Lizenz

Dieses Projekt steht unter der MIT-Lizenz.

Contributors

KingIronMan2011dependabot[bot]

Issues