A caching HTTP reverse proxy CLI. Point it at any origin server and it forwards
requests to that origin, caches successful GET responses in memory, and
serves repeat requests from the cache — no restart or external cache store
required.
- Transparent reverse proxy for any HTTP(S) origin
- In-memory caching of
GETresponses (2xx only) X-Cache: HIT/X-Cache: MISSresponse header on every request- TTL-based expiry (60s) and LRU eviction (100 entries max)
- Cache clearing via CLI flag or HTTP endpoint, without restarting the server
- Safe redirect handling (single bounded same-origin hop, no auto-follow to arbitrary hosts)
- Hop-by-hop headers and
Set-Cookiehandled correctly (not replayed across clients on cache hits)
- Node.js (
node:http,node:stream,node:util) - TypeScript
- tsx for running TypeScript directly in dev
- Node's built-in test runner (
node:test) for tests - No external runtime dependencies
- Node.js (see
@types/nodeinpackage.jsonfor the targeted version range) - pnpm
pnpm installRun the proxy directly from TypeScript source (dev):
npx tsx src/cli.ts --port 3000 --origin http://dummyjson.comBuild to plain JS (what actually ships):
pnpm buildRun the built CLI:
node dist/cli.js --port 3000 --origin http://dummyjson.comClear the cache of a running instance:
node dist/cli.js --clear-cache
# or, in dev:
npx tsx src/cli.ts --clear-cache--clear-cache defaults to port 3000; pass --port <number> to target a
different running instance.
Run tests:
pnpm testcaching-proxy --port <number> --origin <url>
caching-proxy --clear-cache [--port <number>]
| Flag | Description |
|---|---|
--port |
Port the proxy listens on |
--origin |
Origin server URL to forward requests to |
--clear-cache |
Clear the cache of a running instance and exit |
npx tsx src/cli.ts --port 3000 --origin http://dummyjson.comBasic request — first call is a MISS, second is a HIT:
curl -sD - -o /dev/null http://127.0.0.1:3000/products/1 | grep -i x-cache # MISS
curl -sD - -o /dev/null http://127.0.0.1:3000/products/1 | grep -i x-cache # HITFull response with headers and body:
curl -s -D - -o /tmp/body.json http://127.0.0.1:3000/products/1Clear the cache over HTTP directly:
curl -s -D - -o - -X DELETE http://127.0.0.1:3000/_cachePOST request (body forwarded, not cached):
curl -s -D - -o /dev/null -X POST http://127.0.0.1:3000/products/add \
-H "Content-Type: application/json" -d '{"title":"test"}'Confirm no double-compressed/duplicated headers:
curl -sL -D - -o /dev/null --compressed http://127.0.0.1:3000/products/1 | \
grep -iE "content-encoding|content-length|transfer-encoding|^HTTP"Malformed request-target (expect 400):
curl -s -D - -o - -x http://127.0.0.1:3000 http://example.com/anything- Only
GETrequests with a2xxupstream response are cached. - Cache key is
METHOD:URL. - Entries expire after 60 seconds (
TTL_MSinsrc/index.ts). - Cache is capped at 100 entries (
MAX_ENTRIES); oldest entry is evicted (LRU, not FIFO) when a new entry is stored past that limit. Set-Cookieand hop-by-hop headers (Connection,Transfer-Encoding, etc.) are stripped from cached/replayed responses to avoid leaking session state between clients.- Redirects from the origin are only auto-followed for
GET/HEADwhen theLocationhost matches the origin host — anything else is relayed as-is to the client, not followed server-side.
ISC