eggrd
Sheet 1 of 1  ·  Section through the request path  ·  Apache-2.0

The front door
your app shipped
without.

One static binary in front of your app. It owns the way in: authentication, rate limiting, TLS, input rules. It also owns the way out: redaction, hardened response headers, and hard ceilings on what your LLM calls may spend.

No changes to the app behind it.

Project
eggrd
Drawn as
Section A–A
Licence
Apache-2.0
Status
v2 landed · v2.5 underway
Read the source crates.io

What each chamber does

Schedules · both directions
Request path schedule — inbound
StageConfigBehaviour
TLS · ACME[tls]Terminates TLS with a supplied certificate ✓ PROVEN — exercised 2026-08-23: TLS 1.3, the certificate verified, the upstream response proxied back through it, plaintext refused on the TLS port, and every hardening header applied through the tunnel. Automatic issuance is proven too — a real Let's Encrypt certificate, see the revision block.
Authentication[auth.jwt]Validates a JWT before the request reaches your app.
Rate limit[ratelimit]Per-IP and per-key ceilings. store = "redis" shares one ceiling across replicas
Input rules[waf]WAF-lite inspection. Off by default — you turn it on deliberately.
IP access[access]allow and deny lists evaluated before anything downstream.
Response path schedule — outbound
StageConfigBehaviour
Headers[headers]CSP, HSTS and cookie hardening applied to what your app returns.
Compression[validation]compress_responses — negotiated response compression.
CORS preflight[cors]Preflight answered at the edge, with the allow-list held in config.

Three details, drawn larger

Callouts A · B · C
A

Shared-store rate limit

A per-process counter stops meaning anything the moment you run two replicas. eggrd can hold the limit in a store both replicas read, so the ceiling is the ceiling rather than the ceiling times your replica count.

[ratelimit] store = "redis" ✓ PROVEN

B

Reversible redaction

An irreversible [REDACTED] protects the provider's view and destroys yours. On the LLM lane eggrd keeps a per-request mask map: the provider sees a placeholder, and the response is unmasked back to that caller's own values — buffered or streamed.

[llm.dlp] mode = "redact" · reversible = true

C

Budgets that hold

A ceiling checked after the fact is a report, not a limit. eggrd reserves against the budget before the provider call and reconciles after, so a burst of concurrent requests cannot walk past the number together.

[[llm.budgets]] · fail-closed

The metered line

Detail C · LLM traffic

The same binary sitting in front of your app can sit in front of your model provider. It parses OpenAI-compatible traffic, counts input, output, cached and reasoning tokens separately, then prices them against a book you supply.

Metering is observe-only until you say otherwise: with no price book and no budgets it counts and reports, and changes nothing about the request. Turn on a budget and the line becomes a ceiling, enforced before the call rather than after the invoice.

An unknown model is a decision, not a default. on_unpriced_model either counts it and flags it, or rejects the request outright, so a model you never priced cannot quietly bill at zero.

# edgeguard.toml
[llm]
enabled = true
on_unpriced_model = "block"

[llm.models."gpt-4o"]
input_per_1m  = 2.5
output_per_1m = 10.0

[[llm.budgets]]
name  = "team-platform"
scope = "key"
unit  = "usd"
limit = 250.0
window = "30d"

[alerts]
budget_consumed_threshold = 0.8

Revision block

Three proven · none outstanding
ItemStateWhat that means
Shared-store rate limiter ✓ PROVEN Exercised 2026-08-23 across two replicas sharing one Redis. Thirty requests from one client, alternating between replicas, were allowed 5 times — the configured burst, enforced once globally, against a single Redis key. The same run with store = "local" allowed 10, which is the documented per-replica behaviour and the reason the shared store exists.
ACME certificate issuance ✓ PROVEN Issued a real certificate on 2026-08-23: CN=acme-test.eggrd.dev, issuer (STAGING) Artificial Amaranth YE1, from Let's Encrypt on a domain we control — five seconds from order to stored. Also passes against Pebble locally. It was broken until then, not merely untested: instant-acme 0.7.2 could not parse the CA's authorization payload. Bumped to 0.8. How to re-run it, and everything that was wrong.
WASM edge worker ✓ PROVEN Built and then run. worker-build --release now produces the deployable bundle, and it was executed on workerd — the runtime Cloudflare runs in production — against a live origin on 2026-08-24: no credentials and a wrong password each returned 401, the correct password returned 200 from the origin carrying all six hardening headers, with Server and X-Powered-By stripped. The build had been failing on strip = true, not on the toolchain. Not yet deployed to a Cloudflare account, so routes, custom domains and secret bindings remain untested.

Drawings carry a revision block because the honest state of a design is part of the design. All three have now been exercised against live infrastructure and say how. Checking them changed every entry here. The rate limiter passed. ACME turned out to be broken rather than merely untested — a two-year-old client that could no longer read the CA's replies — and only issues today because that was found and fixed. The WASM row claimed more than the build could deliver, and stayed marked unproven for as long as that was true; the build was failing on a strip = true in its own manifest rather than on the toolchain it had been blamed on. Nothing on this page is marked proven without a run behind it, and the runs are written down in docs/ so you can repeat them. Everything in the schedules above is tested in-process.

Put it in front of something

Two commands, or one image
# install
cargo install eggrd

# scaffold a starter config (and a Dockerfile) beside your app
edgeguard init

# edit edgeguard.toml, then check it before it sees traffic
edgeguard doctor

The crate is eggrd; the binary it installs is still named edgeguard, an earlier working title kept so existing deployments keep working.

# or skip the toolchain entirely
docker run -p 8080:8080 \
  -v ./edgeguard.toml:/etc/edgeguard/edgeguard.toml \
  mancube/eggrd:0.3.1

An 8.2 MB image: a static musl binary on distroless, so there is no shell and no package manager inside it to attack. linux/amd64 and linux/arm64, each built on its own native runner — as of 0.3.0, which also fixes ACME issuance. It was larger than 0.2.2 by about a megabyte and a half, which is what the working ACME client costs.

init scaffolds a starter edgeguard.toml and a Dockerfile rather than handing you a blank file, and refuses to clobber one that already exists. doctor then lints that config and validates the boot path, so a bad setting fails at your terminal instead of in front of traffic.

It is one static binary and one TOML file. There is no agent to install in your app, no SDK to import, and no library call to make. That is the point: the app behind it does not change.