npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@remotelinker/reverse-ws-tunnel

v1.0.4

Published

**A Node.js library for creating secure reverse tunnels over WebSocket connections.**

Readme

🚀 Reverse WebSocket Tunnel

A Node.js library for creating secure reverse tunnels over WebSocket connections.

Version License

📖 What is Reverse WebSocket Tunnel?

Reverse WebSocket Tunnel is a library that enables you to expose local services to the internet through a WebSocket tunnel, similar to tools like ngrok or localtunnel. It consists of two main components:

  • Server: Runs on a publicly accessible server and accepts WebSocket connections from clients
  • Client: Runs locally and creates a tunnel to expose local services through the server

Use Cases

  • Development: Expose local development servers for testing webhooks, APIs, or sharing work
  • IoT & Edge: Connect devices behind NAT/firewalls to cloud services
  • Microservices: Enable secure communication between services across different networks
  • CI/CD: Create temporary endpoints for automated testing

How It Works

  1. The server listens for WebSocket connections and HTTP requests
  2. The client connects to the server via WebSocket and registers a tunnel ID
  3. When the server receives HTTP requests for a specific tunnel, it forwards them through the WebSocket to the client
  4. The client proxies the requests to the local target service and sends responses back through the tunnel

📦 Installation

npm install @remotelinker/reverse-ws-tunnel

🚀 Quick Start

Server Setup

const { startWebSocketServer } = require('@remotelinker/reverse-ws-tunnel/server');

// Start the WebSocket tunnel server
startWebSocketServer({
  port: 443,
  host: '0.0.0.0',
  path: '/tunnel',
  tunnelIdHeaderName: 'x-tunnel-id',
});

Client Setup

const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');

// Connect to the tunnel server and expose local service
const client = startClient({
  tunnelId: '1cf2755f-c151-4281-b3f0-55c399035f87',
  wsUrl: 'wss://yourdomain.com/tunnel',
  targetUrl: 'http://localhost:3000',
  tunnelEntryPort: 4443,
  allowInsicureCerts: false,
});

// Listen for events
client.on('connected', () => {
  console.log('Connected to tunnel');
});

client.on('disconnected', () => {
  console.log('Disconnected from tunnel');
});

// Close connection
// client.close();

⚙️ Configuration

You can configure the library using:

  1. Environment variables
  2. TOML configuration files (config.toml)
  3. Direct JavaScript parameters

Configuration priority: JavaScript parameters > config.toml > environment variables

🖥️ Server Configuration

JavaScript API

const { startWebSocketServer } = require('@remotelinker/reverse-ws-tunnel/server');

startWebSocketServer({
  port: 443, // WebSocket server port
  host: '0.0.0.0', // Host to bind (optional)
  path: '/tunnel', // WebSocket path (optional)
  tunnelIdHeaderName: 'x-tunnel-id', // Header name for tunnel identification
});

Environment Variables

| Variable | Description | Default | Example | | ----------------------- | ------------------------- | ------------- | ------------- | | WS_PORT | WebSocket server port | 443 | 8080 | | HOST | Host address to bind | undefined | 0.0.0.0 | | PATH_URL | WebSocket endpoint path | undefined | /tunnel | | TUNNEL_ID_HEADER_NAME | HTTP header for tunnel ID | x-tunnel-id | x-tunnel-id | | LOG_LEVEL | Logging verbosity | info | debug |

TOML Configuration (config.toml)

# WebSocket server configuration
wsPort = 443
host = "0.0.0.0"
path = "/tunnel"
tunnelIdHeaderName = "x-tunnel-id"

Example Server

# Run the example server
npm run example:server

💻 Client Configuration

JavaScript API

const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');

const client = startClient({
  tunnelId: '1cf2755f-c151-4281-b3f0-55c399035f87', // Unique tunnel identifier (UUID)
  wsUrl: 'wss://example.com/tunnel', // WebSocket server URL
  targetUrl: 'http://localhost:3000', // Local service to expose
  tunnelEntryUrl: 'http://localhost:4443', // Optional: tunnel entry URL
  tunnelEntryPort: 4443, // TCP port for tunnel entry
  allowInsicureCerts: false, // Allow insecure SSL certificates
  headers: {
    // Optional: custom headers
    Authorization: 'Bearer token',
    'X-Custom-Header': 'value',
  },
  autoReconnect: true, // Automatically reconnect on close (default: true)
});

// Event handling
client.on('connected', () => console.log('Tunnel connected'));
client.on('disconnected', () => console.log('Tunnel disconnected'));

// Close the tunnel
// client.close();

Environment Variables

| Variable | Description | Required | Default | Example | | ---------------------- | ---------------------------------- | -------- | ------- | -------------------------------------- | | TUNNEL_ID | Unique tunnel identifier (UUID-v4) | ✅ | - | 1cf2755f-c151-4281-b3f0-55c399035f87 | | WS_URL | WebSocket server URL | ✅ | - | wss://example.com/tunnel | | TARGET_URL | Local service URL to expose | ✅ | - | http://localhost:3000 | | TUNNEL_ENTRY_URL | Tunnel entry point URL | ❌ | - | http://localhost:4443 | | TUNNEL_ENTRY_PORT | TCP port for tunnel entry | ❌ | - | 4443 | | HEADERS | Custom headers (JSON string) | ❌ | - | {"Authorization":"Bearer token"} | | ALLOW_INSICURE_CERTS | Allow insecure SSL certificates | ❌ | false | true | | AUTO_RECONNECT | Automatically reconnect on close | ❌ | true | false | | LOG_LEVEL | Logging level | ❌ | info | debug |

