tcp-reverse-proxy
v1.0.0
Published
Configurable Layer 4 TCP reverse proxy with both CLI and programmatic APIs.
Maintainers
Readme
tcp-reverse-proxy
Configurable Layer 4 TCP reverse proxy for tunneling HTTPS/TCP traffic between clients and an upstream target. Ships as both a CLI (tcp-reverse-proxy) and a programmatic API so you can embed it into other tooling.
Table of Contents
Installation
Install from npm:
npm install tcp-reverse-proxyRun with CLI:
npx tcp-reverse-proxy --helpUsage
CLI
Configuration can be supplied either as CLI flags or environment variables (CLI flags win when both are provided). The CLI always requires a backend host.
Example using only CLI flags:
tcp-reverse-proxy \
--backend-host 192.168.131.170 \
--backend-port 5015 \
--frontend-port 8443 \
--listen-host 0.0.0.0Example with response delay:
BACKEND_HOST=192.168.131.170 \
BACKEND_PORT=5015 \
FRONTEND_PORT=8443 \
RESPONSE_DELAY_MS=3000 \
tcp-reverse-proxyExample development runs with ts-node:
npx ts-node src/app.ts \
--backend-host 192.168.131.170 \
--backend-port 5015 \
--frontend-port 8443 \
--listen-host 0.0.0.0With response delay:
npx ts-node src/app.ts \
--backend-host 192.168.1.123 \
--backend-port 5015 \
--response-delay 2000Available CLI flags:
| Flag | Description |
| ---- | ----------- |
| -H, --backend-host <host> | Target host/IP to forward traffic to (required) |
| -P, --backend-port <port> | Target port on the backend host (default: FRONTEND_PORT) |
| -F, --frontend-port <port> | Local listening port (default: 5015) |
| -L, --listen-host <host> | Host/IP to bind to (default: auto-detected local IPv4) |
| -X, --local-ip-prefix <prefix> | Prefix used when auto-detecting the local IPv4 (default: 192.) |
| -D, --response-delay <ms> | Delay response to client by milliseconds (default: 0) |
| -h, --help | Show inline help and exit |
Available environment variables:
| Variable | Required | Default | Description |
| -------- | -------- | ------- | ----------- |
| BACKEND_HOST | yes | – | Target host or IP to forward traffic to |
| BACKEND_PORT | no | FRONTEND_PORT | Target port on the backend host |
| FRONTEND_PORT | no | 5015 | Local listening port |
| LISTEN_HOST | no | auto-detected local IPv4 | Hostname/IP to bind the listener |
| LOCAL_IP_PREFIX | no | 192. | Prefix used when auto-detecting local IPv4 |
| RESPONSE_DELAY_MS | no | 0 | Delay response to client by milliseconds |
Programmatic API
import { startProxy } from 'tcp-reverse-proxy';
const server = startProxy({
frontendPort: 8443,
backendHost: '192.168.131.170',
backendPort: 5015,
responseDelayMs: 2000, // Optional: delay responses by 2 seconds
});
server.on('listening', () => console.log('Proxy ready!'));How Proxy Flow Works
flowchart LR
subgraph Before Proxy
C1[Client] -->|Direct TCP| B1[Backend]
endflowchart LR
subgraph After Proxy
C2[Client] -->|TCP In| P[tcp-reverse-proxy]
P -->|TCP Out| B2[Backend]
B2 -->|Response| P
P -->|Forwarded Response| C2
endExample setup:
- Backend service:
192.168.131.170:5015 - Proxy listener:
0.0.0.0:8443 - Client now connects to:
<proxy-host>:8443
What happens:
- Client opens a socket to the proxy listener.
- Proxy opens a socket to the backend.
- Client bytes are forwarded to backend.
- Backend bytes are forwarded back to client.
- Proxy logs connection events and data flow on both directions.
Example logs you can see in the proxy:
[2026-03-28T21:12:01.202Z] L4 reverse proxy running on 0.0.0.0:8443, forwarding to 192.168.131.170:5015
New connection from 10.0.0.25:60344
Forwarding connection to 192.168.131.170:5015
[2026-03-28T21:12:08.901Z] Data from client: GET /health HTTP/1.1
[2026-03-28T21:12:08.908Z] Data from backend: HTTP/1.1 200 OK
[2026-03-28T21:12:08.909Z] Data sent to client without delay: HTTP/1.1 200 OK
[2026-03-28T21:12:08.909Z] requestCounter: 1
[2026-03-28T21:12:09.154Z] Client disconnectedIf you start the proxy with --response-delay 2000, you will see Data sent to client after 2000ms delay: ... in logs.
Release Automation
This repository uses semantic-release on pushes to main.
Commit message standards (Conventional Commits):
feat: ...-> releases a new minor versionfix: ...-> releases a new patch versionfeat!: ...orBREAKING CHANGE:-> releases a new major versionchore: ...-> CI build runs, npm release is skipped
Skip GitHub Actions entirely by adding one of these tokens to your commit message:
[skip ci][ci skip][no ci][skip actions][actions skip]
Examples:
feat: add backend timeout support
fix: handle client disconnect race
chore: update docs [skip ci]Developer Guide
Contributor workflow and release conventions are documented in developer.md.
License
This project is licensed under the MIT License.
