@remotelinker/reverse-ws-tunnel 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cookbook.md ADDED
@@ -0,0 +1,595 @@
1
+ # WebSocket Tunneling Cookbook: Building Reverse Tunnels in Node.js
2
+
3
+ ## Overview
4
+
5
+ This cookbook provides comprehensive examples and technical deep-dives into reverse WebSocket tunneling using the Node.js library. Whether you're a developer exposing local services, a DevOps engineer deploying production tunnels, or an IoT developer connecting edge devices, this guide offers practical implementations and detailed explanations.
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Quick Start Examples](#quick-start-examples)
10
+ 2. [Architecture Deep Dive](#architecture-deep-dive)
11
+ 3. [Communication Protocol](#communication-protocol)
12
+ 4. [Security Best Practices](#security-best-practices)
13
+ 5. [Production Deployment](#production-deployment)
14
+ 6. [Troubleshooting Guide](#troubleshooting-guide)
15
+ 7. [Advanced Use Cases](#advanced-use-cases)
16
+
17
+ ## Quick Start Examples
18
+
19
+ ### Example 1: Local Development Server Exposure
20
+
21
+ **Scenario**: You're developing a web app on `localhost:3000` and need to share it with a client for feedback.
22
+
23
+ **Step 1: Set up your local service**
24
+ ```bash
25
+ # Create a simple Express server
26
+ npm init -y
27
+ npm install express
28
+ ```
29
+
30
+ ```javascript
31
+ // server.js
32
+ const express = require('express');
33
+ const app = express();
34
+
35
+ app.get('/', (req, res) => {
36
+ res.send('Hello from my development server!');
37
+ });
38
+
39
+ app.listen(3000, () => {
40
+ console.log('Dev server running on http://localhost:3000');
41
+ });
42
+ ```
43
+
44
+ **Step 2: Install the tunneling library**
45
+ ```bash
46
+ npm install @remotelinker/reverse-ws-tunnel
47
+ ```
48
+
49
+ **Step 3: Create tunnel configuration**
50
+ ```javascript
51
+ // tunnel-config.js
52
+ const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');
53
+
54
+ const client = startClient({
55
+ tunnelId: '550e8400-e29b-41d4-a716-446655440000', // Generate a UUID
56
+ wsUrl: 'wss://your-tunnel-server.com/tunnel',
57
+ targetUrl: 'http://localhost:3000',
58
+ tunnelEntryPort: 4443
59
+ });
60
+
61
+ client.on('connected', () => {
62
+ console.log('🎉 Tunnel active! Access at: https://your-tunnel-server.com?tunnelId=550e8400-e29b-41d4-a716-446655440000');
63
+ });
64
+ ```
65
+
66
+ ### Example 2: IoT Device Connectivity
67
+
68
+ **Scenario**: Connect a Raspberry Pi running a sensor service behind NAT to the cloud.
69
+
70
+ ```javascript
71
+ // iot-tunnel.js
72
+ const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');
73
+
74
+ const client = startClient({
75
+ tunnelId: 'device-001-sensor-data',
76
+ wsUrl: 'wss://iot-gateway.yourcompany.com/tunnel',
77
+ targetUrl: 'http://localhost:8080',
78
+ headers: {
79
+ 'Authorization': 'Bearer device-token-123',
80
+ 'Device-Type': 'raspberry-pi-4',
81
+ 'Sensor-Capabilities': 'temperature,humidity'
82
+ },
83
+ autoReconnect: true
84
+ });
85
+
86
+ client.on('connected', () => {
87
+ console.log('IoT device connected to cloud');
88
+ });
89
+
90
+ client.on('disconnected', () => {
91
+ console.log('Connection lost, auto-reconnecting...');
92
+ });
93
+ ```
94
+
95
+ ### Example 3: API Development with Webhook Testing
96
+
97
+ **Scenario**: Develop and test webhooks for payment processing.
98
+
99
+ ```javascript
100
+ // webhook-tester.js
101
+ const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');
102
+ const express = require('express');
103
+
104
+ const app = express();
105
+ app.use(express.json());
106
+
107
+ // Webhook endpoint for payment provider
108
+ app.post('/webhooks/payments', (req, res) => {
109
+ console.log('Received payment webhook:', req.body);
110
+ res.json({ status: 'processed' });
111
+ });
112
+
113
+ const server = app.listen(3001, () => {
114
+ console.log('Webhook server ready on port 3001');
115
+ });
116
+
117
+ // Create tunnel for webhook testing
118
+ const client = startClient({
119
+ tunnelId: 'webhook-test-session-123',
120
+ wsUrl: 'wss://tunnel.stripe-test.com/tunnel',
121
+ targetUrl: 'http://localhost:3001',
122
+ headers: {
123
+ 'X-Webhook-Secret': 'whsec_test_secret'
124
+ }
125
+ });
126
+
127
+ client.on('connected', () => {
128
+ console.log('Webhook tunnel active - configure your Stripe dashboard with:');
129
+ console.log('https://tunnel.stripe-test.com/webhooks?tunnelId=webhook-test-session-123');
130
+ });
131
+ ```
132
+
133
+ ## Architecture Deep Dive
134
+
135
+ ### Core Components
136
+
137
+ The library consists of three main architectural components:
138
+
139
+ **1. WebSocket Server Component**
140
+ - Handles persistent WebSocket connections from clients
141
+ - Manages tunnel registration and state
142
+ - Routes incoming HTTP requests based on tunnel IDs
143
+
144
+ **2. Client Component**
145
+ - Establishes outbound WebSocket connection
146
+ - Proxies local service requests
147
+ - Handles connection lifecycle and reconnection
148
+
149
+ **3. TCP Proxy Layer**
150
+ - Receives external HTTP requests
151
+ - Forwards requests through WebSocket tunnels
152
+ - Manages connection multiplexing
153
+
154
+ ### System Architecture Diagram
155
+
156
+ ```mermaid
157
+ architecture-beta
158
+ group internet[Internet]
159
+
160
+ service ext[External Client] in internet
161
+ service tcp[TCP Server] in internet
162
+
163
+ end
164
+
165
+ service ws[WebSocket Server] in internet
166
+
167
+ group local[Local Network]
168
+
169
+ service proxy[HTTP Proxy] in local
170
+ service target[Target Service] in local
171
+ service client[WebSocket Client] in local
172
+
173
+ end
174
+
175
+ ext:R -- L:HTTP Request
176
+ tcp:L -- R:Route by tunnel-id
177
+ tcp:R -- L:WS DATA message
178
+ ws:L -- R:Forward to tunnel
179
+ client:R -- L:Receive WS message
180
+ client:R -- L:Forward to proxy
181
+ proxy:L -- R:HTTP to target
182
+ target:R -- L:Response
183
+ proxy:R -- L:TCP data back
184
+ client:R -- L:WS DATA response
185
+ ws:R -- L:Forward to TCP
186
+ tcp:R -- L:HTTP response
187
+ ext:L -- R:Receive response
188
+ ```
189
+
190
+ *Reverse tunneling architecture showing request flow from external clients to local services*
191
+
192
+ ## Communication Protocol
193
+
194
+ ### Message Format
195
+
196
+ The tunneling protocol uses a custom binary message format optimized for efficiency:
197
+
198
+ ```
199
+ [4 bytes: length] [36 bytes: tunnel_id] [36 bytes: connection_uuid] [1 byte: type] [payload]
200
+ ```
201
+
202
+ **Message Types:**
203
+ - **CONFIG (0x01)**: Initial tunnel setup with target URL, ports, and metadata
204
+ - **DATA (0x02)**: Bidirectional data transfer for HTTP requests/responses
205
+
206
+ ### Connection Lifecycle
207
+
208
+ ```mermaid
209
+ sequenceDiagram
210
+ participant Local as Local Service
211
+ participant Proxy as Client Proxy
212
+ participant WSClient as Client WS
213
+ participant WSServer as Server WS
214
+ participant TCPServer as Server TCP
215
+ participant Ext as External Client
216
+
217
+ Note over WSClient,WSServer: 1. Tunnel Establishment
218
+ WSClient->>WSServer: WS Connect + CONFIG message
219
+ WSServer->>WSClient: Acknowledgment
220
+
221
+ Note over TCPServer,Ext: 2. External Request
222
+ Ext->>TCPServer: HTTP Request + x-tunnel-id header
223
+ TCPServer->>WSServer: Parse HTTP → WS DATA message
224
+
225
+ Note over WSClient,Proxy: 3. Request Forwarding
226
+ WSServer->>WSClient: WS DATA message
227
+ WSClient->>Proxy: TCP data to local proxy
228
+ Proxy->>Local: HTTP request to target service
229
+
230
+ Note over Local,WSClient: 4. Response Flow
231
+ Local-->>Proxy: HTTP response
232
+ Proxy-->>WSClient: TCP data
233
+ WSClient-->>WSServer: WS DATA message
234
+ WSServer-->>TCPServer: Forward to TCP socket
235
+ TCPServer-->>Ext: HTTP response
236
+ ```
237
+
238
+ *Complete request-response cycle through the tunnel*
239
+
240
+ ## Security Best Practices
241
+
242
+ ### Authentication & Authorization
243
+
244
+ ```javascript
245
+ // Secure tunnel with multiple auth methods
246
+ const secureClient = startClient({
247
+ tunnelId: 'prod-api-gateway',
248
+ wsUrl: 'wss://secure-tunnel.yourcompany.com/tunnel',
249
+ targetUrl: 'http://localhost:8080',
250
+ headers: {
251
+ 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIs...',
252
+ 'X-API-Key': 'sk_prod_1234567890',
253
+ 'X-Client-Cert': 'certificate_fingerprint'
254
+ },
255
+ allowInsicureCerts: false // Always false in production
256
+ });
257
+ ```
258
+
259
+ ### SSL/TLS Configuration
260
+
261
+ **Server-side SSL termination:**
262
+ ```javascript
263
+ const https = require('https');
264
+ const { startWebSocketServer } = require('@remotelinker/reverse-ws-tunnel/server');
265
+
266
+ const sslOptions = {
267
+ key: fs.readFileSync('server.key'),
268
+ cert: fs.readFileSync('server.crt'),
269
+ ca: fs.readFileSync('ca.crt')
270
+ };
271
+
272
+ const server = https.createServer(sslOptions);
273
+ startWebSocketServer({
274
+ server, // Use existing HTTPS server
275
+ path: '/secure-tunnel'
276
+ });
277
+ ```
278
+
279
+ ### Network Security
280
+
281
+ - **Firewall Rules**: Restrict WebSocket server access to known client IPs
282
+ - **Rate Limiting**: Implement request throttling to prevent abuse
283
+ - **Connection Monitoring**: Log and monitor tunnel usage patterns
284
+ - **Certificate Pinning**: Pin SSL certificates to prevent MITM attacks
285
+
286
+ ## Production Deployment
287
+
288
+ ### Docker Compose Setup
289
+
290
+ ```yaml
291
+ # docker-compose.yml
292
+ version: '3.8'
293
+ services:
294
+ tunnel-server:
295
+ image: remotelinker/reverse-ws-tunnel:latest
296
+ ports:
297
+ - "443:443"
298
+ - "80:80"
299
+ environment:
300
+ - WS_PORT=443
301
+ - HOST=0.0.0.0
302
+ - TUNNEL_ID_HEADER_NAME=x-tunnel-id
303
+ - LOG_LEVEL=info
304
+ volumes:
305
+ - ./ssl:/app/ssl:ro
306
+ - ./config:/app/config:ro
307
+ restart: unless-stopped
308
+
309
+ tunnel-client:
310
+ image: remotelinker/reverse-ws-tunnel:latest
311
+ environment:
312
+ - TUNNEL_ID=prod-service-001
313
+ - WS_URL=wss://tunnel.yourdomain.com/tunnel
314
+ - TARGET_URL=http://host.docker.internal:3000
315
+ - LOG_LEVEL=debug
316
+ depends_on:
317
+ - tunnel-server
318
+ restart: unless-stopped
319
+ ```
320
+
321
+ ### Kubernetes Deployment
322
+
323
+ ```yaml
324
+ # tunnel-server-deployment.yaml
325
+ apiVersion: apps/v1
326
+ kind: Deployment
327
+ metadata:
328
+ name: tunnel-server
329
+ spec:
330
+ replicas: 3
331
+ selector:
332
+ matchLabels:
333
+ app: tunnel-server
334
+ template:
335
+ metadata:
336
+ labels:
337
+ app: tunnel-server
338
+ spec:
339
+ containers:
340
+ - name: tunnel-server
341
+ image: remotelinker/reverse-ws-tunnel:latest
342
+ ports:
343
+ - containerPort: 443
344
+ env:
345
+ - name: WS_PORT
346
+ value: "443"
347
+ - name: LOG_LEVEL
348
+ value: "info"
349
+ resources:
350
+ requests:
351
+ memory: "128Mi"
352
+ cpu: "100m"
353
+ limits:
354
+ memory: "512Mi"
355
+ cpu: "500m"
356
+ livenessProbe:
357
+ httpGet:
358
+ path: /health
359
+ port: 443
360
+ scheme: HTTPS
361
+ initialDelaySeconds: 30
362
+ periodSeconds: 10
363
+ ```
364
+
365
+ ### Monitoring & Observability
366
+
367
+ ```javascript
368
+ // Monitoring integration
369
+ const client = startClient({
370
+ // ... config
371
+ });
372
+
373
+ client.on('connected', () => {
374
+ // Send metrics to monitoring system
375
+ prometheusGauge.set({ tunnel_id: config.tunnelId }, 1);
376
+ });
377
+
378
+ client.on('disconnected', () => {
379
+ prometheusGauge.set({ tunnel_id: config.tunnelId }, 0);
380
+ });
381
+
382
+ // Custom metrics collection
383
+ setInterval(() => {
384
+ const metrics = {
385
+ tunnelId: config.tunnelId,
386
+ uptime: process.uptime(),
387
+ memoryUsage: process.memoryUsage(),
388
+ activeConnections: getActiveConnectionCount()
389
+ };
390
+
391
+ sendToMonitoring(metrics);
392
+ }, 30000);
393
+ ```
394
+
395
+ ## Troubleshooting Guide
396
+
397
+ ### Common Issues
398
+
399
+ **Connection Refused**
400
+ ```bash
401
+ # Check if server is running
402
+ curl -I https://your-tunnel-server.com/tunnel
403
+
404
+ # Verify WebSocket connectivity
405
+ wscat -c wss://your-tunnel-server.com/tunnel
406
+ ```
407
+
408
+ **SSL Certificate Errors**
409
+ ```javascript
410
+ // For development only
411
+ const client = startClient({
412
+ // ... config
413
+ allowInsicureCerts: true, // Remove in production
414
+ rejectUnauthorized: false
415
+ });
416
+ ```
417
+
418
+ **Tunnel Not Receiving Traffic**
419
+ ```bash
420
+ # Test with curl
421
+ curl -H "x-tunnel-id: your-tunnel-id" \
422
+ https://your-tunnel-server.com/
423
+
424
+ # Check server logs for routing errors
425
+ docker logs tunnel-server
426
+ ```
427
+
428
+ **Connection Drops**
429
+ ```javascript
430
+ // Implement reconnection logic
431
+ const client = startClient({
432
+ // ... config
433
+ autoReconnect: true,
434
+ reconnectInterval: 5000,
435
+ maxReconnectAttempts: 10
436
+ });
437
+
438
+ client.on('disconnected', (reason) => {
439
+ console.log('Disconnected:', reason);
440
+ // Implement exponential backoff
441
+ });
442
+ ```
443
+
444
+ ### Debug Logging
445
+
446
+ ```javascript
447
+ // Enable detailed logging
448
+ process.env.LOG_LEVEL = 'debug';
449
+
450
+ // Or programmatically
451
+ const { setLogLevel } = require('@remotelinker/reverse-ws-tunnel/utils');
452
+ setLogLevel('trace');
453
+ ```
454
+
455
+ ## Advanced Use Cases
456
+
457
+ ### Load Balancing Multiple Instances
458
+
459
+ ```javascript
460
+ // Load balancer configuration
461
+ const clients = [];
462
+
463
+ for (let i = 0; i < 3; i++) {
464
+ const client = startClient({
465
+ tunnelId: `api-server-${i}`,
466
+ wsUrl: 'wss://load-balancer.com/tunnel',
467
+ targetUrl: `http://api-server-${i}:3000`,
468
+ headers: {
469
+ 'X-Instance-ID': i,
470
+ 'X-Load-Balancer': 'round-robin'
471
+ }
472
+ });
473
+
474
+ clients.push(client);
475
+ }
476
+
477
+ // Health check monitoring
478
+ clients.forEach((client, index) => {
479
+ client.on('connected', () => {
480
+ console.log(`Instance ${index} connected`);
481
+ });
482
+ });
483
+ ```
484
+
485
+ ### Custom Authentication Middleware
486
+
487
+ ```javascript
488
+ // Server-side auth validation
489
+ const { startWebSocketServer } = require('@remotelinker/reverse-ws-tunnel/server');
490
+
491
+ const authenticateTunnel = (headers) => {
492
+ const token = headers['authorization'];
493
+ if (!token) return false;
494
+
495
+ // Validate JWT token
496
+ try {
497
+ const decoded = jwt.verify(token, process.env.JWT_SECRET);
498
+ return decoded.role === 'tunnel-client';
499
+ } catch (err) {
500
+ return false;
501
+ }
502
+ };
503
+
504
+ startWebSocketServer({
505
+ port: 443,
506
+ authenticate: authenticateTunnel
507
+ });
508
+ ```
509
+
510
+ ### WebSocket Upgrade Handling
511
+
512
+ ```javascript
513
+ // Handle WebSocket connections through tunnel
514
+ const WebSocket = require('ws');
515
+ const { startClient } = require('@remotelinker/reverse-ws-tunnel/client');
516
+
517
+ const client = startClient({
518
+ tunnelId: 'websocket-service',
519
+ wsUrl: 'wss://tunnel.com/tunnel',
520
+ targetUrl: 'http://localhost:8080'
521
+ });
522
+
523
+ // The tunnel automatically handles WebSocket upgrades
524
+ // No additional configuration needed for WS connections
525
+ ```
526
+
527
+ ### File Upload/Download Tunneling
528
+
529
+ ```javascript
530
+ // Large file transfer configuration
531
+ const client = startClient({
532
+ tunnelId: 'file-transfer-service',
533
+ wsUrl: 'wss://tunnel.com/tunnel',
534
+ targetUrl: 'http://localhost:3000',
535
+ // Increase buffer sizes for large files
536
+ maxPayloadSize: '100MB',
537
+ timeout: 300000 // 5 minutes
538
+ });
539
+
540
+ // Server-side file handling
541
+ const express = require('express');
542
+ const multer = require('multer');
543
+ const app = express();
544
+
545
+ const upload = multer({
546
+ dest: 'uploads/',
547
+ limits: { fileSize: 100 * 1024 * 1024 } // 100MB
548
+ });
549
+
550
+ app.post('/upload', upload.single('file'), (req, res) => {
551
+ res.json({ message: 'File uploaded successfully' });
552
+ });
553
+ ```
554
+
555
+ ## Performance Optimization
556
+
557
+ ### Connection Pooling
558
+
559
+ ```javascript
560
+ // Optimize for high-throughput scenarios
561
+ const client = startClient({
562
+ tunnelId: 'high-throughput-api',
563
+ wsUrl: 'wss://tunnel.com/tunnel',
564
+ targetUrl: 'http://localhost:3000',
565
+ // Connection pooling settings
566
+ maxConnections: 100,
567
+ keepAlive: true,
568
+ keepAliveTimeout: 60000
569
+ });
570
+ ```
571
+
572
+ ### Compression
573
+
574
+ ```javascript
575
+ // Enable compression for text-based content
576
+ const compression = require('compression');
577
+
578
+ app.use(compression({
579
+ level: 6, // Balance between speed and compression
580
+ threshold: 1024 // Only compress responses > 1KB
581
+ }));
582
+ ```
583
+
584
+ ## Conclusion
585
+
586
+ This WebSocket tunneling library provides a robust, flexible solution for exposing local services to the internet. From simple development workflows to complex production deployments, the examples in this cookbook demonstrate the library's versatility across different use cases.
587
+
588
+ Key takeaways:
589
+ - **Security First**: Always use SSL/TLS and implement proper authentication
590
+ - **Monitoring**: Implement comprehensive logging and metrics collection
591
+ - **Scalability**: Design for horizontal scaling with load balancing
592
+ - **Reliability**: Use auto-reconnection and proper error handling
593
+
594
+ For more advanced implementations and custom integrations, refer to the library's source code and API documentation.</content>
595
+ <parameter name="filePath">cookbook.md
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@remotelinker/reverse-ws-tunnel",
3
+ "version": "1.0.4",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "config": {
7
+ "dockerRegistry": {
8
+ "prod": "",
9
+ "localDev": ""
10
+ }
11
+ },
12
+ "scripts": {
13
+ "test": "jest",
14
+ "test:safe": "node run-tests.js",
15
+ "test:coverage": "jest --coverage",
16
+ "test:watch": "jest --watch",
17
+ "pack": "npm pack && mv *.tgz dist/",
18
+ "docker:build": "cross-conf-env docker image build -f Dockerfile . -t $npm_package_config_dockerRegistry_prodremotelinker/reverse-ws-tunnel:$npm_package_version",
19
+ "docker:deploy": "docker-compose up -d",
20
+ "example:server": "node examples/server/server-example.js",
21
+ "example:client": "node examples/client/client-example.js",
22
+ "example:webserver": "node examples/webserver/webserver-example.js"
23
+ },
24
+ "exports": {
25
+ "./server": "./server/index.js",
26
+ "./client": "./client/index.js",
27
+ "./utils": "./utils/index.js"
28
+ },
29
+ "keywords": [],
30
+ "author": "Andrea Trentin <at30in@gmail.com>",
31
+ "license": "ISC",
32
+ "dependencies": {
33
+ "@iarna/toml": "^2.2.5",
34
+ "cookie": "^1.0.2",
35
+ "cross-conf-env": "^1.3.0",
36
+ "dotenv": "^17.2.1",
37
+ "express": "^4.21.2",
38
+ "http-parser-js": "^0.5.10",
39
+ "http-proxy": "^1.18.1",
40
+ "uuid": "^11.1.0",
41
+ "winston": "^3.17.0",
42
+ "ws": "^8.18.0"
43
+ },
44
+ "devDependencies": {
45
+ "jest": "^29.7.0"
46
+ }
47
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ PING_INTERVAL: 1000 * 30,
3
+ HTTP_TIMEOUT: 1000 * 30,
4
+ RECONNECT_INTERVAL: 1000 * 5,
5
+ MESSAGE_TYPE_CONFIG: 0x01,
6
+ MESSAGE_TYPE_DATA: 0x02,
7
+ };
@@ -0,0 +1,8 @@
1
+ // require('dotenv').config();
2
+ const { startWebSocketServer } = require('./websocketServer');
3
+ const { setLogContext } = require('../utils/logger');
4
+
5
+ module.exports = {
6
+ startWebSocketServer,
7
+ setLogContext,
8
+ };