- Correct action types to only 'forward' and 'socket-handler' - Remove references to non-existent helper functions (createStaticFileRoute, createSecurityConfig, etc.) - Add documentation for missing helper functions (createPortMappingRoute, createDynamicRoute, etc.) - Update all code examples to use correct API (redirects/blocks via socket handlers) - Fix interface definitions to match actual codebase - Add comprehensive socket handler documentation and examples - Clarify that security configuration is at route level, not action level - Update architecture section to reflect current module structure - Remove references to deprecated modules (Port80Handler, certificate module)
1761 lines
57 KiB
Markdown
1761 lines
57 KiB
Markdown
# @push.rocks/smartproxy
|
|
|
|
A unified high-performance proxy toolkit for Node.js, with **SmartProxy** as the central API to handle all your proxy needs:
|
|
|
|
- **Unified Route-Based Configuration**: Match/action pattern for clean, consistent traffic routing
|
|
- **SSL/TLS Support**: Automatic HTTPS with Let's Encrypt certificate provisioning
|
|
- **Flexible Matching Patterns**: Route by port, domain, path, client IP, and TLS version
|
|
- **Advanced SNI Handling**: Smart TCP/SNI-based forwarding with IP filtering
|
|
- **Multiple Action Types**: Forward traffic or handle with custom socket handlers
|
|
- **Dynamic Port Management**: Add or remove listening ports at runtime without restart
|
|
- **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
|
|
|
|
## Project Architecture Overview
|
|
|
|
SmartProxy has been restructured using a modern, modular architecture with a unified route-based configuration system:
|
|
|
|
```
|
|
/ts
|
|
├── /core # Core functionality
|
|
│ ├── /models # Data models and interfaces
|
|
│ ├── /utils # Shared utilities (IP validation, logging, etc.)
|
|
│ └── /events # Common event definitions
|
|
├── /forwarding # Forwarding system
|
|
│ ├── /handlers # Various forwarding handlers
|
|
│ │ ├── base-handler.ts # Abstract base handler
|
|
│ │ ├── http-handler.ts # HTTP-only handler
|
|
│ │ └── ... # Other handlers
|
|
│ ├── /config # Configuration models
|
|
│ └── /factory # Factory for creating handlers
|
|
├── /proxies # Different proxy implementations
|
|
│ ├── /smart-proxy # SmartProxy implementation
|
|
│ │ ├── /models # SmartProxy-specific interfaces
|
|
│ │ │ ├── route-types.ts # Route-based configuration types
|
|
│ │ │ └── interfaces.ts # SmartProxy interfaces
|
|
│ │ ├── certificate-manager.ts # SmartCertManager
|
|
│ │ ├── cert-store.ts # Certificate file storage
|
|
│ │ ├── route-helpers.ts # Helper functions for creating routes
|
|
│ │ ├── route-manager.ts # Route management system
|
|
│ │ ├── smart-proxy.ts # Main SmartProxy class
|
|
│ │ └── ... # Supporting classes
|
|
│ ├── /http-proxy # HttpProxy implementation (HTTP/HTTPS handling)
|
|
│ └── /nftables-proxy # NfTablesProxy implementation
|
|
├── /tls # TLS-specific functionality
|
|
│ ├── /sni # SNI handling components
|
|
│ └── /alerts # TLS alerts system
|
|
└── /routing # Routing functionality
|
|
└── /router # HTTP routing system
|
|
```
|
|
|
|
## Main Components
|
|
|
|
### Primary API (Recommended)
|
|
|
|
- **SmartProxy** (`ts/proxies/smart-proxy/smart-proxy.ts`)
|
|
The central unified API for all proxy needs, featuring:
|
|
- Route-based configuration with match/action pattern
|
|
- Flexible matching criteria (ports, domains, paths, client IPs)
|
|
- Multiple action types (forward, redirect, block, socket-handler)
|
|
- Automatic certificate management
|
|
- Advanced security controls
|
|
- Custom socket handling capabilities
|
|
|
|
### Helper Functions
|
|
|
|
- **createHttpRoute**, **createHttpsTerminateRoute**, **createHttpsPassthroughRoute**
|
|
Helper functions to create different route configurations with clean syntax
|
|
- **createHttpToHttpsRedirect**
|
|
Helper function for HTTP to HTTPS redirects using socket handlers
|
|
- **createLoadBalancerRoute**, **createCompleteHttpsServer**
|
|
Helper functions for complex configurations
|
|
- **createSocketHandlerRoute**, **SocketHandlers**
|
|
Helper functions for custom socket handling
|
|
- **createNfTablesRoute**, **createNfTablesTerminateRoute**, **createCompleteNfTablesHttpsServer**
|
|
Helper functions for NFTables-based high-performance kernel-level routing
|
|
- **createPortMappingRoute**, **createOffsetPortMappingRoute**, **createDynamicRoute**, **createSmartLoadBalancer**
|
|
Helper functions for dynamic routing and port mapping
|
|
- **createApiGatewayRoute**, **addRateLimiting**, **addBasicAuth**, **addJwtAuth**
|
|
Helper functions for API gateway features and authentication
|
|
|
|
### Specialized Components
|
|
|
|
- **HttpProxy** (`ts/proxies/http-proxy/http-proxy.ts`)
|
|
HTTP/HTTPS reverse proxy with TLS termination and WebSocket support
|
|
- **NfTablesProxy** (`ts/proxies/nftables-proxy/nftables-proxy.ts`)
|
|
Low-level port forwarding using nftables NAT rules
|
|
- **SniHandler** (`ts/tls/sni/sni-handler.ts`)
|
|
Utilities for SNI extraction from TLS handshakes
|
|
|
|
### Core Utilities
|
|
|
|
- **ValidationUtils** (`ts/core/utils/validation-utils.ts`)
|
|
Domain, port, and configuration validation
|
|
- **IpUtils** (`ts/core/utils/ip-utils.ts`)
|
|
IP address validation and filtering with glob patterns
|
|
|
|
### Interfaces and Types
|
|
|
|
- `IRouteConfig`, `IRouteMatch`, `IRouteAction` (`ts/proxies/smart-proxy/models/route-types.ts`)
|
|
- `IRoutedSmartProxyOptions` (`ts/proxies/smart-proxy/models/route-types.ts`)
|
|
- `IHttpProxyOptions` (`ts/proxies/http-proxy/models/types.ts`)
|
|
- `INfTableProxySettings` (`ts/proxies/nftables-proxy/models/interfaces.ts`)
|
|
|
|
## Installation
|
|
Install via npm:
|
|
```bash
|
|
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.
|
|
|
|
```typescript
|
|
import {
|
|
SmartProxy,
|
|
createHttpRoute,
|
|
createHttpsTerminateRoute,
|
|
createHttpsPassthroughRoute,
|
|
createHttpToHttpsRedirect,
|
|
createCompleteHttpsServer,
|
|
createLoadBalancerRoute,
|
|
createApiRoute,
|
|
createWebSocketRoute,
|
|
createSocketHandlerRoute,
|
|
createNfTablesRoute,
|
|
createNfTablesTerminateRoute,
|
|
createCompleteNfTablesHttpsServer,
|
|
createPortMappingRoute,
|
|
createOffsetPortMappingRoute,
|
|
createDynamicRoute,
|
|
createSmartLoadBalancer,
|
|
createApiGatewayRoute,
|
|
addRateLimiting,
|
|
addBasicAuth,
|
|
addJwtAuth,
|
|
SocketHandlers
|
|
} from '@push.rocks/smartproxy';
|
|
|
|
// Create a new SmartProxy instance with route-based configuration
|
|
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
|
|
renewCheckIntervalHours: 24 // Check for renewals daily
|
|
},
|
|
|
|
// Define all your routing rules in a single array
|
|
routes: [
|
|
// Basic HTTP route - forward traffic from port 80 to internal service
|
|
createHttpRoute('api.example.com', { host: 'localhost', port: 3000 }),
|
|
|
|
// HTTPS route with TLS termination and automatic certificates
|
|
createHttpsTerminateRoute('secure.example.com', { host: 'localhost', port: 8080 }, {
|
|
certificate: 'auto' // Uses global ACME settings
|
|
}),
|
|
|
|
// HTTPS passthrough for legacy systems
|
|
createHttpsPassthroughRoute('legacy.example.com', { host: '192.168.1.10', port: 443 }),
|
|
|
|
// Redirect HTTP to HTTPS for all domains and subdomains
|
|
createHttpToHttpsRedirect(['example.com', '*.example.com']),
|
|
|
|
// Complete HTTPS server (creates both HTTPS route and HTTP redirect)
|
|
...createCompleteHttpsServer('complete.example.com', { host: 'localhost', port: 3000 }, {
|
|
certificate: 'auto'
|
|
}),
|
|
|
|
// API route with CORS headers
|
|
createApiRoute('api.service.com', '/v1', { host: 'api-backend', port: 8081 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
addCorsHeaders: true
|
|
}),
|
|
|
|
// WebSocket route for real-time communication
|
|
createWebSocketRoute('ws.example.com', '/socket', { host: 'socket-server', port: 8082 }, {
|
|
useTls: true,
|
|
certificate: 'auto',
|
|
pingInterval: 30000
|
|
}),
|
|
|
|
|
|
// Load balancer with multiple backend servers
|
|
createLoadBalancerRoute(
|
|
'app.example.com',
|
|
['192.168.1.10', '192.168.1.11', '192.168.1.12'],
|
|
8080,
|
|
{
|
|
tls: {
|
|
mode: 'terminate',
|
|
certificate: 'auto'
|
|
}
|
|
}
|
|
),
|
|
|
|
// Custom socket handler for specialized protocols
|
|
createSocketHandlerRoute('telnet.example.com', 23, SocketHandlers.lineProtocol((line, socket) => {
|
|
console.log('Received:', line);
|
|
socket.write(`Echo: ${line}\n`);
|
|
})),
|
|
|
|
// High-performance NFTables route (requires root/sudo)
|
|
createNfTablesRoute('fast.example.com', { host: 'backend-server', port: 8080 }, {
|
|
ports: 80,
|
|
protocol: 'tcp',
|
|
preserveSourceIP: true,
|
|
ipAllowList: ['10.0.0.*']
|
|
}),
|
|
|
|
// NFTables HTTPS termination for ultra-fast TLS handling
|
|
createNfTablesTerminateRoute('secure-fast.example.com', { host: 'backend-ssl', port: 443 }, {
|
|
ports: 443,
|
|
certificate: 'auto',
|
|
maxRate: '100mbps'
|
|
}),
|
|
|
|
// Route with security configuration
|
|
{
|
|
name: 'secure-admin',
|
|
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.*'],
|
|
ipBlockList: ['192.168.1.100'],
|
|
maxConnections: 100
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
// Start the proxy
|
|
await proxy.start();
|
|
|
|
// Dynamically add new routes later
|
|
await proxy.updateRoutes([
|
|
...proxy.settings.routes,
|
|
createHttpsTerminateRoute('new-domain.com', { host: 'localhost', port: 9000 }, {
|
|
certificate: 'auto'
|
|
})
|
|
]);
|
|
|
|
// Dynamically add or remove port listeners
|
|
await proxy.addListeningPort(8081);
|
|
await proxy.removeListeningPort(8081);
|
|
console.log('Currently listening on ports:', proxy.getListeningPorts());
|
|
|
|
// Later, gracefully shut down
|
|
await proxy.stop();
|
|
```
|
|
|
|
## Route-Based Configuration System
|
|
|
|
SmartProxy uses a unified route configuration system based on the `IRouteConfig` interface. This system follows a match/action pattern that makes routing more powerful, flexible, and declarative.
|
|
|
|
### IRouteConfig Interface
|
|
|
|
The `IRouteConfig` interface is the core building block of SmartProxy's configuration system. Each route definition consists of match criteria and an action to perform on matched traffic:
|
|
|
|
```typescript
|
|
interface IRouteConfig {
|
|
// What traffic to match (required)
|
|
match: IRouteMatch;
|
|
|
|
// What to do with matched traffic (required)
|
|
action: IRouteAction;
|
|
|
|
// Security configuration (optional)
|
|
security?: IRouteSecurity;
|
|
|
|
// Metadata (all optional)
|
|
name?: string; // Human-readable name for this route
|
|
description?: string; // Description of the route's purpose
|
|
priority?: number; // Controls matching order (higher = matched first)
|
|
tags?: string[]; // Arbitrary tags for categorization
|
|
enabled?: boolean; // Whether the route is active (default: true)
|
|
}
|
|
```
|
|
|
|
#### Match Criteria (IRouteMatch)
|
|
|
|
The `match` property defines criteria for identifying which incoming traffic should be handled by this route:
|
|
|
|
```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<string, string | RegExp>; // Match specific HTTP headers
|
|
}
|
|
```
|
|
|
|
**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:**
|
|
- **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:**
|
|
- **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
|
|
|
|
**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:
|
|
|
|
```typescript
|
|
interface IRouteAction {
|
|
// Action type (required)
|
|
type: 'forward' | 'socket-handler';
|
|
|
|
// For 'forward' actions
|
|
target?: IRouteTarget;
|
|
|
|
// TLS handling for 'forward' actions
|
|
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;
|
|
};
|
|
|
|
// 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:
|
|
|
|
```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
|
|
}
|
|
}
|
|
}
|
|
]
|
|
});
|
|
```
|
|
|
|
#### Route-Specific ACME Configuration
|
|
Override global settings for specific routes:
|
|
|
|
```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')
|
|
}
|
|
}
|
|
```
|
|
|
|
**Socket Handler Action:**
|
|
When `type: 'socket-handler'`, custom socket handling logic is applied:
|
|
```typescript
|
|
type TSocketHandler = (socket: net.Socket, context: IRouteContext) => void | Promise<void>;
|
|
```
|
|
|
|
The socket handler receives:
|
|
- `socket`: The raw Node.js Socket object
|
|
- `context`: Route context containing clientIp, port, domain, route info, etc.
|
|
|
|
### Socket Handlers
|
|
|
|
SmartProxy v19.5.0 introduces socket handlers for custom protocol handling:
|
|
|
|
```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),
|
|
|
|
// TCP proxy
|
|
createSocketHandlerRoute('proxy.example.com', 8000, SocketHandlers.proxy('backend-server', 8080)),
|
|
|
|
// 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) => {
|
|
if (req.url === '/health') {
|
|
res.status(200);
|
|
res.send('OK');
|
|
} else {
|
|
res.status(404);
|
|
res.send('Not Found');
|
|
}
|
|
}))
|
|
```
|
|
|
|
### 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
|
|
}
|
|
```
|
|
|
|
### 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);
|
|
});
|
|
})
|
|
```
|
|
|
|
## 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<br>(Match/Action)"]
|
|
RouteManager["Route Manager"]
|
|
SmartProxy["SmartProxy<br>(TCP/SNI Proxy)"]
|
|
HttpProxyBridge["HttpProxy Bridge"]
|
|
HttpProxy["HttpProxy<br>(HTTPS/TLS Termination)"]
|
|
NfTablesManager["NFTables Manager<br>(Kernel Routing)"]
|
|
CertManager["SmartCertManager<br>(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 Hooks & Events
|
|
|
|
Listen for certificate events via EventEmitter:
|
|
- **SmartProxy**:
|
|
- `certificate` (domain, publicKey, privateKey, expiryDate, source, isRenewal)
|
|
- Events from CertManager are propagated
|
|
|
|
Provide a `certProvisionFunction(domain)` in SmartProxy settings to supply static certs or return `'http01'`.
|
|
|
|
## 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
|
|
}
|
|
}
|
|
]
|
|
});
|
|
|
|
await apiGateway.start();
|
|
```
|
|
|
|
### 2. Complete HTTPS Server with HTTP Redirect
|
|
|
|
Easily set up a secure HTTPS server with automatic redirection from HTTP:
|
|
|
|
```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<string, string | RegExp>` (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)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Configuration Options
|
|
|
|
### 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`
|
|
- `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`
|
|
|
|
## License and Legal Information
|
|
|
|
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
|
|
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
|
|
|
### Trademarks
|
|
|
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
|
|
|
### Company Information
|
|
|
|
Task Venture Capital GmbH
|
|
Registered at District court Bremen HRB 35230 HB, Germany
|
|
|
|
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
|
|
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works. |