
Security News
RubyGems Adds Cooldown Feature to Bundler for Newly Published Gems
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.
@openapi-typescript-infra/cluster-proxy
Advanced tools
Configurable cluster-aware HTTP/S proxy for local development with DNS, TLS, service registry, and TUI
A configurable local development proxy that routes traffic to Kubernetes-style services. It combines an HTTP/HTTPS proxy, a DNS server, a service registry, and a terminal UI into a single tool so you can develop against multiple services locally without editing /etc/hosts or managing individual DNS entries.
/etc/resolver/* files when running with sudoCreate a cluster-proxy.json:
{
"zones": ["local.dev.mycompany.com", "mc"],
"clusterSuffix": ".mc.svc.cluster.local"
}
npx @openapi-typescript-infra/cluster-proxy --config cluster-proxy.json
npx @openapi-typescript-infra/cluster-proxy \
--zone local.dev.mycompany.com \
--zone mc \
--clusterSuffix .mc.svc.cluster.local
sudo npx @openapi-typescript-infra/cluster-proxy \
--config cluster-proxy.json \
--host 127.0.0.2 --httpPort 80 --httpsPort 443
┌──────────────┐
Browser request │ DNS Server │ Resolves *.zone → proxy IP
*.local.dev.myco.com │ (port 5533) │
│ └──────────────┘
▼
┌──────────────────┐
│ HTTP / HTTPS │
│ Proxy Server │
└────────┬─────────┘
│
┌───────┴────────┐
▼ ▼
Registered? Not registered
│ │
▼ ▼
registerHost:PORT hostname.clusterSuffix
(from registry) (e.g. api.mc.svc.cluster.local)
api from api.local.dev.mycompany.com).<registerHost>:<registered port>.<hostname>.<clusterSuffix>.All options can be set in a JSON config file passed via --config:
{
"name": "My Proxy",
"zones": ["local.dev.mycompany.com", "mc"],
"clusterSuffix": ".mc.svc.cluster.local",
"usePortForwarding": true,
"primaryZone": "local.dev.mycompany.com",
"registerHost": "127.0.0.1",
"certs": {
"keyFile": "~/.certs/my.keyfile.pem",
"certFile": "~/.certs/my.certfile.pem",
"mkcertDomains": ["local.dev.mycompany.com", "*.local.dev.mycompany.com"]
},
"auth": {
"cookieName": "session_token",
"endpoint": "http://auth.mc.svc.cluster.local/token-check",
"headerNames": ["x-auth-token"]
},
"inspectRequests": true,
"maxStoredRequests": 500,
"maxBodyCaptureBytes": 65536,
"host": "127.0.0.1",
"advertisedHost": "127.0.0.1",
"httpPort": 9080,
"httpsPort": 9443,
"dnsPort": 5533
}
| Field | Required | Default | Description |
|---|---|---|---|
zones | yes | — | DNS zones the proxy handles. Requests to *.zone are resolved and routed by the proxy. |
clusterSuffix | no | — | Combined namespace/domain suffix for cluster routing (e.g. .mc.svc.cluster.local). The first label is used as the default namespace. |
defaultNamespace | no | default | Kubernetes namespace used when a service name has no explicit namespace. Ignored when clusterSuffix is set. |
clusterDomain | no | svc.cluster.local | Kubernetes cluster DNS domain appended after the namespace. Ignored when clusterSuffix is set. |
usePortForwarding | no | false | Use kubectl port-forward through the shell's active Kubernetes context for unregistered cluster fallback traffic. |
name | no | "Cluster Proxy" | Display name for the TUI logo and error pages. |
primaryZone | no | zones[0] | The zone used for default certificate paths. |
registerHost | no | primaryZone | Hostname used when services register local ports with the registry. |
certs.keyFile | no | ~/.certs/_wildcard.<primaryZone>.keyfile.pem | Path to TLS key file. |
certs.certFile | no | ~/.certs/_wildcard.<primaryZone>.certfile.pem | Path to TLS cert file. |
certs.mkcertDomains | no | [primaryZone, "*.primaryZone"] | Domains passed to mkcert when auto-generating certificates. |
auth.cookieName | no | — | Cookie to look for on incoming requests. Auth is disabled if auth is not set. |
auth.endpoint | no | — | URL to call for token exchange when the cookie is present. |
auth.headerNames | no | — | Response headers to extract from the auth endpoint and forward upstream. |
inspectRequests | no | true when the TUI is enabled | Capture request metadata for the TUI/inspector. Non-TUI mode does not retain request history unless this is explicitly set to true. |
maxStoredRequests | no | 500 | Maximum inspected requests retained in memory. Set to 0 to disable retention. |
maxBodyCaptureBytes | no | 65536 | Maximum request or response body bytes captured per inspected request. Set to 0 to capture metadata only. |
bodyCaptureContentTypes | no | text, JSON, XML, form content | Response content types eligible for body capture. Use entries like "text/", "application/json", or "+json". |
host | no | 127.0.0.1 | Bind address. |
advertisedHost | no | host, or 127.0.0.1 when host is 0.0.0.0 | Address returned by the built-in DNS server for handled zones. Useful when binding to 0.0.0.0 but advertising a loopback alias such as 127.0.0.2. |
httpPort | no | 9080 | HTTP listen port. |
httpsPort | no | 9443 | HTTPS listen port. |
dnsPort | no | 5533 | DNS listen port. Set to 0 to disable DNS. |
logLevel | no | debug | Pino log level. |
CLI arguments override config file values.
--config <path> Path to JSON config file
--zone <domain> DNS zone (repeatable, e.g. --zone foo.com --zone bar)
--clusterSuffix <s> Cluster service suffix
--usePortForwarding Use kubectl port-forward for cluster fallback
--registerHost <host> Hostname used for service registration targets
--name <name> Display name
--host <ip> Bind address (default: 127.0.0.1)
--advertisedHost <ip> DNS answer address (default: bind host, or 127.0.0.1 for 0.0.0.0)
--httpPort <port> HTTP listen port (default: 9080)
--httpsPort <port> HTTPS listen port (default: 9443)
--dnsPort <port> DNS listen port, 0=off (default: 5533)
--key <path> TLS key file path
--cert <path> TLS cert file path
--logLevel <level> Pino log level (default: debug)
--no-inspectRequests Disable request inspection
--maxStoredRequests <n> Retained inspected requests (default: 500)
--maxBodyCaptureBytes <bytes> Body capture cap per request/response (default: 65536)
--bodyCaptureContentTypes <list> Comma-separated response content types to capture
--no-pretty Disable pretty-printed logs
--tui false Disable the terminal UI
Services register themselves by sending a POST to the proxy's registry endpoint:
curl http://registry.local.dev.mycompany.com/register \
-H "Content-Type: application/json" \
-d '{"name": "my-api", "port": 8080, "protocol": "http"}'
After registration, my-api.local.dev.mycompany.com routes to http://<registerHost>:8080.
The request can include host to override registerHost for that service, which is useful for services running in Docker or on another machine:
curl http://registry.local.dev.mycompany.com/register \
-H "Content-Type: application/json" \
-d '{"name": "my-api", "host": "host.docker.internal", "port": 8080, "protocol": "http"}'
-web automatically get a base name alias (e.g. registering my-api-web also creates a my-api route).ECONNREFUSED when forwarding to a registered service, it automatically unregisters and falls back to cluster routing.To unregister a service, send a DELETE to the same endpoint:
curl -X DELETE http://registry.local.dev.mycompany.com/register/my-api
# or
curl -X DELETE http://registry.local.dev.mycompany.com/register \
-H "Content-Type: application/json" \
-d '{"name": "my-api"}'
The paired -web/base alias (if any) is removed automatically.
You can optionally include host, port, and/or protocol to guard against a stale instance unregistering a newer one. If supplied and they don't match the current registration, the request is ignored:
curl -X DELETE "http://registry.local.dev.mycompany.com/register/my-api?host=host.docker.internal&port=8080&protocol=http"
# or
curl -X DELETE http://registry.local.dev.mycompany.com/register \
-H "Content-Type: application/json" \
-d '{"name": "my-api", "host": "host.docker.internal", "port": 8080, "protocol": "http"}'
When auth is configured, the proxy checks each HTTPS request for the specified cookie. If found, it calls the auth endpoint with the cookie and extracts the configured header from the response, forwarding it upstream. This is useful for reproducing the behavior of an auth sidecar (like Envoy) in local development.
When running in an interactive terminal, the proxy displays a TUI with:
Keyboard shortcuts:
| Key | Action |
|---|---|
f | Open filter (by hostname or path, supports * wildcards) |
c | Clear request history |
q | Quit |
Enter | Inspect selected request |
Esc / b | Back to dashboard |
Up / Down | Scroll / navigate |
When dnsPort is non-zero, the proxy starts a DNS server that resolves all configured zones to the bind address. On macOS with sudo, it automatically creates resolver files at /etc/resolver/<zone> so lookups work without any manual DNS configuration. These files are cleaned up on exit.
Without sudo, a warning is logged with the manual commands to run.
The proxy can also be used as a library:
import { createMainProxy, type ClusterProxyConfig } from '@openapi-typescript-infra/cluster-proxy';
const config: ClusterProxyConfig = {
zones: ['local.dev.mycompany.com'],
clusterSuffix: '.mc.svc.cluster.local',
};
const { proxy, httpsServer, httpServer, dnsServer } = await createMainProxy({
key: '...pem contents...',
cert: '...pem contents...',
httpPort: 9080,
httpsPort: 9443,
logger,
config,
});
MIT
FAQs
Configurable cluster-aware HTTP/S proxy for local development with DNS, TLS, service registry, and TUI
We found that @openapi-typescript-infra/cluster-proxy demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.

Security News
Federal audit finds NIST lacked a plan to clear the NVD backlog, wasted funds on duplicate work, and delayed use of CISA data.