Skip to content

OpenShield-L7 โ€‹

An L7-protected reverse web proxy, written in Rust. OpenShield-L7 is a filter: it sits in front of your destination web servers (ip:port), terminates ports 80/443, and forwards only clean traffic onward. It never hosts content itself โ€” the only bytes it originates are block pages, challenge pages, and the admin API.

One binary (openshield-l7), one global config file, one YAML file per proxied site. No database, no external services.

๐Ÿ›ก๏ธ Built for PingLess Studios by AnAverageBeingGitHub Repo (currently private) ยท MIT License


Key Features โ€‹

๐ŸŒ Hostname Routing on 80/443 โ€‹

Many sites share one pair of listeners. Exact and wildcard (*.example.com) host matching, case-insensitive, port- and trailing-dot-tolerant. SNI-based certificate selection on 443. Unknown hosts get 421 โ€” bare-IP scanners never reach a site.

๐Ÿ”’ Optional Per-Site TLS โ€‹

Per-site cert/key with SNI routing (HTTP/2 + HTTP/1.1), HTTPโ†’HTTPS 308 redirect, optional HSTS. Sites without TLS config simply never get a cert.

๐Ÿงฑ L7 WAF โ€‹

SQLi, XSS, path traversal, and RCE pattern sets, scanner/bad-UA blocking, heuristic bot scoring, plus per-site custom regex rules over URI / query / body / method / any header. All matching is linear-time (regex crate) โ€” no ReDoS, and input is percent-decoded once before matching.

๐Ÿšฆ Rate + Connection Limits โ€‹

Per-IP and per-site sliding-window request limits, concurrent in-flight connection caps, and automatic temp-bans with escalating durations for repeat offenders (doubling up to 24h). Auto-mitigation tightens all of a site's limits by a configured factor when its RPS crosses a threshold, renewing while the flood continues.

๐Ÿ“‹ Blacklists / Whitelists โ€‹

A global ACL evaluated before any site logic, plus a per-site ACL. CIDRs or plain IPs, IPv4 and IPv6; the whitelist always wins.

๐Ÿงฉ JS Proof-of-Work Challenges โ€‹

SHA-256 PoW page with HMAC-signed clearance cookies (osc_clear) and server-signed, self-authenticating seeds โ€” fully stateless: the server keeps nothing per client. Modes: off / auto (verdict-driven) / on (challenge everything).

๐Ÿ“Š Monthly Quotas + Speed Caps โ€‹

Per-site monthly byte quotas (persisted to disk, reset on a configurable day of month; over-quota sites serve 509 or drop connections) plus sustained bytes/sec token-bucket caps per site and per client IP.

๐Ÿ•ต๏ธ Transparent Client-IP Forwarding โ€‹

Five forward modes (none / X-Forwarded-For / X-Real-Ip / Forwarded / custom header), HAProxy PROXY protocol v1/v2, and a Linux IP_TRANSPARENT mode where the origin's socket table shows the real client IP with zero origin configuration. Trusted-proxy-aware resolution walks the XFF chain right-to-left.

๐Ÿ”ฅ Hot-Reload Per-Site Configs โ€‹

A file watcher re-parses only the changed file (~300 ms debounce). A broken edit never affects other sites โ€” the last good config keeps serving for the broken one. API writes and file edits are the same pipeline.

๐Ÿ“ก Token-Secured Admin API + SSE โ€‹

REST control surface and a live Server-Sent Events telemetry stream on 127.0.0.1:9090, role-gated (admin / operator / readonly), with deep per-site analytics: top IPs/paths/UAs/rule hits, latency percentiles, and per-minute RPS/bandwidth series.


Quick Start โ€‹

bash
cargo build --release && ./target/release/openshield-l7 run

First run writes a documented default config.yaml and prints one admin token โ€” once. Add a site file, and you're proxying. The full 30-second path is in Quick Start.


Architecture โ€‹

One Request's Path โ€‹

Listener โ†’ resolve client IP (trusted-proxy aware) โ†’ hostname โ†’ site config snapshot โ†’ inspector chain (first non-Allow verdict wins) โ†’ challenge page / block page, or forward to the origin over a pooled keep-alive connection with byte metering and throttling applied to the response stream. Every request produces exactly one telemetry event on the bus, consumed by the metrics engine, the REST analytics endpoints, and the SSE stream.


Comparison โ€‹

Factual positioning against the two common self-hosted alternatives: nginx + ModSecurity (CRS) and a hand-assembled Cloudflare-free stack (nginx + fail2ban + limit_req + scripts).

CapabilityOpenShield-L7nginx + ModSecurityCloudflare-free DIY stack
DeploymentOne Rust binary, one global YAML + one YAML per sitenginx + module + CRS ruleset + tuningnginx + fail2ban + cron + scripts
WAF engineFixed pattern families + custom rules, linear-time regex (no ReDoS)OWASP CRS on PCRE โ€” powerful but ReDoS-prone, heavy FP tuningWhatever you wire together
Rate limitingPer-IP + per-site sliding windows, escalating auto-bans, RPS-triggered auto-mitigationlimit_req fixed zones; no auto-ban, no auto-tighteninglimit_req + fail2ban regexes on logs (seconds of lag)
Bot challengesBuilt-in stateless JS proof-of-work with HMAC clearance cookiesNone built inExternal (e.g. Anubis, custom pages)
Client-IP forwarding5 header modes + PROXY v1/v2 + IP_TRANSPARENT (origin sees real IP, zero origin config)XFF headers onlyXFF (+ PROXY with extra modules)
Bandwidth quotasMonthly per-site byte quotas, persisted, 509/close on exceedNot built inNot built in
Speed capsSustained bps token buckets per site and per IPlimit_rate per connection onlylimit_rate per connection only
Hot reloadPer-file, validated, failure-isolated, atomic swap; API and file edits are one pipelineFull config reload; one bad file breaks the whole reloadSame as nginx
Admin surfaceToken REST API + SSE events + per-site analytics (tops, latency percentiles, series)Access logsAccess logs + your own parsing
Content hostingNever โ€” reverse proxy onlyYes (it's a web server)Yes
MaturityNew, small codebase you can read end-to-endBattle-tested everywhereVaries

Bottom line: if you want a focused L7 filter in front of existing web servers โ€” with challenges, quotas, transparent client IP and a live API built in rather than bolted on โ€” OpenShield-L7 replaces a pile of moving parts with one binary. If you need a general-purpose web server or a decade of CRS rule coverage, nginx + ModSecurity remains the incumbent.


Verified Numbers โ€‹

From the automated e2e + attack battery (Testing & Benchmarks, testing/RESULTS.md):

MetricResult
Unit tests215 passed (cargo test --workspace)
E2E battery85 / 85 passed (routing, TLS/SNI, XFF modes, WAF, limits, PoW, quotas, API roles, hot reload, bans, SSE, keep-alive, WebSocket, PROXY v1/v2, transparent mode, graceful shutdown)
Attack scenarios8 / 8 passed (HTTP flood ร—2, random-Host flood ร—2, POST flood, slowloris, WAF sweep, XFF spoofing)
HTTP flood absorbed152,735 rps loopback, 100% 429 โ€” benign site kept 100% 200 at p95 2.3 ms
Random-Host flood150,426 rps โ†’ 100% 421, legitimate site untouched
Proxied throughput (loopback, protections ON)67,666 rps (p50 0.66 ms, p99 1.88 ms, zero errors in 541,881 requests)

Next Steps โ€‹