A reusable Node.js utility package that auto-establishes a SOCKS5 tunnel over SSH and selectively routes specific outbound fetch requests through it.
This is particularly useful when developing locally on a dynamic IP but interacting with third-party APIs (e.g., TerraPay) that require IP whitelisting.
- Auto-Establishing SSH Tunnel: Automatically spawns and maintains the
ssh -D <port> -N -C ...process when initialized. - Selective Proxy Routing: Dynamically intercepts
globalThis.fetchto route specific target hosts (e.g.*.terrapay.com) through the SOCKS tunnel, while sending all other requests directly. - Redacted Request Headers: Logs headers for routed requests with sensitive headers (like API keys, passwords, authorizations) automatically redacted.
- Response Body Logs: Logs target server responses and truncates/prints body content for dev/debugging clarity.
- Self-Cleaning: Automatically kills the spawned SSH child process when the parent Node.js application process terminates.
npm install socks-sshAll required dependencies (fetch-socks, undici, socks) are installed automatically — no extra setup needed.
Set up these variables in your target project's .env file (see .env.example):
# Option 1: Full SSH connect string
SSH_CONNECT=root@128.33.453.3
# Option 2: Split parameters
# SSH_USER=root
# SSH_HOST=128.33.453.3
# SSH_PORT=22
# SSH_KEY=~/.ssh/id_rsa
# Port SOCKS5 listens on (maps to ssh -D <port>)
SOCKS_PORT=1080
# Comma-separated list of host suffixes to route through the tunnel
SOCKS_PROXY_HOSTS=terrapay.com,routefusion.com
# Production hardening (recommended):
# Cap/disable response body logging (default: 2000 chars; 0 = unlimited, not recommended)
SOCKS_PROXY_BODY_MAX=2000
# Pin the remote host key instead of trust-on-first-connect (accept-new)
SSH_KNOWN_HOSTS_FILE=/path/to/known_hosts
SSH_STRICT_HOST_KEY_CHECKING=yesLaunch your Node.js application (like Next.js or a backend server) using the --import flag. This automatically configures the proxy without needing any code changes inside your project:
{
"scripts": {
"dev:proxy": "NODE_OPTIONS='--import socks-ssh/register' next dev"
}
}If you want to initialize it conditionally inside your code (e.g., in server.ts or index.js):
import { init } from 'socks-ssh';
if (process.env.NODE_ENV === 'development') {
// init() returns a Promise that resolves when the tunnel and local proxies are fully ready.
await init();
}socks-ssh supports both Node.js and Bun environments transparently:
- Node.js (18+): Configures a custom
undiciAgent dispatcher to selectively route requests through the SOCKS5 proxy. - Bun: Since Bun's native HTTP client does not support SOCKS5 natively and intercepts Undici,
socks-sshautomatically spins up a local HTTP-to-SOCKS5 forwarding CONNECT proxy and redirects matchingfetchcalls through it using Bun's nativeproxyoption. No manual proxy setup or background commands are required.