TOML Configuration (config.toml)

# Unique identifier of the tunnel (UUID-v4)
tunnelId = "1cf2755f-c151-4281-b3f0-55c399035f87"

# WebSocket server URL to connect to
wsUrl = "wss://example.com/tunnel"

# Target URL where the traffic will be forwarded
targetUrl = "http://localhost:3000"

# Optional URL for tunnel entry point
tunnelEntryUrl = "http://localhost:4443"

# TCP port to open for incoming tunnel connections
tunnelEntryPort = 4443

# Whether to allow insecure SSL certificates (dev/test only)
allowInsicureCerts = false

# Automatically reconnect on close
autoReconnect = true

# Log verbosity level: error, warn, info, debug, trace
logLevel = "info"

# Custom headers to send with requests
[headers]
Authorization = "Bearer your-token"
X-Custom-Header = "custom-value"

Example Client

# Run the example client
npm run example:client

🐳 Docker Deployment

Building the Docker Image

npm run docker:build

Running with Docker Compose

npm run docker:deploy

The service will start on port 4443 by default.

Docker Environment Variables

When using Docker, you can pass all the environment variables mentioned above:

docker run -e TUNNEL_ID=your-uuid -e WS_URL=wss://example.com -e TARGET_URL=http://localhost:3000 remotelinker/reverse-ws-tunnel

📝 Logging

The library uses Winston for logging with configurable levels:

  • error: Only error messages
  • warn: Warnings and errors
  • info: General information (default)
  • debug: Detailed debugging information
  • trace: Very verbose output including message traces

Set the log level via:

  • Environment variable: LOG_LEVEL=debug
  • TOML config: logLevel = "debug"

🔧 Advanced Usage

Custom Headers

You can send custom headers with tunnel requests:

// Environment variable (JSON string)
process.env.HEADERS = JSON.stringify({
  'Authorization': 'Bearer your-token',
  'X-API-Key': 'your-api-key'
});

// Or in config.toml
[headers]
Authorization = "Bearer your-token"
X-API-Key = "your-api-key"

SSL/TLS Configuration

For development, you might need to allow insecure certificates:

startClient({
  // ... other config
  allowInsicureCerts: true, // Only for development!
});

Multiple Tunnels

Each client needs a unique tunnelId (UUID-v4). You can run multiple clients with different tunnel IDs to expose multiple services.


🧪 Examples

The repository includes working examples:

  • Server: examples/server/ - Shows how to set up a tunnel server.
  • Client: examples/client/ - Shows how to connect and expose a local service.
  • Web Server: examples/webserver/ - A minimal target web server.

Complete Reverse Tunnel Example

This example demonstrates how to set up a complete reverse tunnel to expose a local web server to the internet.

1. Start the Target Web Server

First, start the minimal web server that will be the destination of our tunnel. This server will respond with "Hello, World!".

# Terminal 1: Start the web server
node examples/webserver/webserver-example.js
# Server running on http://localhost:3000/

2. Start the Tunnel Server

Next, start the tunnel server. This server runs on a publicly accessible machine and listens for WebSocket connections from the tunnel client.

The example server is located in examples/server/.

# Terminal 2: Start the tunnel server
npm run example:server

This will start the server using the configuration from examples/server/config.toml. By default, it listens on port 3000 for WebSocket connections and port 4443 for public HTTP requests.

3. Start the Tunnel Client

Now, start the tunnel client. The client connects to the tunnel server and exposes the local web server.

We need to configure the client to connect to our tunnel server and point to our local web server. The example client configuration is in examples/client/config.toml. Let's modify it to match our setup.

examples/client/config.toml

# Unique identifier of the tunnel (UUID-v4)
tunnelId = "1cf2755f-c151-4281-b3f0-55c399035f87"

# WebSocket server URL to connect to
wsUrl = "ws://localhost:8080/tunnel"

# Target URL where the traffic will be forwarded
targetUrl = "http://localhost:8080"

# TCP port to open for incoming tunnel connections
tunnelEntryPort = 4443

Now, run the client:

# Terminal 3: Start the tunnel client
npm run example:client

4. Test the Tunnel

The tunnel is now active. The tunnel server is listening for requests on port 4443 and will forward them to your local web server running on port 8080.

You can test it by making a curl request to the tunnel server's public endpoint, including the x-tunnel-id header:

# Terminal 4: Test the tunnel
curl -X GET http://localhost:8083 -H "x-tunnel-id: 1cf2755f-c151-4281-b3f0-55c399035f87"

You should see the "Hello, World!" response from your local web server.

Hello, World!

⚠️ Security Considerations

  • Production Use: Ready for production use
  • SSL/TLS: Always use secure WebSocket connections (wss://) in production
  • Authentication: Implement proper authentication mechanisms for your tunnels
  • Rate Limiting: Consider implementing rate limiting on the server side
  • Firewall: Ensure proper firewall rules are in place

📄 License

ISC License - see LICENSE file for details.


🤝 Contributing

This project is in active development. Contributions, issues, and feature requests are welcome!

📞 Support

For questions and support, please open an issue on the GitHub repository.