@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/CHANGELOG.md +54 -0
- package/README.md +406 -0
- package/client/index.js +34 -0
- package/client/proxyServer.js +74 -0
- package/client/tunnelClient.js +196 -0
- package/client/utils.js +24 -0
- package/cookbook.md +595 -0
- package/package.json +47 -0
- package/server/constants.js +7 -0
- package/server/index.js +8 -0
- package/server/messageHandler.js +79 -0
- package/server/state.js +1 -0
- package/server/tcpServer.js +137 -0
- package/server/websocketServer.js +142 -0
- package/utils/index.js +8 -0
- package/utils/loadConfig.js +54 -0
- package/utils/logger.js +136 -0
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
|
+
}
|