npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

run-proxy-server

v1.1.0

Published

Simple tool to proxy HTTP/HTTPS requests via a local Node.js server with built-in caching

Readme

run-proxy-server

cli-available node version npm version downloads size license github-ci

Simple CLI tool to run a local HTTP/HTTPS proxy server with built-in caching, powered by vanilla Node.js.

Give a ⭐️ if this project helped you!

Features

  • 🚀 Create a local proxy server (HTTP or HTTPS)
  • ⚡ Cache proxied responses to avoid redundant network requests
  • 💾 Cache stored in ~/.cache/run-proxy-server, keyed by a SHA-256 hash of the full URL
  • 🧰 Supports a denylist to exclude specific URLs or patterns from caching
  • 🎯 Denylist patterns support wildcards (*)
  • 🔒 Only GET responses are cached; Set-Cookie, Cache-Control: private/no-store, authorized requests and 5xx are always fetched fresh
  • 🏠 Listens on loopback (127.0.0.1) only unless you opt in with --host

Quick Start

Install

npm install -g run-proxy-server

Or run without installing:

npx run-proxy-server https://example.com --port 8000

One-time HTTPS setup

If you plan to proxy an HTTPS target, run this once first:

run-proxy-server --setup-https
# or
npx run-proxy-server --setup-https

This creates key.pem and cert.pem in $XDG_CONFIG_HOME/run-proxy-server/certs (falling back to ~/.config/run-proxy-server/certs). The certificates belong to the user, not to the package, so a global reinstall does not wipe them.

HTTP

run-proxy-server https://example.com --port 8000

Then make requests to the proxy:

curl http://localhost:8000/

HTTPS

After the one-time HTTPS setup above, start the proxy pointing to an HTTPS target:

run-proxy-server https://example.com --port 8443

If you prefer manual certificate creation instead of --setup-https, you can run:

mkdir -p ~/.config/run-proxy-server/certs
openssl req -x509 -newkey rsa:2048 -keyout ~/.config/run-proxy-server/certs/key.pem -out ~/.config/run-proxy-server/certs/cert.pem -days 365 -nodes -subj "/CN=localhost"

Note: Browsers will show a security warning for self-signed certificates - this is expected in local development. For production, use a certificate from a trusted CA (e.g. Let's Encrypt).

Options

| Argument/Option | Required | Default | Description | | --- | --- | --- | --- | | URL | yes | - | Target URL to proxy requests to | | --host | no | localhost | Interface to listen on (0.0.0.0 exposes the proxy to the network) | | --port | no | 8000 | Port for the local proxy server | | --denylist | no | - | Comma-separated URL patterns to exclude from cache | | --no-cache | no | false | Disable cache reads and writes for this process | | --clear-cache | no | false | Remove all cached responses and exit | | --setup-https | no | false | Generate local HTTPS certificates and exit |

Examples

Proxy an API with caching

run-proxy-server https://api.github.com --port 8000

# First request - proxied and cached
curl http://localhost:8000/users/octocat

# Second request - served from cache (no network call)
curl http://localhost:8000/users/octocat

Exclude dynamic endpoints from cache

run-proxy-server https://example.com --port 8000 --denylist "*/api/*,*.json"

# API calls are never cached (always fresh)
curl http://localhost:8000/api/users

# Static assets are cached
curl http://localhost:8000/index.html

Expose the proxy to other devices

By default the proxy listens on loopback (127.0.0.1) only, because it replays cached responses to every client. Opt in explicitly when you need it on the network:

run-proxy-server https://example.com --host 0.0.0.0 --port 8000

Disable cache entirely for a run

run-proxy-server https://example.com --port 8000 --no-cache

# Every request is fetched from upstream (cache is bypassed)
curl http://localhost:8000/

Denylist pattern syntax

Patterns are matched against the full URL. * matches any characters.

| Pattern | Matches | | --------------------------- | ------------------------------------- | | *.json | https://example.com/data.json | | */api/* | https://example.com/api/users | | */admin/* | https://example.com/admin/dashboard | | https://cdn.example.com/* | https://cdn.example.com/image.png |

Multiple patterns are separated by commas:

--denylist "*/api/*,*.json,*/admin/*"

Cache

Responses live in $XDG_CACHE_HOME/run-proxy-server, falling back to ~/.cache/run-proxy-server. The cache belongs to the user, not to the package - installed globally, the package directory sits inside node_modules, which is read-only in many setups and wiped on every reinstall.

  • First request: proxied to the target, response saved to the cache
  • Subsequent requests: served directly from the cache
  • Only GET: HEAD, POST and other methods always go upstream and are never stored
  • Never stored: responses with Set-Cookie or Cache-Control: private / no-store, responses to requests carrying Authorization, and 5xx errors
  • Denylisted URLs: always fetched fresh, never cached
  • --no-cache mode: cache is fully disabled (no reads and no writes)
  • Expiry: entries are valid for 365 days; set CACHE_TTL_HOURS to change the window, or 0 to keep them forever

Each entry is a JSON file named after the first 32 hex characters of the SHA-256 hash of the URL. Binary bodies are stored base64-encoded.

# Keep responses for an hour instead of a year
CACHE_TTL_HOURS=1 run-proxy-server https://example.com

Clear the cache at any time:

run-proxy-server --clear-cache
# or
npx run-proxy-server --clear-cache

Development

Run with auto-reload on file changes:

npm run dev -- https://example.com --port 8000

Testing

npm test

Tests cover cache operations, denylist pattern matching, request handling (cache rules, hop-by-hop headers, binary bodies, 502/504 mapping) and certificate lookup across Node.js 20, 22, and 24.

Format and lint before committing:

npm run format:check
npm run lint

🤝 Contributing

Contributions, issues and feature requests are welcome! Feel free to check issues page.

License

The MIT License @ 2026