Reach private TCP services through your own public relay.
node-tunnel is a small, self-hosted reverse TCP tunnel. It connects a local
client to a private service through a relay on a public host. SSH, RDP,
databases, HTTP, and other TCP protocols use the same setup.
Use node-tunnel when:
- the target service is behind NAT or a firewall;
- you control a publicly reachable host; and
- you want a self-hosted tunnel with no runtime dependencies.
Know that it requires relay, agent, and client processes, supports TCP only, and currently uses one shared key for all peers. The project is still a prototype; read the security limitations before exposing it to an untrusted network.
The agent and client both connect outward to the relay. In this example, the
client exposes 127.0.0.1:8000 and routes it to port 22 beside the agent.
You need Node.js 24 or newer on all three hosts. Clone the project on each host:
git clone https://github.com/mgrybyk/node-tunnel.git
cd node-tunnelGenerate one private key and use it in all three configuration files:
openssl rand -hex 16Create relay.env:
N_T_CRYPT_KEY=<same-32-character-key>
N_T_RELAY_BIND_HOST=0.0.0.0
N_T_RELAY_PORT=32121Allow inbound TCP traffic on port 32121, then run:
npm run relay -- relay.envCreate agent.env beside the SSH service:
N_T_CRYPT_KEY=<same-32-character-key>
N_T_RELAY_HOST=relay.example.com
N_T_RELAY_PORT=32121
N_T_AGENT_NAME=my-ssh
N_T_AGENT_DATA_HOST=127.0.0.1
N_T_AGENT_DATA_PORTS=22npm run agent -- agent.envThe target can be any host reachable by the agent, not only the agent host.
Create client.env:
N_T_CRYPT_KEY=<same-32-character-key>
N_T_RELAY_HOST=relay.example.com
N_T_RELAY_PORT=32121
N_T_CLIENT_NAME=my-ssh
N_T_CLIENT_BIND_HOST=127.0.0.1
N_T_CLIENT_PORTS=8000npm run client -- client.envThe client and agent names must match. Connect through the local port:
ssh user@127.0.0.1 -p 8000For another TCP service, change the agent target, client port, and route name.
- Configuration — all settings and the JavaScript API
- Deployment — TLS, HAProxy, reliability, and diagnostics
- Security — trust model and current limitations
- Architecture — connection flow and implementation
- Benchmarking — load and recovery scenarios
Relay, agent, and client must use the same protocol version. Upgrade them together.
npm ci
npm run check
npm test
npm run test:coverageSee Architecture before changing connection or lifecycle
behavior. For releases, run npm pack --dry-run, update CHANGELOG.md, and bump
PROTOCOL_VERSION only for incompatible wire changes.
