From 26f7431111aff1f37dafd773fefb3cd18da6039f Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Mon, 21 Jul 2025 12:23:22 +0000 Subject: [PATCH] fix(docs): update documentation to improve clarity --- changelog.md | 8 + package.json | 2 +- readme.md | 3026 ++++++++++---------------------------------------- 3 files changed, 585 insertions(+), 2451 deletions(-) diff --git a/changelog.md b/changelog.md index 2005a3f..7fb3bcb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-07-21 - 20.0.2 - fix(docs) +Update documentation to improve clarity + +- Enhanced readme with clearer breaking change warning for v20.0.0 +- Fixed example email address from ssl@bleu.de to ssl@example.com +- Added load balancing and failover features to feature list +- Improved documentation structure and examples + ## 2025-07-20 - 20.0.1 - BREAKING_CHANGE(routing) Refactor route configuration to support multiple targets diff --git a/package.json b/package.json index 26aa8f9..b88ec8c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@push.rocks/smartproxy", - "version": "20.0.1", + "version": "20.0.2", "private": false, "description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.", "main": "dist_ts/index.js", diff --git a/readme.md b/readme.md index e68cb47..69ca6c8 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ A unified high-performance proxy toolkit for Node.js, with **SmartProxy** as the - **Security Features**: Route-specific IP allowlists, blocklists, connection limits, and authentication - **NFTables Integration**: High-performance kernel-level packet forwarding with Linux NFTables - **Socket Handlers**: Custom socket handling for specialized protocols and use cases +- **Multiple Targets**: Load balancing and failover with support for multiple upstream targets ## Project Architecture Overview @@ -61,6 +62,7 @@ SmartProxy has been restructured using a modern, modular architecture with a uni - Automatic certificate management - Advanced security controls - Custom socket handling capabilities + - Load balancing with multiple targets ### Helper Functions @@ -110,7 +112,9 @@ npm install @push.rocks/smartproxy ## Quick Start with SmartProxy -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. +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. + +**⚠️ 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. ```typescript import { @@ -142,11 +146,11 @@ import { const proxy = new SmartProxy({ // Global ACME settings for all routes with certificate: 'auto' acme: { - email: 'ssl@bleu.de', // Required for Let's Encrypt - useProduction: false, // Use staging by default - renewThresholdDays: 30, // Renew 30 days before expiry - port: 80, // Port for HTTP-01 challenges (use 8080 for non-privileged) - autoRenew: true, // Enable automatic renewal + email: 'ssl@example.com', // Required for Let's Encrypt + useProduction: false, // Use staging by default + renewThresholdDays: 30, // Renew 30 days before expiry + port: 80, // Port for HTTP-01 challenges (use 8080 for non-privileged) + autoRenew: true, // Enable automatic renewal renewCheckIntervalHours: 24 // Check for renewals daily }, @@ -229,7 +233,7 @@ const proxy = new SmartProxy({ }, action: { type: 'forward', - target: { host: 'localhost', port: 8080 }, + targets: [{ host: 'localhost', port: 8080 }], // Note: targets is an array tls: { mode: 'terminate', certificate: 'auto' @@ -298,291 +302,262 @@ The `match` property defines criteria for identifying which incoming traffic sho ```typescript interface IRouteMatch { - // Listen on these ports (required) - ports: TPortRange; // number | number[] | Array<{ from: number; to: number }> - - // Optional domain patterns to match (default: all domains) - domains?: string | string[]; // Supports wildcards like '*.example.com' - - // Advanced matching criteria (all optional) - path?: string; // Match specific URL paths, supports glob patterns - clientIp?: string[]; // Match specific client IPs, supports glob patterns - tlsVersion?: string[]; // Match specific TLS versions e.g. ['TLSv1.2', 'TLSv1.3'] - headers?: Record; // Match specific HTTP headers + // Port(s) to match + ports: number | number[] | string; // Single port, array, or range like '8000-8999' + + // Domain matching (optional - if not specified, matches all domains) + domains?: string | string[]; // Exact domains or patterns with wildcards + + // Path matching (optional) + path?: string; // URL path pattern (supports wildcards) + + // Client IP matching (optional) + clientIp?: string | string[]; // IP addresses or CIDR ranges + + // Protocol matching (optional) + protocol?: 'tcp' | 'udp' | 'http' | 'https' | 'ws' | 'wss'; + + // TLS version matching (optional) + tlsVersion?: string | string[]; // e.g., ['TLSv1.2', 'TLSv1.3'] + + // Custom matcher function (optional) + customMatcher?: (context: IRouteContext) => boolean | Promise; } ``` -**Port Specification:** -- **Single port:** `ports: 80` -- **Multiple ports:** `ports: [80, 443]` -- **Port ranges:** `ports: [{ from: 8000, to: 8100 }]` -- **Mixed format:** `ports: [80, 443, { from: 8000, to: 8100 }]` +**Domain Matching Patterns:** +- Exact match: `example.com` +- Wildcard subdomain: `*.example.com` +- Multiple domains: `['example.com', '*.example.com', 'example.org']` +- All domains: omit the `domains` field -**Domain Matching:** -- **Single domain:** `domains: 'example.com'` -- **Multiple domains:** `domains: ['example.com', 'api.example.com']` -- **Wildcard domains:** `domains: '*.example.com'` (matches any subdomain) -- **Root domain + subdomains:** `domains: ['example.com', '*.example.com']` +**Path Matching Patterns:** +- Exact path: `/api/users` +- Path prefix with wildcard: `/api/*` +- Path with parameter: `/api/users/:id` +- Multiple path segments: `/api/*/details` -**Path Matching:** -- **Exact path:** `path: '/api'` (matches only /api exactly) -- **Prefix match:** `path: '/api/*'` (matches /api and any paths under it) -- **Multiple patterns:** Use multiple routes with different priorities +#### Action Types (IRouteAction) -**Client IP Matching:** -- **Exact IP:** `clientIp: ['192.168.1.1']` -- **Subnet wildcards:** `clientIp: ['10.0.0.*', '192.168.1.*']` -- **CIDR notation:** `clientIp: ['10.0.0.0/24']` - -**TLS Version Matching:** -- `tlsVersion: ['TLSv1.2', 'TLSv1.3']` (only match these TLS versions) - -#### Action Configuration (IRouteAction) - -The `action` property defines what to do with traffic that matches the criteria: +The `action` property defines what to do with matched traffic: ```typescript interface IRouteAction { // Action type (required) - type: 'forward' | 'socket-handler'; - - // For 'forward' actions - target?: IRouteTarget; - - // TLS handling for 'forward' actions + type: 'forward' | 'redirect' | 'block' | 'socket-handler'; + + // For 'forward' type - array of upstream targets + targets?: IRouteTarget[]; + + // For 'redirect' type + redirectUrl?: string; // URL template with placeholders + redirectCode?: number; // HTTP status code (301, 302, etc.) + + // For 'socket-handler' type + socketHandler?: (socket: net.Socket, context: IRouteContext) => void | Promise; + + // TLS configuration (optional) tls?: IRouteTls; - - // For 'socket-handler' actions - socketHandler?: TSocketHandler; - - // WebSocket support - websocket?: IRouteWebSocket; - - // Load balancing options - loadBalancing?: IRouteLoadBalancing; - - // Advanced options - advanced?: IRouteAdvanced; - // Additional backend-specific options - options?: { - backendProtocol?: 'http1' | 'http2'; - [key: string]: any; + // WebSocket configuration (optional) + websocket?: { + enabled: boolean; + pingInterval?: number; // Milliseconds between pings + pingTimeout?: number; // Milliseconds to wait for pong + }; + + // Headers manipulation (optional) + headers?: { + request?: Record; // Headers to add to requests + response?: Record; // Headers to add to responses }; - - // Forwarding engine selection - forwardingEngine?: 'node' | 'nftables'; - - // NFTables-specific options - nftables?: INfTablesOptions; } ``` -#### Security Configuration (IRouteSecurity) - -Security is configured at the route level, not within the action: - +**Forward Action with Multiple Targets:** ```typescript -interface IRouteSecurity { - // Access control lists - ipAllowList?: string[]; // IP addresses that are allowed to connect - ipBlockList?: string[]; // IP addresses that are blocked from connecting - - // Connection limits - maxConnections?: number; // Maximum concurrent connections - - // Authentication (requires TLS termination) - authentication?: IRouteAuthentication; - - // Rate limiting - rateLimit?: IRouteRateLimit; -} -``` - -### ACME/Let's Encrypt Configuration - -SmartProxy supports automatic certificate provisioning and renewal with Let's Encrypt. ACME can be configured globally or per-route. - -#### Global ACME Configuration -Set default ACME settings for all routes with `certificate: 'auto'`: - -```typescript -const proxy = new SmartProxy({ - // Global ACME configuration - acme: { - email: 'ssl@example.com', // Required - Let's Encrypt account email - useProduction: false, // Use staging (false) or production (true) - renewThresholdDays: 30, // Renew certificates 30 days before expiry - port: 80, // Port for HTTP-01 challenges - certificateStore: './certs', // Directory to store certificates - autoRenew: true, // Enable automatic renewal - renewCheckIntervalHours: 24 // Check for renewals every 24 hours - }, - - routes: [ - // This route will use the global ACME settings - { - name: 'website', - match: { ports: 443, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { - mode: 'terminate', - certificate: 'auto' // Uses global ACME configuration - } - } - } +{ + type: 'forward', + targets: [ + { host: 'backend1.example.com', port: 8080 }, + { host: 'backend2.example.com', port: 8080 }, + { host: 'backend3.example.com', port: 8080 } ] -}); +} ``` -#### Route-Specific ACME Configuration -Override global settings for specific routes: - +**Redirect Action:** ```typescript { - name: 'api', - match: { ports: 443, domains: 'api.example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 3000 }, - tls: { - mode: 'terminate', - certificate: 'auto', - acme: { - email: 'api-ssl@example.com', // Different email for this route - useProduction: true, // Use production while global uses staging - renewBeforeDays: 60 // Route-specific renewal threshold - } - } - } -} -``` - -### Action Types - -**Forward Action:** -When `type: 'forward'`, the traffic is forwarded to the specified target: -```typescript -interface IRouteTarget { - host: string | string[] | ((context: IRouteContext) => string | string[]); // Target host(s) - string array enables round-robin, function enables dynamic routing - port: number | 'preserve' | ((context: IRouteContext) => number); // Target port - 'preserve' keeps incoming port, function enables dynamic port mapping -} -``` - -**TLS Configuration:** -When forwarding with TLS, you can configure how TLS is handled: -```typescript -interface IRouteTls { - mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt'; - certificate?: 'auto' | { // 'auto' = use ACME (Let's Encrypt) - key: string; // TLS private key content - cert: string; // TLS certificate content - }; -} -``` - -**TLS Modes:** -- **passthrough:** Forward raw encrypted TLS traffic without decryption -- **terminate:** Terminate TLS and forward as HTTP -- **terminate-and-reencrypt:** Terminate TLS and create a new TLS connection to the backend - -**Forwarding Engine:** -When `forwardingEngine` is specified, it determines how packets are forwarded: -- **node:** (default) Application-level forwarding using Node.js -- **nftables:** Kernel-level forwarding using Linux NFTables (requires root privileges) - -**NFTables Options:** -When using `forwardingEngine: 'nftables'`, you can configure: -```typescript -interface INfTablesOptions { - protocol?: 'tcp' | 'udp' | 'all'; - preserveSourceIP?: boolean; - maxRate?: string; // Rate limiting (e.g., '100mbps') - priority?: number; // QoS priority - tableName?: string; // Custom NFTables table name - useIPSets?: boolean; // Use IP sets for performance - useAdvancedNAT?: boolean; // Use connection tracking -} -``` - -**Redirect and Block Actions:** -Redirects and blocks are implemented using socket handlers. Use the helper functions or pre-built handlers: -```typescript -// HTTP to HTTPS redirect -createHttpToHttpsRedirect('example.com', 443) - -// Block connections -{ - action: { - type: 'socket-handler', - socketHandler: SocketHandlers.httpBlock(403, 'Access denied') - } + type: 'redirect', + redirectUrl: 'https://{domain}/{path}', // Placeholders: {domain}, {path}, {clientIp} + redirectCode: 301 } ``` **Socket Handler Action:** -When `type: 'socket-handler'`, custom socket handling logic is applied: ```typescript -type TSocketHandler = (socket: net.Socket, context: IRouteContext) => void | Promise; +{ + type: 'socket-handler', + socketHandler: (socket, context) => { + // Custom logic for handling the socket + socket.write('Hello from custom handler\n'); + socket.end(); + } +} ``` -The socket handler receives: -- `socket`: The raw Node.js Socket object -- `context`: Route context containing clientIp, port, domain, route info, etc. +### Route Examples -### Socket Handlers +#### Basic HTTP Forwarding +```typescript +{ + match: { + ports: 80, + domains: 'api.example.com' + }, + action: { + type: 'forward', + targets: [{ host: 'localhost', port: 3000 }] + } +} +``` -SmartProxy v19.5.0 introduces socket handlers for custom protocol handling: +#### HTTPS with TLS Termination and Load Balancing +```typescript +{ + match: { + ports: 443, + domains: ['secure.example.com', '*.secure.example.com'] + }, + action: { + type: 'forward', + targets: [ + { host: '10.0.0.10', port: 8080 }, + { host: '10.0.0.11', port: 8080 }, + { host: '10.0.0.12', port: 8080 } + ], + tls: { + mode: 'terminate', + certificate: 'auto' // Automatic Let's Encrypt certificate + } + } +} +``` + +#### WebSocket Route +```typescript +{ + match: { + ports: 443, + domains: 'ws.example.com', + path: '/socket/*' + }, + action: { + type: 'forward', + targets: [{ host: 'websocket-server', port: 8080 }], + tls: { + mode: 'terminate', + certificate: 'auto' + }, + websocket: { + enabled: true, + pingInterval: 30000, + pingTimeout: 5000 + } + } +} +``` + +#### API Gateway with Security +```typescript +{ + match: { + ports: 443, + domains: 'api.example.com', + path: '/v1/*' + }, + action: { + type: 'forward', + targets: [{ host: 'api-backend', port: 8080 }], + tls: { + mode: 'terminate', + certificate: 'auto' + }, + headers: { + request: { + 'X-API-Version': 'v1', + 'X-Real-IP': '{clientIp}' + }, + response: { + 'Access-Control-Allow-Origin': '*', + 'X-Powered-By': 'SmartProxy' + } + } + }, + security: { + ipAllowList: ['10.0.0.0/8', '172.16.0.0/12'], + rateLimit: { + maxRequests: 100, + windowMs: 60000 + }, + authentication: { + type: 'basic', + realm: 'API Access', + users: { + 'apiuser': 'hashedpassword' + } + } + } +} +``` + +## NFTables Integration + +SmartProxy includes high-performance kernel-level packet forwarding using Linux NFTables. This provides ultra-low latency forwarding by operating at the kernel level. + +### Requirements +- Linux kernel with NFTables support +- Root/sudo privileges +- `nft` command-line tool installed + +### NFTables Route Example +```typescript +// Basic NFTables forwarding +createNfTablesRoute('fast.example.com', { host: 'backend', port: 8080 }, { + ports: 80, + protocol: 'tcp', + preserveSourceIP: true +}) + +// NFTables with TLS termination +createNfTablesTerminateRoute('secure-fast.example.com', { host: 'backend', port: 8080 }, { + ports: 443, + certificate: 'auto', + maxRate: '100mbps' +}) +``` + +## Socket Handlers + +SmartProxy supports custom socket handlers for implementing specialized protocols or custom logic: + +### Pre-built Socket Handlers ```typescript -// Create a custom socket handler route -createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => { - console.log(`New connection from ${context.clientIp}`); - - // Custom protocol handling - socket.write('Welcome to custom protocol server\n'); - - socket.on('data', (data) => { - // Process custom protocol data - const response = processProtocolData(data); - socket.write(response); - }); - - socket.on('error', (err) => { - console.error('Socket error:', err); - }); -}); - -// Use pre-built socket handlers -import { SocketHandlers } from '@push.rocks/smartproxy'; - // Echo server -createSocketHandlerRoute('echo.example.com', 7000, SocketHandlers.echo), +createSocketHandlerRoute('echo.example.com', 7, SocketHandlers.echo) -// TCP proxy -createSocketHandlerRoute('proxy.example.com', 8000, SocketHandlers.proxy('backend-server', 8080)), +// HTTP redirect +createHttpToHttpsRedirect('example.com') // Line-based protocol createSocketHandlerRoute('telnet.example.com', 23, SocketHandlers.lineProtocol((line, socket) => { socket.write(`You said: ${line}\n`); -})), +})) -// HTTP response -createSocketHandlerRoute('simple.example.com', 8080, SocketHandlers.httpResponse(200, 'Hello World')), - -// HTTP redirect -createSocketHandlerRoute('redirect.example.com', 80, SocketHandlers.httpRedirect('https://{domain}{path}', 301)), - -// HTTP blocking with custom message -createSocketHandlerRoute('forbidden.example.com', 80, SocketHandlers.httpBlock(403, 'Access Forbidden')), - -// Block connections immediately -createSocketHandlerRoute('blocked.example.com', 443, SocketHandlers.block('Access denied')), - -// Full HTTP server for complex handling -createSocketHandlerRoute('http-api.example.com', 8080, SocketHandlers.httpServer((req, res) => { +// HTTP server for custom logic +createSocketHandlerRoute('custom.example.com', 8080, SocketHandlers.httpServer((req, res) => { if (req.url === '/health') { res.status(200); res.send('OK'); @@ -590,447 +565,297 @@ createSocketHandlerRoute('http-api.example.com', 8080, SocketHandlers.httpServer res.status(404); res.send('Not Found'); } + res.end(); })) + +// Block connections +createSocketHandlerRoute('blocked.example.com', 443, SocketHandlers.block('Access Denied')) + +// TCP proxy +createSocketHandlerRoute('proxy.example.com', 8080, SocketHandlers.proxy('internal-server', 3000)) ``` -### Dynamic Routing - -SmartProxy supports dynamic routing using functions for host and port selection: - -```typescript -// Dynamic host selection based on domain -createDynamicRoute({ - ports: 80, - domains: ['*.tenant.example.com'], - targetHost: (context) => { - // Extract tenant from subdomain - const tenant = context.domain.split('.')[0]; - return `${tenant}-backend`; - }, - portMapper: (context) => 8080 -}); - -// Port mapping with offset -createOffsetPortMappingRoute({ - ports: [8000, 8001, 8002], - targetHost: 'backend', - offset: -1000 // Maps 8000->7000, 8001->7001, etc. -}); - -// Smart load balancer with domain-based routing -createSmartLoadBalancer({ - ports: 443, - domainTargets: { - 'api.example.com': ['api-1', 'api-2'], - 'web.example.com': ['web-1', 'web-2', 'web-3'], - 'admin.example.com': 'admin-server' - }, - portMapper: (context) => 8080, - defaultTarget: 'fallback-server' -}); -``` - -### Route Context - -The `IRouteContext` interface provides information about the current connection: - -```typescript -interface IRouteContext { - clientIp: string; // Client's IP address - port: number; // Incoming port - domain?: string; // Domain from SNI or Host header - path?: string; // Request path (HTTP only) - sni?: string; // SNI hostname (TLS only) - protocol?: string; // Protocol information - route?: IRouteConfig; // Matched route configuration -} -``` - -### Template Variables - -String values in redirect URLs and headers can include variables: - -- `{domain}`: The requested domain name -- `{port}`: The incoming port number -- `{path}`: The requested URL path -- `{query}`: The query string -- `{clientIp}`: The client's IP address -- `{sni}`: The SNI hostname - -Example with template variables: -```typescript -redirect: { - to: 'https://{domain}{path}?source=redirect', - status: 301 -} -``` - -## Forwarding Modes Guide - -This section provides a comprehensive reference for all forwarding modes available in SmartProxy, helping you choose the right configuration for your use case. - -### Visual Overview - -```mermaid -graph TD - A[Incoming Traffic] --> B{Action Type?} - - B -->|forward| C{TLS Mode?} - B -->|socket-handler| D[Custom Handler] - - C -->|terminate| E[Decrypt TLS] - C -->|passthrough| F[Forward Encrypted] - C -->|terminate-and-reencrypt| G[Decrypt & Re-encrypt] - C -->|none/HTTP| H[Forward HTTP] - - E --> I{Engine?} - F --> I - G --> I - H --> I - - I -->|node| J[Node.js Processing] - I -->|nftables| K[Kernel NAT] - - J --> L[Backend] - K --> L - D --> M[Custom Logic] - - style B fill:#f9f,stroke:#333,stroke-width:2px - style C fill:#bbf,stroke:#333,stroke-width:2px - style I fill:#bfb,stroke:#333,stroke-width:2px -``` - -### Overview - -SmartProxy offers flexible traffic forwarding through combinations of: -- **Action Types**: How to handle matched traffic -- **TLS Modes**: How to handle HTTPS/TLS connections -- **Forwarding Engines**: Where packet processing occurs - -### Quick Reference - -#### Modern Route-Based Configuration - -| Use Case | Action Type | TLS Mode | Engine | Performance | Security | -|----------|------------|----------|---------|-------------|----------| -| HTTP web server | `forward` | N/A | `node` | Good | Basic | -| HTTPS web server (inspect traffic) | `forward` | `terminate` | `node` | Good | Full inspection | -| HTTPS passthrough (no inspection) | `forward` | `passthrough` | `node` | Better | End-to-end encryption | -| HTTPS gateway (re-encrypt to backend) | `forward` | `terminate-and-reencrypt` | `node` | Moderate | Full control | -| High-performance TCP forwarding | `forward` | `passthrough` | `nftables` | Excellent | Basic | -| Custom protocol handling | `socket-handler` | N/A | `node` | Varies | Custom | - -#### Legacy Forwarding Types (Deprecated) - -| Legacy Type | Modern Equivalent | -|------------|------------------| -| `http-only` | `action.type: 'forward'` with port 80 | -| `https-passthrough` | `action.type: 'forward'` + `tls.mode: 'passthrough'` | -| `https-terminate-to-http` | `action.type: 'forward'` + `tls.mode: 'terminate'` | -| `https-terminate-to-https` | `action.type: 'forward'` + `tls.mode: 'terminate-and-reencrypt'` | - -### Forwarding Mode Categories - -#### 1. Action Types - -##### Forward Action -Routes traffic to a backend server. This is the most common action type. - -```typescript -{ - action: { - type: 'forward', - target: { - host: 'backend-server', - port: 8080 - } - } -} -``` - -##### Socket Handler Action -Provides custom handling for any TCP protocol. Used for specialized protocols or custom logic. +### Custom Socket Handler ```typescript { + match: { + ports: 9999, + domains: 'custom.example.com' + }, action: { type: 'socket-handler', socketHandler: async (socket, context) => { - // Custom protocol implementation - } - } -} -``` - -#### 2. TLS Modes (for Forward Action) - -##### Passthrough Mode -- **What**: Forwards encrypted TLS traffic without decryption -- **When**: Backend handles its own TLS termination -- **Pros**: Maximum performance, true end-to-end encryption -- **Cons**: Cannot inspect or modify HTTPS traffic - -```mermaid -graph LR - Client -->|TLS| SmartProxy - SmartProxy -->|TLS| Backend - style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px -``` - -##### Terminate Mode -- **What**: Decrypts TLS, forwards as plain HTTP -- **When**: Backend doesn't support HTTPS or you need to inspect traffic -- **Pros**: Can modify headers, inspect content, add security headers -- **Cons**: Backend connection is unencrypted - -```mermaid -graph LR - Client -->|TLS| SmartProxy - SmartProxy -->|HTTP| Backend - style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px -``` - -##### Terminate-and-Reencrypt Mode -- **What**: Decrypts TLS, then creates new TLS connection to backend -- **When**: Need traffic inspection but backend requires HTTPS -- **Pros**: Full control while maintaining backend security -- **Cons**: Higher CPU usage, increased latency - -```mermaid -graph LR - Client -->|TLS| SmartProxy - SmartProxy -->|New TLS| Backend - style SmartProxy fill:#f9f,stroke:#333,stroke-width:2px -``` - -#### 3. Forwarding Engines - -##### Node.js Engine (Default) -- **Processing**: Application-level in Node.js event loop -- **Features**: Full protocol support, header manipulation, WebSockets -- **Performance**: Good for most use cases -- **Use when**: You need application-layer features - -##### NFTables Engine -- **Processing**: Kernel-level packet forwarding -- **Features**: Basic NAT, minimal overhead -- **Performance**: Excellent, near wire-speed -- **Use when**: Maximum performance is critical -- **Requirements**: Linux, root permissions, NFTables installed - -### Detailed Mode Explanations - -#### HTTP Forwarding (Port 80) - -Simple HTTP forwarding without encryption: - -```typescript -{ - match: { ports: 80, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 } - } -} -``` - -**Data Flow**: Client → SmartProxy (HTTP) → Backend (HTTP) - -#### HTTPS with TLS Termination - -Decrypt HTTPS and forward as HTTP: - -```typescript -{ - match: { ports: 443, domains: 'secure.example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { - mode: 'terminate', - certificate: 'auto' // Use Let's Encrypt - } - } -} -``` - -**Data Flow**: Client → SmartProxy (HTTPS decrypt) → Backend (HTTP) - -#### HTTPS Passthrough - -Forward encrypted traffic without decryption: - -```typescript -{ - match: { ports: 443, domains: 'legacy.example.com' }, - action: { - type: 'forward', - target: { host: '192.168.1.10', port: 443 }, - tls: { - mode: 'passthrough' - } - } -} -``` - -**Data Flow**: Client → SmartProxy (TLS forwarding) → Backend (Original TLS) - -#### HTTPS Gateway (Terminate and Re-encrypt) - -Decrypt, inspect, then re-encrypt to backend: - -```typescript -{ - match: { ports: 443, domains: 'api.example.com' }, - action: { - type: 'forward', - target: { host: 'api-backend', port: 443 }, - tls: { - mode: 'terminate-and-reencrypt', - certificate: 'auto' - }, - advanced: { - headers: { - 'X-Forwarded-Proto': 'https', - 'X-Real-IP': '{clientIp}' - } - } - } -} -``` - -**Data Flow**: Client → SmartProxy (HTTPS decrypt) → SmartProxy (New HTTPS) → Backend - -#### High-Performance NFTables Forwarding - -Kernel-level forwarding for maximum performance: - -```typescript -{ - match: { ports: 443, domains: 'fast.example.com' }, - action: { - type: 'forward', - target: { host: 'backend', port: 443 }, - tls: { mode: 'passthrough' }, - forwardingEngine: 'nftables', - nftables: { - preserveSourceIP: true, - maxRate: '10gbps' - } - } -} -``` - -**Data Flow**: Client → Kernel (NFTables NAT) → Backend - -#### Custom Socket Handler - -Handle custom protocols or implement specialized logic: - -```typescript -{ - match: { ports: 9000, domains: 'custom.example.com' }, - action: { - type: 'socket-handler', - socketHandler: async (socket, context) => { - console.log(`Connection from ${context.clientIp}`); + console.log(`New connection from ${context.clientIp} to ${context.domain}`); - socket.write('Welcome to custom protocol server\n'); + socket.write('Welcome to the custom protocol server\n'); socket.on('data', (data) => { - // Handle custom protocol - const response = processCustomProtocol(data); - socket.write(response); + // Process incoming data + const command = data.toString().trim(); + + if (command === 'QUIT') { + socket.end('Goodbye\n'); + } else { + socket.write(`Unknown command: ${command}\n`); + } + }); + + socket.on('error', (err) => { + console.error('Socket error:', err); }); } } } ``` -### Decision Guide +## Dynamic Port Management -#### Choose HTTP Forwarding When: -- Backend only supports HTTP -- Internal services not exposed to internet -- Development/testing environments +SmartProxy allows you to dynamically add or remove listening ports without restarting: -#### Choose HTTPS Termination When: -- Need to inspect/modify HTTP traffic -- Backend doesn't support HTTPS -- Want to add security headers -- Need to cache responses +```typescript +// Add a new listening port +await proxy.addListeningPort(8443); -#### Choose HTTPS Passthrough When: -- Backend manages its own certificates -- Need true end-to-end encryption -- Compliance requires no MITM -- WebSocket connections to backend +// Remove a listening port +await proxy.removeListeningPort(8080); -#### Choose HTTPS Terminate-and-Reencrypt When: -- Need traffic inspection AND backend requires HTTPS -- API gateway scenarios -- Adding authentication layers -- Different certificates for client/backend +// Get all currently listening ports +const ports = proxy.getListeningPorts(); // [80, 443, 8443] +``` -#### Choose NFTables Engine When: -- Handling 1Gbps+ traffic -- Thousands of concurrent connections -- Minimal latency is critical -- Don't need application-layer features +## Certificate Management -#### Choose Socket Handler When: -- Implementing custom protocols -- Need fine-grained connection control -- Building protocol adapters -- Special authentication flows +SmartProxy includes automatic certificate management with Let's Encrypt support: -### Complete Examples +### Automatic Certificates (Let's Encrypt) +```typescript +{ + action: { + tls: { + mode: 'terminate', + certificate: 'auto' // Automatic Let's Encrypt certificate + } + } +} +``` -#### Example 1: Complete Web Application +### Manual Certificates +```typescript +{ + action: { + tls: { + mode: 'terminate', + certificate: { + key: fs.readFileSync('./certs/private.key', 'utf8'), + cert: fs.readFileSync('./certs/certificate.crt', 'utf8') + } + } + } +} +``` +### Certificate Store +Certificates are automatically stored and managed: +- Auto certificates: `./certificates/{domain}/` +- Manual certificates: In-memory only + +## Security Features + +### IP-Based Access Control +```typescript +{ + security: { + ipAllowList: ['10.0.0.0/8', '192.168.*', '::1'], + ipBlockList: ['192.168.1.100', '10.0.0.0/24'] + } +} +``` + +### Connection Limits +```typescript +{ + security: { + maxConnections: 1000, // Total connections + maxConnectionsPerIp: 10 // Per IP address + } +} +``` + +### Rate Limiting +```typescript +{ + security: { + rateLimit: { + maxRequests: 100, // Maximum requests + windowMs: 60000 // Time window (1 minute) + } + } +} +``` + +### Authentication +```typescript +// Basic Authentication +{ + security: { + authentication: { + type: 'basic', + realm: 'Protected Area', + users: { + 'admin': 'hashedpassword' + } + } + } +} + +// JWT Authentication +{ + security: { + authentication: { + type: 'jwt', + secret: 'your-secret-key', + algorithms: ['HS256'] + } + } +} +``` + +## Advanced Features + +### Custom Route Matching +```typescript +{ + match: { + ports: 443, + customMatcher: async (context) => { + // Custom logic to determine if route should match + const hour = new Date().getHours(); + return hour >= 9 && hour < 17; // Only match during business hours + } + } +} +``` + +### Header Manipulation +```typescript +{ + action: { + headers: { + request: { + 'X-Real-IP': '{clientIp}', + 'X-Forwarded-For': '{clientIp}', + 'X-Custom-Header': 'value' + }, + response: { + 'X-Powered-By': 'SmartProxy', + 'Strict-Transport-Security': 'max-age=31536000' + } + } + } +} +``` + +### Dynamic Target Selection +```typescript +{ + action: { + type: 'forward', + targets: [ + { + host: ['backend1.example.com', 'backend2.example.com'], // Round-robin + port: (context) => { + // Dynamic port based on path + return context.path.startsWith('/api/v1') ? 8081 : 8080; + } + } + ] + } +} +``` + +## Complete Examples + +### Multi-Domain HTTPS Server with Redirects +```typescript +const proxy = new SmartProxy({ + acme: { + email: 'admin@example.com', + useProduction: true + }, + routes: [ + // HTTPS routes + ...['example.com', 'app.example.com', 'api.example.com'].map(domain => + createHttpsTerminateRoute(domain, { host: 'localhost', port: 3000 }, { + certificate: 'auto' + }) + ), + + // HTTP to HTTPS redirects + createHttpToHttpsRedirect(['example.com', '*.example.com']) + ] +}); +``` + +### API Gateway with Multiple Services ```typescript const proxy = new SmartProxy({ routes: [ - // HTTP to HTTPS redirect - { - match: { ports: 80, domains: ['example.com', 'www.example.com'] }, - action: { - type: 'socket-handler', - socketHandler: SocketHandlers.httpRedirect('https://{domain}{path}') - } - }, + // User service + createApiRoute('api.example.com', '/users', { host: 'user-service', port: 8081 }), - // Main website with TLS termination + // Product service + createApiRoute('api.example.com', '/products', { host: 'product-service', port: 8082 }), + + // Order service with authentication { - match: { ports: 443, domains: ['example.com', 'www.example.com'] }, + match: { + ports: 443, + domains: 'api.example.com', + path: '/orders/*' + }, action: { type: 'forward', - target: { host: 'web-backend', port: 3000 }, + targets: [{ host: 'order-service', port: 8083 }], + tls: { + mode: 'terminate', + certificate: 'auto' + } + }, + security: { + authentication: { + type: 'jwt', + secret: process.env.JWT_SECRET + } + } + } + ] +}); +``` + +### WebSocket Server with Load Balancing +```typescript +const proxy = new SmartProxy({ + routes: [ + { + match: { + ports: 443, + domains: 'ws.example.com' + }, + action: { + type: 'forward', + targets: [ + { host: 'ws-server-1', port: 8080 }, + { host: 'ws-server-2', port: 8080 }, + { host: 'ws-server-3', port: 8080 } + ], tls: { mode: 'terminate', certificate: 'auto' }, - websocket: { enabled: true } - } - }, - - // API with re-encryption - { - match: { ports: 443, domains: 'api.example.com' }, - action: { - type: 'forward', - target: { host: 'api-backend', port: 443 }, - tls: { - mode: 'terminate-and-reencrypt', - certificate: 'auto' - } - }, - security: { - ipAllowList: ['10.0.0.0/8'], - rateLimit: { + websocket: { enabled: true, - maxRequests: 100, - window: 60 + pingInterval: 30000 } } } @@ -1038,1835 +863,136 @@ const proxy = new SmartProxy({ }); ``` -#### Example 2: Multi-Mode Proxy Setup +## Troubleshooting +### Common Issues + +#### Certificate Provisioning +- Ensure domains are publicly accessible +- Check firewall rules for port 80 (ACME challenges) +- Verify DNS resolution +- Check ACME email configuration + +#### Connection Issues +- Verify route matching criteria +- Check security rules (IP lists, authentication) +- Ensure target servers are accessible +- Check for port conflicts + +#### Performance Issues +- Consider using NFTables for high-traffic routes +- Adjust connection pool sizes +- Enable connection keep-alive +- Monitor resource usage + +### Debug Mode +Enable detailed logging: ```typescript const proxy = new SmartProxy({ - routes: [ - // Legacy app with passthrough - { - match: { ports: 443, domains: 'legacy.example.com' }, - action: { - type: 'forward', - target: { host: 'legacy-server', port: 443 }, - tls: { mode: 'passthrough' } - } - }, - - // High-performance streaming with NFTables - { - match: { ports: 8080, domains: 'stream.example.com' }, - action: { - type: 'forward', - target: { host: 'stream-backend', port: 8080 }, - forwardingEngine: 'nftables', - nftables: { - protocol: 'tcp', - preserveSourceIP: true - } - } - }, - - // Custom protocol handler - { - match: { ports: 9999 }, - action: { - type: 'socket-handler', - socketHandler: SocketHandlers.proxy('custom-backend', 9999) - } - } - ] -}); -``` - -### Performance Considerations - -#### Node.js Engine Performance - -| Metric | Typical Performance | -|--------|-------------------| -| Throughput | 1-10 Gbps | -| Connections | 10,000-50,000 concurrent | -| Latency | 1-5ms added | -| CPU Usage | Moderate | - -**Best for**: Most web applications, APIs, sites needing inspection - -#### NFTables Engine Performance - -| Metric | Typical Performance | -|--------|-------------------| -| Throughput | 10-100 Gbps | -| Connections | 100,000+ concurrent | -| Latency | <0.1ms added | -| CPU Usage | Minimal | - -**Best for**: High-traffic services, streaming, gaming, TCP forwarding - -#### Performance Tips - -1. **Use passthrough mode** when you don't need inspection -2. **Enable NFTables** for high-traffic services -3. **Terminate TLS only when necessary** - it adds CPU overhead -4. **Use connection pooling** for terminate-and-reencrypt mode -5. **Enable HTTP/2** for better multiplexing - -### Security Implications - -#### TLS Termination Security - -**Pros:** -- Inspect traffic for threats -- Add security headers -- Implement WAF rules -- Log requests for audit - -**Cons:** -- Proxy has access to decrypted data -- Requires secure certificate storage -- Potential compliance issues - -**Best Practices:** -- Use auto-renewal with Let's Encrypt -- Store certificates securely -- Implement proper access controls -- Use strong TLS configurations - -#### Passthrough Security - -**Pros:** -- True end-to-end encryption -- No MITM concerns -- Backend controls security - -**Cons:** -- Cannot inspect traffic -- Cannot add security headers -- Limited DDoS protection - -#### Socket Handler Security - -**Risks:** -- Custom code may have vulnerabilities -- Resource exhaustion possible -- Authentication bypass risks - -**Mitigations:** -```typescript -{ - action: { - type: 'socket-handler', - socketHandler: async (socket, context) => { - // Always validate and sanitize input - socket.on('data', (data) => { - if (data.length > MAX_SIZE) { - socket.destroy(); - return; - } - // Process safely... - }); - - // Set timeouts - socket.setTimeout(30000); - - // Rate limit connections - if (connectionsFromIP(context.clientIp) > 10) { - socket.destroy(); - } - } - } -} -``` - -### Migration from Legacy Types - -#### From `http-only` - -**Old:** -```typescript -{ - type: 'http-only', - target: { host: 'localhost', port: 8080 } -} -``` - -**New:** -```typescript -{ - match: { ports: 80, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 } - } -} -``` - -#### From `https-passthrough` - -**Old:** -```typescript -{ - type: 'https-passthrough', - target: { host: 'backend', port: 443 } -} -``` - -**New:** -```typescript -{ - match: { ports: 443, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'backend', port: 443 }, - tls: { mode: 'passthrough' } - } -} -``` - -#### From `https-terminate-to-http` - -**Old:** -```typescript -{ - type: 'https-terminate-to-http', - target: { host: 'localhost', port: 8080 }, - ssl: { /* certs */ } -} -``` - -**New:** -```typescript -{ - match: { ports: 443, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { - mode: 'terminate', - certificate: 'auto' // or provide cert/key - } - } -} -``` - -#### From `https-terminate-to-https` - -**Old:** -```typescript -{ - type: 'https-terminate-to-https', - target: { host: 'backend', port: 443 }, - ssl: { /* certs */ } -} -``` - -**New:** -```typescript -{ - match: { ports: 443, domains: 'example.com' }, - action: { - type: 'forward', - target: { host: 'backend', port: 443 }, - tls: { - mode: 'terminate-and-reencrypt', - certificate: 'auto' - } - } -} -``` - -### Helper Functions Quick Reference - -SmartProxy provides helper functions for common configurations: - -```typescript -// HTTP forwarding -createHttpRoute('example.com', { host: 'localhost', port: 8080 }) - -// HTTPS with termination -createHttpsTerminateRoute('secure.com', { host: 'localhost', port: 8080 }, { - certificate: 'auto' -}) - -// HTTPS passthrough -createHttpsPassthroughRoute('legacy.com', { host: 'backend', port: 443 }) - -// Complete HTTPS setup (includes HTTP redirect) -...createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, { - certificate: 'auto' -}) - -// NFTables high-performance -createNfTablesRoute('fast.com', { host: 'backend', port: 8080 }, { - ports: 80, - preserveSourceIP: true -}) - -// Custom socket handler -createSocketHandlerRoute('custom.com', 9000, async (socket, context) => { - // Handler implementation -}) -``` - -### Summary - -SmartProxy's forwarding modes provide flexibility for any proxy scenario: - -- **Simple HTTP/HTTPS forwarding** for most web applications -- **TLS passthrough** for end-to-end encryption -- **TLS termination** for traffic inspection and modification -- **NFTables** for extreme performance requirements -- **Socket handlers** for custom protocols - -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. - -### Route Metadata and Prioritization - -You can add metadata to routes to help with organization and control matching priority: - -```typescript -{ - name: 'API Server', // Human-readable name - description: 'Main API endpoints', // Description - priority: 100, // Matching priority (higher = matched first) - tags: ['api', 'internal'] // Arbitrary tags -} -``` - -Routes with higher priority values are matched first, allowing you to create specialized routes that take precedence over more general ones. - -### Complete Route Configuration Example - -```typescript -// Example of a complete route configuration -{ - match: { - ports: 443, - domains: ['api.example.com', 'api-v2.example.com'], - path: '/secure/*', - clientIp: ['10.0.0.*', '192.168.1.*'] - }, - action: { - type: 'forward', - target: { - host: ['10.0.0.1', '10.0.0.2'], // Round-robin between these hosts - port: 8080 - }, - tls: { - mode: 'terminate', - certificate: 'auto' // Use Let's Encrypt - }, - advanced: { - timeout: 30000, - headers: { - 'X-Original-Host': '{domain}', - 'X-Client-IP': '{clientIp}' - }, - keepAlive: true - } - }, - security: { - ipAllowList: ['10.0.0.*'], - maxConnections: 100 - }, - name: 'Secure API Route', - description: 'Route for secure API endpoints with authentication', - priority: 100, - tags: ['api', 'secure', 'internal'] -} - -// Example with NFTables forwarding engine -{ - match: { - ports: [80, 443], - domains: 'high-traffic.example.com' - }, - action: { - type: 'forward', - target: { - host: 'backend-server', - port: 8080 - }, - forwardingEngine: 'nftables', // Use kernel-level forwarding - nftables: { - protocol: 'tcp', - preserveSourceIP: true, - maxRate: '1gbps', - useIPSets: true - } - }, - security: { - ipAllowList: ['10.0.0.*'], - ipBlockList: ['malicious.ip.range.*'] - }, - name: 'High Performance NFTables Route', - description: 'Kernel-level forwarding for maximum performance', - priority: 150 -} -``` - -## Using Helper Functions - -While you can create route configurations manually, SmartProxy provides helper functions to make it easier: - -```typescript -// Instead of building the full object: -const route = { - match: { ports: 80, domains: 'example.com' }, - action: { type: 'forward', target: { host: 'localhost', port: 8080 } }, - name: 'Web Server' -}; - -// Use the helper function for cleaner syntax: -const route = createHttpRoute('example.com', { host: 'localhost', port: 8080 }, { - name: 'Web Server' -}); -``` - -Available helper functions: -- `createHttpRoute()` - Create an HTTP forwarding route -- `createHttpsTerminateRoute()` - Create an HTTPS route with TLS termination -- `createHttpsPassthroughRoute()` - Create an HTTPS passthrough route -- `createHttpToHttpsRedirect()` - Create an HTTP to HTTPS redirect using socket handler -- `createCompleteHttpsServer()` - Create a complete HTTPS server setup with HTTP redirect -- `createLoadBalancerRoute()` - Create a route for load balancing across multiple backends -- `createApiRoute()` - Create an API route with path matching and CORS support -- `createWebSocketRoute()` - Create a route for WebSocket connections -- `createSocketHandlerRoute()` - Create a route with custom socket handling -- `createNfTablesRoute()` - Create a high-performance NFTables route -- `createNfTablesTerminateRoute()` - Create an NFTables route with TLS termination -- `createCompleteNfTablesHttpsServer()` - Create a complete NFTables HTTPS setup with HTTP redirect -- `createPortMappingRoute()` - Create a route with dynamic port mapping -- `createOffsetPortMappingRoute()` - Create a route with port offset mapping -- `createDynamicRoute()` - Create a route with dynamic host/port selection -- `createSmartLoadBalancer()` - Create a smart load balancer with domain-based routing -- `createApiGatewayRoute()` - Create an API gateway route with advanced features -- `addRateLimiting()` - Add rate limiting to a route -- `addBasicAuth()` - Add basic authentication to a route -- `addJwtAuth()` - Add JWT authentication to a route - -## What You Can Do with SmartProxy - -1. **Route-Based Traffic Management** - ```typescript - // Route requests for different domains to different backend servers - createHttpsTerminateRoute('api.example.com', { host: 'api-server', port: 3000 }, { - certificate: 'auto' - }) - ``` - -2. **Automatic SSL with Let's Encrypt** - ```typescript - // Get and automatically renew certificates - createHttpsTerminateRoute('secure.example.com', { host: 'localhost', port: 8080 }, { - certificate: 'auto' - }) - ``` - -3. **Load Balancing** - ```typescript - // Distribute traffic across multiple backend servers - createLoadBalancerRoute( - 'app.example.com', - ['10.0.0.1', '10.0.0.2', '10.0.0.3'], - 8080, - { - tls: { - mode: 'terminate', - certificate: 'auto' - } - } - ) - ``` - -4. **Security Controls** - ```typescript - // Restrict access based on IP addresses - { - match: { ports: 443, domains: 'admin.example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { mode: 'terminate', certificate: 'auto' } - }, - security: { - ipAllowList: ['10.0.0.*', '192.168.1.*'], - maxConnections: 100 - } - } - ``` - -5. **Wildcard Domains** - ```typescript - // Handle all subdomains with one config - createHttpsPassthroughRoute(['example.com', '*.example.com'], { host: 'backend-server', port: 443 }) - ``` - -6. **Path-Based Routing** - ```typescript - // Route based on URL path - createApiRoute('example.com', '/api', { host: 'api-server', port: 3000 }, { - useTls: true, - certificate: 'auto' - }) - ``` - -7. **Block Malicious Traffic** - ```typescript - // Block traffic from specific IPs or patterns - { - match: { ports: [80, 443], clientIp: ['1.2.3.*', '5.6.7.*'] }, - action: { - type: 'socket-handler', - socketHandler: SocketHandlers.httpBlock(403, 'Access denied') - }, - priority: 1000 // High priority to ensure blocking - } - ``` - -8. **Dynamic Port Management** - ```typescript - // Start the proxy with initial configuration - const proxy = new SmartProxy({ - routes: [ - createHttpRoute('example.com', { host: 'localhost', port: 8080 }) - ] - }); - await proxy.start(); - - // Dynamically add a new port listener - await proxy.addListeningPort(8081); - - // Add a route for the new port - const currentRoutes = proxy.settings.routes; - const newRoute = createHttpRoute('api.example.com', { host: 'api-server', port: 3000 }); - newRoute.match.ports = 8081; // Override the default port - - // Update routes - will automatically sync port listeners - await proxy.updateRoutes([...currentRoutes, newRoute]); - - // Later, remove a port listener when needed - await proxy.removeListeningPort(8081); - ``` - -9. **High-Performance NFTables Routing** - ```typescript - // Use kernel-level packet forwarding for maximum performance - createNfTablesRoute('high-traffic.example.com', { host: 'backend', port: 8080 }, { - ports: 80, - preserveSourceIP: true, - maxRate: '1gbps' - }) - ``` - -10. **Custom Protocol Handling** - ```typescript - // Implement custom protocols or specialized handling - createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => { - // Your custom protocol logic here - socket.write('CUSTOM PROTOCOL v1.0\n'); - - socket.on('data', (data) => { - // Handle custom protocol messages - const response = processCustomProtocol(data); - socket.write(response); - }); - }) - ``` - -## Metrics and Monitoring - -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. - -### Enabling Metrics - -```typescript -const proxy = new SmartProxy({ - // Enable metrics collection - metrics: { - enabled: true, - sampleIntervalMs: 1000, // Sample throughput every second - retentionSeconds: 3600 // Keep 1 hour of history - }, - routes: [/* your routes */] -}); - -await proxy.start(); -``` - -### Getting Metrics - -```typescript -// Access metrics through the getMetrics() method -const metrics = proxy.getMetrics(); - -// The metrics object provides grouped methods for different categories -``` - -### Connection Metrics - -Monitor active connections, total connections, and connection distribution: - -```typescript -// Get current active connections -console.log(`Active connections: ${metrics.connections.active()}`); - -// Get total connections since start -console.log(`Total connections: ${metrics.connections.total()}`); - -// Get connections by route -const routeConnections = metrics.connections.byRoute(); -for (const [route, count] of routeConnections) { - console.log(`Route ${route}: ${count} connections`); -} - -// Get connections by IP address -const ipConnections = metrics.connections.byIP(); -for (const [ip, count] of ipConnections) { - console.log(`IP ${ip}: ${count} connections`); -} - -// Get top IPs by connection count -const topIPs = metrics.connections.topIPs(10); -topIPs.forEach(({ ip, count }) => { - console.log(`${ip}: ${count} connections`); -}); -``` - -### Throughput Metrics - -Real-time and historical throughput data with customizable time windows: - -```typescript -// Get instant throughput (last 1 second) -const instant = metrics.throughput.instant(); -console.log(`Current: ${instant.in} bytes/sec in, ${instant.out} bytes/sec out`); - -// Get recent throughput (last 10 seconds average) -const recent = metrics.throughput.recent(); -console.log(`Recent: ${recent.in} bytes/sec in, ${recent.out} bytes/sec out`); - -// Get average throughput (last 60 seconds) -const average = metrics.throughput.average(); -console.log(`Average: ${average.in} bytes/sec in, ${average.out} bytes/sec out`); - -// Get custom time window (e.g., last 5 minutes) -const custom = metrics.throughput.custom(300); -console.log(`5-min avg: ${custom.in} bytes/sec in, ${custom.out} bytes/sec out`); - -// Get throughput history for graphing -const history = metrics.throughput.history(300); // Last 5 minutes -history.forEach(point => { - console.log(`${new Date(point.timestamp)}: ${point.in} in, ${point.out} out`); -}); - -// Get throughput by route -const routeThroughput = metrics.throughput.byRoute(60); // Last 60 seconds -routeThroughput.forEach((stats, route) => { - console.log(`Route ${route}: ${stats.in} in, ${stats.out} out bytes/sec`); -}); - -// Get throughput by IP -const ipThroughput = metrics.throughput.byIP(60); -ipThroughput.forEach((stats, ip) => { - console.log(`IP ${ip}: ${stats.in} in, ${stats.out} out bytes/sec`); -}); -``` - -### Request Metrics - -Track request rates: - -```typescript -// Get requests per second -console.log(`RPS: ${metrics.requests.perSecond()}`); - -// Get requests per minute -console.log(`RPM: ${metrics.requests.perMinute()}`); - -// Get total requests -console.log(`Total requests: ${metrics.requests.total()}`); -``` - -### Cumulative Totals - -Track total bytes transferred and connections: - -```typescript -// Get total bytes -console.log(`Total bytes in: ${metrics.totals.bytesIn()}`); -console.log(`Total bytes out: ${metrics.totals.bytesOut()}`); -console.log(`Total connections: ${metrics.totals.connections()}`); -``` - -### Performance Percentiles - -Get percentile statistics (when implemented): - -```typescript -// Connection duration percentiles -const durations = metrics.percentiles.connectionDuration(); -console.log(`Connection durations - P50: ${durations.p50}ms, P95: ${durations.p95}ms, P99: ${durations.p99}ms`); - -// Bytes transferred percentiles -const bytes = metrics.percentiles.bytesTransferred(); -console.log(`Bytes in - P50: ${bytes.in.p50}, P95: ${bytes.in.p95}, P99: ${bytes.in.p99}`); -console.log(`Bytes out - P50: ${bytes.out.p50}, P95: ${bytes.out.p95}, P99: ${bytes.out.p99}`); -``` - -### Complete Monitoring Example - -```typescript -// Create a monitoring dashboard -setInterval(() => { - const metrics = proxy.getMetrics(); - - // Log key metrics - console.log({ - timestamp: new Date().toISOString(), - connections: { - active: metrics.connections.active(), - total: metrics.connections.total() - }, - throughput: { - instant: metrics.throughput.instant(), - average: metrics.throughput.average() - }, - requests: { - rps: metrics.requests.perSecond(), - total: metrics.requests.total() - }, - totals: { - bytesIn: metrics.totals.bytesIn(), - bytesOut: metrics.totals.bytesOut() - } - }); - - // Alert on high connection counts - const topIPs = metrics.connections.topIPs(5); - topIPs.forEach(({ ip, count }) => { - if (count > 100) { - console.warn(`High connection count from ${ip}: ${count}`); - } - }); - - // Alert on high throughput - const instant = metrics.throughput.instant(); - if (instant.in > 100_000_000) { // 100 MB/s - console.warn(`High incoming throughput: ${instant.in} bytes/sec`); - } -}, 10000); // Every 10 seconds -``` - -### Exporting Metrics - -Export metrics in various formats for external monitoring systems: - -```typescript -// Export as JSON -app.get('/metrics.json', (req, res) => { - const metrics = proxy.getMetrics(); - res.json({ - connections: { - active: metrics.connections.active(), - total: metrics.connections.total(), - byRoute: Object.fromEntries(metrics.connections.byRoute()), - byIP: Object.fromEntries(metrics.connections.byIP()) - }, - throughput: { - instant: metrics.throughput.instant(), - recent: metrics.throughput.recent(), - average: metrics.throughput.average() - }, - requests: { - perSecond: metrics.requests.perSecond(), - perMinute: metrics.requests.perMinute(), - total: metrics.requests.total() - }, - totals: { - bytesIn: metrics.totals.bytesIn(), - bytesOut: metrics.totals.bytesOut(), - connections: metrics.totals.connections() - } - }); -}); - -// Export as Prometheus format -app.get('/metrics', (req, res) => { - const metrics = proxy.getMetrics(); - const instant = metrics.throughput.instant(); - - res.set('Content-Type', 'text/plain'); - res.send(` -# HELP smartproxy_connections_active Current active connections -# TYPE smartproxy_connections_active gauge -smartproxy_connections_active ${metrics.connections.active()} - -# HELP smartproxy_connections_total Total connections since start -# TYPE smartproxy_connections_total counter -smartproxy_connections_total ${metrics.connections.total()} - -# HELP smartproxy_throughput_bytes_per_second Current throughput in bytes per second -# TYPE smartproxy_throughput_bytes_per_second gauge -smartproxy_throughput_bytes_per_second{direction="in"} ${instant.in} -smartproxy_throughput_bytes_per_second{direction="out"} ${instant.out} - -# HELP smartproxy_requests_per_second Current requests per second -# TYPE smartproxy_requests_per_second gauge -smartproxy_requests_per_second ${metrics.requests.perSecond()} - -# HELP smartproxy_bytes_total Total bytes transferred -# TYPE smartproxy_bytes_total counter -smartproxy_bytes_total{direction="in"} ${metrics.totals.bytesIn()} -smartproxy_bytes_total{direction="out"} ${metrics.totals.bytesOut()} -`); -}); -``` - -### Metrics API Reference - -The metrics API is organized into logical groups: - -```typescript -interface IMetrics { - connections: { - active(): number; - total(): number; - byRoute(): Map; - byIP(): Map; - topIPs(limit?: number): Array<{ ip: string; count: number }>; - }; - - throughput: { - instant(): IThroughputData; // Last 1 second - recent(): IThroughputData; // Last 10 seconds - average(): IThroughputData; // Last 60 seconds - custom(seconds: number): IThroughputData; - history(seconds: number): Array; - byRoute(windowSeconds?: number): Map; - byIP(windowSeconds?: number): Map; - }; - - requests: { - perSecond(): number; - perMinute(): number; - total(): number; - }; - - totals: { - bytesIn(): number; - bytesOut(): number; - connections(): number; - }; - - percentiles: { - connectionDuration(): { p50: number; p95: number; p99: number }; - bytesTransferred(): { - in: { p50: number; p95: number; p99: number }; - out: { p50: number; p95: number; p99: number }; - }; - }; -} -``` - -Where `IThroughputData` is: -```typescript -interface IThroughputData { - in: number; // Bytes per second incoming - out: number; // Bytes per second outgoing -} -``` - -And `IThroughputHistoryPoint` is: -```typescript -interface IThroughputHistoryPoint { - timestamp: number; // Unix timestamp in milliseconds - in: number; // Bytes per second at this point - out: number; // Bytes per second at this point -} -``` - -## Other Components - -While SmartProxy provides a unified API for most needs, you can also use individual components: - -### HttpProxy -For HTTP/HTTPS reverse proxy with TLS termination and WebSocket support. Now with native route-based configuration support: - -```typescript -import { HttpProxy } from '@push.rocks/smartproxy'; -import * as fs from 'fs'; - -const proxy = new HttpProxy({ port: 443 }); -await proxy.start(); - -// Modern route-based configuration (recommended) -await proxy.updateRouteConfigs([ - { - match: { - ports: 443, - domains: 'example.com' - }, - action: { - type: 'forward', - target: { - host: '127.0.0.1', - port: 3000 - }, - tls: { - mode: 'terminate', - certificate: { - cert: fs.readFileSync('cert.pem', 'utf8'), - key: fs.readFileSync('key.pem', 'utf8') - } - }, - advanced: { - headers: { - 'X-Forwarded-By': 'HttpProxy' - }, - urlRewrite: { - pattern: '^/old/(.*)$', - target: '/new/$1', - flags: 'g' - } - }, - websocket: { - enabled: true, - pingInterval: 30000 - } - } - } -]); -``` - -### NfTablesProxy -For low-level port forwarding using nftables: - -```typescript -import { NfTablesProxy } from '@push.rocks/smartproxy'; - -const nft = new NfTablesProxy({ - fromPort: 80, - toPort: 8080, - toHost: 'localhost', - preserveSourceIP: true -}); -await nft.start(); -``` - -### SniHandler -For SNI extraction from TLS handshakes: - -```typescript -import { SniHandler } from '@push.rocks/smartproxy'; - -// The SniHandler is typically used internally by SmartProxy -// but can be used directly for custom implementations -``` - -## NFTables Integration - -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. - -### When to Use NFTables - -NFTables routing is ideal for: -- High-traffic TCP/UDP forwarding where performance is critical -- Port forwarding scenarios where you need minimal latency -- Load balancing across multiple backend servers -- Security filtering with IP allowlists/blocklists at kernel level - -### Requirements - -NFTables support requires: -- Linux operating system with NFTables installed -- Root or sudo permissions to configure NFTables rules -- NFTables kernel modules loaded - -### NFTables Route Configuration - -Use the NFTables helper functions to create high-performance routes: - -```typescript -import { SmartProxy, createNfTablesRoute, createNfTablesTerminateRoute } from '@push.rocks/smartproxy'; - -const proxy = new SmartProxy({ - routes: [ - // Basic TCP forwarding with NFTables - createNfTablesRoute('tcp-forward', { - host: 'backend-server', - port: 8080 - }, { - ports: 80, - protocol: 'tcp' - }), - - // NFTables with IP filtering - createNfTablesRoute('secure-tcp', { - host: 'secure-backend', - port: 8443 - }, { - ports: 443, - ipAllowList: ['10.0.0.*', '192.168.1.*'], - preserveSourceIP: true - }), - - // NFTables with QoS (rate limiting) - createNfTablesRoute('limited-service', { - host: 'api-server', - port: 3000 - }, { - ports: 8080, - maxRate: '50mbps', - priority: 1 - }), - - // NFTables TLS termination - createNfTablesTerminateRoute('https-nftables', { - host: 'backend', - port: 8080 - }, { - ports: 443, - certificate: 'auto', - useAdvancedNAT: true - }), - - // Complete NFTables HTTPS server with HTTP redirect - ...createCompleteNfTablesHttpsServer('complete-nftables.example.com', { - host: 'backend', - port: 8080 - }, { - certificate: 'auto', - preserveSourceIP: true - }) - ] -}); - -await proxy.start(); -``` - -### NFTables Route Options - -The NFTables integration supports these options: - -- `protocol`: 'tcp' | 'udp' | 'all' - Protocol to forward -- `preserveSourceIP`: boolean - Preserve client IP for backend -- `ipAllowList`: string[] - Allow only these IPs (glob patterns) -- `ipBlockList`: string[] - Block these IPs (glob patterns) -- `maxRate`: string - Rate limit (e.g., '100mbps', '1gbps') -- `priority`: number - QoS priority level -- `tableName`: string - Custom NFTables table name -- `useIPSets`: boolean - Use IP sets for better performance -- `useAdvancedNAT`: boolean - Enable connection tracking - -### NFTables Status Monitoring - -You can monitor the status of NFTables rules: - -```typescript -// Get status of all NFTables rules -const nftStatus = await proxy.getNfTablesStatus(); - -// Status includes: -// - active: boolean -// - ruleCount: { total, added, removed } -// - packetStats: { forwarded, dropped } -// - lastUpdate: Date -``` - -### Performance Considerations - -NFTables provides significantly better performance than application-level proxying: -- Operates at kernel level with minimal overhead -- Can handle millions of packets per second -- Direct packet forwarding without copying to userspace -- Hardware offload support on compatible network cards - -### Limitations - -NFTables routing has some limitations: -- Cannot modify HTTP headers or content -- Limited to basic NAT and forwarding operations -- Requires root permissions -- Linux-only (not available on Windows/macOS) -- No WebSocket message inspection - -For scenarios requiring application-level features (header manipulation, WebSocket handling, etc.), use the standard SmartProxy routes without NFTables. - -## Migration to v19.5.3 - -Version 19.5.3 includes important fixes and improvements: - -### Key Changes - -1. **Security Configuration Location**: Security configuration is now at the route level (`route.security`), not inside the action (`route.action.security`) -2. **Socket Handler Support**: New `socket-handler` action type for custom protocol handling -3. **Improved ACME Timing**: Certificate provisioning now waits for ports to be ready -4. **Route-Specific Security**: IP allow/block lists are now properly enforced per route -5. **Enhanced Helper Functions**: New helpers for socket handling and NFTables complete server setup - -### Migration Example - -**Before (v18.x and earlier)**: -```typescript -{ - match: { ports: 443, domains: 'api.example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 3000 }, - security: { // WRONG: Security was incorrectly placed here - ipAllowList: ['10.0.0.*'] - } - } -} -``` - -**After (v19.5.3)**: -```typescript -{ - match: { ports: 443, domains: 'api.example.com' }, - action: { - type: 'forward', - target: { host: 'localhost', port: 3000 } - }, - security: { // CORRECT: Security is at the route level - ipAllowList: ['10.0.0.*'] - } -} -``` - -### New Features in v19.5.x - -1. **Socket Handlers** - Custom protocol handling: - ```typescript - createSocketHandlerRoute('custom.example.com', 9000, async (socket, context) => { - // Custom protocol implementation - }) - ``` - -2. **Pre-built Socket Handlers** - Common patterns: - - `SocketHandlers.echo` - Echo server - - `SocketHandlers.proxy` - TCP proxy - - `SocketHandlers.lineProtocol` - Line-based protocols - - `SocketHandlers.httpResponse` - Simple HTTP responses - - `SocketHandlers.httpRedirect` - HTTP redirects - - `SocketHandlers.httpBlock` - HTTP blocking with status code - - `SocketHandlers.block` - Connection blocking - - `SocketHandlers.httpServer` - Full HTTP server handler - -3. **Complete NFTables Server** - HTTPS with HTTP redirect: - ```typescript - ...createCompleteNfTablesHttpsServer('example.com', { - host: 'backend', - port: 8080 - }, { - certificate: 'auto' - }) - ``` - -### Complete Migration Steps - -1. Move any security configuration from `action.security` to `route.security` -2. Update to use new socket handler features for custom protocols -3. Take advantage of improved ACME timing (no action needed, just update) -4. Use the new helper functions for cleaner configuration -5. Review and update any custom route creation code - -## Architecture & Flow Diagrams - -```mermaid -flowchart TB - Client([Client]) - - subgraph "SmartProxy Components" - direction TB - RouteConfig["Route Configuration
(Match/Action)"] - RouteManager["Route Manager"] - SmartProxy["SmartProxy
(TCP/SNI Proxy)"] - HttpProxyBridge["HttpProxy Bridge"] - HttpProxy["HttpProxy
(HTTPS/TLS Termination)"] - NfTablesManager["NFTables Manager
(Kernel Routing)"] - CertManager["SmartCertManager
(ACME/Let's Encrypt)"] - Certs[(SSL Certificates)] - end - - subgraph "Backend Services" - Service1[Service 1] - Service2[Service 2] - Service3[Service 3] - end - - Client -->|HTTP/HTTPS Request| SmartProxy - - SmartProxy -->|Route Matching| RouteManager - RouteManager -->|Use| RouteConfig - RouteManager -->|Execute Action| SmartProxy - - SmartProxy -->|TLS Termination| HttpProxyBridge - HttpProxyBridge -->|Forward| HttpProxy - SmartProxy -->|Kernel Routing| NfTablesManager - - SmartProxy -->|Forward| Service1 - SmartProxy -->|Redirect| Client - SmartProxy -->|Forward| Service2 - SmartProxy -->|Forward| Service3 - - CertManager -.->|Generate/Manage| Certs - Certs -.->|Provide TLS Certs| SmartProxy - Certs -.->|Provide TLS Certs| HttpProxy - - classDef component fill:#f9f,stroke:#333,stroke-width:2px; - classDef backend fill:#bbf,stroke:#333,stroke-width:1px; - classDef client fill:#dfd,stroke:#333,stroke-width:2px; - - class Client client; - class RouteConfig,RouteManager,SmartProxy,HttpProxyBridge,HttpProxy,NfTablesManager,CertManager component; - class Service1,Service2,Service3 backend; -``` - -### Route-Based Connection Handling -This diagram illustrates how requests are matched and processed using the route-based configuration: - -```mermaid -sequenceDiagram - participant Client - participant SmartProxy - participant RouteManager - participant SecurityManager - participant Backend - - Client->>SmartProxy: Connection (TCP/HTTP/HTTPS) - - SmartProxy->>RouteManager: Match connection against routes - - RouteManager->>RouteManager: Check port match - RouteManager->>RouteManager: Check domain match (if SNI) - RouteManager->>RouteManager: Check path match (if HTTP) - RouteManager->>RouteManager: Check client IP match - RouteManager->>RouteManager: Check TLS version match - - RouteManager->>RouteManager: Determine highest priority matching route - - alt Route Matched - SmartProxy->>SecurityManager: Check route security - SecurityManager->>SecurityManager: Validate IP allow/block lists - SecurityManager->>SecurityManager: Check connection limits - - alt Security Check Passed - alt Forward Action - SmartProxy->>SmartProxy: Apply action configuration - - alt TLS Termination - SmartProxy->>SmartProxy: Terminate TLS - SmartProxy->>Backend: Forward as HTTP/HTTPS - else TLS Passthrough - SmartProxy->>Backend: Forward raw TCP - else Socket Handler - SmartProxy->>SmartProxy: Execute custom handler - end - - else Redirect Action - SmartProxy->>Client: Send redirect response - - else Block Action - SmartProxy->>Client: Close connection - end - else Security Check Failed - SmartProxy->>Client: Close connection (unauthorized) - end - else No Route Matched - SmartProxy->>Client: Close connection (no route) - end - - loop Connection Active - SmartProxy-->>SmartProxy: Monitor Activity - SmartProxy-->>SecurityManager: Check Security Rules - alt Security Violation or Timeout - SmartProxy->>Client: Close Connection - SmartProxy->>Backend: Close Connection - end - end -``` - -## Features - -- **Route-Based Traffic Management** - • Match/action pattern for flexible routing - • Port, domain, path, client IP, and TLS version matching - • Forward traffic or use custom socket handlers for any protocol - -- **TLS Handling Options** - • TLS passthrough for end-to-end encryption - • TLS termination for content inspection - • TLS termination with re-encryption for gateway scenarios - -- **Automatic ACME Certificates** - • HTTP-01 challenge handling - • Certificate issuance/renewal - • Pluggable storage - • Per-route and global configuration - -- **Security Controls** - • Route-specific IP allow/block lists with glob pattern support - • Connection limits and rate limiting - • Timeout controls and connection monitoring - • Authentication support (Basic, JWT, OAuth) - -- **Load Balancing** - • Round-robin distribution across multiple backends - • Dynamic host selection based on context - • Health checks and failure handling - -- **Custom Protocol Support** - • Socket handler action type for custom protocols - • Pre-built handlers for common patterns - • Full control over socket lifecycle - -- **Advanced Features** - • Custom header manipulation - • URL rewriting - • Template variables for dynamic values - • Priority-based route matching - • WebSocket support with configuration - • Static file serving - -- **High Performance** - • NFTables integration for kernel-level forwarding - • Connection pooling and keep-alive - • Efficient SNI extraction - • Minimal overhead routing - -## Certificate Management - -### Custom Certificate Provision Function - -SmartProxy supports a custom certificate provision function that allows you to provide your own certificate generation logic while maintaining compatibility with Let's Encrypt: - -```typescript -const proxy = new SmartProxy({ - certProvisionFunction: async (domain: string): Promise => { - // Option 1: Return a custom certificate - if (domain === 'internal.example.com') { - return { - cert: customCertPEM, - key: customKeyPEM, - ca: customCAPEM // Optional CA chain - }; - } - - // Option 2: Fallback to Let's Encrypt - return 'http01'; - }, - - // Control fallback behavior when custom provision fails - certProvisionFallbackToAcme: true, // Default: true - + debug: true, routes: [...] }); ``` -**Key Features:** -- Called for any route with `certificate: 'auto'` -- Return custom certificate object or `'http01'` to use Let's Encrypt -- Participates in automatic renewal cycle (checked every 12 hours) -- Custom certificates stored with source type 'custom' for tracking - -**Configuration Options:** -- `certProvisionFunction`: Async function that receives domain and returns certificate or 'http01' -- `certProvisionFallbackToAcme`: Whether to fallback to Let's Encrypt if custom provision fails (default: true) - -**Advanced Example with Certificate Manager:** - +### Route Testing +Test route matching: ```typescript -const certManager = new MyCertificateManager(); - -const proxy = new SmartProxy({ - certProvisionFunction: async (domain: string) => { - try { - // Check if we have a custom certificate for this domain - if (await certManager.hasCustomCert(domain)) { - const cert = await certManager.getCertificate(domain); - return { - cert: cert.certificate, - key: cert.privateKey, - ca: cert.chain - }; - } - - // Use Let's Encrypt for public domains - if (domain.endsWith('.example.com')) { - return 'http01'; - } - - // Generate self-signed for internal domains - if (domain.endsWith('.internal')) { - const selfSigned = await certManager.generateSelfSigned(domain); - return { - cert: selfSigned.cert, - key: selfSigned.key, - ca: '' - }; - } - - // Default to Let's Encrypt - return 'http01'; - } catch (error) { - console.error(`Certificate provision failed for ${domain}:`, error); - // Will fallback to Let's Encrypt if certProvisionFallbackToAcme is true - throw error; - } - }, - - certProvisionFallbackToAcme: true, - - routes: [ - // Routes that use automatic certificates - { - match: { ports: 443, domains: ['app.example.com', '*.internal'] }, - action: { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { mode: 'terminate', certificate: 'auto' } - } - } - ] -}); -``` - -### Certificate Events - -Listen for certificate events via EventEmitter: -- **SmartProxy**: - - `certificate` (domain, publicKey, privateKey, expiryDate, source, isRenewal) - - Events from CertManager are propagated - -```typescript -proxy.on('certificate', (domain, cert, key, expiryDate, source, isRenewal) => { - console.log(`Certificate ${isRenewal ? 'renewed' : 'provisioned'} for ${domain}`); - console.log(`Source: ${source}`); // 'acme', 'static', or 'custom' - console.log(`Expires: ${expiryDate}`); -}); -``` - -## SmartProxy: Common Use Cases - -The SmartProxy component with route-based configuration offers a clean, unified approach to handle virtually any proxy scenario. - -### 1. API Gateway / Backend Routing - -Create a flexible API gateway to route traffic to different microservices based on domain and path: - -```typescript -import { SmartProxy, createApiRoute, createHttpsTerminateRoute } from '@push.rocks/smartproxy'; - -const apiGateway = new SmartProxy({ - routes: [ - // Users API - createApiRoute('api.example.com', '/users', { host: 'users-service', port: 3000 }, { - useTls: true, - certificate: 'auto', - addCorsHeaders: true - }), - - // Products API - createApiRoute('api.example.com', '/products', { host: 'products-service', port: 3001 }, { - useTls: true, - certificate: 'auto', - addCorsHeaders: true - }), - - // Admin dashboard with extra security - { - match: { ports: 443, domains: 'admin.example.com' }, - action: { - type: 'forward', - target: { host: 'admin-dashboard', port: 8080 }, - tls: { mode: 'terminate', certificate: 'auto' } - }, - security: { - ipAllowList: ['10.0.0.*', '192.168.1.*'] // Only allow internal network - } - } - ] +const matchedRoute = proxy.findMatchingRoute({ + port: 443, + domain: 'example.com', + path: '/api/users', + clientIp: '192.168.1.100' }); -await apiGateway.start(); +console.log('Matched route:', matchedRoute?.name); ``` -### 2. Complete HTTPS Server with HTTP Redirect +## Migration Guide -Easily set up a secure HTTPS server with automatic redirection from HTTP: +### From v19.x to v20.x +The main breaking change is the route action configuration: + +**Before (v19.x):** ```typescript -import { SmartProxy, createCompleteHttpsServer } from '@push.rocks/smartproxy'; - -const webServer = new SmartProxy({ - routes: [ - // createCompleteHttpsServer creates both the HTTPS route and HTTP redirect - ...createCompleteHttpsServer('example.com', { host: 'localhost', port: 8080 }, { - certificate: 'auto' - }) - ] -}); - -await webServer.start(); -``` - -### 3. Multi-Tenant Application with Wildcard Domains - -Support dynamically created tenants with wildcard domain matching: - -```typescript -import { SmartProxy, createDynamicRoute } from '@push.rocks/smartproxy'; - -const multiTenantApp = new SmartProxy({ - routes: [ - // Dynamic routing based on subdomain - createDynamicRoute({ - ports: 443, - domains: '*.tenant.example.com', - targetHost: (context) => { - // Extract tenant ID from subdomain - const tenant = context.domain.split('.')[0]; - return `${tenant}-backend.internal`; - }, - portMapper: (context) => 8080 - }), - - // Redirect HTTP to HTTPS for all subdomains - createHttpToHttpsRedirect(['*.tenant.example.com']) - ] -}); - -await multiTenantApp.start(); -``` - -### 4. Complex Multi-Service Infrastructure - -Create a comprehensive proxy solution with multiple services and security controls: - -```typescript -import { - SmartProxy, - createHttpsTerminateRoute, - createHttpsPassthroughRoute, - createSocketHandlerRoute, - createHttpToHttpsRedirect, - SocketHandlers -} from '@push.rocks/smartproxy'; - -const enterpriseProxy = new SmartProxy({ - routes: [ - // Web application with automatic HTTPS - createHttpsTerminateRoute('app.example.com', { host: 'web-app', port: 8080 }, { - certificate: 'auto' - }), - - // Legacy system that needs HTTPS passthrough - createHttpsPassthroughRoute('legacy.example.com', { host: 'legacy-server', port: 443 }), - - // Internal APIs with IP restrictions - { - match: { ports: 443, domains: 'api.internal.example.com' }, - action: { - type: 'forward', - target: { host: 'api-gateway', port: 3000 }, - tls: { mode: 'terminate', certificate: 'auto' } - }, - security: { - ipAllowList: ['10.0.0.0/16', '192.168.0.0/16'], - maxConnections: 500 - } - }, - - // Custom protocol handler - createSocketHandlerRoute('telnet.example.com', 23, SocketHandlers.lineProtocol((line, socket) => { - // Handle telnet-like protocol - socket.write(`Command received: ${line}\n`); - })), - - // Block known malicious IPs - { - match: { ports: [80, 443], clientIp: ['1.2.3.*', '5.6.7.*'] }, - action: { - type: 'socket-handler', - socketHandler: SocketHandlers.block('Access denied') - }, - priority: 1000 // High priority to ensure blocking - }, - - // Redirect all HTTP to HTTPS - createHttpToHttpsRedirect(['*.example.com', 'example.com']) - ], - - // Enable connection timeouts for security - inactivityTimeout: 30000, - - // Using global certificate management - acme: { - email: 'admin@example.com', - useProduction: true, - renewThresholdDays: 30 - } -}); - -await enterpriseProxy.start(); -``` - -## Route-Based Configuration Details - -### Match Criteria Options - -- **ports**: `number | number[] | Array<{ from: number; to: number }>` (required) - Listen on specific ports or port ranges - -- **domains**: `string | string[]` (optional) - Match specific domain names, supports wildcards (e.g., `*.example.com`) - -- **path**: `string` (optional) - Match specific URL paths, supports glob patterns - -- **clientIp**: `string[]` (optional) - Match client IP addresses, supports glob patterns - -- **tlsVersion**: `string[]` (optional) - Match specific TLS versions (e.g., `TLSv1.2`, `TLSv1.3`) - -- **headers**: `Record` (optional) - Match specific HTTP headers - -### Action Types - -1. **Forward**: - ```typescript - { - type: 'forward', - target: { host: 'localhost', port: 8080 }, - tls: { mode: 'terminate', certificate: 'auto' } - } - ``` - -2. **Socket Handler**: - ```typescript - { - type: 'socket-handler', - socketHandler: async (socket, context) => { - // Custom protocol handling - } - } - ``` - -### TLS Modes - -- **passthrough**: Forward raw TLS traffic without decryption -- **terminate**: Terminate TLS and forward as HTTP -- **terminate-and-reencrypt**: Terminate TLS and create a new TLS connection to the backend - -### Template Variables - -Template variables can be used in string values: - -- `{domain}`: The requested domain name -- `{port}`: The incoming port number -- `{path}`: The requested URL path -- `{query}`: The query string -- `{clientIp}`: The client's IP address -- `{sni}`: The SNI hostname - -Example: -```typescript -// Using the HTTP redirect helper -createHttpToHttpsRedirect('old.example.com', 443) - -// Or with custom redirect using socket handler { - match: { ports: 80, domains: 'old.example.com' }, action: { - type: 'socket-handler', - socketHandler: SocketHandlers.httpRedirect('https://new.example.com{path}?source=redirect', 301) + type: 'forward', + target: { host: 'localhost', port: 8080 } // Single target } } ``` -## WebSocket Keep-Alive Configuration - -If your WebSocket connections are disconnecting every 30 seconds in SNI passthrough mode, here's how to configure keep-alive settings: - -### Extended Keep-Alive Treatment (Recommended) - +**After (v20.x):** ```typescript -const proxy = new SmartProxy({ - // Extend timeout for keep-alive connections - keepAliveTreatment: 'extended', - keepAliveInactivityMultiplier: 10, // 10x the base timeout - inactivityTimeout: 14400000, // 4 hours base (40 hours with multiplier) - - routes: [ - { - name: 'websocket-passthrough', - match: { - ports: 443, - domains: ['ws.example.com', 'wss.example.com'] - }, - action: { - type: 'forward', - target: { host: 'backend', port: 443 }, - tls: { mode: 'passthrough' } - } - } - ] -}); +{ + action: { + type: 'forward', + targets: [{ host: 'localhost', port: 8080 }] // Array of targets + } +} ``` -### Immortal Connections (Never Timeout) +Helper functions have been updated to use the new format automatically. + +## Best Practices + +1. **Use Helper Functions**: They provide sensible defaults and reduce configuration errors +2. **Set Route Priorities**: Higher priority routes are matched first +3. **Use Specific Matches**: More specific routes should have higher priorities +4. **Enable Security Features**: Always use IP filtering and rate limiting for public services +5. **Monitor Performance**: Use debug logging and metrics to identify bottlenecks +6. **Regular Certificate Checks**: Monitor certificate expiration and renewal +7. **Graceful Shutdown**: Always call `proxy.stop()` for clean shutdown + +## API Reference + +### SmartProxy Class ```typescript -const proxy = new SmartProxy({ - // Never timeout keep-alive connections - keepAliveTreatment: 'immortal', +class SmartProxy { + constructor(options: IRoutedSmartProxyOptions); - routes: [ - // ... same as above - ] -}); + // Lifecycle methods + start(): Promise; + stop(): Promise; + + // Route management + updateRoutes(routes: IRouteConfig[]): Promise; + addRoute(route: IRouteConfig): Promise; + removeRoute(routeName: string): Promise; + findMatchingRoute(context: Partial): IRouteConfig | null; + + // Port management + addListeningPort(port: number): Promise; + removeListeningPort(port: number): Promise; + getListeningPorts(): number[]; + + // Certificate management + getCertificateInfo(domain: string): ICertificateInfo | null; + renewCertificate(domain: string): Promise; + + // Status and monitoring + getStatus(): IProxyStatus; + getMetrics(): IProxyMetrics; +} ``` -### Understanding the Issue +### Route Configuration Types -In SNI passthrough mode: -1. **WebSocket Heartbeat**: The HTTP proxy's WebSocket handler sends ping frames every 30 seconds -2. **SNI Passthrough**: In passthrough mode, traffic is encrypted end-to-end -3. **Can't Inject Pings**: The proxy can't inject ping frames into encrypted traffic -4. **Connection Terminated**: After 30 seconds, connection is marked inactive and closed +See the TypeScript definitions in: +- `ts/proxies/smart-proxy/models/route-types.ts` +- `ts/proxies/smart-proxy/models/interfaces.ts` -The solution involves: -- Longer grace periods for encrypted connections (5 minutes vs 30 seconds) -- Relying on OS-level TCP keep-alive instead of application-level heartbeat -- Different timeout strategies per route type +## Contributing -## Configuration Options +Contributions are welcome! Please follow these guidelines: -### SmartProxy (IRoutedSmartProxyOptions) -- `routes` (IRouteConfig[], required) - Array of route configurations -- `defaults` (object) - Default settings for all routes -- `acme` (IAcmeOptions) - ACME certificate options -- `useHttpProxy` (number[], optional) - Array of ports to forward to HttpProxy (e.g. `[80, 443]`) -- `httpProxyPort` (number, default 8443) - Port where HttpProxy listens for forwarded connections -- Connection timeouts: `initialDataTimeout`, `socketTimeout`, `inactivityTimeout`, etc. -- Socket opts: `noDelay`, `keepAlive`, `enableKeepAliveProbes` -- Keep-alive configuration: `keepAliveTreatment` ('standard'|'extended'|'immortal'), `keepAliveInactivityMultiplier` -- `certProvisionFunction` (callback) - Custom certificate provisioning - -#### SmartProxy Dynamic Port Management Methods -- `async addListeningPort(port: number)` - Add a new port listener without changing routes -- `async removeListeningPort(port: number)` - Remove a port listener without changing routes -- `getListeningPorts()` - Get all ports currently being listened on -- `async updateRoutes(routes: IRouteConfig[])` - Update routes and automatically adjust port listeners - -### HttpProxy (IHttpProxyOptions) -- `port` (number, required) - Main port to listen on -- `backendProtocol` ('http1'|'http2', default 'http1') - Protocol to use with backend servers -- `maxConnections` (number, default 10000) - Maximum concurrent connections -- `keepAliveTimeout` (ms, default 120000) - Connection keep-alive timeout -- `headersTimeout` (ms, default 60000) - Timeout for receiving complete headers -- `cors` (object) - Cross-Origin Resource Sharing configuration -- `connectionPoolSize` (number, default 50) - Size of the connection pool for backend servers -- `logLevel` ('error'|'warn'|'info'|'debug') - Logging verbosity level -- `acme` (IAcmeOptions) - ACME certificate configuration -- `useExternalPort80Handler` (boolean) - Use external port 80 handler for ACME challenges -- `portProxyIntegration` (boolean) - Integration with other proxies - -#### HttpProxy Enhanced Features -HttpProxy now supports full route-based configuration including: -- Advanced request and response header manipulation -- URL rewriting with RegExp pattern matching -- Template variable resolution for dynamic values (e.g. `{domain}`, `{clientIp}`) -- Function-based dynamic target resolution -- Security features (IP filtering, rate limiting, authentication) -- WebSocket configuration with path rewriting, custom headers, ping control, and size limits -- Context-aware CORS configuration - -### NfTablesProxy (INfTableProxySettings) -- `fromPort` / `toPort` (number|range|array) -- `toHost` (string, default 'localhost') -- `preserveSourceIP`, `deleteOnExit`, `protocol`, `enableLogging`, `ipv6Support` (booleans) -- `allowedSourceIPs`, `bannedSourceIPs` (string[]) -- `useIPSets` (boolean, default true) -- `qos`, `netProxyIntegration` (objects) - -## Documentation - -- [Certificate Management](docs/certificate-management.md) - Detailed guide on certificate provisioning and ACME integration -- [Port Handling](docs/porthandling.md) - Dynamic port management and runtime configuration -- [NFTables Integration](docs/nftables-integration.md) - High-performance kernel-level forwarding - -## Troubleshooting - -### SmartProxy -- If routes aren't matching as expected, check their priorities -- For domain matching issues, verify SNI extraction is working -- Use higher priority for block routes to ensure they take precedence -- Enable `enableDetailedLogging` or `enableTlsDebugLogging` for debugging -- Security configuration must be at route level (`route.security`), not in action - -### ACME HTTP-01 Challenges -- If ACME HTTP-01 challenges fail, ensure: - 1. Port 80 (or configured ACME port) is included in `useHttpProxy` - 2. You're using SmartProxy v19.3.9+ for proper timing (ports must be listening before provisioning) -- Since v19.3.8: Non-TLS connections on ports listed in `useHttpProxy` are properly forwarded to HttpProxy -- Since v19.3.9: Certificate provisioning waits for ports to be ready before starting ACME challenges -- Example configuration for ACME on port 80: - ```typescript - const proxy = new SmartProxy({ - useHttpProxy: [80], // Ensure port 80 is forwarded to HttpProxy - httpProxyPort: 8443, - acme: { - email: 'ssl@example.com', - port: 80 - }, - routes: [/* your routes */] - }); - ``` -- Common issues: - - "Connection refused" during challenges → Update to v19.3.9+ for timing fix - - HTTP requests not parsed → Ensure port is in `useHttpProxy` array - -### Socket Handlers -- Socket handlers require initial data from the client to trigger routing -- For async handlers, initial data is buffered until handler setup completes (v19.5.0+) -- Use `SocketHandlers.httpServer` for ACME challenge handling in custom implementations -- Test socket handlers with telnet or nc for debugging - -### NFTables Integration -- Ensure NFTables is installed: `apt install nftables` or `yum install nftables` -- Verify root/sudo permissions for NFTables operations -- Check NFTables service is running: `systemctl status nftables` -- For debugging, check the NFTables rules: `nft list ruleset` -- Monitor NFTables rule status: `await proxy.getNfTablesStatus()` - -### TLS/Certificates -- For certificate issues, check the ACME settings and domain validation -- Ensure domains are publicly accessible for Let's Encrypt validation -- For TLS handshake issues, increase `initialDataTimeout` and `maxPendingDataSize` -- Certificate configuration can be global or per-route - -### HttpProxy -- Verify ports, certificates and `rejectUnauthorized` for TLS errors -- Configure CORS for preflight issues -- Increase `maxConnections` or `connectionPoolSize` under load -- HttpProxy is designed for HTTPS/TLS termination, use direct forwarding for plain HTTP - -### Security Configuration -- Security must be defined at route level: `route.security` -- IP lists support glob patterns: `192.168.*`, `10.?.?.1` -- Block lists take precedence over allow lists -- Authentication requires TLS termination -- Route matching is separate from security enforcement - -### NfTablesProxy -- Ensure `nft` is installed and run with sufficient privileges -- Use `forceCleanSlate:true` to clear conflicting rules -- Check kernel modules are loaded: `lsmod | grep nf_tables` +1. Fork the repository +2. Create a feature branch +3. Write tests for new functionality +4. Ensure all tests pass +5. Submit a pull request ## License and Legal Information