@push.rocks/smartproxy 20.0.1 → 21.1.0
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 +26 -0
- package/dist_ts/core/utils/proxy-protocol.d.ts +5 -17
- package/dist_ts/core/utils/proxy-protocol.js +13 -97
- package/dist_ts/core/utils/websocket-utils.d.ts +6 -7
- package/dist_ts/core/utils/websocket-utils.js +10 -66
- package/dist_ts/detection/detectors/http-detector-v2.d.ts +33 -0
- package/dist_ts/detection/detectors/http-detector-v2.js +87 -0
- package/dist_ts/detection/detectors/http-detector.d.ts +33 -0
- package/dist_ts/detection/detectors/http-detector.js +89 -0
- package/dist_ts/detection/detectors/quick-detector.d.ts +28 -0
- package/dist_ts/detection/detectors/quick-detector.js +131 -0
- package/dist_ts/detection/detectors/routing-extractor.d.ts +28 -0
- package/dist_ts/detection/detectors/routing-extractor.js +122 -0
- package/dist_ts/detection/detectors/tls-detector-v2.d.ts +33 -0
- package/dist_ts/detection/detectors/tls-detector-v2.js +80 -0
- package/dist_ts/detection/detectors/tls-detector.d.ts +33 -0
- package/dist_ts/detection/detectors/tls-detector.js +106 -0
- package/dist_ts/detection/index.d.ts +17 -0
- package/dist_ts/detection/index.js +22 -0
- package/dist_ts/detection/models/detection-types.d.ts +87 -0
- package/dist_ts/detection/models/detection-types.js +5 -0
- package/dist_ts/detection/models/interfaces.d.ts +97 -0
- package/dist_ts/detection/models/interfaces.js +5 -0
- package/dist_ts/detection/protocol-detector-v2.d.ts +46 -0
- package/dist_ts/detection/protocol-detector-v2.js +116 -0
- package/dist_ts/detection/protocol-detector.d.ts +74 -0
- package/dist_ts/detection/protocol-detector.js +173 -0
- package/dist_ts/detection/utils/buffer-utils.d.ts +61 -0
- package/dist_ts/detection/utils/buffer-utils.js +127 -0
- package/dist_ts/detection/utils/fragment-manager.d.ts +31 -0
- package/dist_ts/detection/utils/fragment-manager.js +53 -0
- package/dist_ts/detection/utils/parser-utils.d.ts +42 -0
- package/dist_ts/detection/utils/parser-utils.js +63 -0
- package/dist_ts/index.d.ts +2 -1
- package/dist_ts/index.js +3 -2
- package/dist_ts/protocols/common/fragment-handler.d.ts +73 -0
- package/dist_ts/protocols/common/fragment-handler.js +117 -0
- package/dist_ts/protocols/common/index.d.ts +7 -0
- package/dist_ts/protocols/common/index.js +8 -0
- package/dist_ts/protocols/common/types.d.ts +68 -0
- package/dist_ts/protocols/common/types.js +7 -0
- package/dist_ts/protocols/http/constants.d.ts +119 -0
- package/dist_ts/protocols/http/constants.js +200 -0
- package/dist_ts/protocols/http/index.d.ts +7 -0
- package/dist_ts/protocols/http/index.js +8 -0
- package/dist_ts/protocols/http/parser.d.ts +58 -0
- package/dist_ts/protocols/http/parser.js +184 -0
- package/dist_ts/protocols/http/types.d.ts +62 -0
- package/dist_ts/protocols/http/types.js +5 -0
- package/dist_ts/protocols/index.d.ts +11 -0
- package/dist_ts/protocols/index.js +12 -0
- package/dist_ts/protocols/proxy/index.d.ts +6 -0
- package/dist_ts/protocols/proxy/index.js +7 -0
- package/dist_ts/protocols/proxy/parser.d.ts +44 -0
- package/dist_ts/protocols/proxy/parser.js +153 -0
- package/dist_ts/protocols/proxy/types.d.ts +47 -0
- package/dist_ts/protocols/proxy/types.js +6 -0
- package/dist_ts/protocols/tls/alerts/index.d.ts +4 -0
- package/dist_ts/protocols/tls/alerts/index.js +5 -0
- package/dist_ts/protocols/tls/alerts/tls-alert.d.ts +150 -0
- package/dist_ts/protocols/tls/alerts/tls-alert.js +226 -0
- package/dist_ts/protocols/tls/constants.d.ts +122 -0
- package/dist_ts/protocols/tls/constants.js +135 -0
- package/dist_ts/protocols/tls/index.d.ts +12 -0
- package/dist_ts/protocols/tls/index.js +27 -0
- package/dist_ts/protocols/tls/parser.d.ts +53 -0
- package/dist_ts/protocols/tls/parser.js +294 -0
- package/dist_ts/protocols/tls/sni/client-hello-parser.d.ts +100 -0
- package/dist_ts/protocols/tls/sni/client-hello-parser.js +463 -0
- package/dist_ts/protocols/tls/sni/index.d.ts +5 -0
- package/dist_ts/protocols/tls/sni/index.js +6 -0
- package/dist_ts/protocols/tls/sni/sni-extraction.d.ts +58 -0
- package/dist_ts/protocols/tls/sni/sni-extraction.js +275 -0
- package/dist_ts/protocols/tls/types.d.ts +65 -0
- package/dist_ts/protocols/tls/types.js +5 -0
- package/dist_ts/protocols/tls/utils/index.d.ts +4 -0
- package/dist_ts/protocols/tls/utils/index.js +5 -0
- package/dist_ts/protocols/tls/utils/tls-utils.d.ts +158 -0
- package/dist_ts/protocols/tls/utils/tls-utils.js +187 -0
- package/dist_ts/protocols/websocket/constants.d.ts +55 -0
- package/dist_ts/protocols/websocket/constants.js +58 -0
- package/dist_ts/protocols/websocket/index.d.ts +7 -0
- package/dist_ts/protocols/websocket/index.js +8 -0
- package/dist_ts/protocols/websocket/types.d.ts +47 -0
- package/dist_ts/protocols/websocket/types.js +5 -0
- package/dist_ts/protocols/websocket/utils.d.ts +25 -0
- package/dist_ts/protocols/websocket/utils.js +103 -0
- package/dist_ts/proxies/http-proxy/models/http-types.d.ts +25 -27
- package/dist_ts/proxies/http-proxy/models/http-types.js +24 -44
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/models/route-types.js +1 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +81 -61
- package/dist_ts/proxies/smart-proxy/tls-manager.js +2 -1
- package/dist_ts/proxies/smart-proxy/utils/index.d.ts +1 -2
- package/dist_ts/proxies/smart-proxy/utils/index.js +3 -4
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.d.ts +112 -8
- package/dist_ts/proxies/smart-proxy/utils/route-helpers.js +231 -76
- package/dist_ts/tls/index.d.ts +5 -7
- package/dist_ts/tls/index.js +8 -11
- package/dist_ts/tls/sni/client-hello-parser.js +3 -2
- package/dist_ts/tls/sni/sni-handler.js +4 -4
- package/dist_ts/tls/utils/tls-utils.d.ts +1 -110
- package/dist_ts/tls/utils/tls-utils.js +4 -116
- package/package.json +17 -8
- package/readme.md +471 -2345
- package/readme.plan.md +0 -0
- package/ts/core/utils/proxy-protocol.ts +14 -131
- package/ts/core/utils/websocket-utils.ts +12 -60
- package/ts/detection/detectors/http-detector.ts +114 -0
- package/ts/detection/detectors/quick-detector.ts +148 -0
- package/ts/detection/detectors/routing-extractor.ts +147 -0
- package/ts/detection/detectors/tls-detector.ts +120 -0
- package/ts/detection/index.ts +25 -0
- package/ts/detection/models/detection-types.ts +102 -0
- package/ts/detection/models/interfaces.ts +115 -0
- package/ts/detection/protocol-detector.ts +230 -0
- package/ts/detection/utils/buffer-utils.ts +141 -0
- package/ts/detection/utils/fragment-manager.ts +64 -0
- package/ts/detection/utils/parser-utils.ts +77 -0
- package/ts/index.ts +3 -2
- package/ts/protocols/common/fragment-handler.ts +163 -0
- package/ts/protocols/common/index.ts +8 -0
- package/ts/protocols/common/types.ts +76 -0
- package/ts/protocols/http/constants.ts +219 -0
- package/ts/protocols/http/index.ts +8 -0
- package/ts/protocols/http/parser.ts +219 -0
- package/ts/protocols/http/types.ts +70 -0
- package/ts/protocols/index.ts +12 -0
- package/ts/protocols/proxy/index.ts +7 -0
- package/ts/protocols/proxy/parser.ts +183 -0
- package/ts/protocols/proxy/types.ts +53 -0
- package/ts/{tls → protocols/tls}/alerts/tls-alert.ts +1 -1
- package/ts/protocols/tls/index.ts +37 -0
- package/ts/protocols/tls/sni/index.ts +6 -0
- package/ts/{tls → protocols/tls}/utils/tls-utils.ts +1 -1
- package/ts/protocols/websocket/constants.ts +60 -0
- package/ts/protocols/websocket/index.ts +8 -0
- package/ts/protocols/websocket/types.ts +53 -0
- package/ts/protocols/websocket/utils.ts +98 -0
- package/ts/proxies/http-proxy/models/http-types.ts +29 -46
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -1
- package/ts/proxies/smart-proxy/models/route-types.ts +0 -1
- package/ts/proxies/smart-proxy/route-connection-handler.ts +91 -68
- package/ts/proxies/smart-proxy/tls-manager.ts +1 -0
- package/ts/proxies/smart-proxy/utils/index.ts +2 -13
- package/ts/proxies/smart-proxy/utils/route-helpers.ts +323 -86
- package/ts/tls/index.ts +8 -12
- package/ts/tls/sni/sni-handler.ts +3 -3
- package/ts/forwarding/config/forwarding-types.ts +0 -76
- package/ts/forwarding/config/index.ts +0 -26
- package/ts/forwarding/factory/forwarding-factory.ts +0 -189
- package/ts/forwarding/factory/index.ts +0 -5
- package/ts/forwarding/handlers/base-handler.ts +0 -155
- package/ts/forwarding/handlers/http-handler.ts +0 -163
- package/ts/forwarding/handlers/https-passthrough-handler.ts +0 -185
- package/ts/forwarding/handlers/https-terminate-to-http-handler.ts +0 -312
- package/ts/forwarding/handlers/https-terminate-to-https-handler.ts +0 -297
- package/ts/forwarding/handlers/index.ts +0 -9
- package/ts/forwarding/index.ts +0 -35
- package/ts/proxies/smart-proxy/utils/route-patterns.ts +0 -403
- /package/ts/{tls → protocols/tls}/alerts/index.ts +0 -0
- /package/ts/{tls → protocols/tls}/sni/client-hello-parser.ts +0 -0
- /package/ts/{tls → protocols/tls}/sni/sni-extraction.ts +0 -0
- /package/ts/{tls → protocols/tls}/utils/index.ts +0 -0
package/readme.md
CHANGED
|
@@ -11,6 +11,7 @@ A unified high-performance proxy toolkit for Node.js, with **SmartProxy** as the
|
|
|
11
11
|
- **Security Features**: Route-specific IP allowlists, blocklists, connection limits, and authentication
|
|
12
12
|
- **NFTables Integration**: High-performance kernel-level packet forwarding with Linux NFTables
|
|
13
13
|
- **Socket Handlers**: Custom socket handling for specialized protocols and use cases
|
|
14
|
+
- **Multiple Targets**: Load balancing and failover with support for multiple upstream targets
|
|
14
15
|
|
|
15
16
|
## Project Architecture Overview
|
|
16
17
|
|
|
@@ -61,6 +62,7 @@ SmartProxy has been restructured using a modern, modular architecture with a uni
|
|
|
61
62
|
- Automatic certificate management
|
|
62
63
|
- Advanced security controls
|
|
63
64
|
- Custom socket handling capabilities
|
|
65
|
+
- Load balancing with multiple targets
|
|
64
66
|
|
|
65
67
|
### Helper Functions
|
|
66
68
|
|
|
@@ -110,7 +112,9 @@ npm install @push.rocks/smartproxy
|
|
|
110
112
|
|
|
111
113
|
## Quick Start with SmartProxy
|
|
112
114
|
|
|
113
|
-
SmartProxy
|
|
115
|
+
SmartProxy v20.0.0 provides a unified route-based configuration system with enhanced certificate management, NFTables integration for high-performance kernel-level routing, custom socket handling, and improved helper functions for common proxy setups.
|
|
116
|
+
|
|
117
|
+
**⚠️ Breaking Change in v20.0.0**: The route action configuration has changed from single `target` to `targets` array to support multiple upstream targets for load balancing and failover.
|
|
114
118
|
|
|
115
119
|
```typescript
|
|
116
120
|
import {
|
|
@@ -142,11 +146,11 @@ import {
|
|
|
142
146
|
const proxy = new SmartProxy({
|
|
143
147
|
// Global ACME settings for all routes with certificate: 'auto'
|
|
144
148
|
acme: {
|
|
145
|
-
email: 'ssl@
|
|
146
|
-
useProduction: false,
|
|
147
|
-
renewThresholdDays: 30,
|
|
148
|
-
port: 80,
|
|
149
|
-
autoRenew: true,
|
|
149
|
+
email: 'ssl@example.com', // Required for Let's Encrypt
|
|
150
|
+
useProduction: false, // Use staging by default
|
|
151
|
+
renewThresholdDays: 30, // Renew 30 days before expiry
|
|
152
|
+
port: 80, // Port for HTTP-01 challenges (use 8080 for non-privileged)
|
|
153
|
+
autoRenew: true, // Enable automatic renewal
|
|
150
154
|
renewCheckIntervalHours: 24 // Check for renewals daily
|
|
151
155
|
},
|
|
152
156
|
|
|
@@ -229,7 +233,7 @@ const proxy = new SmartProxy({
|
|
|
229
233
|
},
|
|
230
234
|
action: {
|
|
231
235
|
type: 'forward',
|
|
232
|
-
|
|
236
|
+
targets: [{ host: 'localhost', port: 8080 }], // Note: targets is an array
|
|
233
237
|
tls: {
|
|
234
238
|
mode: 'terminate',
|
|
235
239
|
certificate: 'auto'
|
|
@@ -298,291 +302,262 @@ The `match` property defines criteria for identifying which incoming traffic sho
|
|
|
298
302
|
|
|
299
303
|
```typescript
|
|
300
304
|
interface IRouteMatch {
|
|
301
|
-
//
|
|
302
|
-
ports:
|
|
303
|
-
|
|
304
|
-
//
|
|
305
|
-
domains?: string | string[];
|
|
306
|
-
|
|
307
|
-
//
|
|
308
|
-
path?: string;
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
305
|
+
// Port(s) to match
|
|
306
|
+
ports: number | number[] | string; // Single port, array, or range like '8000-8999'
|
|
307
|
+
|
|
308
|
+
// Domain matching (optional - if not specified, matches all domains)
|
|
309
|
+
domains?: string | string[]; // Exact domains or patterns with wildcards
|
|
310
|
+
|
|
311
|
+
// Path matching (optional)
|
|
312
|
+
path?: string; // URL path pattern (supports wildcards)
|
|
313
|
+
|
|
314
|
+
// Client IP matching (optional)
|
|
315
|
+
clientIp?: string | string[]; // IP addresses or CIDR ranges
|
|
316
|
+
|
|
317
|
+
// Protocol matching (optional)
|
|
318
|
+
protocol?: 'tcp' | 'udp' | 'http' | 'https' | 'ws' | 'wss';
|
|
319
|
+
|
|
320
|
+
// TLS version matching (optional)
|
|
321
|
+
tlsVersion?: string | string[]; // e.g., ['TLSv1.2', 'TLSv1.3']
|
|
322
|
+
|
|
323
|
+
// Custom matcher function (optional)
|
|
324
|
+
customMatcher?: (context: IRouteContext) => boolean | Promise<boolean>;
|
|
312
325
|
}
|
|
313
326
|
```
|
|
314
327
|
|
|
315
|
-
**
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
319
|
-
-
|
|
320
|
-
|
|
321
|
-
**Domain Matching:**
|
|
322
|
-
- **Single domain:** `domains: 'example.com'`
|
|
323
|
-
- **Multiple domains:** `domains: ['example.com', 'api.example.com']`
|
|
324
|
-
- **Wildcard domains:** `domains: '*.example.com'` (matches any subdomain)
|
|
325
|
-
- **Root domain + subdomains:** `domains: ['example.com', '*.example.com']`
|
|
326
|
-
|
|
327
|
-
**Path Matching:**
|
|
328
|
-
- **Exact path:** `path: '/api'` (matches only /api exactly)
|
|
329
|
-
- **Prefix match:** `path: '/api/*'` (matches /api and any paths under it)
|
|
330
|
-
- **Multiple patterns:** Use multiple routes with different priorities
|
|
331
|
-
|
|
332
|
-
**Client IP Matching:**
|
|
333
|
-
- **Exact IP:** `clientIp: ['192.168.1.1']`
|
|
334
|
-
- **Subnet wildcards:** `clientIp: ['10.0.0.*', '192.168.1.*']`
|
|
335
|
-
- **CIDR notation:** `clientIp: ['10.0.0.0/24']`
|
|
328
|
+
**Domain Matching Patterns:**
|
|
329
|
+
- Exact match: `example.com`
|
|
330
|
+
- Wildcard subdomain: `*.example.com`
|
|
331
|
+
- Multiple domains: `['example.com', '*.example.com', 'example.org']`
|
|
332
|
+
- All domains: omit the `domains` field
|
|
336
333
|
|
|
337
|
-
**
|
|
338
|
-
-
|
|
334
|
+
**Path Matching Patterns:**
|
|
335
|
+
- Exact path: `/api/users`
|
|
336
|
+
- Path prefix with wildcard: `/api/*`
|
|
337
|
+
- Path with parameter: `/api/users/:id`
|
|
338
|
+
- Multiple path segments: `/api/*/details`
|
|
339
339
|
|
|
340
|
-
#### Action
|
|
340
|
+
#### Action Types (IRouteAction)
|
|
341
341
|
|
|
342
|
-
The `action` property defines what to do with traffic
|
|
342
|
+
The `action` property defines what to do with matched traffic:
|
|
343
343
|
|
|
344
344
|
```typescript
|
|
345
345
|
interface IRouteAction {
|
|
346
346
|
// Action type (required)
|
|
347
|
-
type: 'forward' | 'socket-handler';
|
|
348
|
-
|
|
349
|
-
// For 'forward'
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
//
|
|
347
|
+
type: 'forward' | 'redirect' | 'block' | 'socket-handler';
|
|
348
|
+
|
|
349
|
+
// For 'forward' type - array of upstream targets
|
|
350
|
+
targets?: IRouteTarget[];
|
|
351
|
+
|
|
352
|
+
// For 'redirect' type
|
|
353
|
+
redirectUrl?: string; // URL template with placeholders
|
|
354
|
+
redirectCode?: number; // HTTP status code (301, 302, etc.)
|
|
355
|
+
|
|
356
|
+
// For 'socket-handler' type
|
|
357
|
+
socketHandler?: (socket: net.Socket, context: IRouteContext) => void | Promise<void>;
|
|
358
|
+
|
|
359
|
+
// TLS configuration (optional)
|
|
353
360
|
tls?: IRouteTls;
|
|
354
|
-
|
|
355
|
-
// For 'socket-handler' actions
|
|
356
|
-
socketHandler?: TSocketHandler;
|
|
357
|
-
|
|
358
|
-
// WebSocket support
|
|
359
|
-
websocket?: IRouteWebSocket;
|
|
360
|
-
|
|
361
|
-
// Load balancing options
|
|
362
|
-
loadBalancing?: IRouteLoadBalancing;
|
|
363
|
-
|
|
364
|
-
// Advanced options
|
|
365
|
-
advanced?: IRouteAdvanced;
|
|
366
361
|
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
362
|
+
// WebSocket configuration (optional)
|
|
363
|
+
websocket?: {
|
|
364
|
+
enabled: boolean;
|
|
365
|
+
pingInterval?: number; // Milliseconds between pings
|
|
366
|
+
pingTimeout?: number; // Milliseconds to wait for pong
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// Headers manipulation (optional)
|
|
370
|
+
headers?: {
|
|
371
|
+
request?: Record<string, string>; // Headers to add to requests
|
|
372
|
+
response?: Record<string, string>; // Headers to add to responses
|
|
371
373
|
};
|
|
372
|
-
|
|
373
|
-
// Forwarding engine selection
|
|
374
|
-
forwardingEngine?: 'node' | 'nftables';
|
|
375
|
-
|
|
376
|
-
// NFTables-specific options
|
|
377
|
-
nftables?: INfTablesOptions;
|
|
378
374
|
}
|
|
379
375
|
```
|
|
380
376
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
Security is configured at the route level, not within the action:
|
|
384
|
-
|
|
377
|
+
**Forward Action with Multiple Targets:**
|
|
385
378
|
```typescript
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
// Authentication (requires TLS termination)
|
|
395
|
-
authentication?: IRouteAuthentication;
|
|
396
|
-
|
|
397
|
-
// Rate limiting
|
|
398
|
-
rateLimit?: IRouteRateLimit;
|
|
379
|
+
{
|
|
380
|
+
type: 'forward',
|
|
381
|
+
targets: [
|
|
382
|
+
{ host: 'backend1.example.com', port: 8080 },
|
|
383
|
+
{ host: 'backend2.example.com', port: 8080 },
|
|
384
|
+
{ host: 'backend3.example.com', port: 8080 }
|
|
385
|
+
]
|
|
399
386
|
}
|
|
400
387
|
```
|
|
401
388
|
|
|
402
|
-
|
|
389
|
+
**Redirect Action:**
|
|
390
|
+
```typescript
|
|
391
|
+
{
|
|
392
|
+
type: 'redirect',
|
|
393
|
+
redirectUrl: 'https://{domain}/{path}', // Placeholders: {domain}, {path}, {clientIp}
|
|
394
|
+
redirectCode: 301
|
|
395
|
+
}
|
|
396
|
+
```
|
|
403
397
|
|
|
404
|
-
|
|
398
|
+
**Socket Handler Action:**
|
|
399
|
+
```typescript
|
|
400
|
+
{
|
|
401
|
+
type: 'socket-handler',
|
|
402
|
+
socketHandler: (socket, context) => {
|
|
403
|
+
// Custom logic for handling the socket
|
|
404
|
+
socket.write('Hello from custom handler\n');
|
|
405
|
+
socket.end();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
405
409
|
|
|
406
|
-
|
|
407
|
-
Set default ACME settings for all routes with `certificate: 'auto'`:
|
|
410
|
+
### Route Examples
|
|
408
411
|
|
|
412
|
+
#### Basic HTTP Forwarding
|
|
409
413
|
```typescript
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
useProduction: false, // Use staging (false) or production (true)
|
|
415
|
-
renewThresholdDays: 30, // Renew certificates 30 days before expiry
|
|
416
|
-
port: 80, // Port for HTTP-01 challenges
|
|
417
|
-
certificateStore: './certs', // Directory to store certificates
|
|
418
|
-
autoRenew: true, // Enable automatic renewal
|
|
419
|
-
renewCheckIntervalHours: 24 // Check for renewals every 24 hours
|
|
414
|
+
{
|
|
415
|
+
match: {
|
|
416
|
+
ports: 80,
|
|
417
|
+
domains: 'api.example.com'
|
|
420
418
|
},
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
match: { ports: 443, domains: 'example.com' },
|
|
427
|
-
action: {
|
|
428
|
-
type: 'forward',
|
|
429
|
-
target: { host: 'localhost', port: 8080 },
|
|
430
|
-
tls: {
|
|
431
|
-
mode: 'terminate',
|
|
432
|
-
certificate: 'auto' // Uses global ACME configuration
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
]
|
|
437
|
-
});
|
|
419
|
+
action: {
|
|
420
|
+
type: 'forward',
|
|
421
|
+
targets: [{ host: 'localhost', port: 3000 }]
|
|
422
|
+
}
|
|
423
|
+
}
|
|
438
424
|
```
|
|
439
425
|
|
|
440
|
-
####
|
|
441
|
-
Override global settings for specific routes:
|
|
442
|
-
|
|
426
|
+
#### HTTPS with TLS Termination and Load Balancing
|
|
443
427
|
```typescript
|
|
444
428
|
{
|
|
445
|
-
|
|
446
|
-
|
|
429
|
+
match: {
|
|
430
|
+
ports: 443,
|
|
431
|
+
domains: ['secure.example.com', '*.secure.example.com']
|
|
432
|
+
},
|
|
447
433
|
action: {
|
|
448
434
|
type: 'forward',
|
|
449
|
-
|
|
435
|
+
targets: [
|
|
436
|
+
{ host: '10.0.0.10', port: 8080 },
|
|
437
|
+
{ host: '10.0.0.11', port: 8080 },
|
|
438
|
+
{ host: '10.0.0.12', port: 8080 }
|
|
439
|
+
],
|
|
450
440
|
tls: {
|
|
451
441
|
mode: 'terminate',
|
|
452
|
-
certificate: 'auto'
|
|
453
|
-
acme: {
|
|
454
|
-
email: 'api-ssl@example.com', // Different email for this route
|
|
455
|
-
useProduction: true, // Use production while global uses staging
|
|
456
|
-
renewBeforeDays: 60 // Route-specific renewal threshold
|
|
457
|
-
}
|
|
442
|
+
certificate: 'auto' // Automatic Let's Encrypt certificate
|
|
458
443
|
}
|
|
459
444
|
}
|
|
460
445
|
}
|
|
461
446
|
```
|
|
462
447
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
**Forward Action:**
|
|
466
|
-
When `type: 'forward'`, the traffic is forwarded to the specified target:
|
|
448
|
+
#### WebSocket Route
|
|
467
449
|
```typescript
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
450
|
+
{
|
|
451
|
+
match: {
|
|
452
|
+
ports: 443,
|
|
453
|
+
domains: 'ws.example.com',
|
|
454
|
+
path: '/socket/*'
|
|
455
|
+
},
|
|
456
|
+
action: {
|
|
457
|
+
type: 'forward',
|
|
458
|
+
targets: [{ host: 'websocket-server', port: 8080 }],
|
|
459
|
+
tls: {
|
|
460
|
+
mode: 'terminate',
|
|
461
|
+
certificate: 'auto'
|
|
462
|
+
},
|
|
463
|
+
websocket: {
|
|
464
|
+
enabled: true,
|
|
465
|
+
pingInterval: 30000,
|
|
466
|
+
pingTimeout: 5000
|
|
467
|
+
}
|
|
468
|
+
}
|
|
471
469
|
}
|
|
472
470
|
```
|
|
473
471
|
|
|
474
|
-
|
|
475
|
-
When forwarding with TLS, you can configure how TLS is handled:
|
|
472
|
+
#### API Gateway with Security
|
|
476
473
|
```typescript
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
474
|
+
{
|
|
475
|
+
match: {
|
|
476
|
+
ports: 443,
|
|
477
|
+
domains: 'api.example.com',
|
|
478
|
+
path: '/v1/*'
|
|
479
|
+
},
|
|
480
|
+
action: {
|
|
481
|
+
type: 'forward',
|
|
482
|
+
targets: [{ host: 'api-backend', port: 8080 }],
|
|
483
|
+
tls: {
|
|
484
|
+
mode: 'terminate',
|
|
485
|
+
certificate: 'auto'
|
|
486
|
+
},
|
|
487
|
+
headers: {
|
|
488
|
+
request: {
|
|
489
|
+
'X-API-Version': 'v1',
|
|
490
|
+
'X-Real-IP': '{clientIp}'
|
|
491
|
+
},
|
|
492
|
+
response: {
|
|
493
|
+
'Access-Control-Allow-Origin': '*',
|
|
494
|
+
'X-Powered-By': 'SmartProxy'
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
security: {
|
|
499
|
+
ipAllowList: ['10.0.0.0/8', '172.16.0.0/12'],
|
|
500
|
+
rateLimit: {
|
|
501
|
+
maxRequests: 100,
|
|
502
|
+
windowMs: 60000
|
|
503
|
+
},
|
|
504
|
+
authentication: {
|
|
505
|
+
type: 'basic',
|
|
506
|
+
realm: 'API Access',
|
|
507
|
+
users: {
|
|
508
|
+
'apiuser': 'hashedpassword'
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
483
512
|
}
|
|
484
513
|
```
|
|
485
514
|
|
|
486
|
-
|
|
487
|
-
- **passthrough:** Forward raw encrypted TLS traffic without decryption
|
|
488
|
-
- **terminate:** Terminate TLS and forward as HTTP
|
|
489
|
-
- **terminate-and-reencrypt:** Terminate TLS and create a new TLS connection to the backend
|
|
515
|
+
## NFTables Integration
|
|
490
516
|
|
|
491
|
-
|
|
492
|
-
When `forwardingEngine` is specified, it determines how packets are forwarded:
|
|
493
|
-
- **node:** (default) Application-level forwarding using Node.js
|
|
494
|
-
- **nftables:** Kernel-level forwarding using Linux NFTables (requires root privileges)
|
|
517
|
+
SmartProxy includes high-performance kernel-level packet forwarding using Linux NFTables. This provides ultra-low latency forwarding by operating at the kernel level.
|
|
495
518
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
protocol?: 'tcp' | 'udp' | 'all';
|
|
501
|
-
preserveSourceIP?: boolean;
|
|
502
|
-
maxRate?: string; // Rate limiting (e.g., '100mbps')
|
|
503
|
-
priority?: number; // QoS priority
|
|
504
|
-
tableName?: string; // Custom NFTables table name
|
|
505
|
-
useIPSets?: boolean; // Use IP sets for performance
|
|
506
|
-
useAdvancedNAT?: boolean; // Use connection tracking
|
|
507
|
-
}
|
|
508
|
-
```
|
|
519
|
+
### Requirements
|
|
520
|
+
- Linux kernel with NFTables support
|
|
521
|
+
- Root/sudo privileges
|
|
522
|
+
- `nft` command-line tool installed
|
|
509
523
|
|
|
510
|
-
|
|
511
|
-
Redirects and blocks are implemented using socket handlers. Use the helper functions or pre-built handlers:
|
|
524
|
+
### NFTables Route Example
|
|
512
525
|
```typescript
|
|
513
|
-
//
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
type: 'socket-handler',
|
|
520
|
-
socketHandler: SocketHandlers.httpBlock(403, 'Access denied')
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
```
|
|
526
|
+
// Basic NFTables forwarding
|
|
527
|
+
createNfTablesRoute('fast.example.com', { host: 'backend', port: 8080 }, {
|
|
528
|
+
ports: 80,
|
|
529
|
+
protocol: 'tcp',
|
|
530
|
+
preserveSourceIP: true
|
|
531
|
+
})
|
|
524
532
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
533
|
+
// NFTables with TLS termination
|
|
534
|
+
createNfTablesTerminateRoute('secure-fast.example.com', { host: 'backend', port: 8080 }, {
|
|
535
|
+
ports: 443,
|
|
536
|
+
certificate: 'auto',
|
|
537
|
+
maxRate: '100mbps'
|
|
538
|
+
})
|
|
529
539
|
```
|
|
530
540
|
|
|
531
|
-
|
|
532
|
-
- `socket`: The raw Node.js Socket object
|
|
533
|
-
- `context`: Route context containing clientIp, port, domain, route info, etc.
|
|
541
|
+
## Socket Handlers
|
|
534
542
|
|
|
535
|
-
|
|
543
|
+
SmartProxy supports custom socket handlers for implementing specialized protocols or custom logic:
|
|
536
544
|
|
|
537
|
-
|
|
545
|
+
### Pre-built Socket Handlers
|
|
538
546
|
|
|
539
547
|
```typescript
|
|
540
|
-
// Create a custom socket handler route
|
|
541
|
-
createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => {
|
|
542
|
-
console.log(`New connection from ${context.clientIp}`);
|
|
543
|
-
|
|
544
|
-
// Custom protocol handling
|
|
545
|
-
socket.write('Welcome to custom protocol server\n');
|
|
546
|
-
|
|
547
|
-
socket.on('data', (data) => {
|
|
548
|
-
// Process custom protocol data
|
|
549
|
-
const response = processProtocolData(data);
|
|
550
|
-
socket.write(response);
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
socket.on('error', (err) => {
|
|
554
|
-
console.error('Socket error:', err);
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
// Use pre-built socket handlers
|
|
559
|
-
import { SocketHandlers } from '@push.rocks/smartproxy';
|
|
560
|
-
|
|
561
548
|
// Echo server
|
|
562
|
-
createSocketHandlerRoute('echo.example.com',
|
|
549
|
+
createSocketHandlerRoute('echo.example.com', 7, SocketHandlers.echo)
|
|
563
550
|
|
|
564
|
-
//
|
|
565
|
-
|
|
551
|
+
// HTTP redirect
|
|
552
|
+
createHttpToHttpsRedirect('example.com')
|
|
566
553
|
|
|
567
554
|
// Line-based protocol
|
|
568
555
|
createSocketHandlerRoute('telnet.example.com', 23, SocketHandlers.lineProtocol((line, socket) => {
|
|
569
556
|
socket.write(`You said: ${line}\n`);
|
|
570
|
-
}))
|
|
571
|
-
|
|
572
|
-
// HTTP response
|
|
573
|
-
createSocketHandlerRoute('simple.example.com', 8080, SocketHandlers.httpResponse(200, 'Hello World')),
|
|
574
|
-
|
|
575
|
-
// HTTP redirect
|
|
576
|
-
createSocketHandlerRoute('redirect.example.com', 80, SocketHandlers.httpRedirect('https://{domain}{path}', 301)),
|
|
577
|
-
|
|
578
|
-
// HTTP blocking with custom message
|
|
579
|
-
createSocketHandlerRoute('forbidden.example.com', 80, SocketHandlers.httpBlock(403, 'Access Forbidden')),
|
|
580
|
-
|
|
581
|
-
// Block connections immediately
|
|
582
|
-
createSocketHandlerRoute('blocked.example.com', 443, SocketHandlers.block('Access denied')),
|
|
557
|
+
}))
|
|
583
558
|
|
|
584
|
-
//
|
|
585
|
-
createSocketHandlerRoute('
|
|
559
|
+
// HTTP server for custom logic
|
|
560
|
+
createSocketHandlerRoute('custom.example.com', 8080, SocketHandlers.httpServer((req, res) => {
|
|
586
561
|
if (req.url === '/health') {
|
|
587
562
|
res.status(200);
|
|
588
563
|
res.send('OK');
|
|
@@ -590,447 +565,267 @@ createSocketHandlerRoute('http-api.example.com', 8080, SocketHandlers.httpServer
|
|
|
590
565
|
res.status(404);
|
|
591
566
|
res.send('Not Found');
|
|
592
567
|
}
|
|
568
|
+
res.end();
|
|
593
569
|
}))
|
|
594
|
-
```
|
|
595
|
-
|
|
596
|
-
### Dynamic Routing
|
|
597
|
-
|
|
598
|
-
SmartProxy supports dynamic routing using functions for host and port selection:
|
|
599
|
-
|
|
600
|
-
```typescript
|
|
601
|
-
// Dynamic host selection based on domain
|
|
602
|
-
createDynamicRoute({
|
|
603
|
-
ports: 80,
|
|
604
|
-
domains: ['*.tenant.example.com'],
|
|
605
|
-
targetHost: (context) => {
|
|
606
|
-
// Extract tenant from subdomain
|
|
607
|
-
const tenant = context.domain.split('.')[0];
|
|
608
|
-
return `${tenant}-backend`;
|
|
609
|
-
},
|
|
610
|
-
portMapper: (context) => 8080
|
|
611
|
-
});
|
|
612
570
|
|
|
613
|
-
//
|
|
614
|
-
|
|
615
|
-
ports: [8000, 8001, 8002],
|
|
616
|
-
targetHost: 'backend',
|
|
617
|
-
offset: -1000 // Maps 8000->7000, 8001->7001, etc.
|
|
618
|
-
});
|
|
571
|
+
// Block connections
|
|
572
|
+
createSocketHandlerRoute('blocked.example.com', 443, SocketHandlers.block('Access Denied'))
|
|
619
573
|
|
|
620
|
-
//
|
|
621
|
-
|
|
622
|
-
ports: 443,
|
|
623
|
-
domainTargets: {
|
|
624
|
-
'api.example.com': ['api-1', 'api-2'],
|
|
625
|
-
'web.example.com': ['web-1', 'web-2', 'web-3'],
|
|
626
|
-
'admin.example.com': 'admin-server'
|
|
627
|
-
},
|
|
628
|
-
portMapper: (context) => 8080,
|
|
629
|
-
defaultTarget: 'fallback-server'
|
|
630
|
-
});
|
|
574
|
+
// TCP proxy
|
|
575
|
+
createSocketHandlerRoute('proxy.example.com', 8080, SocketHandlers.proxy('internal-server', 3000))
|
|
631
576
|
```
|
|
632
577
|
|
|
633
|
-
###
|
|
634
|
-
|
|
635
|
-
The `IRouteContext` interface provides information about the current connection:
|
|
578
|
+
### Custom Socket Handler
|
|
636
579
|
|
|
637
580
|
```typescript
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
581
|
+
{
|
|
582
|
+
match: {
|
|
583
|
+
ports: 9999,
|
|
584
|
+
domains: 'custom.example.com'
|
|
585
|
+
},
|
|
586
|
+
action: {
|
|
587
|
+
type: 'socket-handler',
|
|
588
|
+
socketHandler: async (socket, context) => {
|
|
589
|
+
console.log(`New connection from ${context.clientIp} to ${context.domain}`);
|
|
590
|
+
|
|
591
|
+
socket.write('Welcome to the custom protocol server\n');
|
|
592
|
+
|
|
593
|
+
socket.on('data', (data) => {
|
|
594
|
+
// Process incoming data
|
|
595
|
+
const command = data.toString().trim();
|
|
596
|
+
|
|
597
|
+
if (command === 'QUIT') {
|
|
598
|
+
socket.end('Goodbye\n');
|
|
599
|
+
} else {
|
|
600
|
+
socket.write(`Unknown command: ${command}\n`);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
socket.on('error', (err) => {
|
|
605
|
+
console.error('Socket error:', err);
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
646
609
|
}
|
|
647
610
|
```
|
|
648
611
|
|
|
649
|
-
|
|
612
|
+
## Dynamic Port Management
|
|
650
613
|
|
|
651
|
-
|
|
614
|
+
SmartProxy allows you to dynamically add or remove listening ports without restarting:
|
|
652
615
|
|
|
653
|
-
- `{domain}`: The requested domain name
|
|
654
|
-
- `{port}`: The incoming port number
|
|
655
|
-
- `{path}`: The requested URL path
|
|
656
|
-
- `{query}`: The query string
|
|
657
|
-
- `{clientIp}`: The client's IP address
|
|
658
|
-
- `{sni}`: The SNI hostname
|
|
659
|
-
|
|
660
|
-
Example with template variables:
|
|
661
616
|
```typescript
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
status: 301
|
|
665
|
-
}
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
## Forwarding Modes Guide
|
|
617
|
+
// Add a new listening port
|
|
618
|
+
await proxy.addListeningPort(8443);
|
|
669
619
|
|
|
670
|
-
|
|
620
|
+
// Remove a listening port
|
|
621
|
+
await proxy.removeListeningPort(8080);
|
|
671
622
|
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
```mermaid
|
|
675
|
-
graph TD
|
|
676
|
-
A[Incoming Traffic] --> B{Action Type?}
|
|
677
|
-
|
|
678
|
-
B -->|forward| C{TLS Mode?}
|
|
679
|
-
B -->|socket-handler| D[Custom Handler]
|
|
680
|
-
|
|
681
|
-
C -->|terminate| E[Decrypt TLS]
|
|
682
|
-
C -->|passthrough| F[Forward Encrypted]
|
|
683
|
-
C -->|terminate-and-reencrypt| G[Decrypt & Re-encrypt]
|
|
684
|
-
C -->|none/HTTP| H[Forward HTTP]
|
|
685
|
-
|
|
686
|
-
E --> I{Engine?}
|
|
687
|
-
F --> I
|
|
688
|
-
G --> I
|
|
689
|
-
H --> I
|
|
690
|
-
|
|
691
|
-
I -->|node| J[Node.js Processing]
|
|
692
|
-
I -->|nftables| K[Kernel NAT]
|
|
693
|
-
|
|
694
|
-
J --> L[Backend]
|
|
695
|
-
K --> L
|
|
696
|
-
D --> M[Custom Logic]
|
|
697
|
-
|
|
698
|
-
style B fill:#f9f,stroke:#333,stroke-width:2px
|
|
699
|
-
style C fill:#bbf,stroke:#333,stroke-width:2px
|
|
700
|
-
style I fill:#bfb,stroke:#333,stroke-width:2px
|
|
623
|
+
// Get all currently listening ports
|
|
624
|
+
const ports = proxy.getListeningPorts(); // [80, 443, 8443]
|
|
701
625
|
```
|
|
702
626
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
SmartProxy offers flexible traffic forwarding through combinations of:
|
|
706
|
-
- **Action Types**: How to handle matched traffic
|
|
707
|
-
- **TLS Modes**: How to handle HTTPS/TLS connections
|
|
708
|
-
- **Forwarding Engines**: Where packet processing occurs
|
|
709
|
-
|
|
710
|
-
### Quick Reference
|
|
711
|
-
|
|
712
|
-
#### Modern Route-Based Configuration
|
|
713
|
-
|
|
714
|
-
| Use Case | Action Type | TLS Mode | Engine | Performance | Security |
|
|
715
|
-
|----------|------------|----------|---------|-------------|----------|
|
|
716
|
-
| HTTP web server | `forward` | N/A | `node` | Good | Basic |
|
|
717
|
-
| HTTPS web server (inspect traffic) | `forward` | `terminate` | `node` | Good | Full inspection |
|
|
718
|
-
| HTTPS passthrough (no inspection) | `forward` | `passthrough` | `node` | Better | End-to-end encryption |
|
|
719
|
-
| HTTPS gateway (re-encrypt to backend) | `forward` | `terminate-and-reencrypt` | `node` | Moderate | Full control |
|
|
720
|
-
| High-performance TCP forwarding | `forward` | `passthrough` | `nftables` | Excellent | Basic |
|
|
721
|
-
| Custom protocol handling | `socket-handler` | N/A | `node` | Varies | Custom |
|
|
722
|
-
|
|
723
|
-
#### Legacy Forwarding Types (Deprecated)
|
|
724
|
-
|
|
725
|
-
| Legacy Type | Modern Equivalent |
|
|
726
|
-
|------------|------------------|
|
|
727
|
-
| `http-only` | `action.type: 'forward'` with port 80 |
|
|
728
|
-
| `https-passthrough` | `action.type: 'forward'` + `tls.mode: 'passthrough'` |
|
|
729
|
-
| `https-terminate-to-http` | `action.type: 'forward'` + `tls.mode: 'terminate'` |
|
|
730
|
-
| `https-terminate-to-https` | `action.type: 'forward'` + `tls.mode: 'terminate-and-reencrypt'` |
|
|
731
|
-
|
|
732
|
-
### Forwarding Mode Categories
|
|
733
|
-
|
|
734
|
-
#### 1. Action Types
|
|
627
|
+
## Certificate Management
|
|
735
628
|
|
|
736
|
-
|
|
737
|
-
Routes traffic to a backend server. This is the most common action type.
|
|
629
|
+
SmartProxy includes automatic certificate management with Let's Encrypt support:
|
|
738
630
|
|
|
631
|
+
### Automatic Certificates (Let's Encrypt)
|
|
739
632
|
```typescript
|
|
740
633
|
{
|
|
741
634
|
action: {
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
port: 8080
|
|
635
|
+
tls: {
|
|
636
|
+
mode: 'terminate',
|
|
637
|
+
certificate: 'auto' // Automatic Let's Encrypt certificate
|
|
746
638
|
}
|
|
747
639
|
}
|
|
748
640
|
}
|
|
749
641
|
```
|
|
750
642
|
|
|
751
|
-
|
|
752
|
-
Provides custom handling for any TCP protocol. Used for specialized protocols or custom logic.
|
|
753
|
-
|
|
643
|
+
### Manual Certificates
|
|
754
644
|
```typescript
|
|
755
645
|
{
|
|
756
646
|
action: {
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
647
|
+
tls: {
|
|
648
|
+
mode: 'terminate',
|
|
649
|
+
certificate: {
|
|
650
|
+
key: fs.readFileSync('./certs/private.key', 'utf8'),
|
|
651
|
+
cert: fs.readFileSync('./certs/certificate.crt', 'utf8')
|
|
652
|
+
}
|
|
760
653
|
}
|
|
761
654
|
}
|
|
762
655
|
}
|
|
763
656
|
```
|
|
764
657
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
-
|
|
769
|
-
- **When**: Backend handles its own TLS termination
|
|
770
|
-
- **Pros**: Maximum performance, true end-to-end encryption
|
|
771
|
-
- **Cons**: Cannot inspect or modify HTTPS traffic
|
|
772
|
-
|
|
773
|
-
```mermaid
|
|
774
|
-
graph LR
|
|
775
|
-
Client -->|TLS| SmartProxy
|
|
776
|
-
SmartProxy -->|TLS| Backend
|
|
777
|
-
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
778
|
-
```
|
|
779
|
-
|
|
780
|
-
##### Terminate Mode
|
|
781
|
-
- **What**: Decrypts TLS, forwards as plain HTTP
|
|
782
|
-
- **When**: Backend doesn't support HTTPS or you need to inspect traffic
|
|
783
|
-
- **Pros**: Can modify headers, inspect content, add security headers
|
|
784
|
-
- **Cons**: Backend connection is unencrypted
|
|
785
|
-
|
|
786
|
-
```mermaid
|
|
787
|
-
graph LR
|
|
788
|
-
Client -->|TLS| SmartProxy
|
|
789
|
-
SmartProxy -->|HTTP| Backend
|
|
790
|
-
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
791
|
-
```
|
|
792
|
-
|
|
793
|
-
##### Terminate-and-Reencrypt Mode
|
|
794
|
-
- **What**: Decrypts TLS, then creates new TLS connection to backend
|
|
795
|
-
- **When**: Need traffic inspection but backend requires HTTPS
|
|
796
|
-
- **Pros**: Full control while maintaining backend security
|
|
797
|
-
- **Cons**: Higher CPU usage, increased latency
|
|
798
|
-
|
|
799
|
-
```mermaid
|
|
800
|
-
graph LR
|
|
801
|
-
Client -->|TLS| SmartProxy
|
|
802
|
-
SmartProxy -->|New TLS| Backend
|
|
803
|
-
style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px
|
|
804
|
-
```
|
|
805
|
-
|
|
806
|
-
#### 3. Forwarding Engines
|
|
807
|
-
|
|
808
|
-
##### Node.js Engine (Default)
|
|
809
|
-
- **Processing**: Application-level in Node.js event loop
|
|
810
|
-
- **Features**: Full protocol support, header manipulation, WebSockets
|
|
811
|
-
- **Performance**: Good for most use cases
|
|
812
|
-
- **Use when**: You need application-layer features
|
|
813
|
-
|
|
814
|
-
##### NFTables Engine
|
|
815
|
-
- **Processing**: Kernel-level packet forwarding
|
|
816
|
-
- **Features**: Basic NAT, minimal overhead
|
|
817
|
-
- **Performance**: Excellent, near wire-speed
|
|
818
|
-
- **Use when**: Maximum performance is critical
|
|
819
|
-
- **Requirements**: Linux, root permissions, NFTables installed
|
|
820
|
-
|
|
821
|
-
### Detailed Mode Explanations
|
|
658
|
+
### Certificate Store
|
|
659
|
+
Certificates are automatically stored and managed:
|
|
660
|
+
- Auto certificates: `./certificates/{domain}/`
|
|
661
|
+
- Manual certificates: In-memory only
|
|
822
662
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
Simple HTTP forwarding without encryption:
|
|
663
|
+
## Security Features
|
|
826
664
|
|
|
665
|
+
### IP-Based Access Control
|
|
827
666
|
```typescript
|
|
828
667
|
{
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
target: { host: 'localhost', port: 8080 }
|
|
668
|
+
security: {
|
|
669
|
+
ipAllowList: ['10.0.0.0/8', '192.168.*', '::1'],
|
|
670
|
+
ipBlockList: ['192.168.1.100', '10.0.0.0/24']
|
|
833
671
|
}
|
|
834
672
|
}
|
|
835
673
|
```
|
|
836
674
|
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
#### HTTPS with TLS Termination
|
|
840
|
-
|
|
841
|
-
Decrypt HTTPS and forward as HTTP:
|
|
842
|
-
|
|
675
|
+
### Connection Limits
|
|
843
676
|
```typescript
|
|
844
677
|
{
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
target: { host: 'localhost', port: 8080 },
|
|
849
|
-
tls: {
|
|
850
|
-
mode: 'terminate',
|
|
851
|
-
certificate: 'auto' // Use Let's Encrypt
|
|
852
|
-
}
|
|
678
|
+
security: {
|
|
679
|
+
maxConnections: 1000, // Total connections
|
|
680
|
+
maxConnectionsPerIp: 10 // Per IP address
|
|
853
681
|
}
|
|
854
682
|
}
|
|
855
683
|
```
|
|
856
684
|
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
#### HTTPS Passthrough
|
|
860
|
-
|
|
861
|
-
Forward encrypted traffic without decryption:
|
|
862
|
-
|
|
685
|
+
### Rate Limiting
|
|
863
686
|
```typescript
|
|
864
687
|
{
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
tls: {
|
|
870
|
-
mode: 'passthrough'
|
|
688
|
+
security: {
|
|
689
|
+
rateLimit: {
|
|
690
|
+
maxRequests: 100, // Maximum requests
|
|
691
|
+
windowMs: 60000 // Time window (1 minute)
|
|
871
692
|
}
|
|
872
693
|
}
|
|
873
694
|
}
|
|
874
695
|
```
|
|
875
696
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
#### HTTPS Gateway (Terminate and Re-encrypt)
|
|
879
|
-
|
|
880
|
-
Decrypt, inspect, then re-encrypt to backend:
|
|
881
|
-
|
|
697
|
+
### Authentication
|
|
882
698
|
```typescript
|
|
699
|
+
// Basic Authentication
|
|
883
700
|
{
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
certificate: 'auto'
|
|
891
|
-
},
|
|
892
|
-
advanced: {
|
|
893
|
-
headers: {
|
|
894
|
-
'X-Forwarded-Proto': 'https',
|
|
895
|
-
'X-Real-IP': '{clientIp}'
|
|
701
|
+
security: {
|
|
702
|
+
authentication: {
|
|
703
|
+
type: 'basic',
|
|
704
|
+
realm: 'Protected Area',
|
|
705
|
+
users: {
|
|
706
|
+
'admin': 'hashedpassword'
|
|
896
707
|
}
|
|
897
708
|
}
|
|
898
709
|
}
|
|
899
710
|
}
|
|
900
|
-
```
|
|
901
|
-
|
|
902
|
-
**Data Flow**: Client → SmartProxy (HTTPS decrypt) → SmartProxy (New HTTPS) → Backend
|
|
903
711
|
|
|
904
|
-
|
|
712
|
+
// JWT Authentication
|
|
713
|
+
{
|
|
714
|
+
security: {
|
|
715
|
+
authentication: {
|
|
716
|
+
type: 'jwt',
|
|
717
|
+
secret: 'your-secret-key',
|
|
718
|
+
algorithms: ['HS256']
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
```
|
|
905
723
|
|
|
906
|
-
|
|
724
|
+
## Advanced Features
|
|
907
725
|
|
|
726
|
+
### Custom Route Matching
|
|
908
727
|
```typescript
|
|
909
728
|
{
|
|
910
|
-
match: {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
nftables: {
|
|
917
|
-
preserveSourceIP: true,
|
|
918
|
-
maxRate: '10gbps'
|
|
729
|
+
match: {
|
|
730
|
+
ports: 443,
|
|
731
|
+
customMatcher: async (context) => {
|
|
732
|
+
// Custom logic to determine if route should match
|
|
733
|
+
const hour = new Date().getHours();
|
|
734
|
+
return hour >= 9 && hour < 17; // Only match during business hours
|
|
919
735
|
}
|
|
920
736
|
}
|
|
921
737
|
}
|
|
922
738
|
```
|
|
923
739
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
#### Custom Socket Handler
|
|
927
|
-
|
|
928
|
-
Handle custom protocols or implement specialized logic:
|
|
929
|
-
|
|
740
|
+
### Header Manipulation
|
|
930
741
|
```typescript
|
|
931
742
|
{
|
|
932
|
-
match: { ports: 9000, domains: 'custom.example.com' },
|
|
933
743
|
action: {
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
});
|
|
744
|
+
headers: {
|
|
745
|
+
request: {
|
|
746
|
+
'X-Real-IP': '{clientIp}',
|
|
747
|
+
'X-Forwarded-For': '{clientIp}',
|
|
748
|
+
'X-Custom-Header': 'value'
|
|
749
|
+
},
|
|
750
|
+
response: {
|
|
751
|
+
'X-Powered-By': 'SmartProxy',
|
|
752
|
+
'Strict-Transport-Security': 'max-age=31536000'
|
|
753
|
+
}
|
|
945
754
|
}
|
|
946
755
|
}
|
|
947
756
|
}
|
|
948
757
|
```
|
|
949
758
|
|
|
950
|
-
###
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
- WebSocket connections to backend
|
|
968
|
-
|
|
969
|
-
#### Choose HTTPS Terminate-and-Reencrypt When:
|
|
970
|
-
- Need traffic inspection AND backend requires HTTPS
|
|
971
|
-
- API gateway scenarios
|
|
972
|
-
- Adding authentication layers
|
|
973
|
-
- Different certificates for client/backend
|
|
974
|
-
|
|
975
|
-
#### Choose NFTables Engine When:
|
|
976
|
-
- Handling 1Gbps+ traffic
|
|
977
|
-
- Thousands of concurrent connections
|
|
978
|
-
- Minimal latency is critical
|
|
979
|
-
- Don't need application-layer features
|
|
980
|
-
|
|
981
|
-
#### Choose Socket Handler When:
|
|
982
|
-
- Implementing custom protocols
|
|
983
|
-
- Need fine-grained connection control
|
|
984
|
-
- Building protocol adapters
|
|
985
|
-
- Special authentication flows
|
|
759
|
+
### Dynamic Target Selection
|
|
760
|
+
```typescript
|
|
761
|
+
{
|
|
762
|
+
action: {
|
|
763
|
+
type: 'forward',
|
|
764
|
+
targets: [
|
|
765
|
+
{
|
|
766
|
+
host: ['backend1.example.com', 'backend2.example.com'], // Round-robin
|
|
767
|
+
port: (context) => {
|
|
768
|
+
// Dynamic port based on path
|
|
769
|
+
return context.path.startsWith('/api/v1') ? 8081 : 8080;
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
]
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
```
|
|
986
776
|
|
|
987
|
-
|
|
777
|
+
## Complete Examples
|
|
988
778
|
|
|
989
|
-
|
|
779
|
+
### Multi-Domain HTTPS Server with Redirects
|
|
780
|
+
```typescript
|
|
781
|
+
const proxy = new SmartProxy({
|
|
782
|
+
acme: {
|
|
783
|
+
email: 'admin@example.com',
|
|
784
|
+
useProduction: true
|
|
785
|
+
},
|
|
786
|
+
routes: [
|
|
787
|
+
// HTTPS routes
|
|
788
|
+
...['example.com', 'app.example.com', 'api.example.com'].map(domain =>
|
|
789
|
+
createHttpsTerminateRoute(domain, { host: 'localhost', port: 3000 }, {
|
|
790
|
+
certificate: 'auto'
|
|
791
|
+
})
|
|
792
|
+
),
|
|
793
|
+
|
|
794
|
+
// HTTP to HTTPS redirects
|
|
795
|
+
createHttpToHttpsRedirect(['example.com', '*.example.com'])
|
|
796
|
+
]
|
|
797
|
+
});
|
|
798
|
+
```
|
|
990
799
|
|
|
800
|
+
### API Gateway with Multiple Services
|
|
991
801
|
```typescript
|
|
992
802
|
const proxy = new SmartProxy({
|
|
993
803
|
routes: [
|
|
994
|
-
//
|
|
995
|
-
{
|
|
996
|
-
match: { ports: 80, domains: ['example.com', 'www.example.com'] },
|
|
997
|
-
action: {
|
|
998
|
-
type: 'socket-handler',
|
|
999
|
-
socketHandler: SocketHandlers.httpRedirect('https://{domain}{path}')
|
|
1000
|
-
}
|
|
1001
|
-
},
|
|
804
|
+
// User service
|
|
805
|
+
createApiRoute('api.example.com', '/users', { host: 'user-service', port: 8081 }),
|
|
1002
806
|
|
|
1003
|
-
//
|
|
1004
|
-
{
|
|
1005
|
-
match: { ports: 443, domains: ['example.com', 'www.example.com'] },
|
|
1006
|
-
action: {
|
|
1007
|
-
type: 'forward',
|
|
1008
|
-
target: { host: 'web-backend', port: 3000 },
|
|
1009
|
-
tls: {
|
|
1010
|
-
mode: 'terminate',
|
|
1011
|
-
certificate: 'auto'
|
|
1012
|
-
},
|
|
1013
|
-
websocket: { enabled: true }
|
|
1014
|
-
}
|
|
1015
|
-
},
|
|
807
|
+
// Product service
|
|
808
|
+
createApiRoute('api.example.com', '/products', { host: 'product-service', port: 8082 }),
|
|
1016
809
|
|
|
1017
|
-
//
|
|
810
|
+
// Order service with authentication
|
|
1018
811
|
{
|
|
1019
|
-
match: {
|
|
812
|
+
match: {
|
|
813
|
+
ports: 443,
|
|
814
|
+
domains: 'api.example.com',
|
|
815
|
+
path: '/orders/*'
|
|
816
|
+
},
|
|
1020
817
|
action: {
|
|
1021
818
|
type: 'forward',
|
|
1022
|
-
|
|
819
|
+
targets: [{ host: 'order-service', port: 8083 }],
|
|
1023
820
|
tls: {
|
|
1024
|
-
mode: 'terminate
|
|
821
|
+
mode: 'terminate',
|
|
1025
822
|
certificate: 'auto'
|
|
1026
823
|
}
|
|
1027
824
|
},
|
|
1028
825
|
security: {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
maxRequests: 100,
|
|
1033
|
-
window: 60
|
|
826
|
+
authentication: {
|
|
827
|
+
type: 'jwt',
|
|
828
|
+
secret: process.env.JWT_SECRET
|
|
1034
829
|
}
|
|
1035
830
|
}
|
|
1036
831
|
}
|
|
@@ -1038,1835 +833,166 @@ const proxy = new SmartProxy({
|
|
|
1038
833
|
});
|
|
1039
834
|
```
|
|
1040
835
|
|
|
1041
|
-
|
|
1042
|
-
|
|
836
|
+
### WebSocket Server with Load Balancing
|
|
1043
837
|
```typescript
|
|
1044
838
|
const proxy = new SmartProxy({
|
|
1045
839
|
routes: [
|
|
1046
|
-
// Legacy app with passthrough
|
|
1047
|
-
{
|
|
1048
|
-
match: { ports: 443, domains: 'legacy.example.com' },
|
|
1049
|
-
action: {
|
|
1050
|
-
type: 'forward',
|
|
1051
|
-
target: { host: 'legacy-server', port: 443 },
|
|
1052
|
-
tls: { mode: 'passthrough' }
|
|
1053
|
-
}
|
|
1054
|
-
},
|
|
1055
|
-
|
|
1056
|
-
// High-performance streaming with NFTables
|
|
1057
840
|
{
|
|
1058
|
-
match: {
|
|
841
|
+
match: {
|
|
842
|
+
ports: 443,
|
|
843
|
+
domains: 'ws.example.com'
|
|
844
|
+
},
|
|
1059
845
|
action: {
|
|
1060
846
|
type: 'forward',
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
847
|
+
targets: [
|
|
848
|
+
{ host: 'ws-server-1', port: 8080 },
|
|
849
|
+
{ host: 'ws-server-2', port: 8080 },
|
|
850
|
+
{ host: 'ws-server-3', port: 8080 }
|
|
851
|
+
],
|
|
852
|
+
tls: {
|
|
853
|
+
mode: 'terminate',
|
|
854
|
+
certificate: 'auto'
|
|
855
|
+
},
|
|
856
|
+
websocket: {
|
|
857
|
+
enabled: true,
|
|
858
|
+
pingInterval: 30000
|
|
1066
859
|
}
|
|
1067
860
|
}
|
|
1068
|
-
},
|
|
1069
|
-
|
|
1070
|
-
// Custom protocol handler
|
|
1071
|
-
{
|
|
1072
|
-
match: { ports: 9999 },
|
|
1073
|
-
action: {
|
|
1074
|
-
type: 'socket-handler',
|
|
1075
|
-
socketHandler: SocketHandlers.proxy('custom-backend', 9999)
|
|
1076
|
-
}
|
|
1077
861
|
}
|
|
1078
862
|
]
|
|
1079
863
|
});
|
|
1080
864
|
```
|
|
1081
865
|
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
#### Node.js Engine Performance
|
|
1085
|
-
|
|
1086
|
-
| Metric | Typical Performance |
|
|
1087
|
-
|--------|-------------------|
|
|
1088
|
-
| Throughput | 1-10 Gbps |
|
|
1089
|
-
| Connections | 10,000-50,000 concurrent |
|
|
1090
|
-
| Latency | 1-5ms added |
|
|
1091
|
-
| CPU Usage | Moderate |
|
|
1092
|
-
|
|
1093
|
-
**Best for**: Most web applications, APIs, sites needing inspection
|
|
1094
|
-
|
|
1095
|
-
#### NFTables Engine Performance
|
|
1096
|
-
|
|
1097
|
-
| Metric | Typical Performance |
|
|
1098
|
-
|--------|-------------------|
|
|
1099
|
-
| Throughput | 10-100 Gbps |
|
|
1100
|
-
| Connections | 100,000+ concurrent |
|
|
1101
|
-
| Latency | <0.1ms added |
|
|
1102
|
-
| CPU Usage | Minimal |
|
|
1103
|
-
|
|
1104
|
-
**Best for**: High-traffic services, streaming, gaming, TCP forwarding
|
|
1105
|
-
|
|
1106
|
-
#### Performance Tips
|
|
1107
|
-
|
|
1108
|
-
1. **Use passthrough mode** when you don't need inspection
|
|
1109
|
-
2. **Enable NFTables** for high-traffic services
|
|
1110
|
-
3. **Terminate TLS only when necessary** - it adds CPU overhead
|
|
1111
|
-
4. **Use connection pooling** for terminate-and-reencrypt mode
|
|
1112
|
-
5. **Enable HTTP/2** for better multiplexing
|
|
1113
|
-
|
|
1114
|
-
### Security Implications
|
|
1115
|
-
|
|
1116
|
-
#### TLS Termination Security
|
|
1117
|
-
|
|
1118
|
-
**Pros:**
|
|
1119
|
-
- Inspect traffic for threats
|
|
1120
|
-
- Add security headers
|
|
1121
|
-
- Implement WAF rules
|
|
1122
|
-
- Log requests for audit
|
|
1123
|
-
|
|
1124
|
-
**Cons:**
|
|
1125
|
-
- Proxy has access to decrypted data
|
|
1126
|
-
- Requires secure certificate storage
|
|
1127
|
-
- Potential compliance issues
|
|
1128
|
-
|
|
1129
|
-
**Best Practices:**
|
|
1130
|
-
- Use auto-renewal with Let's Encrypt
|
|
1131
|
-
- Store certificates securely
|
|
1132
|
-
- Implement proper access controls
|
|
1133
|
-
- Use strong TLS configurations
|
|
1134
|
-
|
|
1135
|
-
#### Passthrough Security
|
|
1136
|
-
|
|
1137
|
-
**Pros:**
|
|
1138
|
-
- True end-to-end encryption
|
|
1139
|
-
- No MITM concerns
|
|
1140
|
-
- Backend controls security
|
|
1141
|
-
|
|
1142
|
-
**Cons:**
|
|
1143
|
-
- Cannot inspect traffic
|
|
1144
|
-
- Cannot add security headers
|
|
1145
|
-
- Limited DDoS protection
|
|
1146
|
-
|
|
1147
|
-
#### Socket Handler Security
|
|
866
|
+
## Troubleshooting
|
|
1148
867
|
|
|
1149
|
-
|
|
1150
|
-
- Custom code may have vulnerabilities
|
|
1151
|
-
- Resource exhaustion possible
|
|
1152
|
-
- Authentication bypass risks
|
|
868
|
+
### Common Issues
|
|
1153
869
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
socketHandler: async (socket, context) => {
|
|
1160
|
-
// Always validate and sanitize input
|
|
1161
|
-
socket.on('data', (data) => {
|
|
1162
|
-
if (data.length > MAX_SIZE) {
|
|
1163
|
-
socket.destroy();
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
// Process safely...
|
|
1167
|
-
});
|
|
1168
|
-
|
|
1169
|
-
// Set timeouts
|
|
1170
|
-
socket.setTimeout(30000);
|
|
1171
|
-
|
|
1172
|
-
// Rate limit connections
|
|
1173
|
-
if (connectionsFromIP(context.clientIp) > 10) {
|
|
1174
|
-
socket.destroy();
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
```
|
|
870
|
+
#### Certificate Provisioning
|
|
871
|
+
- Ensure domains are publicly accessible
|
|
872
|
+
- Check firewall rules for port 80 (ACME challenges)
|
|
873
|
+
- Verify DNS resolution
|
|
874
|
+
- Check ACME email configuration
|
|
1180
875
|
|
|
1181
|
-
|
|
876
|
+
#### Connection Issues
|
|
877
|
+
- Verify route matching criteria
|
|
878
|
+
- Check security rules (IP lists, authentication)
|
|
879
|
+
- Ensure target servers are accessible
|
|
880
|
+
- Check for port conflicts
|
|
1182
881
|
|
|
1183
|
-
####
|
|
882
|
+
#### Performance Issues
|
|
883
|
+
- Consider using NFTables for high-traffic routes
|
|
884
|
+
- Adjust connection pool sizes
|
|
885
|
+
- Enable connection keep-alive
|
|
886
|
+
- Monitor resource usage
|
|
1184
887
|
|
|
1185
|
-
|
|
888
|
+
### Debug Mode
|
|
889
|
+
Enable detailed logging:
|
|
1186
890
|
```typescript
|
|
1187
|
-
{
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
}
|
|
891
|
+
const proxy = new SmartProxy({
|
|
892
|
+
debug: true,
|
|
893
|
+
routes: [...]
|
|
894
|
+
});
|
|
1191
895
|
```
|
|
1192
896
|
|
|
1193
|
-
|
|
897
|
+
### Route Testing
|
|
898
|
+
Test route matching:
|
|
1194
899
|
```typescript
|
|
1195
|
-
{
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
```
|
|
1203
|
-
|
|
1204
|
-
#### From `https-passthrough`
|
|
900
|
+
const matchedRoute = proxy.findMatchingRoute({
|
|
901
|
+
port: 443,
|
|
902
|
+
domain: 'example.com',
|
|
903
|
+
path: '/api/users',
|
|
904
|
+
clientIp: '192.168.1.100'
|
|
905
|
+
});
|
|
1205
906
|
|
|
1206
|
-
|
|
1207
|
-
```typescript
|
|
1208
|
-
{
|
|
1209
|
-
type: 'https-passthrough',
|
|
1210
|
-
target: { host: 'backend', port: 443 }
|
|
1211
|
-
}
|
|
907
|
+
console.log('Matched route:', matchedRoute?.name);
|
|
1212
908
|
```
|
|
1213
909
|
|
|
1214
|
-
|
|
1215
|
-
```typescript
|
|
1216
|
-
{
|
|
1217
|
-
match: { ports: 443, domains: 'example.com' },
|
|
1218
|
-
action: {
|
|
1219
|
-
type: 'forward',
|
|
1220
|
-
target: { host: 'backend', port: 443 },
|
|
1221
|
-
tls: { mode: 'passthrough' }
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
```
|
|
910
|
+
## Migration Guide
|
|
1225
911
|
|
|
1226
|
-
|
|
912
|
+
### From v19.x to v20.x
|
|
1227
913
|
|
|
1228
|
-
|
|
1229
|
-
```typescript
|
|
1230
|
-
{
|
|
1231
|
-
type: 'https-terminate-to-http',
|
|
1232
|
-
target: { host: 'localhost', port: 8080 },
|
|
1233
|
-
ssl: { /* certs */ }
|
|
1234
|
-
}
|
|
1235
|
-
```
|
|
914
|
+
The main breaking change is the route action configuration:
|
|
1236
915
|
|
|
1237
|
-
**
|
|
916
|
+
**Before (v19.x):**
|
|
1238
917
|
```typescript
|
|
1239
918
|
{
|
|
1240
|
-
match: { ports: 443, domains: 'example.com' },
|
|
1241
919
|
action: {
|
|
1242
920
|
type: 'forward',
|
|
1243
|
-
target: { host: 'localhost', port: 8080 }
|
|
1244
|
-
tls: {
|
|
1245
|
-
mode: 'terminate',
|
|
1246
|
-
certificate: 'auto' // or provide cert/key
|
|
1247
|
-
}
|
|
921
|
+
target: { host: 'localhost', port: 8080 } // Single target
|
|
1248
922
|
}
|
|
1249
923
|
}
|
|
1250
924
|
```
|
|
1251
925
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
**Old:**
|
|
1255
|
-
```typescript
|
|
1256
|
-
{
|
|
1257
|
-
type: 'https-terminate-to-https',
|
|
1258
|
-
target: { host: 'backend', port: 443 },
|
|
1259
|
-
ssl: { /* certs */ }
|
|
1260
|
-
}
|
|
1261
|
-
```
|
|
1262
|
-
|
|
1263
|
-
**New:**
|
|
926
|
+
**After (v20.x):**
|
|
1264
927
|
```typescript
|
|
1265
928
|
{
|
|
1266
|
-
match: { ports: 443, domains: 'example.com' },
|
|
1267
929
|
action: {
|
|
1268
930
|
type: 'forward',
|
|
1269
|
-
|
|
1270
|
-
tls: {
|
|
1271
|
-
mode: 'terminate-and-reencrypt',
|
|
1272
|
-
certificate: 'auto'
|
|
1273
|
-
}
|
|
931
|
+
targets: [{ host: 'localhost', port: 8080 }] // Array of targets
|
|
1274
932
|
}
|
|
1275
933
|
}
|
|
1276
934
|
```
|
|
1277
935
|
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
SmartProxy provides helper functions for common configurations:
|
|
1281
|
-
|
|
1282
|
-
```typescript
|
|
1283
|
-
// HTTP forwarding
|
|
1284
|
-
createHttpRoute('example.com', { host: 'localhost', port: 8080 })
|
|
1285
|
-
|
|
1286
|
-
// HTTPS with termination
|
|
1287
|
-
createHttpsTerminateRoute('secure.com', { host: 'localhost', port: 8080 }, {
|
|
1288
|
-
certificate: 'auto'
|
|
1289
|
-
})
|
|
1290
|
-
|
|
1291
|
-
// HTTPS passthrough
|
|
1292
|
-
createHttpsPassthroughRoute('legacy.com', { host: 'backend', port: 443 })
|
|
1293
|
-
|
|
1294
|
-
// Complete HTTPS setup (includes HTTP redirect)
|
|
1295
|
-
...createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, {
|
|
1296
|
-
certificate: 'auto'
|
|
1297
|
-
})
|
|
1298
|
-
|
|
1299
|
-
// NFTables high-performance
|
|
1300
|
-
createNfTablesRoute('fast.com', { host: 'backend', port: 8080 }, {
|
|
1301
|
-
ports: 80,
|
|
1302
|
-
preserveSourceIP: true
|
|
1303
|
-
})
|
|
1304
|
-
|
|
1305
|
-
// Custom socket handler
|
|
1306
|
-
createSocketHandlerRoute('custom.com', 9000, async (socket, context) => {
|
|
1307
|
-
// Handler implementation
|
|
1308
|
-
})
|
|
1309
|
-
```
|
|
1310
|
-
|
|
1311
|
-
### Summary
|
|
1312
|
-
|
|
1313
|
-
SmartProxy's forwarding modes provide flexibility for any proxy scenario:
|
|
1314
|
-
|
|
1315
|
-
- **Simple HTTP/HTTPS forwarding** for most web applications
|
|
1316
|
-
- **TLS passthrough** for end-to-end encryption
|
|
1317
|
-
- **TLS termination** for traffic inspection and modification
|
|
1318
|
-
- **NFTables** for extreme performance requirements
|
|
1319
|
-
- **Socket handlers** for custom protocols
|
|
1320
|
-
|
|
1321
|
-
Choose based on your security requirements, performance needs, and whether you need to inspect or modify traffic. The modern route-based configuration provides a consistent interface regardless of the forwarding mode you choose.
|
|
1322
|
-
|
|
1323
|
-
### Route Metadata and Prioritization
|
|
1324
|
-
|
|
1325
|
-
You can add metadata to routes to help with organization and control matching priority:
|
|
1326
|
-
|
|
1327
|
-
```typescript
|
|
1328
|
-
{
|
|
1329
|
-
name: 'API Server', // Human-readable name
|
|
1330
|
-
description: 'Main API endpoints', // Description
|
|
1331
|
-
priority: 100, // Matching priority (higher = matched first)
|
|
1332
|
-
tags: ['api', 'internal'] // Arbitrary tags
|
|
1333
|
-
}
|
|
1334
|
-
```
|
|
1335
|
-
|
|
1336
|
-
Routes with higher priority values are matched first, allowing you to create specialized routes that take precedence over more general ones.
|
|
1337
|
-
|
|
1338
|
-
### Complete Route Configuration Example
|
|
1339
|
-
|
|
1340
|
-
```typescript
|
|
1341
|
-
// Example of a complete route configuration
|
|
1342
|
-
{
|
|
1343
|
-
match: {
|
|
1344
|
-
ports: 443,
|
|
1345
|
-
domains: ['api.example.com', 'api-v2.example.com'],
|
|
1346
|
-
path: '/secure/*',
|
|
1347
|
-
clientIp: ['10.0.0.*', '192.168.1.*']
|
|
1348
|
-
},
|
|
1349
|
-
action: {
|
|
1350
|
-
type: 'forward',
|
|
1351
|
-
target: {
|
|
1352
|
-
host: ['10.0.0.1', '10.0.0.2'], // Round-robin between these hosts
|
|
1353
|
-
port: 8080
|
|
1354
|
-
},
|
|
1355
|
-
tls: {
|
|
1356
|
-
mode: 'terminate',
|
|
1357
|
-
certificate: 'auto' // Use Let's Encrypt
|
|
1358
|
-
},
|
|
1359
|
-
advanced: {
|
|
1360
|
-
timeout: 30000,
|
|
1361
|
-
headers: {
|
|
1362
|
-
'X-Original-Host': '{domain}',
|
|
1363
|
-
'X-Client-IP': '{clientIp}'
|
|
1364
|
-
},
|
|
1365
|
-
keepAlive: true
|
|
1366
|
-
}
|
|
1367
|
-
},
|
|
1368
|
-
security: {
|
|
1369
|
-
ipAllowList: ['10.0.0.*'],
|
|
1370
|
-
maxConnections: 100
|
|
1371
|
-
},
|
|
1372
|
-
name: 'Secure API Route',
|
|
1373
|
-
description: 'Route for secure API endpoints with authentication',
|
|
1374
|
-
priority: 100,
|
|
1375
|
-
tags: ['api', 'secure', 'internal']
|
|
1376
|
-
}
|
|
1377
|
-
|
|
1378
|
-
// Example with NFTables forwarding engine
|
|
1379
|
-
{
|
|
1380
|
-
match: {
|
|
1381
|
-
ports: [80, 443],
|
|
1382
|
-
domains: 'high-traffic.example.com'
|
|
1383
|
-
},
|
|
1384
|
-
action: {
|
|
1385
|
-
type: 'forward',
|
|
1386
|
-
target: {
|
|
1387
|
-
host: 'backend-server',
|
|
1388
|
-
port: 8080
|
|
1389
|
-
},
|
|
1390
|
-
forwardingEngine: 'nftables', // Use kernel-level forwarding
|
|
1391
|
-
nftables: {
|
|
1392
|
-
protocol: 'tcp',
|
|
1393
|
-
preserveSourceIP: true,
|
|
1394
|
-
maxRate: '1gbps',
|
|
1395
|
-
useIPSets: true
|
|
1396
|
-
}
|
|
1397
|
-
},
|
|
1398
|
-
security: {
|
|
1399
|
-
ipAllowList: ['10.0.0.*'],
|
|
1400
|
-
ipBlockList: ['malicious.ip.range.*']
|
|
1401
|
-
},
|
|
1402
|
-
name: 'High Performance NFTables Route',
|
|
1403
|
-
description: 'Kernel-level forwarding for maximum performance',
|
|
1404
|
-
priority: 150
|
|
1405
|
-
}
|
|
1406
|
-
```
|
|
1407
|
-
|
|
1408
|
-
## Using Helper Functions
|
|
1409
|
-
|
|
1410
|
-
While you can create route configurations manually, SmartProxy provides helper functions to make it easier:
|
|
1411
|
-
|
|
1412
|
-
```typescript
|
|
1413
|
-
// Instead of building the full object:
|
|
1414
|
-
const route = {
|
|
1415
|
-
match: { ports: 80, domains: 'example.com' },
|
|
1416
|
-
action: { type: 'forward', target: { host: 'localhost', port: 8080 } },
|
|
1417
|
-
name: 'Web Server'
|
|
1418
|
-
};
|
|
1419
|
-
|
|
1420
|
-
// Use the helper function for cleaner syntax:
|
|
1421
|
-
const route = createHttpRoute('example.com', { host: 'localhost', port: 8080 }, {
|
|
1422
|
-
name: 'Web Server'
|
|
1423
|
-
});
|
|
1424
|
-
```
|
|
1425
|
-
|
|
1426
|
-
Available helper functions:
|
|
1427
|
-
- `createHttpRoute()` - Create an HTTP forwarding route
|
|
1428
|
-
- `createHttpsTerminateRoute()` - Create an HTTPS route with TLS termination
|
|
1429
|
-
- `createHttpsPassthroughRoute()` - Create an HTTPS passthrough route
|
|
1430
|
-
- `createHttpToHttpsRedirect()` - Create an HTTP to HTTPS redirect using socket handler
|
|
1431
|
-
- `createCompleteHttpsServer()` - Create a complete HTTPS server setup with HTTP redirect
|
|
1432
|
-
- `createLoadBalancerRoute()` - Create a route for load balancing across multiple backends
|
|
1433
|
-
- `createApiRoute()` - Create an API route with path matching and CORS support
|
|
1434
|
-
- `createWebSocketRoute()` - Create a route for WebSocket connections
|
|
1435
|
-
- `createSocketHandlerRoute()` - Create a route with custom socket handling
|
|
1436
|
-
- `createNfTablesRoute()` - Create a high-performance NFTables route
|
|
1437
|
-
- `createNfTablesTerminateRoute()` - Create an NFTables route with TLS termination
|
|
1438
|
-
- `createCompleteNfTablesHttpsServer()` - Create a complete NFTables HTTPS setup with HTTP redirect
|
|
1439
|
-
- `createPortMappingRoute()` - Create a route with dynamic port mapping
|
|
1440
|
-
- `createOffsetPortMappingRoute()` - Create a route with port offset mapping
|
|
1441
|
-
- `createDynamicRoute()` - Create a route with dynamic host/port selection
|
|
1442
|
-
- `createSmartLoadBalancer()` - Create a smart load balancer with domain-based routing
|
|
1443
|
-
- `createApiGatewayRoute()` - Create an API gateway route with advanced features
|
|
1444
|
-
- `addRateLimiting()` - Add rate limiting to a route
|
|
1445
|
-
- `addBasicAuth()` - Add basic authentication to a route
|
|
1446
|
-
- `addJwtAuth()` - Add JWT authentication to a route
|
|
1447
|
-
|
|
1448
|
-
## What You Can Do with SmartProxy
|
|
1449
|
-
|
|
1450
|
-
1. **Route-Based Traffic Management**
|
|
1451
|
-
```typescript
|
|
1452
|
-
// Route requests for different domains to different backend servers
|
|
1453
|
-
createHttpsTerminateRoute('api.example.com', { host: 'api-server', port: 3000 }, {
|
|
1454
|
-
certificate: 'auto'
|
|
1455
|
-
})
|
|
1456
|
-
```
|
|
1457
|
-
|
|
1458
|
-
2. **Automatic SSL with Let's Encrypt**
|
|
1459
|
-
```typescript
|
|
1460
|
-
// Get and automatically renew certificates
|
|
1461
|
-
createHttpsTerminateRoute('secure.example.com', { host: 'localhost', port: 8080 }, {
|
|
1462
|
-
certificate: 'auto'
|
|
1463
|
-
})
|
|
1464
|
-
```
|
|
1465
|
-
|
|
1466
|
-
3. **Load Balancing**
|
|
1467
|
-
```typescript
|
|
1468
|
-
// Distribute traffic across multiple backend servers
|
|
1469
|
-
createLoadBalancerRoute(
|
|
1470
|
-
'app.example.com',
|
|
1471
|
-
['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
|
1472
|
-
8080,
|
|
1473
|
-
{
|
|
1474
|
-
tls: {
|
|
1475
|
-
mode: 'terminate',
|
|
1476
|
-
certificate: 'auto'
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
)
|
|
1480
|
-
```
|
|
1481
|
-
|
|
1482
|
-
4. **Security Controls**
|
|
1483
|
-
```typescript
|
|
1484
|
-
// Restrict access based on IP addresses
|
|
1485
|
-
{
|
|
1486
|
-
match: { ports: 443, domains: 'admin.example.com' },
|
|
1487
|
-
action: {
|
|
1488
|
-
type: 'forward',
|
|
1489
|
-
target: { host: 'localhost', port: 8080 },
|
|
1490
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
1491
|
-
},
|
|
1492
|
-
security: {
|
|
1493
|
-
ipAllowList: ['10.0.0.*', '192.168.1.*'],
|
|
1494
|
-
maxConnections: 100
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
```
|
|
1498
|
-
|
|
1499
|
-
5. **Wildcard Domains**
|
|
1500
|
-
```typescript
|
|
1501
|
-
// Handle all subdomains with one config
|
|
1502
|
-
createHttpsPassthroughRoute(['example.com', '*.example.com'], { host: 'backend-server', port: 443 })
|
|
1503
|
-
```
|
|
1504
|
-
|
|
1505
|
-
6. **Path-Based Routing**
|
|
1506
|
-
```typescript
|
|
1507
|
-
// Route based on URL path
|
|
1508
|
-
createApiRoute('example.com', '/api', { host: 'api-server', port: 3000 }, {
|
|
1509
|
-
useTls: true,
|
|
1510
|
-
certificate: 'auto'
|
|
1511
|
-
})
|
|
1512
|
-
```
|
|
1513
|
-
|
|
1514
|
-
7. **Block Malicious Traffic**
|
|
1515
|
-
```typescript
|
|
1516
|
-
// Block traffic from specific IPs or patterns
|
|
1517
|
-
{
|
|
1518
|
-
match: { ports: [80, 443], clientIp: ['1.2.3.*', '5.6.7.*'] },
|
|
1519
|
-
action: {
|
|
1520
|
-
type: 'socket-handler',
|
|
1521
|
-
socketHandler: SocketHandlers.httpBlock(403, 'Access denied')
|
|
1522
|
-
},
|
|
1523
|
-
priority: 1000 // High priority to ensure blocking
|
|
1524
|
-
}
|
|
1525
|
-
```
|
|
1526
|
-
|
|
1527
|
-
8. **Dynamic Port Management**
|
|
1528
|
-
```typescript
|
|
1529
|
-
// Start the proxy with initial configuration
|
|
1530
|
-
const proxy = new SmartProxy({
|
|
1531
|
-
routes: [
|
|
1532
|
-
createHttpRoute('example.com', { host: 'localhost', port: 8080 })
|
|
1533
|
-
]
|
|
1534
|
-
});
|
|
1535
|
-
await proxy.start();
|
|
1536
|
-
|
|
1537
|
-
// Dynamically add a new port listener
|
|
1538
|
-
await proxy.addListeningPort(8081);
|
|
1539
|
-
|
|
1540
|
-
// Add a route for the new port
|
|
1541
|
-
const currentRoutes = proxy.settings.routes;
|
|
1542
|
-
const newRoute = createHttpRoute('api.example.com', { host: 'api-server', port: 3000 });
|
|
1543
|
-
newRoute.match.ports = 8081; // Override the default port
|
|
1544
|
-
|
|
1545
|
-
// Update routes - will automatically sync port listeners
|
|
1546
|
-
await proxy.updateRoutes([...currentRoutes, newRoute]);
|
|
1547
|
-
|
|
1548
|
-
// Later, remove a port listener when needed
|
|
1549
|
-
await proxy.removeListeningPort(8081);
|
|
1550
|
-
```
|
|
1551
|
-
|
|
1552
|
-
9. **High-Performance NFTables Routing**
|
|
1553
|
-
```typescript
|
|
1554
|
-
// Use kernel-level packet forwarding for maximum performance
|
|
1555
|
-
createNfTablesRoute('high-traffic.example.com', { host: 'backend', port: 8080 }, {
|
|
1556
|
-
ports: 80,
|
|
1557
|
-
preserveSourceIP: true,
|
|
1558
|
-
maxRate: '1gbps'
|
|
1559
|
-
})
|
|
1560
|
-
```
|
|
1561
|
-
|
|
1562
|
-
10. **Custom Protocol Handling**
|
|
1563
|
-
```typescript
|
|
1564
|
-
// Implement custom protocols or specialized handling
|
|
1565
|
-
createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => {
|
|
1566
|
-
// Your custom protocol logic here
|
|
1567
|
-
socket.write('CUSTOM PROTOCOL v1.0\n');
|
|
1568
|
-
|
|
1569
|
-
socket.on('data', (data) => {
|
|
1570
|
-
// Handle custom protocol messages
|
|
1571
|
-
const response = processCustomProtocol(data);
|
|
1572
|
-
socket.write(response);
|
|
1573
|
-
});
|
|
1574
|
-
})
|
|
1575
|
-
```
|
|
1576
|
-
|
|
1577
|
-
## Metrics and Monitoring
|
|
1578
|
-
|
|
1579
|
-
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data. The metrics system uses a clean, grouped API design for intuitive access to different metric categories.
|
|
1580
|
-
|
|
1581
|
-
### Enabling Metrics
|
|
1582
|
-
|
|
1583
|
-
```typescript
|
|
1584
|
-
const proxy = new SmartProxy({
|
|
1585
|
-
// Enable metrics collection
|
|
1586
|
-
metrics: {
|
|
1587
|
-
enabled: true,
|
|
1588
|
-
sampleIntervalMs: 1000, // Sample throughput every second
|
|
1589
|
-
retentionSeconds: 3600 // Keep 1 hour of history
|
|
1590
|
-
},
|
|
1591
|
-
routes: [/* your routes */]
|
|
1592
|
-
});
|
|
1593
|
-
|
|
1594
|
-
await proxy.start();
|
|
1595
|
-
```
|
|
1596
|
-
|
|
1597
|
-
### Getting Metrics
|
|
936
|
+
Helper functions have been updated to use the new format automatically.
|
|
1598
937
|
|
|
1599
|
-
|
|
1600
|
-
// Access metrics through the getMetrics() method
|
|
1601
|
-
const metrics = proxy.getMetrics();
|
|
938
|
+
## Best Practices
|
|
1602
939
|
|
|
1603
|
-
|
|
1604
|
-
|
|
940
|
+
1. **Use Helper Functions**: They provide sensible defaults and reduce configuration errors
|
|
941
|
+
2. **Set Route Priorities**: Higher priority routes are matched first
|
|
942
|
+
3. **Use Specific Matches**: More specific routes should have higher priorities
|
|
943
|
+
4. **Enable Security Features**: Always use IP filtering and rate limiting for public services
|
|
944
|
+
5. **Monitor Performance**: Use debug logging and metrics to identify bottlenecks
|
|
945
|
+
6. **Regular Certificate Checks**: Monitor certificate expiration and renewal
|
|
946
|
+
7. **Graceful Shutdown**: Always call `proxy.stop()` for clean shutdown
|
|
1605
947
|
|
|
1606
|
-
|
|
948
|
+
## API Reference
|
|
1607
949
|
|
|
1608
|
-
|
|
950
|
+
### SmartProxy Class
|
|
1609
951
|
|
|
1610
952
|
```typescript
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
//
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
953
|
+
class SmartProxy {
|
|
954
|
+
constructor(options: IRoutedSmartProxyOptions);
|
|
955
|
+
|
|
956
|
+
// Lifecycle methods
|
|
957
|
+
start(): Promise<void>;
|
|
958
|
+
stop(): Promise<void>;
|
|
959
|
+
|
|
960
|
+
// Route management
|
|
961
|
+
updateRoutes(routes: IRouteConfig[]): Promise<void>;
|
|
962
|
+
addRoute(route: IRouteConfig): Promise<void>;
|
|
963
|
+
removeRoute(routeName: string): Promise<void>;
|
|
964
|
+
findMatchingRoute(context: Partial<IRouteContext>): IRouteConfig | null;
|
|
965
|
+
|
|
966
|
+
// Port management
|
|
967
|
+
addListeningPort(port: number): Promise<void>;
|
|
968
|
+
removeListeningPort(port: number): Promise<void>;
|
|
969
|
+
getListeningPorts(): number[];
|
|
970
|
+
|
|
971
|
+
// Certificate management
|
|
972
|
+
getCertificateInfo(domain: string): ICertificateInfo | null;
|
|
973
|
+
renewCertificate(domain: string): Promise<void>;
|
|
974
|
+
|
|
975
|
+
// Status and monitoring
|
|
976
|
+
getStatus(): IProxyStatus;
|
|
977
|
+
getMetrics(): IProxyMetrics;
|
|
1627
978
|
}
|
|
1628
|
-
|
|
1629
|
-
// Get top IPs by connection count
|
|
1630
|
-
const topIPs = metrics.connections.topIPs(10);
|
|
1631
|
-
topIPs.forEach(({ ip, count }) => {
|
|
1632
|
-
console.log(`${ip}: ${count} connections`);
|
|
1633
|
-
});
|
|
1634
|
-
```
|
|
1635
|
-
|
|
1636
|
-
### Throughput Metrics
|
|
1637
|
-
|
|
1638
|
-
Real-time and historical throughput data with customizable time windows:
|
|
1639
|
-
|
|
1640
|
-
```typescript
|
|
1641
|
-
// Get instant throughput (last 1 second)
|
|
1642
|
-
const instant = metrics.throughput.instant();
|
|
1643
|
-
console.log(`Current: ${instant.in} bytes/sec in, ${instant.out} bytes/sec out`);
|
|
1644
|
-
|
|
1645
|
-
// Get recent throughput (last 10 seconds average)
|
|
1646
|
-
const recent = metrics.throughput.recent();
|
|
1647
|
-
console.log(`Recent: ${recent.in} bytes/sec in, ${recent.out} bytes/sec out`);
|
|
1648
|
-
|
|
1649
|
-
// Get average throughput (last 60 seconds)
|
|
1650
|
-
const average = metrics.throughput.average();
|
|
1651
|
-
console.log(`Average: ${average.in} bytes/sec in, ${average.out} bytes/sec out`);
|
|
1652
|
-
|
|
1653
|
-
// Get custom time window (e.g., last 5 minutes)
|
|
1654
|
-
const custom = metrics.throughput.custom(300);
|
|
1655
|
-
console.log(`5-min avg: ${custom.in} bytes/sec in, ${custom.out} bytes/sec out`);
|
|
1656
|
-
|
|
1657
|
-
// Get throughput history for graphing
|
|
1658
|
-
const history = metrics.throughput.history(300); // Last 5 minutes
|
|
1659
|
-
history.forEach(point => {
|
|
1660
|
-
console.log(`${new Date(point.timestamp)}: ${point.in} in, ${point.out} out`);
|
|
1661
|
-
});
|
|
1662
|
-
|
|
1663
|
-
// Get throughput by route
|
|
1664
|
-
const routeThroughput = metrics.throughput.byRoute(60); // Last 60 seconds
|
|
1665
|
-
routeThroughput.forEach((stats, route) => {
|
|
1666
|
-
console.log(`Route ${route}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1667
|
-
});
|
|
1668
|
-
|
|
1669
|
-
// Get throughput by IP
|
|
1670
|
-
const ipThroughput = metrics.throughput.byIP(60);
|
|
1671
|
-
ipThroughput.forEach((stats, ip) => {
|
|
1672
|
-
console.log(`IP ${ip}: ${stats.in} in, ${stats.out} out bytes/sec`);
|
|
1673
|
-
});
|
|
1674
979
|
```
|
|
1675
980
|
|
|
1676
|
-
###
|
|
1677
|
-
|
|
1678
|
-
Track request rates:
|
|
1679
|
-
|
|
1680
|
-
```typescript
|
|
1681
|
-
// Get requests per second
|
|
1682
|
-
console.log(`RPS: ${metrics.requests.perSecond()}`);
|
|
1683
|
-
|
|
1684
|
-
// Get requests per minute
|
|
1685
|
-
console.log(`RPM: ${metrics.requests.perMinute()}`);
|
|
981
|
+
### Route Configuration Types
|
|
1686
982
|
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
983
|
+
See the TypeScript definitions in:
|
|
984
|
+
- `ts/proxies/smart-proxy/models/route-types.ts`
|
|
985
|
+
- `ts/proxies/smart-proxy/models/interfaces.ts`
|
|
1690
986
|
|
|
1691
|
-
|
|
987
|
+
## Contributing
|
|
1692
988
|
|
|
1693
|
-
|
|
989
|
+
Contributions are welcome! Please follow these guidelines:
|
|
1694
990
|
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
```
|
|
1701
|
-
|
|
1702
|
-
### Performance Percentiles
|
|
1703
|
-
|
|
1704
|
-
Get percentile statistics (when implemented):
|
|
1705
|
-
|
|
1706
|
-
```typescript
|
|
1707
|
-
// Connection duration percentiles
|
|
1708
|
-
const durations = metrics.percentiles.connectionDuration();
|
|
1709
|
-
console.log(`Connection durations - P50: ${durations.p50}ms, P95: ${durations.p95}ms, P99: ${durations.p99}ms`);
|
|
1710
|
-
|
|
1711
|
-
// Bytes transferred percentiles
|
|
1712
|
-
const bytes = metrics.percentiles.bytesTransferred();
|
|
1713
|
-
console.log(`Bytes in - P50: ${bytes.in.p50}, P95: ${bytes.in.p95}, P99: ${bytes.in.p99}`);
|
|
1714
|
-
console.log(`Bytes out - P50: ${bytes.out.p50}, P95: ${bytes.out.p95}, P99: ${bytes.out.p99}`);
|
|
1715
|
-
```
|
|
1716
|
-
|
|
1717
|
-
### Complete Monitoring Example
|
|
1718
|
-
|
|
1719
|
-
```typescript
|
|
1720
|
-
// Create a monitoring dashboard
|
|
1721
|
-
setInterval(() => {
|
|
1722
|
-
const metrics = proxy.getMetrics();
|
|
1723
|
-
|
|
1724
|
-
// Log key metrics
|
|
1725
|
-
console.log({
|
|
1726
|
-
timestamp: new Date().toISOString(),
|
|
1727
|
-
connections: {
|
|
1728
|
-
active: metrics.connections.active(),
|
|
1729
|
-
total: metrics.connections.total()
|
|
1730
|
-
},
|
|
1731
|
-
throughput: {
|
|
1732
|
-
instant: metrics.throughput.instant(),
|
|
1733
|
-
average: metrics.throughput.average()
|
|
1734
|
-
},
|
|
1735
|
-
requests: {
|
|
1736
|
-
rps: metrics.requests.perSecond(),
|
|
1737
|
-
total: metrics.requests.total()
|
|
1738
|
-
},
|
|
1739
|
-
totals: {
|
|
1740
|
-
bytesIn: metrics.totals.bytesIn(),
|
|
1741
|
-
bytesOut: metrics.totals.bytesOut()
|
|
1742
|
-
}
|
|
1743
|
-
});
|
|
1744
|
-
|
|
1745
|
-
// Alert on high connection counts
|
|
1746
|
-
const topIPs = metrics.connections.topIPs(5);
|
|
1747
|
-
topIPs.forEach(({ ip, count }) => {
|
|
1748
|
-
if (count > 100) {
|
|
1749
|
-
console.warn(`High connection count from ${ip}: ${count}`);
|
|
1750
|
-
}
|
|
1751
|
-
});
|
|
1752
|
-
|
|
1753
|
-
// Alert on high throughput
|
|
1754
|
-
const instant = metrics.throughput.instant();
|
|
1755
|
-
if (instant.in > 100_000_000) { // 100 MB/s
|
|
1756
|
-
console.warn(`High incoming throughput: ${instant.in} bytes/sec`);
|
|
1757
|
-
}
|
|
1758
|
-
}, 10000); // Every 10 seconds
|
|
1759
|
-
```
|
|
1760
|
-
|
|
1761
|
-
### Exporting Metrics
|
|
1762
|
-
|
|
1763
|
-
Export metrics in various formats for external monitoring systems:
|
|
1764
|
-
|
|
1765
|
-
```typescript
|
|
1766
|
-
// Export as JSON
|
|
1767
|
-
app.get('/metrics.json', (req, res) => {
|
|
1768
|
-
const metrics = proxy.getMetrics();
|
|
1769
|
-
res.json({
|
|
1770
|
-
connections: {
|
|
1771
|
-
active: metrics.connections.active(),
|
|
1772
|
-
total: metrics.connections.total(),
|
|
1773
|
-
byRoute: Object.fromEntries(metrics.connections.byRoute()),
|
|
1774
|
-
byIP: Object.fromEntries(metrics.connections.byIP())
|
|
1775
|
-
},
|
|
1776
|
-
throughput: {
|
|
1777
|
-
instant: metrics.throughput.instant(),
|
|
1778
|
-
recent: metrics.throughput.recent(),
|
|
1779
|
-
average: metrics.throughput.average()
|
|
1780
|
-
},
|
|
1781
|
-
requests: {
|
|
1782
|
-
perSecond: metrics.requests.perSecond(),
|
|
1783
|
-
perMinute: metrics.requests.perMinute(),
|
|
1784
|
-
total: metrics.requests.total()
|
|
1785
|
-
},
|
|
1786
|
-
totals: {
|
|
1787
|
-
bytesIn: metrics.totals.bytesIn(),
|
|
1788
|
-
bytesOut: metrics.totals.bytesOut(),
|
|
1789
|
-
connections: metrics.totals.connections()
|
|
1790
|
-
}
|
|
1791
|
-
});
|
|
1792
|
-
});
|
|
1793
|
-
|
|
1794
|
-
// Export as Prometheus format
|
|
1795
|
-
app.get('/metrics', (req, res) => {
|
|
1796
|
-
const metrics = proxy.getMetrics();
|
|
1797
|
-
const instant = metrics.throughput.instant();
|
|
1798
|
-
|
|
1799
|
-
res.set('Content-Type', 'text/plain');
|
|
1800
|
-
res.send(`
|
|
1801
|
-
# HELP smartproxy_connections_active Current active connections
|
|
1802
|
-
# TYPE smartproxy_connections_active gauge
|
|
1803
|
-
smartproxy_connections_active ${metrics.connections.active()}
|
|
1804
|
-
|
|
1805
|
-
# HELP smartproxy_connections_total Total connections since start
|
|
1806
|
-
# TYPE smartproxy_connections_total counter
|
|
1807
|
-
smartproxy_connections_total ${metrics.connections.total()}
|
|
1808
|
-
|
|
1809
|
-
# HELP smartproxy_throughput_bytes_per_second Current throughput in bytes per second
|
|
1810
|
-
# TYPE smartproxy_throughput_bytes_per_second gauge
|
|
1811
|
-
smartproxy_throughput_bytes_per_second{direction="in"} ${instant.in}
|
|
1812
|
-
smartproxy_throughput_bytes_per_second{direction="out"} ${instant.out}
|
|
1813
|
-
|
|
1814
|
-
# HELP smartproxy_requests_per_second Current requests per second
|
|
1815
|
-
# TYPE smartproxy_requests_per_second gauge
|
|
1816
|
-
smartproxy_requests_per_second ${metrics.requests.perSecond()}
|
|
1817
|
-
|
|
1818
|
-
# HELP smartproxy_bytes_total Total bytes transferred
|
|
1819
|
-
# TYPE smartproxy_bytes_total counter
|
|
1820
|
-
smartproxy_bytes_total{direction="in"} ${metrics.totals.bytesIn()}
|
|
1821
|
-
smartproxy_bytes_total{direction="out"} ${metrics.totals.bytesOut()}
|
|
1822
|
-
`);
|
|
1823
|
-
});
|
|
1824
|
-
```
|
|
1825
|
-
|
|
1826
|
-
### Metrics API Reference
|
|
1827
|
-
|
|
1828
|
-
The metrics API is organized into logical groups:
|
|
1829
|
-
|
|
1830
|
-
```typescript
|
|
1831
|
-
interface IMetrics {
|
|
1832
|
-
connections: {
|
|
1833
|
-
active(): number;
|
|
1834
|
-
total(): number;
|
|
1835
|
-
byRoute(): Map<string, number>;
|
|
1836
|
-
byIP(): Map<string, number>;
|
|
1837
|
-
topIPs(limit?: number): Array<{ ip: string; count: number }>;
|
|
1838
|
-
};
|
|
1839
|
-
|
|
1840
|
-
throughput: {
|
|
1841
|
-
instant(): IThroughputData; // Last 1 second
|
|
1842
|
-
recent(): IThroughputData; // Last 10 seconds
|
|
1843
|
-
average(): IThroughputData; // Last 60 seconds
|
|
1844
|
-
custom(seconds: number): IThroughputData;
|
|
1845
|
-
history(seconds: number): Array<IThroughputHistoryPoint>;
|
|
1846
|
-
byRoute(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1847
|
-
byIP(windowSeconds?: number): Map<string, IThroughputData>;
|
|
1848
|
-
};
|
|
1849
|
-
|
|
1850
|
-
requests: {
|
|
1851
|
-
perSecond(): number;
|
|
1852
|
-
perMinute(): number;
|
|
1853
|
-
total(): number;
|
|
1854
|
-
};
|
|
1855
|
-
|
|
1856
|
-
totals: {
|
|
1857
|
-
bytesIn(): number;
|
|
1858
|
-
bytesOut(): number;
|
|
1859
|
-
connections(): number;
|
|
1860
|
-
};
|
|
1861
|
-
|
|
1862
|
-
percentiles: {
|
|
1863
|
-
connectionDuration(): { p50: number; p95: number; p99: number };
|
|
1864
|
-
bytesTransferred(): {
|
|
1865
|
-
in: { p50: number; p95: number; p99: number };
|
|
1866
|
-
out: { p50: number; p95: number; p99: number };
|
|
1867
|
-
};
|
|
1868
|
-
};
|
|
1869
|
-
}
|
|
1870
|
-
```
|
|
1871
|
-
|
|
1872
|
-
Where `IThroughputData` is:
|
|
1873
|
-
```typescript
|
|
1874
|
-
interface IThroughputData {
|
|
1875
|
-
in: number; // Bytes per second incoming
|
|
1876
|
-
out: number; // Bytes per second outgoing
|
|
1877
|
-
}
|
|
1878
|
-
```
|
|
1879
|
-
|
|
1880
|
-
And `IThroughputHistoryPoint` is:
|
|
1881
|
-
```typescript
|
|
1882
|
-
interface IThroughputHistoryPoint {
|
|
1883
|
-
timestamp: number; // Unix timestamp in milliseconds
|
|
1884
|
-
in: number; // Bytes per second at this point
|
|
1885
|
-
out: number; // Bytes per second at this point
|
|
1886
|
-
}
|
|
1887
|
-
```
|
|
1888
|
-
|
|
1889
|
-
## Other Components
|
|
1890
|
-
|
|
1891
|
-
While SmartProxy provides a unified API for most needs, you can also use individual components:
|
|
1892
|
-
|
|
1893
|
-
### HttpProxy
|
|
1894
|
-
For HTTP/HTTPS reverse proxy with TLS termination and WebSocket support. Now with native route-based configuration support:
|
|
1895
|
-
|
|
1896
|
-
```typescript
|
|
1897
|
-
import { HttpProxy } from '@push.rocks/smartproxy';
|
|
1898
|
-
import * as fs from 'fs';
|
|
1899
|
-
|
|
1900
|
-
const proxy = new HttpProxy({ port: 443 });
|
|
1901
|
-
await proxy.start();
|
|
1902
|
-
|
|
1903
|
-
// Modern route-based configuration (recommended)
|
|
1904
|
-
await proxy.updateRouteConfigs([
|
|
1905
|
-
{
|
|
1906
|
-
match: {
|
|
1907
|
-
ports: 443,
|
|
1908
|
-
domains: 'example.com'
|
|
1909
|
-
},
|
|
1910
|
-
action: {
|
|
1911
|
-
type: 'forward',
|
|
1912
|
-
target: {
|
|
1913
|
-
host: '127.0.0.1',
|
|
1914
|
-
port: 3000
|
|
1915
|
-
},
|
|
1916
|
-
tls: {
|
|
1917
|
-
mode: 'terminate',
|
|
1918
|
-
certificate: {
|
|
1919
|
-
cert: fs.readFileSync('cert.pem', 'utf8'),
|
|
1920
|
-
key: fs.readFileSync('key.pem', 'utf8')
|
|
1921
|
-
}
|
|
1922
|
-
},
|
|
1923
|
-
advanced: {
|
|
1924
|
-
headers: {
|
|
1925
|
-
'X-Forwarded-By': 'HttpProxy'
|
|
1926
|
-
},
|
|
1927
|
-
urlRewrite: {
|
|
1928
|
-
pattern: '^/old/(.*)$',
|
|
1929
|
-
target: '/new/$1',
|
|
1930
|
-
flags: 'g'
|
|
1931
|
-
}
|
|
1932
|
-
},
|
|
1933
|
-
websocket: {
|
|
1934
|
-
enabled: true,
|
|
1935
|
-
pingInterval: 30000
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
]);
|
|
1940
|
-
```
|
|
1941
|
-
|
|
1942
|
-
### NfTablesProxy
|
|
1943
|
-
For low-level port forwarding using nftables:
|
|
1944
|
-
|
|
1945
|
-
```typescript
|
|
1946
|
-
import { NfTablesProxy } from '@push.rocks/smartproxy';
|
|
1947
|
-
|
|
1948
|
-
const nft = new NfTablesProxy({
|
|
1949
|
-
fromPort: 80,
|
|
1950
|
-
toPort: 8080,
|
|
1951
|
-
toHost: 'localhost',
|
|
1952
|
-
preserveSourceIP: true
|
|
1953
|
-
});
|
|
1954
|
-
await nft.start();
|
|
1955
|
-
```
|
|
1956
|
-
|
|
1957
|
-
### SniHandler
|
|
1958
|
-
For SNI extraction from TLS handshakes:
|
|
1959
|
-
|
|
1960
|
-
```typescript
|
|
1961
|
-
import { SniHandler } from '@push.rocks/smartproxy';
|
|
1962
|
-
|
|
1963
|
-
// The SniHandler is typically used internally by SmartProxy
|
|
1964
|
-
// but can be used directly for custom implementations
|
|
1965
|
-
```
|
|
1966
|
-
|
|
1967
|
-
## NFTables Integration
|
|
1968
|
-
|
|
1969
|
-
SmartProxy v18.0.0 includes full integration with Linux NFTables for high-performance kernel-level packet forwarding. NFTables operates directly in the Linux kernel, providing much better performance than user-space proxying for high-traffic scenarios.
|
|
1970
|
-
|
|
1971
|
-
### When to Use NFTables
|
|
1972
|
-
|
|
1973
|
-
NFTables routing is ideal for:
|
|
1974
|
-
- High-traffic TCP/UDP forwarding where performance is critical
|
|
1975
|
-
- Port forwarding scenarios where you need minimal latency
|
|
1976
|
-
- Load balancing across multiple backend servers
|
|
1977
|
-
- Security filtering with IP allowlists/blocklists at kernel level
|
|
1978
|
-
|
|
1979
|
-
### Requirements
|
|
1980
|
-
|
|
1981
|
-
NFTables support requires:
|
|
1982
|
-
- Linux operating system with NFTables installed
|
|
1983
|
-
- Root or sudo permissions to configure NFTables rules
|
|
1984
|
-
- NFTables kernel modules loaded
|
|
1985
|
-
|
|
1986
|
-
### NFTables Route Configuration
|
|
1987
|
-
|
|
1988
|
-
Use the NFTables helper functions to create high-performance routes:
|
|
1989
|
-
|
|
1990
|
-
```typescript
|
|
1991
|
-
import { SmartProxy, createNfTablesRoute, createNfTablesTerminateRoute } from '@push.rocks/smartproxy';
|
|
1992
|
-
|
|
1993
|
-
const proxy = new SmartProxy({
|
|
1994
|
-
routes: [
|
|
1995
|
-
// Basic TCP forwarding with NFTables
|
|
1996
|
-
createNfTablesRoute('tcp-forward', {
|
|
1997
|
-
host: 'backend-server',
|
|
1998
|
-
port: 8080
|
|
1999
|
-
}, {
|
|
2000
|
-
ports: 80,
|
|
2001
|
-
protocol: 'tcp'
|
|
2002
|
-
}),
|
|
2003
|
-
|
|
2004
|
-
// NFTables with IP filtering
|
|
2005
|
-
createNfTablesRoute('secure-tcp', {
|
|
2006
|
-
host: 'secure-backend',
|
|
2007
|
-
port: 8443
|
|
2008
|
-
}, {
|
|
2009
|
-
ports: 443,
|
|
2010
|
-
ipAllowList: ['10.0.0.*', '192.168.1.*'],
|
|
2011
|
-
preserveSourceIP: true
|
|
2012
|
-
}),
|
|
2013
|
-
|
|
2014
|
-
// NFTables with QoS (rate limiting)
|
|
2015
|
-
createNfTablesRoute('limited-service', {
|
|
2016
|
-
host: 'api-server',
|
|
2017
|
-
port: 3000
|
|
2018
|
-
}, {
|
|
2019
|
-
ports: 8080,
|
|
2020
|
-
maxRate: '50mbps',
|
|
2021
|
-
priority: 1
|
|
2022
|
-
}),
|
|
2023
|
-
|
|
2024
|
-
// NFTables TLS termination
|
|
2025
|
-
createNfTablesTerminateRoute('https-nftables', {
|
|
2026
|
-
host: 'backend',
|
|
2027
|
-
port: 8080
|
|
2028
|
-
}, {
|
|
2029
|
-
ports: 443,
|
|
2030
|
-
certificate: 'auto',
|
|
2031
|
-
useAdvancedNAT: true
|
|
2032
|
-
}),
|
|
2033
|
-
|
|
2034
|
-
// Complete NFTables HTTPS server with HTTP redirect
|
|
2035
|
-
...createCompleteNfTablesHttpsServer('complete-nftables.example.com', {
|
|
2036
|
-
host: 'backend',
|
|
2037
|
-
port: 8080
|
|
2038
|
-
}, {
|
|
2039
|
-
certificate: 'auto',
|
|
2040
|
-
preserveSourceIP: true
|
|
2041
|
-
})
|
|
2042
|
-
]
|
|
2043
|
-
});
|
|
2044
|
-
|
|
2045
|
-
await proxy.start();
|
|
2046
|
-
```
|
|
2047
|
-
|
|
2048
|
-
### NFTables Route Options
|
|
2049
|
-
|
|
2050
|
-
The NFTables integration supports these options:
|
|
2051
|
-
|
|
2052
|
-
- `protocol`: 'tcp' | 'udp' | 'all' - Protocol to forward
|
|
2053
|
-
- `preserveSourceIP`: boolean - Preserve client IP for backend
|
|
2054
|
-
- `ipAllowList`: string[] - Allow only these IPs (glob patterns)
|
|
2055
|
-
- `ipBlockList`: string[] - Block these IPs (glob patterns)
|
|
2056
|
-
- `maxRate`: string - Rate limit (e.g., '100mbps', '1gbps')
|
|
2057
|
-
- `priority`: number - QoS priority level
|
|
2058
|
-
- `tableName`: string - Custom NFTables table name
|
|
2059
|
-
- `useIPSets`: boolean - Use IP sets for better performance
|
|
2060
|
-
- `useAdvancedNAT`: boolean - Enable connection tracking
|
|
2061
|
-
|
|
2062
|
-
### NFTables Status Monitoring
|
|
2063
|
-
|
|
2064
|
-
You can monitor the status of NFTables rules:
|
|
2065
|
-
|
|
2066
|
-
```typescript
|
|
2067
|
-
// Get status of all NFTables rules
|
|
2068
|
-
const nftStatus = await proxy.getNfTablesStatus();
|
|
2069
|
-
|
|
2070
|
-
// Status includes:
|
|
2071
|
-
// - active: boolean
|
|
2072
|
-
// - ruleCount: { total, added, removed }
|
|
2073
|
-
// - packetStats: { forwarded, dropped }
|
|
2074
|
-
// - lastUpdate: Date
|
|
2075
|
-
```
|
|
2076
|
-
|
|
2077
|
-
### Performance Considerations
|
|
2078
|
-
|
|
2079
|
-
NFTables provides significantly better performance than application-level proxying:
|
|
2080
|
-
- Operates at kernel level with minimal overhead
|
|
2081
|
-
- Can handle millions of packets per second
|
|
2082
|
-
- Direct packet forwarding without copying to userspace
|
|
2083
|
-
- Hardware offload support on compatible network cards
|
|
2084
|
-
|
|
2085
|
-
### Limitations
|
|
2086
|
-
|
|
2087
|
-
NFTables routing has some limitations:
|
|
2088
|
-
- Cannot modify HTTP headers or content
|
|
2089
|
-
- Limited to basic NAT and forwarding operations
|
|
2090
|
-
- Requires root permissions
|
|
2091
|
-
- Linux-only (not available on Windows/macOS)
|
|
2092
|
-
- No WebSocket message inspection
|
|
2093
|
-
|
|
2094
|
-
For scenarios requiring application-level features (header manipulation, WebSocket handling, etc.), use the standard SmartProxy routes without NFTables.
|
|
2095
|
-
|
|
2096
|
-
## Migration to v19.5.3
|
|
2097
|
-
|
|
2098
|
-
Version 19.5.3 includes important fixes and improvements:
|
|
2099
|
-
|
|
2100
|
-
### Key Changes
|
|
2101
|
-
|
|
2102
|
-
1. **Security Configuration Location**: Security configuration is now at the route level (`route.security`), not inside the action (`route.action.security`)
|
|
2103
|
-
2. **Socket Handler Support**: New `socket-handler` action type for custom protocol handling
|
|
2104
|
-
3. **Improved ACME Timing**: Certificate provisioning now waits for ports to be ready
|
|
2105
|
-
4. **Route-Specific Security**: IP allow/block lists are now properly enforced per route
|
|
2106
|
-
5. **Enhanced Helper Functions**: New helpers for socket handling and NFTables complete server setup
|
|
2107
|
-
|
|
2108
|
-
### Migration Example
|
|
2109
|
-
|
|
2110
|
-
**Before (v18.x and earlier)**:
|
|
2111
|
-
```typescript
|
|
2112
|
-
{
|
|
2113
|
-
match: { ports: 443, domains: 'api.example.com' },
|
|
2114
|
-
action: {
|
|
2115
|
-
type: 'forward',
|
|
2116
|
-
target: { host: 'localhost', port: 3000 },
|
|
2117
|
-
security: { // WRONG: Security was incorrectly placed here
|
|
2118
|
-
ipAllowList: ['10.0.0.*']
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
```
|
|
2123
|
-
|
|
2124
|
-
**After (v19.5.3)**:
|
|
2125
|
-
```typescript
|
|
2126
|
-
{
|
|
2127
|
-
match: { ports: 443, domains: 'api.example.com' },
|
|
2128
|
-
action: {
|
|
2129
|
-
type: 'forward',
|
|
2130
|
-
target: { host: 'localhost', port: 3000 }
|
|
2131
|
-
},
|
|
2132
|
-
security: { // CORRECT: Security is at the route level
|
|
2133
|
-
ipAllowList: ['10.0.0.*']
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
```
|
|
2137
|
-
|
|
2138
|
-
### New Features in v19.5.x
|
|
2139
|
-
|
|
2140
|
-
1. **Socket Handlers** - Custom protocol handling:
|
|
2141
|
-
```typescript
|
|
2142
|
-
createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => {
|
|
2143
|
-
// Custom protocol implementation
|
|
2144
|
-
})
|
|
2145
|
-
```
|
|
2146
|
-
|
|
2147
|
-
2. **Pre-built Socket Handlers** - Common patterns:
|
|
2148
|
-
- `SocketHandlers.echo` - Echo server
|
|
2149
|
-
- `SocketHandlers.proxy` - TCP proxy
|
|
2150
|
-
- `SocketHandlers.lineProtocol` - Line-based protocols
|
|
2151
|
-
- `SocketHandlers.httpResponse` - Simple HTTP responses
|
|
2152
|
-
- `SocketHandlers.httpRedirect` - HTTP redirects
|
|
2153
|
-
- `SocketHandlers.httpBlock` - HTTP blocking with status code
|
|
2154
|
-
- `SocketHandlers.block` - Connection blocking
|
|
2155
|
-
- `SocketHandlers.httpServer` - Full HTTP server handler
|
|
2156
|
-
|
|
2157
|
-
3. **Complete NFTables Server** - HTTPS with HTTP redirect:
|
|
2158
|
-
```typescript
|
|
2159
|
-
...createCompleteNfTablesHttpsServer('example.com', {
|
|
2160
|
-
host: 'backend',
|
|
2161
|
-
port: 8080
|
|
2162
|
-
}, {
|
|
2163
|
-
certificate: 'auto'
|
|
2164
|
-
})
|
|
2165
|
-
```
|
|
2166
|
-
|
|
2167
|
-
### Complete Migration Steps
|
|
2168
|
-
|
|
2169
|
-
1. Move any security configuration from `action.security` to `route.security`
|
|
2170
|
-
2. Update to use new socket handler features for custom protocols
|
|
2171
|
-
3. Take advantage of improved ACME timing (no action needed, just update)
|
|
2172
|
-
4. Use the new helper functions for cleaner configuration
|
|
2173
|
-
5. Review and update any custom route creation code
|
|
2174
|
-
|
|
2175
|
-
## Architecture & Flow Diagrams
|
|
2176
|
-
|
|
2177
|
-
```mermaid
|
|
2178
|
-
flowchart TB
|
|
2179
|
-
Client([Client])
|
|
2180
|
-
|
|
2181
|
-
subgraph "SmartProxy Components"
|
|
2182
|
-
direction TB
|
|
2183
|
-
RouteConfig["Route Configuration<br>(Match/Action)"]
|
|
2184
|
-
RouteManager["Route Manager"]
|
|
2185
|
-
SmartProxy["SmartProxy<br>(TCP/SNI Proxy)"]
|
|
2186
|
-
HttpProxyBridge["HttpProxy Bridge"]
|
|
2187
|
-
HttpProxy["HttpProxy<br>(HTTPS/TLS Termination)"]
|
|
2188
|
-
NfTablesManager["NFTables Manager<br>(Kernel Routing)"]
|
|
2189
|
-
CertManager["SmartCertManager<br>(ACME/Let's Encrypt)"]
|
|
2190
|
-
Certs[(SSL Certificates)]
|
|
2191
|
-
end
|
|
2192
|
-
|
|
2193
|
-
subgraph "Backend Services"
|
|
2194
|
-
Service1[Service 1]
|
|
2195
|
-
Service2[Service 2]
|
|
2196
|
-
Service3[Service 3]
|
|
2197
|
-
end
|
|
2198
|
-
|
|
2199
|
-
Client -->|HTTP/HTTPS Request| SmartProxy
|
|
2200
|
-
|
|
2201
|
-
SmartProxy -->|Route Matching| RouteManager
|
|
2202
|
-
RouteManager -->|Use| RouteConfig
|
|
2203
|
-
RouteManager -->|Execute Action| SmartProxy
|
|
2204
|
-
|
|
2205
|
-
SmartProxy -->|TLS Termination| HttpProxyBridge
|
|
2206
|
-
HttpProxyBridge -->|Forward| HttpProxy
|
|
2207
|
-
SmartProxy -->|Kernel Routing| NfTablesManager
|
|
2208
|
-
|
|
2209
|
-
SmartProxy -->|Forward| Service1
|
|
2210
|
-
SmartProxy -->|Redirect| Client
|
|
2211
|
-
SmartProxy -->|Forward| Service2
|
|
2212
|
-
SmartProxy -->|Forward| Service3
|
|
2213
|
-
|
|
2214
|
-
CertManager -.->|Generate/Manage| Certs
|
|
2215
|
-
Certs -.->|Provide TLS Certs| SmartProxy
|
|
2216
|
-
Certs -.->|Provide TLS Certs| HttpProxy
|
|
2217
|
-
|
|
2218
|
-
classDef component fill:#f9f,stroke:#333,stroke-width:2px;
|
|
2219
|
-
classDef backend fill:#bbf,stroke:#333,stroke-width:1px;
|
|
2220
|
-
classDef client fill:#dfd,stroke:#333,stroke-width:2px;
|
|
2221
|
-
|
|
2222
|
-
class Client client;
|
|
2223
|
-
class RouteConfig,RouteManager,SmartProxy,HttpProxyBridge,HttpProxy,NfTablesManager,CertManager component;
|
|
2224
|
-
class Service1,Service2,Service3 backend;
|
|
2225
|
-
```
|
|
2226
|
-
|
|
2227
|
-
### Route-Based Connection Handling
|
|
2228
|
-
This diagram illustrates how requests are matched and processed using the route-based configuration:
|
|
2229
|
-
|
|
2230
|
-
```mermaid
|
|
2231
|
-
sequenceDiagram
|
|
2232
|
-
participant Client
|
|
2233
|
-
participant SmartProxy
|
|
2234
|
-
participant RouteManager
|
|
2235
|
-
participant SecurityManager
|
|
2236
|
-
participant Backend
|
|
2237
|
-
|
|
2238
|
-
Client->>SmartProxy: Connection (TCP/HTTP/HTTPS)
|
|
2239
|
-
|
|
2240
|
-
SmartProxy->>RouteManager: Match connection against routes
|
|
2241
|
-
|
|
2242
|
-
RouteManager->>RouteManager: Check port match
|
|
2243
|
-
RouteManager->>RouteManager: Check domain match (if SNI)
|
|
2244
|
-
RouteManager->>RouteManager: Check path match (if HTTP)
|
|
2245
|
-
RouteManager->>RouteManager: Check client IP match
|
|
2246
|
-
RouteManager->>RouteManager: Check TLS version match
|
|
2247
|
-
|
|
2248
|
-
RouteManager->>RouteManager: Determine highest priority matching route
|
|
2249
|
-
|
|
2250
|
-
alt Route Matched
|
|
2251
|
-
SmartProxy->>SecurityManager: Check route security
|
|
2252
|
-
SecurityManager->>SecurityManager: Validate IP allow/block lists
|
|
2253
|
-
SecurityManager->>SecurityManager: Check connection limits
|
|
2254
|
-
|
|
2255
|
-
alt Security Check Passed
|
|
2256
|
-
alt Forward Action
|
|
2257
|
-
SmartProxy->>SmartProxy: Apply action configuration
|
|
2258
|
-
|
|
2259
|
-
alt TLS Termination
|
|
2260
|
-
SmartProxy->>SmartProxy: Terminate TLS
|
|
2261
|
-
SmartProxy->>Backend: Forward as HTTP/HTTPS
|
|
2262
|
-
else TLS Passthrough
|
|
2263
|
-
SmartProxy->>Backend: Forward raw TCP
|
|
2264
|
-
else Socket Handler
|
|
2265
|
-
SmartProxy->>SmartProxy: Execute custom handler
|
|
2266
|
-
end
|
|
2267
|
-
|
|
2268
|
-
else Redirect Action
|
|
2269
|
-
SmartProxy->>Client: Send redirect response
|
|
2270
|
-
|
|
2271
|
-
else Block Action
|
|
2272
|
-
SmartProxy->>Client: Close connection
|
|
2273
|
-
end
|
|
2274
|
-
else Security Check Failed
|
|
2275
|
-
SmartProxy->>Client: Close connection (unauthorized)
|
|
2276
|
-
end
|
|
2277
|
-
else No Route Matched
|
|
2278
|
-
SmartProxy->>Client: Close connection (no route)
|
|
2279
|
-
end
|
|
2280
|
-
|
|
2281
|
-
loop Connection Active
|
|
2282
|
-
SmartProxy-->>SmartProxy: Monitor Activity
|
|
2283
|
-
SmartProxy-->>SecurityManager: Check Security Rules
|
|
2284
|
-
alt Security Violation or Timeout
|
|
2285
|
-
SmartProxy->>Client: Close Connection
|
|
2286
|
-
SmartProxy->>Backend: Close Connection
|
|
2287
|
-
end
|
|
2288
|
-
end
|
|
2289
|
-
```
|
|
2290
|
-
|
|
2291
|
-
## Features
|
|
2292
|
-
|
|
2293
|
-
- **Route-Based Traffic Management**
|
|
2294
|
-
• Match/action pattern for flexible routing
|
|
2295
|
-
• Port, domain, path, client IP, and TLS version matching
|
|
2296
|
-
• Forward traffic or use custom socket handlers for any protocol
|
|
2297
|
-
|
|
2298
|
-
- **TLS Handling Options**
|
|
2299
|
-
• TLS passthrough for end-to-end encryption
|
|
2300
|
-
• TLS termination for content inspection
|
|
2301
|
-
• TLS termination with re-encryption for gateway scenarios
|
|
2302
|
-
|
|
2303
|
-
- **Automatic ACME Certificates**
|
|
2304
|
-
• HTTP-01 challenge handling
|
|
2305
|
-
• Certificate issuance/renewal
|
|
2306
|
-
• Pluggable storage
|
|
2307
|
-
• Per-route and global configuration
|
|
2308
|
-
|
|
2309
|
-
- **Security Controls**
|
|
2310
|
-
• Route-specific IP allow/block lists with glob pattern support
|
|
2311
|
-
• Connection limits and rate limiting
|
|
2312
|
-
• Timeout controls and connection monitoring
|
|
2313
|
-
• Authentication support (Basic, JWT, OAuth)
|
|
2314
|
-
|
|
2315
|
-
- **Load Balancing**
|
|
2316
|
-
• Round-robin distribution across multiple backends
|
|
2317
|
-
• Dynamic host selection based on context
|
|
2318
|
-
• Health checks and failure handling
|
|
2319
|
-
|
|
2320
|
-
- **Custom Protocol Support**
|
|
2321
|
-
• Socket handler action type for custom protocols
|
|
2322
|
-
• Pre-built handlers for common patterns
|
|
2323
|
-
• Full control over socket lifecycle
|
|
2324
|
-
|
|
2325
|
-
- **Advanced Features**
|
|
2326
|
-
• Custom header manipulation
|
|
2327
|
-
• URL rewriting
|
|
2328
|
-
• Template variables for dynamic values
|
|
2329
|
-
• Priority-based route matching
|
|
2330
|
-
• WebSocket support with configuration
|
|
2331
|
-
• Static file serving
|
|
2332
|
-
|
|
2333
|
-
- **High Performance**
|
|
2334
|
-
• NFTables integration for kernel-level forwarding
|
|
2335
|
-
• Connection pooling and keep-alive
|
|
2336
|
-
• Efficient SNI extraction
|
|
2337
|
-
• Minimal overhead routing
|
|
2338
|
-
|
|
2339
|
-
## Certificate Management
|
|
2340
|
-
|
|
2341
|
-
### Custom Certificate Provision Function
|
|
2342
|
-
|
|
2343
|
-
SmartProxy supports a custom certificate provision function that allows you to provide your own certificate generation logic while maintaining compatibility with Let's Encrypt:
|
|
2344
|
-
|
|
2345
|
-
```typescript
|
|
2346
|
-
const proxy = new SmartProxy({
|
|
2347
|
-
certProvisionFunction: async (domain: string): Promise<TSmartProxyCertProvisionObject> => {
|
|
2348
|
-
// Option 1: Return a custom certificate
|
|
2349
|
-
if (domain === 'internal.example.com') {
|
|
2350
|
-
return {
|
|
2351
|
-
cert: customCertPEM,
|
|
2352
|
-
key: customKeyPEM,
|
|
2353
|
-
ca: customCAPEM // Optional CA chain
|
|
2354
|
-
};
|
|
2355
|
-
}
|
|
2356
|
-
|
|
2357
|
-
// Option 2: Fallback to Let's Encrypt
|
|
2358
|
-
return 'http01';
|
|
2359
|
-
},
|
|
2360
|
-
|
|
2361
|
-
// Control fallback behavior when custom provision fails
|
|
2362
|
-
certProvisionFallbackToAcme: true, // Default: true
|
|
2363
|
-
|
|
2364
|
-
routes: [...]
|
|
2365
|
-
});
|
|
2366
|
-
```
|
|
2367
|
-
|
|
2368
|
-
**Key Features:**
|
|
2369
|
-
- Called for any route with `certificate: 'auto'`
|
|
2370
|
-
- Return custom certificate object or `'http01'` to use Let's Encrypt
|
|
2371
|
-
- Participates in automatic renewal cycle (checked every 12 hours)
|
|
2372
|
-
- Custom certificates stored with source type 'custom' for tracking
|
|
2373
|
-
|
|
2374
|
-
**Configuration Options:**
|
|
2375
|
-
- `certProvisionFunction`: Async function that receives domain and returns certificate or 'http01'
|
|
2376
|
-
- `certProvisionFallbackToAcme`: Whether to fallback to Let's Encrypt if custom provision fails (default: true)
|
|
2377
|
-
|
|
2378
|
-
**Advanced Example with Certificate Manager:**
|
|
2379
|
-
|
|
2380
|
-
```typescript
|
|
2381
|
-
const certManager = new MyCertificateManager();
|
|
2382
|
-
|
|
2383
|
-
const proxy = new SmartProxy({
|
|
2384
|
-
certProvisionFunction: async (domain: string) => {
|
|
2385
|
-
try {
|
|
2386
|
-
// Check if we have a custom certificate for this domain
|
|
2387
|
-
if (await certManager.hasCustomCert(domain)) {
|
|
2388
|
-
const cert = await certManager.getCertificate(domain);
|
|
2389
|
-
return {
|
|
2390
|
-
cert: cert.certificate,
|
|
2391
|
-
key: cert.privateKey,
|
|
2392
|
-
ca: cert.chain
|
|
2393
|
-
};
|
|
2394
|
-
}
|
|
2395
|
-
|
|
2396
|
-
// Use Let's Encrypt for public domains
|
|
2397
|
-
if (domain.endsWith('.example.com')) {
|
|
2398
|
-
return 'http01';
|
|
2399
|
-
}
|
|
2400
|
-
|
|
2401
|
-
// Generate self-signed for internal domains
|
|
2402
|
-
if (domain.endsWith('.internal')) {
|
|
2403
|
-
const selfSigned = await certManager.generateSelfSigned(domain);
|
|
2404
|
-
return {
|
|
2405
|
-
cert: selfSigned.cert,
|
|
2406
|
-
key: selfSigned.key,
|
|
2407
|
-
ca: ''
|
|
2408
|
-
};
|
|
2409
|
-
}
|
|
2410
|
-
|
|
2411
|
-
// Default to Let's Encrypt
|
|
2412
|
-
return 'http01';
|
|
2413
|
-
} catch (error) {
|
|
2414
|
-
console.error(`Certificate provision failed for ${domain}:`, error);
|
|
2415
|
-
// Will fallback to Let's Encrypt if certProvisionFallbackToAcme is true
|
|
2416
|
-
throw error;
|
|
2417
|
-
}
|
|
2418
|
-
},
|
|
2419
|
-
|
|
2420
|
-
certProvisionFallbackToAcme: true,
|
|
2421
|
-
|
|
2422
|
-
routes: [
|
|
2423
|
-
// Routes that use automatic certificates
|
|
2424
|
-
{
|
|
2425
|
-
match: { ports: 443, domains: ['app.example.com', '*.internal'] },
|
|
2426
|
-
action: {
|
|
2427
|
-
type: 'forward',
|
|
2428
|
-
target: { host: 'localhost', port: 8080 },
|
|
2429
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
]
|
|
2433
|
-
});
|
|
2434
|
-
```
|
|
2435
|
-
|
|
2436
|
-
### Certificate Events
|
|
2437
|
-
|
|
2438
|
-
Listen for certificate events via EventEmitter:
|
|
2439
|
-
- **SmartProxy**:
|
|
2440
|
-
- `certificate` (domain, publicKey, privateKey, expiryDate, source, isRenewal)
|
|
2441
|
-
- Events from CertManager are propagated
|
|
2442
|
-
|
|
2443
|
-
```typescript
|
|
2444
|
-
proxy.on('certificate', (domain, cert, key, expiryDate, source, isRenewal) => {
|
|
2445
|
-
console.log(`Certificate ${isRenewal ? 'renewed' : 'provisioned'} for ${domain}`);
|
|
2446
|
-
console.log(`Source: ${source}`); // 'acme', 'static', or 'custom'
|
|
2447
|
-
console.log(`Expires: ${expiryDate}`);
|
|
2448
|
-
});
|
|
2449
|
-
```
|
|
2450
|
-
|
|
2451
|
-
## SmartProxy: Common Use Cases
|
|
2452
|
-
|
|
2453
|
-
The SmartProxy component with route-based configuration offers a clean, unified approach to handle virtually any proxy scenario.
|
|
2454
|
-
|
|
2455
|
-
### 1. API Gateway / Backend Routing
|
|
2456
|
-
|
|
2457
|
-
Create a flexible API gateway to route traffic to different microservices based on domain and path:
|
|
2458
|
-
|
|
2459
|
-
```typescript
|
|
2460
|
-
import { SmartProxy, createApiRoute, createHttpsTerminateRoute } from '@push.rocks/smartproxy';
|
|
2461
|
-
|
|
2462
|
-
const apiGateway = new SmartProxy({
|
|
2463
|
-
routes: [
|
|
2464
|
-
// Users API
|
|
2465
|
-
createApiRoute('api.example.com', '/users', { host: 'users-service', port: 3000 }, {
|
|
2466
|
-
useTls: true,
|
|
2467
|
-
certificate: 'auto',
|
|
2468
|
-
addCorsHeaders: true
|
|
2469
|
-
}),
|
|
2470
|
-
|
|
2471
|
-
// Products API
|
|
2472
|
-
createApiRoute('api.example.com', '/products', { host: 'products-service', port: 3001 }, {
|
|
2473
|
-
useTls: true,
|
|
2474
|
-
certificate: 'auto',
|
|
2475
|
-
addCorsHeaders: true
|
|
2476
|
-
}),
|
|
2477
|
-
|
|
2478
|
-
// Admin dashboard with extra security
|
|
2479
|
-
{
|
|
2480
|
-
match: { ports: 443, domains: 'admin.example.com' },
|
|
2481
|
-
action: {
|
|
2482
|
-
type: 'forward',
|
|
2483
|
-
target: { host: 'admin-dashboard', port: 8080 },
|
|
2484
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
2485
|
-
},
|
|
2486
|
-
security: {
|
|
2487
|
-
ipAllowList: ['10.0.0.*', '192.168.1.*'] // Only allow internal network
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
]
|
|
2491
|
-
});
|
|
2492
|
-
|
|
2493
|
-
await apiGateway.start();
|
|
2494
|
-
```
|
|
2495
|
-
|
|
2496
|
-
### 2. Complete HTTPS Server with HTTP Redirect
|
|
2497
|
-
|
|
2498
|
-
Easily set up a secure HTTPS server with automatic redirection from HTTP:
|
|
2499
|
-
|
|
2500
|
-
```typescript
|
|
2501
|
-
import { SmartProxy, createCompleteHttpsServer } from '@push.rocks/smartproxy';
|
|
2502
|
-
|
|
2503
|
-
const webServer = new SmartProxy({
|
|
2504
|
-
routes: [
|
|
2505
|
-
// createCompleteHttpsServer creates both the HTTPS route and HTTP redirect
|
|
2506
|
-
...createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, {
|
|
2507
|
-
certificate: 'auto'
|
|
2508
|
-
})
|
|
2509
|
-
]
|
|
2510
|
-
});
|
|
2511
|
-
|
|
2512
|
-
await webServer.start();
|
|
2513
|
-
```
|
|
2514
|
-
|
|
2515
|
-
### 3. Multi-Tenant Application with Wildcard Domains
|
|
2516
|
-
|
|
2517
|
-
Support dynamically created tenants with wildcard domain matching:
|
|
2518
|
-
|
|
2519
|
-
```typescript
|
|
2520
|
-
import { SmartProxy, createDynamicRoute } from '@push.rocks/smartproxy';
|
|
2521
|
-
|
|
2522
|
-
const multiTenantApp = new SmartProxy({
|
|
2523
|
-
routes: [
|
|
2524
|
-
// Dynamic routing based on subdomain
|
|
2525
|
-
createDynamicRoute({
|
|
2526
|
-
ports: 443,
|
|
2527
|
-
domains: '*.tenant.example.com',
|
|
2528
|
-
targetHost: (context) => {
|
|
2529
|
-
// Extract tenant ID from subdomain
|
|
2530
|
-
const tenant = context.domain.split('.')[0];
|
|
2531
|
-
return `${tenant}-backend.internal`;
|
|
2532
|
-
},
|
|
2533
|
-
portMapper: (context) => 8080
|
|
2534
|
-
}),
|
|
2535
|
-
|
|
2536
|
-
// Redirect HTTP to HTTPS for all subdomains
|
|
2537
|
-
createHttpToHttpsRedirect(['*.tenant.example.com'])
|
|
2538
|
-
]
|
|
2539
|
-
});
|
|
2540
|
-
|
|
2541
|
-
await multiTenantApp.start();
|
|
2542
|
-
```
|
|
2543
|
-
|
|
2544
|
-
### 4. Complex Multi-Service Infrastructure
|
|
2545
|
-
|
|
2546
|
-
Create a comprehensive proxy solution with multiple services and security controls:
|
|
2547
|
-
|
|
2548
|
-
```typescript
|
|
2549
|
-
import {
|
|
2550
|
-
SmartProxy,
|
|
2551
|
-
createHttpsTerminateRoute,
|
|
2552
|
-
createHttpsPassthroughRoute,
|
|
2553
|
-
createSocketHandlerRoute,
|
|
2554
|
-
createHttpToHttpsRedirect,
|
|
2555
|
-
SocketHandlers
|
|
2556
|
-
} from '@push.rocks/smartproxy';
|
|
2557
|
-
|
|
2558
|
-
const enterpriseProxy = new SmartProxy({
|
|
2559
|
-
routes: [
|
|
2560
|
-
// Web application with automatic HTTPS
|
|
2561
|
-
createHttpsTerminateRoute('app.example.com', { host: 'web-app', port: 8080 }, {
|
|
2562
|
-
certificate: 'auto'
|
|
2563
|
-
}),
|
|
2564
|
-
|
|
2565
|
-
// Legacy system that needs HTTPS passthrough
|
|
2566
|
-
createHttpsPassthroughRoute('legacy.example.com', { host: 'legacy-server', port: 443 }),
|
|
2567
|
-
|
|
2568
|
-
// Internal APIs with IP restrictions
|
|
2569
|
-
{
|
|
2570
|
-
match: { ports: 443, domains: 'api.internal.example.com' },
|
|
2571
|
-
action: {
|
|
2572
|
-
type: 'forward',
|
|
2573
|
-
target: { host: 'api-gateway', port: 3000 },
|
|
2574
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
2575
|
-
},
|
|
2576
|
-
security: {
|
|
2577
|
-
ipAllowList: ['10.0.0.0/16', '192.168.0.0/16'],
|
|
2578
|
-
maxConnections: 500
|
|
2579
|
-
}
|
|
2580
|
-
},
|
|
2581
|
-
|
|
2582
|
-
// Custom protocol handler
|
|
2583
|
-
createSocketHandlerRoute('telnet.example.com', 23, SocketHandlers.lineProtocol((line, socket) => {
|
|
2584
|
-
// Handle telnet-like protocol
|
|
2585
|
-
socket.write(`Command received: ${line}\n`);
|
|
2586
|
-
})),
|
|
2587
|
-
|
|
2588
|
-
// Block known malicious IPs
|
|
2589
|
-
{
|
|
2590
|
-
match: { ports: [80, 443], clientIp: ['1.2.3.*', '5.6.7.*'] },
|
|
2591
|
-
action: {
|
|
2592
|
-
type: 'socket-handler',
|
|
2593
|
-
socketHandler: SocketHandlers.block('Access denied')
|
|
2594
|
-
},
|
|
2595
|
-
priority: 1000 // High priority to ensure blocking
|
|
2596
|
-
},
|
|
2597
|
-
|
|
2598
|
-
// Redirect all HTTP to HTTPS
|
|
2599
|
-
createHttpToHttpsRedirect(['*.example.com', 'example.com'])
|
|
2600
|
-
],
|
|
2601
|
-
|
|
2602
|
-
// Enable connection timeouts for security
|
|
2603
|
-
inactivityTimeout: 30000,
|
|
2604
|
-
|
|
2605
|
-
// Using global certificate management
|
|
2606
|
-
acme: {
|
|
2607
|
-
email: 'admin@example.com',
|
|
2608
|
-
useProduction: true,
|
|
2609
|
-
renewThresholdDays: 30
|
|
2610
|
-
}
|
|
2611
|
-
});
|
|
2612
|
-
|
|
2613
|
-
await enterpriseProxy.start();
|
|
2614
|
-
```
|
|
2615
|
-
|
|
2616
|
-
## Route-Based Configuration Details
|
|
2617
|
-
|
|
2618
|
-
### Match Criteria Options
|
|
2619
|
-
|
|
2620
|
-
- **ports**: `number | number[] | Array<{ from: number; to: number }>` (required)
|
|
2621
|
-
Listen on specific ports or port ranges
|
|
2622
|
-
|
|
2623
|
-
- **domains**: `string | string[]` (optional)
|
|
2624
|
-
Match specific domain names, supports wildcards (e.g., `*.example.com`)
|
|
2625
|
-
|
|
2626
|
-
- **path**: `string` (optional)
|
|
2627
|
-
Match specific URL paths, supports glob patterns
|
|
2628
|
-
|
|
2629
|
-
- **clientIp**: `string[]` (optional)
|
|
2630
|
-
Match client IP addresses, supports glob patterns
|
|
2631
|
-
|
|
2632
|
-
- **tlsVersion**: `string[]` (optional)
|
|
2633
|
-
Match specific TLS versions (e.g., `TLSv1.2`, `TLSv1.3`)
|
|
2634
|
-
|
|
2635
|
-
- **headers**: `Record<string, string | RegExp>` (optional)
|
|
2636
|
-
Match specific HTTP headers
|
|
2637
|
-
|
|
2638
|
-
### Action Types
|
|
2639
|
-
|
|
2640
|
-
1. **Forward**:
|
|
2641
|
-
```typescript
|
|
2642
|
-
{
|
|
2643
|
-
type: 'forward',
|
|
2644
|
-
target: { host: 'localhost', port: 8080 },
|
|
2645
|
-
tls: { mode: 'terminate', certificate: 'auto' }
|
|
2646
|
-
}
|
|
2647
|
-
```
|
|
2648
|
-
|
|
2649
|
-
2. **Socket Handler**:
|
|
2650
|
-
```typescript
|
|
2651
|
-
{
|
|
2652
|
-
type: 'socket-handler',
|
|
2653
|
-
socketHandler: async (socket, context) => {
|
|
2654
|
-
// Custom protocol handling
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
```
|
|
2658
|
-
|
|
2659
|
-
### TLS Modes
|
|
2660
|
-
|
|
2661
|
-
- **passthrough**: Forward raw TLS traffic without decryption
|
|
2662
|
-
- **terminate**: Terminate TLS and forward as HTTP
|
|
2663
|
-
- **terminate-and-reencrypt**: Terminate TLS and create a new TLS connection to the backend
|
|
2664
|
-
|
|
2665
|
-
### Template Variables
|
|
2666
|
-
|
|
2667
|
-
Template variables can be used in string values:
|
|
2668
|
-
|
|
2669
|
-
- `{domain}`: The requested domain name
|
|
2670
|
-
- `{port}`: The incoming port number
|
|
2671
|
-
- `{path}`: The requested URL path
|
|
2672
|
-
- `{query}`: The query string
|
|
2673
|
-
- `{clientIp}`: The client's IP address
|
|
2674
|
-
- `{sni}`: The SNI hostname
|
|
2675
|
-
|
|
2676
|
-
Example:
|
|
2677
|
-
```typescript
|
|
2678
|
-
// Using the HTTP redirect helper
|
|
2679
|
-
createHttpToHttpsRedirect('old.example.com', 443)
|
|
2680
|
-
|
|
2681
|
-
// Or with custom redirect using socket handler
|
|
2682
|
-
{
|
|
2683
|
-
match: { ports: 80, domains: 'old.example.com' },
|
|
2684
|
-
action: {
|
|
2685
|
-
type: 'socket-handler',
|
|
2686
|
-
socketHandler: SocketHandlers.httpRedirect('https://new.example.com{path}?source=redirect', 301)
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
|
-
```
|
|
2690
|
-
|
|
2691
|
-
## WebSocket Keep-Alive Configuration
|
|
2692
|
-
|
|
2693
|
-
If your WebSocket connections are disconnecting every 30 seconds in SNI passthrough mode, here's how to configure keep-alive settings:
|
|
2694
|
-
|
|
2695
|
-
### Extended Keep-Alive Treatment (Recommended)
|
|
2696
|
-
|
|
2697
|
-
```typescript
|
|
2698
|
-
const proxy = new SmartProxy({
|
|
2699
|
-
// Extend timeout for keep-alive connections
|
|
2700
|
-
keepAliveTreatment: 'extended',
|
|
2701
|
-
keepAliveInactivityMultiplier: 10, // 10x the base timeout
|
|
2702
|
-
inactivityTimeout: 14400000, // 4 hours base (40 hours with multiplier)
|
|
2703
|
-
|
|
2704
|
-
routes: [
|
|
2705
|
-
{
|
|
2706
|
-
name: 'websocket-passthrough',
|
|
2707
|
-
match: {
|
|
2708
|
-
ports: 443,
|
|
2709
|
-
domains: ['ws.example.com', 'wss.example.com']
|
|
2710
|
-
},
|
|
2711
|
-
action: {
|
|
2712
|
-
type: 'forward',
|
|
2713
|
-
target: { host: 'backend', port: 443 },
|
|
2714
|
-
tls: { mode: 'passthrough' }
|
|
2715
|
-
}
|
|
2716
|
-
}
|
|
2717
|
-
]
|
|
2718
|
-
});
|
|
2719
|
-
```
|
|
2720
|
-
|
|
2721
|
-
### Immortal Connections (Never Timeout)
|
|
2722
|
-
|
|
2723
|
-
```typescript
|
|
2724
|
-
const proxy = new SmartProxy({
|
|
2725
|
-
// Never timeout keep-alive connections
|
|
2726
|
-
keepAliveTreatment: 'immortal',
|
|
2727
|
-
|
|
2728
|
-
routes: [
|
|
2729
|
-
// ... same as above
|
|
2730
|
-
]
|
|
2731
|
-
});
|
|
2732
|
-
```
|
|
2733
|
-
|
|
2734
|
-
### Understanding the Issue
|
|
2735
|
-
|
|
2736
|
-
In SNI passthrough mode:
|
|
2737
|
-
1. **WebSocket Heartbeat**: The HTTP proxy's WebSocket handler sends ping frames every 30 seconds
|
|
2738
|
-
2. **SNI Passthrough**: In passthrough mode, traffic is encrypted end-to-end
|
|
2739
|
-
3. **Can't Inject Pings**: The proxy can't inject ping frames into encrypted traffic
|
|
2740
|
-
4. **Connection Terminated**: After 30 seconds, connection is marked inactive and closed
|
|
2741
|
-
|
|
2742
|
-
The solution involves:
|
|
2743
|
-
- Longer grace periods for encrypted connections (5 minutes vs 30 seconds)
|
|
2744
|
-
- Relying on OS-level TCP keep-alive instead of application-level heartbeat
|
|
2745
|
-
- Different timeout strategies per route type
|
|
2746
|
-
|
|
2747
|
-
## Configuration Options
|
|
2748
|
-
|
|
2749
|
-
### SmartProxy (IRoutedSmartProxyOptions)
|
|
2750
|
-
- `routes` (IRouteConfig[], required) - Array of route configurations
|
|
2751
|
-
- `defaults` (object) - Default settings for all routes
|
|
2752
|
-
- `acme` (IAcmeOptions) - ACME certificate options
|
|
2753
|
-
- `useHttpProxy` (number[], optional) - Array of ports to forward to HttpProxy (e.g. `[80, 443]`)
|
|
2754
|
-
- `httpProxyPort` (number, default 8443) - Port where HttpProxy listens for forwarded connections
|
|
2755
|
-
- Connection timeouts: `initialDataTimeout`, `socketTimeout`, `inactivityTimeout`, etc.
|
|
2756
|
-
- Socket opts: `noDelay`, `keepAlive`, `enableKeepAliveProbes`
|
|
2757
|
-
- Keep-alive configuration: `keepAliveTreatment` ('standard'|'extended'|'immortal'), `keepAliveInactivityMultiplier`
|
|
2758
|
-
- `certProvisionFunction` (callback) - Custom certificate provisioning
|
|
2759
|
-
|
|
2760
|
-
#### SmartProxy Dynamic Port Management Methods
|
|
2761
|
-
- `async addListeningPort(port: number)` - Add a new port listener without changing routes
|
|
2762
|
-
- `async removeListeningPort(port: number)` - Remove a port listener without changing routes
|
|
2763
|
-
- `getListeningPorts()` - Get all ports currently being listened on
|
|
2764
|
-
- `async updateRoutes(routes: IRouteConfig[])` - Update routes and automatically adjust port listeners
|
|
2765
|
-
|
|
2766
|
-
### HttpProxy (IHttpProxyOptions)
|
|
2767
|
-
- `port` (number, required) - Main port to listen on
|
|
2768
|
-
- `backendProtocol` ('http1'|'http2', default 'http1') - Protocol to use with backend servers
|
|
2769
|
-
- `maxConnections` (number, default 10000) - Maximum concurrent connections
|
|
2770
|
-
- `keepAliveTimeout` (ms, default 120000) - Connection keep-alive timeout
|
|
2771
|
-
- `headersTimeout` (ms, default 60000) - Timeout for receiving complete headers
|
|
2772
|
-
- `cors` (object) - Cross-Origin Resource Sharing configuration
|
|
2773
|
-
- `connectionPoolSize` (number, default 50) - Size of the connection pool for backend servers
|
|
2774
|
-
- `logLevel` ('error'|'warn'|'info'|'debug') - Logging verbosity level
|
|
2775
|
-
- `acme` (IAcmeOptions) - ACME certificate configuration
|
|
2776
|
-
- `useExternalPort80Handler` (boolean) - Use external port 80 handler for ACME challenges
|
|
2777
|
-
- `portProxyIntegration` (boolean) - Integration with other proxies
|
|
2778
|
-
|
|
2779
|
-
#### HttpProxy Enhanced Features
|
|
2780
|
-
HttpProxy now supports full route-based configuration including:
|
|
2781
|
-
- Advanced request and response header manipulation
|
|
2782
|
-
- URL rewriting with RegExp pattern matching
|
|
2783
|
-
- Template variable resolution for dynamic values (e.g. `{domain}`, `{clientIp}`)
|
|
2784
|
-
- Function-based dynamic target resolution
|
|
2785
|
-
- Security features (IP filtering, rate limiting, authentication)
|
|
2786
|
-
- WebSocket configuration with path rewriting, custom headers, ping control, and size limits
|
|
2787
|
-
- Context-aware CORS configuration
|
|
2788
|
-
|
|
2789
|
-
### NfTablesProxy (INfTableProxySettings)
|
|
2790
|
-
- `fromPort` / `toPort` (number|range|array)
|
|
2791
|
-
- `toHost` (string, default 'localhost')
|
|
2792
|
-
- `preserveSourceIP`, `deleteOnExit`, `protocol`, `enableLogging`, `ipv6Support` (booleans)
|
|
2793
|
-
- `allowedSourceIPs`, `bannedSourceIPs` (string[])
|
|
2794
|
-
- `useIPSets` (boolean, default true)
|
|
2795
|
-
- `qos`, `netProxyIntegration` (objects)
|
|
2796
|
-
|
|
2797
|
-
## Documentation
|
|
2798
|
-
|
|
2799
|
-
- [Certificate Management](docs/certificate-management.md) - Detailed guide on certificate provisioning and ACME integration
|
|
2800
|
-
- [Port Handling](docs/porthandling.md) - Dynamic port management and runtime configuration
|
|
2801
|
-
- [NFTables Integration](docs/nftables-integration.md) - High-performance kernel-level forwarding
|
|
2802
|
-
|
|
2803
|
-
## Troubleshooting
|
|
2804
|
-
|
|
2805
|
-
### SmartProxy
|
|
2806
|
-
- If routes aren't matching as expected, check their priorities
|
|
2807
|
-
- For domain matching issues, verify SNI extraction is working
|
|
2808
|
-
- Use higher priority for block routes to ensure they take precedence
|
|
2809
|
-
- Enable `enableDetailedLogging` or `enableTlsDebugLogging` for debugging
|
|
2810
|
-
- Security configuration must be at route level (`route.security`), not in action
|
|
2811
|
-
|
|
2812
|
-
### ACME HTTP-01 Challenges
|
|
2813
|
-
- If ACME HTTP-01 challenges fail, ensure:
|
|
2814
|
-
1. Port 80 (or configured ACME port) is included in `useHttpProxy`
|
|
2815
|
-
2. You're using SmartProxy v19.3.9+ for proper timing (ports must be listening before provisioning)
|
|
2816
|
-
- Since v19.3.8: Non-TLS connections on ports listed in `useHttpProxy` are properly forwarded to HttpProxy
|
|
2817
|
-
- Since v19.3.9: Certificate provisioning waits for ports to be ready before starting ACME challenges
|
|
2818
|
-
- Example configuration for ACME on port 80:
|
|
2819
|
-
```typescript
|
|
2820
|
-
const proxy = new SmartProxy({
|
|
2821
|
-
useHttpProxy: [80], // Ensure port 80 is forwarded to HttpProxy
|
|
2822
|
-
httpProxyPort: 8443,
|
|
2823
|
-
acme: {
|
|
2824
|
-
email: 'ssl@example.com',
|
|
2825
|
-
port: 80
|
|
2826
|
-
},
|
|
2827
|
-
routes: [/* your routes */]
|
|
2828
|
-
});
|
|
2829
|
-
```
|
|
2830
|
-
- Common issues:
|
|
2831
|
-
- "Connection refused" during challenges → Update to v19.3.9+ for timing fix
|
|
2832
|
-
- HTTP requests not parsed → Ensure port is in `useHttpProxy` array
|
|
2833
|
-
|
|
2834
|
-
### Socket Handlers
|
|
2835
|
-
- Socket handlers require initial data from the client to trigger routing
|
|
2836
|
-
- For async handlers, initial data is buffered until handler setup completes (v19.5.0+)
|
|
2837
|
-
- Use `SocketHandlers.httpServer` for ACME challenge handling in custom implementations
|
|
2838
|
-
- Test socket handlers with telnet or nc for debugging
|
|
2839
|
-
|
|
2840
|
-
### NFTables Integration
|
|
2841
|
-
- Ensure NFTables is installed: `apt install nftables` or `yum install nftables`
|
|
2842
|
-
- Verify root/sudo permissions for NFTables operations
|
|
2843
|
-
- Check NFTables service is running: `systemctl status nftables`
|
|
2844
|
-
- For debugging, check the NFTables rules: `nft list ruleset`
|
|
2845
|
-
- Monitor NFTables rule status: `await proxy.getNfTablesStatus()`
|
|
2846
|
-
|
|
2847
|
-
### TLS/Certificates
|
|
2848
|
-
- For certificate issues, check the ACME settings and domain validation
|
|
2849
|
-
- Ensure domains are publicly accessible for Let's Encrypt validation
|
|
2850
|
-
- For TLS handshake issues, increase `initialDataTimeout` and `maxPendingDataSize`
|
|
2851
|
-
- Certificate configuration can be global or per-route
|
|
2852
|
-
|
|
2853
|
-
### HttpProxy
|
|
2854
|
-
- Verify ports, certificates and `rejectUnauthorized` for TLS errors
|
|
2855
|
-
- Configure CORS for preflight issues
|
|
2856
|
-
- Increase `maxConnections` or `connectionPoolSize` under load
|
|
2857
|
-
- HttpProxy is designed for HTTPS/TLS termination, use direct forwarding for plain HTTP
|
|
2858
|
-
|
|
2859
|
-
### Security Configuration
|
|
2860
|
-
- Security must be defined at route level: `route.security`
|
|
2861
|
-
- IP lists support glob patterns: `192.168.*`, `10.?.?.1`
|
|
2862
|
-
- Block lists take precedence over allow lists
|
|
2863
|
-
- Authentication requires TLS termination
|
|
2864
|
-
- Route matching is separate from security enforcement
|
|
2865
|
-
|
|
2866
|
-
### NfTablesProxy
|
|
2867
|
-
- Ensure `nft` is installed and run with sufficient privileges
|
|
2868
|
-
- Use `forceCleanSlate:true` to clear conflicting rules
|
|
2869
|
-
- Check kernel modules are loaded: `lsmod | grep nf_tables`
|
|
991
|
+
1. Fork the repository
|
|
992
|
+
2. Create a feature branch
|
|
993
|
+
3. Write tests for new functionality
|
|
994
|
+
4. Ensure all tests pass
|
|
995
|
+
5. Submit a pull request
|
|
2870
996
|
|
|
2871
997
|
## License and Legal Information
|
|
2872
998
|
|