@push.rocks/smartproxy 20.0.0 → 21.0.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/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 v19.5.3 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.
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@bleu.de', // Required for Let's Encrypt
146
- useProduction: false, // Use staging by default
147
- renewThresholdDays: 30, // Renew 30 days before expiry
148
- port: 80, // Port for HTTP-01 challenges (use 8080 for non-privileged)
149
- autoRenew: true, // Enable automatic renewal
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
- target: { host: 'localhost', port: 8080 },
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
- // Listen on these ports (required)
302
- ports: TPortRange; // number | number[] | Array<{ from: number; to: number }>
303
-
304
- // Optional domain patterns to match (default: all domains)
305
- domains?: string | string[]; // Supports wildcards like '*.example.com'
306
-
307
- // Advanced matching criteria (all optional)
308
- path?: string; // Match specific URL paths, supports glob patterns
309
- clientIp?: string[]; // Match specific client IPs, supports glob patterns
310
- tlsVersion?: string[]; // Match specific TLS versions e.g. ['TLSv1.2', 'TLSv1.3']
311
- headers?: Record<string, string | RegExp>; // Match specific HTTP headers
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
- **Port Specification:**
316
- - **Single port:** `ports: 80`
317
- - **Multiple ports:** `ports: [80, 443]`
318
- - **Port ranges:** `ports: [{ from: 8000, to: 8100 }]`
319
- - **Mixed format:** `ports: [80, 443, { from: 8000, to: 8100 }]`
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
- **TLS Version Matching:**
338
- - `tlsVersion: ['TLSv1.2', 'TLSv1.3']` (only match these TLS versions)
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 Configuration (IRouteAction)
340
+ #### Action Types (IRouteAction)
341
341
 
