Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@openapi-typescript-infra/cluster-proxy

Package Overview
Dependencies
Maintainers
1
Versions
19
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@openapi-typescript-infra/cluster-proxy

Configurable cluster-aware HTTP/S proxy for local development with DNS, TLS, service registry, and TUI

latest
Source
npmnpm
Version
1.14.0
Version published
Maintainers
1
Created
Source

@openapi-typescript-infra/cluster-proxy

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.

Features

  • DNS server that resolves your configured zones to the proxy
  • Service registry where local services announce themselves on startup
  • TLS termination with automatic certificate generation via mkcert
  • Cluster fallback — unregistered hostnames are forwarded to the real cluster
  • WebSocket support with full upgrade handling
  • Auth token exchange — optionally extracts auth cookies and forwards them as headers
  • Terminal UI with live request log, service registry view, filtering, and request inspection
  • macOS resolver integration — automatically creates /etc/resolver/* files when running with sudo

Quick start

With a config file

Create 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

With CLI args only

npx @openapi-typescript-infra/cluster-proxy \
  --zone local.dev.mycompany.com \
  --zone mc \
  --clusterSuffix .mc.svc.cluster.local

On standard ports (requires sudo)

sudo npx @openapi-typescript-infra/cluster-proxy \
  --config cluster-proxy.json \
  --host 127.0.0.2 --httpPort 80 --httpsPort 443

How it works

                        ┌──────────────┐
   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)
  • The DNS server resolves any hostname under your configured zones to the proxy's IP address.
  • When a request arrives, the proxy extracts the first subdomain (e.g. api from api.local.dev.mycompany.com).
  • If that name is in the local registry, the request routes to <registerHost>:<registered port>.
  • Otherwise it forwards to the cluster at <hostname>.<clusterSuffix>.

Configuration

Config file

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
}
FieldRequiredDefaultDescription
zonesyesDNS zones the proxy handles. Requests to *.zone are resolved and routed by the proxy.
clusterSuffixnoCombined namespace/domain suffix for cluster routing (e.g. .mc.svc.cluster.local). The first label is used as the default namespace.
defaultNamespacenodefaultKubernetes namespace used when a service name has no explicit namespace. Ignored when clusterSuffix is set.
clusterDomainnosvc.cluster.localKubernetes cluster DNS domain appended after the namespace. Ignored when clusterSuffix is set.
usePortForwardingnofalseUse kubectl port-forward through the shell's active Kubernetes context for unregistered cluster fallback traffic.
nameno"Cluster Proxy"Display name for the TUI logo and error pages.
primaryZonenozones[0]The zone used for default certificate paths.
registerHostnoprimaryZoneHostname used when services register local ports with the registry.
certs.keyFileno~/.certs/_wildcard.<primaryZone>.keyfile.pemPath to TLS key file.
certs.certFileno~/.certs/_wildcard.<primaryZone>.certfile.pemPath to TLS cert file.
certs.mkcertDomainsno[primaryZone, "*.primaryZone"]Domains passed to mkcert when auto-generating certificates.
auth.cookieNamenoCookie to look for on incoming requests. Auth is disabled if auth is not set.
auth.endpointnoURL to call for token exchange when the cookie is present.
auth.headerNamesnoResponse headers to extract from the auth endpoint and forward upstream.
inspectRequestsnotrue when the TUI is enabledCapture request metadata for the TUI/inspector. Non-TUI mode does not retain request history unless this is explicitly set to true.
maxStoredRequestsno500Maximum inspected requests retained in memory. Set to 0 to disable retention.
maxBodyCaptureBytesno65536Maximum request or response body bytes captured per inspected request. Set to 0 to capture metadata only.
bodyCaptureContentTypesnotext, JSON, XML, form contentResponse content types eligible for body capture. Use entries like "text/", "application/json", or "+json".
hostno127.0.0.1Bind address.
advertisedHostnohost, or 127.0.0.1 when host is 0.0.0.0Address 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.
httpPortno9080HTTP listen port.
httpsPortno9443HTTPS listen port.
dnsPortno5533DNS listen port. Set to 0 to disable DNS.
logLevelnodebugPino log level.

CLI arguments

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

Service registration

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"}'
  • Services ending in -web automatically get a base name alias (e.g. registering my-api-web also creates a my-api route).
  • If a new service registers on the same host and port as an existing one, the old registration is replaced.
  • If the proxy gets 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"}'

Auth token exchange

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.

Terminal UI

When running in an interactive terminal, the proxy displays a TUI with:

  • ASCII art logo and connection info
  • Live list of registered services and cluster hosts
  • Merged activity timeline (logs + requests)
  • Request inspector with full headers and body

Keyboard shortcuts:

KeyAction
fOpen filter (by hostname or path, supports * wildcards)
cClear request history
qQuit
EnterInspect selected request
Esc / bBack to dashboard
Up / DownScroll / navigate

DNS and macOS resolver

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.

Programmatic usage

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,
});

License

MIT

Keywords

typescript

FAQs

Package last updated on 27 May 2026

Did you know?

Socket

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.

Install

Related posts