The reverse proxy
Scrapers, credential-stuffing, runaway agentic retry loops, repeat LLM prompts — all of them are the same shape: infinite-cardinality traffic a fixed-memory structure was built to handle. SketchProxy wires epochsketch straight into net/http and httputil.ReverseProxy. One dependency, one binary, no cache cluster.
| Feature | Gates on | Own Sketch? |
|---|---|---|
| Rate limit | Request volume per IP+Path | Yes |
| Tarpit | The volume band just below the drop threshold | Reuses rate limit's estimate |
| Wallet defense | Request volume per Authorization header | Yes, dedicated |
| Prompt cache | LLM request/response caching, keyed on IP+Auth+body | Yes, feeds admission's TinyLFU filter |
| Anomaly webhook | First-sighting keys (first == true) | Reuses rate limit's Observe |
| Agentic loop breaker | Backend 5xx frequency per caller+path | Yes, dedicated, Observed only on 5xx |
# flags go run ./cmd/sketchproxy -listen :8080 -target http://localhost:5000 # or a config file — CLI flags always override it go run ./cmd/sketchproxy -config config.yaml
server: listen_addr: ":8080" target_url: "http://localhost:5000" rate_limit: enabled: true threshold: 100 # estimate at which a caller+path gets 429'd tarpit: enabled: true threshold: 50 # must be < rate_limit.threshold delay: 2s max_concurrent: 1000 agentic_loop_breaker: enabled: false threshold: 5 # 5xx-frequency estimate that trips the breaker
Measured with go test -bench=. -benchmem (Apple M4 Pro; treat as relative, not absolute, on other hardware).
| Benchmark | ns/op | allocs/op |
|---|---|---|
| Pre-EpochSketch baseline | ~35,200 | 71 |
| IP+Path key extraction | ~14 | 0 |
| Auth key extraction | ~22 | 0 |
| Full pipeline, concurrent | ~14,100 | 83 |
The two key-extraction benchmarks are what matter most for the hot path — zero allocations, whether the key comes from the request line or a header.
docker run -p 8080:8080 ghcr.io/shyam-s00/epochsketch/sketchproxy:latest \ -target http://host.docker.internal:5000