342
- The `action` property defines what to do with traffic that matches the criteria:
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' actions
350
- target?: IRouteTarget;
351
-
352
- // TLS handling for 'forward' actions
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
- // Additional backend-specific options
368
- options?: {
369
- backendProtocol?: 'http1' | 'http2';
370
- [key: string]: any;
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
- #### Security Configuration (IRouteSecurity)
382
-
383
- Security is configured at the route level, not within the action:
384
-
377
+ **Forward Action with Multiple Targets:**
385
378
  ```typescript
386
- interface IRouteSecurity {
387
- // Access control lists
388
- ipAllowList?: string[]; // IP addresses that are allowed to connect
389
- ipBlockList?: string[]; // IP addresses that are blocked from connecting
390
-
391
- // Connection limits
392
- maxConnections?: number; // Maximum concurrent connections
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
- ### ACME/Let's Encrypt Configuration
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
- SmartProxy supports automatic certificate provisioning and renewal with Let's Encrypt. ACME can be configured globally or per-route.
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
- #### Global ACME Configuration
407
- Set default ACME settings for all routes with `certificate: 'auto'`:
410
+ ### Route Examples
408
411
 
412
+ #### Basic HTTP Forwarding
409
413
  ```typescript
410
- const proxy = new SmartProxy({
411
- // Global ACME configuration
412
- acme: {
413
- email: 'ssl@example.com', // Required - Let's Encrypt account email
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
- routes: [
423
- // This route will use the global ACME settings
424
- {
425
- name: 'website',
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
- #### Route-Specific ACME Configuration
441
- Override global settings for specific routes:
442
-
426
+ #### HTTPS with TLS Termination and Load Balancing
443
427
  ```typescript
444
428
  {
445
- name: 'api',
446
- match: { ports: 443, domains: 'api.example.com' },
429
+ match: {
430
+ ports: 443,
431
+ domains: ['secure.example.com', '*.secure.example.com']
432
+ },
447
433
  action: {
448
434
  type: 'forward',
449
- target: { host: 'localhost', port: 3000 },
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
- ### Action Types
464
-
465
- **Forward Action:**
466
- When `type: 'forward'`, the traffic is forwarded to the specified target:
448
+ #### WebSocket Route
467
449
  ```typescript
468
- interface IRouteTarget {
469
- host: string | string[] | ((context: IRouteContext) => string | string[]); // Target host(s) - string array enables round-robin, function enables dynamic routing
470
- port: number | 'preserve' | ((context: IRouteContext) => number); // Target port - 'preserve' keeps incoming port, function enables dynamic port mapping
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
- **TLS Configuration:**
475
- When forwarding with TLS, you can configure how TLS is handled:
472
+ #### API Gateway with Security
476
473
  ```typescript
477
- interface IRouteTls {
478
- mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
479
- certificate?: 'auto' | { // 'auto' = use ACME (Let's Encrypt)
480
- key: string; // TLS private key content
481
- cert: string; // TLS certificate content
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
- **TLS Modes:**
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
- **Forwarding Engine:**
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
- **NFTables Options:**
497
- When using `forwardingEngine: 'nftables'`, you can configure:
498
- ```typescript
499
- interface INfTablesOptions {
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
- **Redirect and Block Actions:**
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
- // HTTP to HTTPS redirect
514
- createHttpToHttpsRedirect('example.com', 443)
515
-
516
- // Block connections
517
- {
518
- action: {
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
- **Socket Handler Action:**
526
- When `type: 'socket-handler'`, custom socket handling logic is applied:
527
- ```typescript
528
- type TSocketHandler = (socket: net.Socket, context: IRouteContext) => void | Promise<void>;
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
- The socket handler receives:
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
- ### Socket Handlers
543
+ SmartProxy supports custom socket handlers for implementing specialized protocols or custom logic:
536
544
 
537
- SmartProxy v19.5.0 introduces socket handlers for custom protocol handling:
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', 7000, SocketHandlers.echo),
549
+ createSocketHandlerRoute('echo.example.com', 7, SocketHandlers.echo)
563
550
 
564
- // TCP proxy
565
- createSocketHandlerRoute('proxy.example.com', 8000, SocketHandlers.proxy('backend-server', 8080)),
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
- // Full HTTP server for complex handling
585
- createSocketHandlerRoute('http-api.example.com', 8080, SocketHandlers.httpServer((req, res) => {
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
- // Port mapping with offset
614
- createOffsetPortMappingRoute({
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
- // Smart load balancer with domain-based routing
621
- createSmartLoadBalancer({
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
- ### Route Context
634
-
635
- The `IRouteContext` interface provides information about the current connection:
578
+ ### Custom Socket Handler
636
579
 
637
580
  ```typescript
638
- interface IRouteContext {
639
- clientIp: string; // Client's IP address
640
- port: number; // Incoming port
641
- domain?: string; // Domain from SNI or Host header
642
- path?: string; // Request path (HTTP only)
643
- sni?: string; // SNI hostname (TLS only)
644
- protocol?: string; // Protocol information
645
- route?: IRouteConfig; // Matched route configuration
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
- ### Template Variables
612
+ ## Dynamic Port Management
650
613
 
651
- String values in redirect URLs and headers can include variables:
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
- redirect: {
663
- to: 'https://{domain}{path}?source=redirect',
664
- status: 301
665
- }
666
- ```
667
-
668
- ## Forwarding Modes Guide
617
+ // Add a new listening port
618
+ await proxy.addListeningPort(8443);
669
619
 
670
- This section provides a comprehensive reference for all forwarding modes available in SmartProxy, helping you choose the right configuration for your use case.
620
+ // Remove a listening port
621
+ await proxy.removeListeningPort(8080);
671
622
 
672
- ### Visual Overview
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
- ### Overview
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
- ##### Forward Action
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
- type: 'forward',
743
- target: {
744
- host: 'backend-server',
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
- ##### Socket Handler Action
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
- type: 'socket-handler',
758
- socketHandler: async (socket, context) => {
759
- // Custom protocol implementation
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
- #### 2. TLS Modes (for Forward Action)
766
-
767
- ##### Passthrough Mode
768
- - **What**: Forwards encrypted TLS traffic without decryption
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
- #### HTTP Forwarding (Port 80)
824
-
825
- Simple HTTP forwarding without encryption:
663
+ ## Security Features
826
664
 
665
+ ### IP-Based Access Control
827
666
  ```typescript
828
667
  {
829
- match: { ports: 80, domains: 'example.com' },
830
- action: {
831
- type: 'forward',
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
- **Data Flow**: Client → SmartProxy (HTTP) → Backend (HTTP)
838
-
839
- #### HTTPS with TLS Termination
840
-
841
- Decrypt HTTPS and forward as HTTP:
842
-
675
+ ### Connection Limits
843
676
  ```typescript
844
677
  {
845
- match: { ports: 443, domains: 'secure.example.com' },
846
- action: {
847
- type: 'forward',
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
- **Data Flow**: Client → SmartProxy (HTTPS decrypt) → Backend (HTTP)
858
-
859
- #### HTTPS Passthrough
860
-
861
- Forward encrypted traffic without decryption:
862
-
685
+ ### Rate Limiting
863
686
  ```typescript
864
687
  {
865
- match: { ports: 443, domains: 'legacy.example.com' },
866
- action: {
867
- type: 'forward',
868
- target: { host: '192.168.1.10', port: 443 },
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
- **Data Flow**: Client → SmartProxy (TLS forwarding) → Backend (Original TLS)
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
- match: { ports: 443, domains: 'api.example.com' },
885
- action: {
886
- type: 'forward',
887
- target: { host: 'api-backend', port: 443 },
888
- tls: {
889
- mode: 'terminate-and-reencrypt',
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
- #### High-Performance NFTables Forwarding
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
- Kernel-level forwarding for maximum performance:
724
+ ## Advanced Features
907
725
 
726
+ ### Custom Route Matching
908
727
  ```typescript
909
728
  {
910
- match: { ports: 443, domains: 'fast.example.com' },
911
- action: {
912
- type: 'forward',
913
- target: { host: 'backend', port: 443 },
914
- tls: { mode: 'passthrough' },
915
- forwardingEngine: 'nftables',
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
- **Data Flow**: Client → Kernel (NFTables NAT) → Backend
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
- type: 'socket-handler',
935
- socketHandler: async (socket, context) => {
936
- console.log(`Connection from ${context.clientIp}`);
937
-
938
- socket.write('Welcome to custom protocol server\n');
939
-
940
- socket.on('data', (data) => {
941
- // Handle custom protocol
942
- const response = processCustomProtocol(data);
943
- socket.write(response);
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
- ### Decision Guide
951
-
952
- #### Choose HTTP Forwarding When:
953
- - Backend only supports HTTP
954
- - Internal services not exposed to internet
955
- - Development/testing environments
956
-
957
- #### Choose HTTPS Termination When:
958
- - Need to inspect/modify HTTP traffic
959
- - Backend doesn't support HTTPS
960
- - Want to add security headers
961
- - Need to cache responses
962
-
963
- #### Choose HTTPS Passthrough When:
964
- - Backend manages its own certificates
965
- - Need true end-to-end encryption
966
- - Compliance requires no MITM
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
- ### Complete Examples
777
+ ## Complete Examples
988
778
 
989
- #### Example 1: Complete Web Application
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
- // HTTP to HTTPS redirect
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
- // Main website with TLS termination
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
- // API with re-encryption
810
+ // Order service with authentication
1018
811
  {
1019
- match: { ports: 443, domains: 'api.example.com' },
812
+ match: {
813
+ ports: 443,
814
+ domains: 'api.example.com',
815
+ path: '/orders/*'
816
+ },
1020
817
  action: {
1021
818
  type: 'forward',
1022
- target: { host: 'api-backend', port: 443 },
819
+ targets: [{ host: 'order-service', port: 8083 }],
1023
820
  tls: {
1024
- mode: 'terminate-and-reencrypt',
821
+ mode: 'terminate',
1025
822
  certificate: 'auto'
1026
823
  }
1027
824
  },
1028
825
  security: {
1029
- ipAllowList: ['10.0.0.0/8'],
1030
- rateLimit: {
1031
- enabled: true,
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
- #### Example 2: Multi-Mode Proxy Setup
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: { ports: 8080, domains: 'stream.example.com' },
841
+ match: {
842
+ ports: 443,
843
+ domains: 'ws.example.com'
844
+ },
1059
845
  action: {
1060
846
  type: 'forward',
1061
- target: { host: 'stream-backend', port: 8080 },
1062
- forwardingEngine: 'nftables',
1063
- nftables: {
1064
- protocol: 'tcp',
1065
- preserveSourceIP: true
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
- ### Performance Considerations
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
- **Risks:**
1150
- - Custom code may have vulnerabilities
1151
- - Resource exhaustion possible
1152
- - Authentication bypass risks
868
+ ### Common Issues
1153
869
 
1154
- **Mitigations:**
1155
- ```typescript
1156
- {
1157
- action: {
1158
- type: 'socket-handler',
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
- ### Migration from Legacy Types
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
- #### From `http-only`
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
- **Old:**
888
+ ### Debug Mode
889
+ Enable detailed logging:
1186
890
  ```typescript
1187
- {
1188
- type: 'http-only',
1189
- target: { host: 'localhost', port: 8080 }
1190
- }
891
+ const proxy = new SmartProxy({
892
+ debug: true,
893
+ routes: [...]
894
+ });
1191
895
  ```
1192
896
 
1193
- **New:**
897
+ ### Route Testing
898
+ Test route matching:
1194
899
  ```typescript
1195
- {
1196
- match: { ports: 80, domains: 'example.com' },
1197
- action: {
1198
- type: 'forward',
1199
- target: { host: 'localhost', port: 8080 }
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
- **Old:**
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
- **New:**
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
- #### From `https-terminate-to-http`
912
+ ### From v19.x to v20.x
1227
913
 
1228
- **Old:**
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
- **New:**
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
- #### From `https-terminate-to-https`
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
- target: { host: 'backend', port: 443 },
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
- ### Helper Functions Quick Reference
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
- ```typescript
1600
- // Access metrics through the getMetrics() method
1601
- const metrics = proxy.getMetrics();
938
+ ## Best Practices
1602
939
 
1603
- // The metrics object provides grouped methods for different categories
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
- ### Connection Metrics
948
+ ## API Reference
1607
949
 
1608
- Monitor active connections, total connections, and connection distribution:
950
+ ### SmartProxy Class
1609
951
 
1610
952
  ```typescript
1611
- // Get current active connections
1612
- console.log(`Active connections: ${metrics.connections.active()}`);
1613
-
1614
- // Get total connections since start
1615
- console.log(`Total connections: ${metrics.connections.total()}`);
1616
-
1617
- // Get connections by route
1618
- const routeConnections = metrics.connections.byRoute();
1619
- for (const [route, count] of routeConnections) {
1620
- console.log(`Route ${route}: ${count} connections`);
1621
- }
1622
-
1623
- // Get connections by IP address
1624
- const ipConnections = metrics.connections.byIP();
1625
- for (const [ip, count] of ipConnections) {
1626
- console.log(`IP ${ip}: ${count} connections`);
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
- ### Request Metrics
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
- // Get total requests
1688
- console.log(`Total requests: ${metrics.requests.total()}`);
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
- ### Cumulative Totals
987
+ ## Contributing
1692
988
 
1693
- Track total bytes transferred and connections:
989
+ Contributions are welcome! Please follow these guidelines:
1694
990
 
1695
- ```typescript
1696
- // Get total bytes
1697
- console.log(`Total bytes in: ${metrics.totals.bytesIn()}`);
1698
- console.log(`Total bytes out: ${metrics.totals.bytesOut()}`);
1699
- console.log(`Total connections: ${metrics.totals.connections()}`);
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