# @push.rocks/smartproxy A high-performance proxy toolkit for Node.js, offering: - HTTP/HTTPS reverse proxy with TLS termination and WebSocket support - Automatic ACME certificate management (HTTP-01) - Low-level port forwarding via nftables - HTTP-to-HTTPS and custom URL redirects - Advanced TCP/SNI-based proxying with IP filtering and rules - Unified forwarding configuration system for all proxy types ## Project Architecture Overview SmartProxy has been restructured using a modern, modular architecture to improve maintainability and clarity: ``` /ts ├── /core # Core functionality │ ├── /models # Data models and interfaces │ ├── /utils # Shared utilities (IP validation, logging, etc.) │ └── /events # Common event definitions ├── /certificate # Certificate management │ ├── /acme # ACME-specific functionality │ ├── /providers # Certificate providers (static, ACME) │ └── /storage # Certificate storage mechanisms ├── /forwarding # Forwarding system │ ├── /handlers # Various forwarding handlers │ │ ├── base-handler.ts # Abstract base handler │ │ ├── http-handler.ts # HTTP-only handler │ │ └── ... # Other handlers │ ├── /config # Configuration models │ │ ├── forwarding-types.ts # Type definitions │ │ ├── domain-config.ts # Domain config utilities │ │ └── domain-manager.ts # Domain routing manager │ └── /factory # Factory for creating handlers ├── /proxies # Different proxy implementations │ ├── /smart-proxy # SmartProxy implementation │ │ ├── /models # SmartProxy-specific interfaces │ │ ├── smart-proxy.ts # Main SmartProxy class │ │ └── ... # Supporting classes │ ├── /network-proxy # NetworkProxy implementation │ │ ├── /models # NetworkProxy-specific interfaces │ │ ├── network-proxy.ts # Main NetworkProxy class │ │ └── ... # Supporting classes │ └── /nftables-proxy # NfTablesProxy implementation ├── /tls # TLS-specific functionality │ ├── /sni # SNI handling components │ └── /alerts # TLS alerts system └── /http # HTTP-specific functionality ├── /port80 # Port80Handler components ├── /router # HTTP routing system └── /redirects # Redirect handlers ``` ## Exports The following classes and interfaces are provided: - **NetworkProxy** (`ts/proxies/network-proxy/network-proxy.ts`) HTTP/HTTPS reverse proxy with TLS termination, WebSocket support, connection pooling, and optional ACME integration. - **Port80Handler** (`ts/http/port80/port80-handler.ts`) ACME HTTP-01 challenge handler and certificate manager. - **NfTablesProxy** (`ts/proxies/nftables-proxy/nftables-proxy.ts`) Low-level port forwarding using nftables NAT rules. - **Redirect**, **SslRedirect** (`ts/http/redirects/redirect-handler.ts`) HTTP/HTTPS redirect server and shortcut for HTTP→HTTPS. - **SmartProxy** (`ts/proxies/smart-proxy/smart-proxy.ts`) TCP/SNI-based proxy with dynamic routing, IP filtering, and unified certificates. - **SniHandler** (`ts/tls/sni/sni-handler.ts`) Static utilities to extract SNI hostnames from TLS handshakes. - **Forwarding Handlers** (`ts/forwarding/handlers/*.ts`) Unified forwarding handlers for different connection types (HTTP, HTTPS passthrough, TLS termination). - **Core Utilities** - **ValidationUtils** (`ts/core/utils/validation-utils.ts`) for domain, port, and configuration validation - **IpUtils** (`ts/core/utils/ip-utils.ts`) for IP address validation and filtering - **Interfaces** - `SmartProxyOptions`, `DomainConfig` (`ts/proxies/smart-proxy/models/interfaces.ts`) - `NetworkProxyOptions` (`ts/proxies/network-proxy/models/types.ts`) - `AcmeOptions`, `DomainOptions` (`ts/core/models/common-types.ts`) - `NfTableProxySettings` (`ts/proxies/nftables-proxy/models/interfaces.ts`) - `ForwardConfig`, `ForwardingType` (`ts/forwarding/config/forwarding-types.ts`) ## Installation Install via npm: ```bash npm install @push.rocks/smartproxy ``` ## Quick Start ### 1. HTTP(S) Reverse Proxy (NetworkProxy) ```typescript import { NetworkProxy } from '@push.rocks/smartproxy'; const proxy = new NetworkProxy({ port: 443 }); await proxy.start(); await proxy.updateProxyConfigs([ { hostName: 'example.com', destinationIps: ['127.0.0.1'], destinationPorts: [3000], publicKey: fs.readFileSync('cert.pem', 'utf8'), privateKey: fs.readFileSync('key.pem', 'utf8'), } ]); // Add default headers to all responses await proxy.addDefaultHeaders({ 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains' }); // ... await proxy.stop(); ``` ### 2. HTTP→HTTPS Redirect (Redirect / SslRedirect) ```typescript import { Redirect, SslRedirect } from '@push.rocks/smartproxy'; import * as fs from 'fs'; // Custom redirect rules const redirect = new Redirect({ httpPort: 80, httpsPort: 443, sslOptions: { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem'), }, rules: [ { fromProtocol: 'http', fromHost: '*', toProtocol: 'https', toHost: '$1', statusCode: 301 } ] }); await redirect.start(); // Quick HTTP→HTTPS helper on port 80 const quick = new SslRedirect(80); await quick.start(); ``` ### 3. Automatic Certificates (ACME Port80Handler) ```typescript import { Port80Handler } from '@push.rocks/smartproxy'; // Configure ACME on port 80 with contact email const acme = new Port80Handler({ port: 80, contactEmail: 'admin@example.com', useProduction: true, renewThresholdDays: 30 }); acme.on('certificate-issued', evt => { console.log(`Certificate ready for ${evt.domain}, expires ${evt.expiryDate}`); }); await acme.start(); acme.addDomain({ domainName: 'example.com', sslRedirect: true, acmeMaintenance: true }); ``` ### 4. Low-Level Port Forwarding (NfTablesProxy) ```typescript import { NfTablesProxy } from '@push.rocks/smartproxy'; // Forward port 80→8080 with source IP preservation const nft = new NfTablesProxy({ fromPort: 80, toPort: 8080, toHost: 'localhost', preserveSourceIP: true, deleteOnExit: true }); await nft.start(); // ... await nft.stop(); ``` ### 5. TCP/SNI Proxy (SmartProxy) ```typescript import { SmartProxy } from '@push.rocks/smartproxy'; import { createDomainConfig, httpOnly, tlsTerminateToHttp, httpsPassthrough } from '@push.rocks/smartproxy'; const smart = new SmartProxy({ fromPort: 443, toPort: 8443, domainConfigs: [ // HTTPS passthrough example createDomainConfig(['example.com', '*.example.com'], httpsPassthrough({ target: { host: '127.0.0.1', port: 443 }, security: { allowedIps: ['*'] } }) ), // HTTPS termination example createDomainConfig('secure.example.com', tlsTerminateToHttp({ target: { host: 'localhost', port: 3000 }, acme: { enabled: true, production: true } }) ) ], sniEnabled: true }); smart.on('certificate', evt => console.log(evt)); await smart.start(); // Update domains later await smart.updateDomainConfigs([/* new configs */]); ``` ### 6. SNI Utilities (SniHandler) ```js import { SniHandler } from '@push.rocks/smartproxy'; // Extract SNI from a TLS ClientHello buffer const sni = SniHandler.extractSNI(buffer); // Reassemble fragmented ClientHello const complete = SniHandler.handleFragmentedClientHello(buf, connId); ``` ### 7. Core Utilities (ValidationUtils, IpUtils) ```typescript import { ValidationUtils, IpUtils } from '@push.rocks/smartproxy'; // Validate a domain name const isValidDomain = ValidationUtils.isValidDomainName('example.com'); // Check if an IP is allowed based on filters const isAllowed = IpUtils.isIPAuthorized( '192.168.1.1', ['192.168.1.*'], // allowed IPs ['192.168.1.100'] // blocked IPs ); // Convert CIDR to glob patterns const globPatterns = IpUtils.cidrToGlobPatterns('10.0.0.0/24'); ``` ## API Reference For full configuration options and type definitions, see the TypeScript interfaces: - `NetworkProxyOptions` (`ts/proxies/network-proxy/models/types.ts`) - `AcmeOptions`, `DomainOptions` (`ts/core/models/common-types.ts`) - `ForwardConfig` (`ts/forwarding/config/forwarding-types.ts`) - `NfTableProxySettings` (`ts/proxies/nftables-proxy/models/interfaces.ts`) - `SmartProxyOptions`, `DomainConfig` (`ts/proxies/smart-proxy/models/interfaces.ts`) ## Architecture & Flow Diagrams ```mermaid flowchart TB Client([Client]) subgraph "SmartProxy Components" direction TB HTTP80["HTTP Port 80
Redirect / SslRedirect"] HTTPS443["HTTPS Port 443
NetworkProxy"] SmartProxy["SmartProxy
(TCP/SNI Proxy)"] NfTables[NfTablesProxy] Router[ProxyRouter] ACME["Port80Handler
(ACME HTTP-01)"] Certs[(SSL Certificates)] end subgraph "Backend Services" Service1[Service 1] Service2[Service 2] Service3[Service 3] end Client -->|HTTP Request| HTTP80 HTTP80 -->|Redirect| Client Client -->|HTTPS Request| HTTPS443 Client -->|TLS/TCP| SmartProxy HTTPS443 -->|Route Request| Router Router -->|Proxy Request| Service1 Router -->|Proxy Request| Service2 SmartProxy -->|Direct TCP| Service2 SmartProxy -->|Direct TCP| Service3 NfTables -.->|Low-level forwarding| SmartProxy HTTP80 -.->|Challenge Response| ACME ACME -.->|Generate/Manage| Certs Certs -.->|Provide TLS Certs| HTTPS443 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 HTTP80,HTTPS443,SmartProxy,NfTables,Router,ACME component; class Service1,Service2,Service3 backend; ``` ### HTTPS Reverse Proxy Flow This diagram shows how HTTPS requests are handled and proxied to backend services: ```mermaid sequenceDiagram participant Client participant NetworkProxy participant ProxyRouter participant Backend Client->>NetworkProxy: HTTPS Request Note over NetworkProxy: TLS Termination NetworkProxy->>ProxyRouter: Route Request ProxyRouter->>ProxyRouter: Match hostname to config alt Authentication Required NetworkProxy->>Client: Request Authentication Client->>NetworkProxy: Send Credentials NetworkProxy->>NetworkProxy: Validate Credentials end NetworkProxy->>Backend: Forward Request Backend->>NetworkProxy: Response Note over NetworkProxy: Add Default Headers NetworkProxy->>Client: Forward Response alt WebSocket Request Client->>NetworkProxy: Upgrade to WebSocket NetworkProxy->>Backend: Upgrade to WebSocket loop WebSocket Active Client->>NetworkProxy: WebSocket Message NetworkProxy->>Backend: Forward Message Backend->>NetworkProxy: WebSocket Message NetworkProxy->>Client: Forward Message NetworkProxy-->>NetworkProxy: Heartbeat Check end end ``` ### SNI-based Connection Handling This diagram illustrates how TCP connections with SNI (Server Name Indication) are processed and forwarded: ```mermaid sequenceDiagram participant Client participant SmartProxy participant Backend Client->>SmartProxy: TLS Connection alt SNI Enabled SmartProxy->>Client: Accept Connection Client->>SmartProxy: TLS ClientHello with SNI SmartProxy->>SmartProxy: Extract SNI Hostname SmartProxy->>SmartProxy: Match Domain Config SmartProxy->>SmartProxy: Validate Client IP alt IP Allowed SmartProxy->>Backend: Forward Connection Note over SmartProxy,Backend: Bidirectional Data Flow else IP Rejected SmartProxy->>Client: Close Connection end else Port-based Routing SmartProxy->>SmartProxy: Match Port Range SmartProxy->>SmartProxy: Find Domain Config SmartProxy->>SmartProxy: Validate Client IP alt IP Allowed SmartProxy->>Backend: Forward Connection Note over SmartProxy,Backend: Bidirectional Data Flow else IP Rejected SmartProxy->>Client: Close Connection end end loop Connection Active SmartProxy-->>SmartProxy: Monitor Activity SmartProxy-->>SmartProxy: Check Max Lifetime alt Inactivity or Max Lifetime Exceeded SmartProxy->>Client: Close Connection SmartProxy->>Backend: Close Connection end end ``` ### Let's Encrypt Certificate Acquisition This diagram shows how certificates are automatically acquired through the ACME protocol: ```mermaid sequenceDiagram participant Client participant Port80Handler participant ACME as Let's Encrypt ACME participant NetworkProxy Client->>Port80Handler: HTTP Request for domain alt Certificate Exists Port80Handler->>Client: Redirect to HTTPS else No Certificate Port80Handler->>Port80Handler: Mark domain as obtaining cert Port80Handler->>ACME: Create account & new order ACME->>Port80Handler: Challenge information Port80Handler->>Port80Handler: Store challenge token & key authorization ACME->>Port80Handler: HTTP-01 Challenge Request Port80Handler->>ACME: Challenge Response ACME->>ACME: Validate domain ownership ACME->>Port80Handler: Challenge validated Port80Handler->>Port80Handler: Generate CSR Port80Handler->>ACME: Submit CSR ACME->>Port80Handler: Issue Certificate Port80Handler->>Port80Handler: Store certificate & private key Port80Handler->>Port80Handler: Mark certificate as obtained Note over Port80Handler,NetworkProxy: Certificate available for use Client->>Port80Handler: Another HTTP Request Port80Handler->>Client: Redirect to HTTPS Client->>NetworkProxy: HTTPS Request Note over NetworkProxy: Uses new certificate end ``` ## Features - HTTP/HTTPS Reverse Proxy (NetworkProxy) • TLS termination, virtual-host routing, HTTP/2 & WebSocket support, pooling & metrics - Automatic ACME Certificates (Port80Handler) • HTTP-01 challenge handling, certificate issuance/renewal, pluggable storage - Low-Level Port Forwarding (NfTablesProxy) • nftables NAT rules for ports/ranges, IPv4/IPv6, IP filtering, QoS & ipset support - Custom Redirects (Redirect / SslRedirect) • URL redirects with wildcard host/path, template variables & status codes - TCP/SNI Proxy (SmartProxy) • SNI-based routing, IP allow/block lists, port ranges, timeouts & graceful shutdown - SNI Utilities (SniHandler) • Robust ClientHello parsing, fragmentation & session resumption support - Core Utilities • ValidationUtils and IpUtils for configuration validation and IP management ## Certificate Hooks & Events Listen for certificate events via EventEmitter: - **Port80Handler**: - `certificate-issued`, `certificate-renewed`, `certificate-failed` - `manager-started`, `manager-stopped`, `request-forwarded` - **SmartProxy**: - `certificate` (domain, publicKey, privateKey, expiryDate, source, isRenewal) Provide a `certProvisionFunction(domain)` in SmartProxy settings to supply static certs or return `'http01'`. ## Unified Forwarding System The SmartProxy Unified Forwarding System provides a clean, use-case driven approach to configuring different types of traffic forwarding. It replaces disparate configuration mechanisms with a unified interface. ### Forwarding Types The system supports four primary forwarding types: 1. **HTTP-only (`http-only`)**: Forwards HTTP traffic to a backend server. 2. **HTTPS Passthrough (`https-passthrough`)**: Passes through raw TLS traffic without termination (SNI forwarding). 3. **HTTPS Termination to HTTP (`https-terminate-to-http`)**: Terminates TLS and forwards the decrypted traffic to an HTTP backend. 4. **HTTPS Termination to HTTPS (`https-terminate-to-https`)**: Terminates TLS and creates a new TLS connection to an HTTPS backend. ### Basic Configuration Each domain is configured with a forwarding type and target: ```typescript { domains: ['example.com'], forwarding: { type: 'http-only', target: { host: 'localhost', port: 3000 } } } ``` ### Helper Functions Helper functions are provided for common configurations: ```typescript import { createDomainConfig, httpOnly, tlsTerminateToHttp, tlsTerminateToHttps, httpsPassthrough } from '@push.rocks/smartproxy'; // HTTP-only await domainManager.addDomainConfig( createDomainConfig('example.com', httpOnly({ target: { host: 'localhost', port: 3000 } })) ); // HTTPS termination to HTTP await domainManager.addDomainConfig( createDomainConfig('secure.example.com', tlsTerminateToHttp({ target: { host: 'localhost', port: 3000 }, acme: { production: true } })) ); // HTTPS termination to HTTPS await domainManager.addDomainConfig( createDomainConfig('api.example.com', tlsTerminateToHttps({ target: { host: 'internal-api', port: 8443 }, http: { redirectToHttps: true } })) ); // HTTPS passthrough (SNI) await domainManager.addDomainConfig( createDomainConfig('passthrough.example.com', httpsPassthrough({ target: { host: '10.0.0.5', port: 443 } })) ); ``` ### Advanced Configuration For more complex scenarios, additional options can be specified: ```typescript { domains: ['api.example.com'], forwarding: { type: 'https-terminate-to-https', target: { host: ['10.0.0.10', '10.0.0.11'], // Round-robin load balancing port: 8443 }, http: { enabled: true, redirectToHttps: true }, https: { // Custom certificate instead of ACME-provisioned customCert: { key: '-----BEGIN PRIVATE KEY-----\n...', cert: '-----BEGIN CERTIFICATE-----\n...' } }, security: { allowedIps: ['10.0.0.*', '192.168.1.*'], blockedIps: ['1.2.3.4'], maxConnections: 100 }, advanced: { timeout: 30000, headers: { 'X-Forwarded-For': '{clientIp}', 'X-Original-Host': '{sni}' } } } } ``` ### Extended Configuration Options #### ForwardConfig - `type`: 'http-only' | 'https-passthrough' | 'https-terminate-to-http' | 'https-terminate-to-https' - `target`: { host: string | string[], port: number } - `http?`: { enabled?: boolean, redirectToHttps?: boolean, headers?: Record } - `https?`: { customCert?: { key: string, cert: string }, forwardSni?: boolean } - `acme?`: { enabled?: boolean, maintenance?: boolean, production?: boolean, forwardChallenges?: { host: string, port: number, useTls?: boolean } } - `security?`: { allowedIps?: string[], blockedIps?: string[], maxConnections?: number } - `advanced?`: { portRanges?: Array<{ from: number, to: number }>, networkProxyPort?: number, keepAlive?: boolean, timeout?: number, headers?: Record } ## Configuration Options ### NetworkProxy (NetworkProxyOptions) - `port` (number, required) - `backendProtocol` ('http1'|'http2', default 'http1') - `maxConnections` (number, default 10000) - `keepAliveTimeout` (ms, default 120000) - `headersTimeout` (ms, default 60000) - `cors` (object) - `connectionPoolSize` (number, default 50) - `logLevel` ('error'|'warn'|'info'|'debug') - `acme` (AcmeOptions) - `useExternalPort80Handler` (boolean) - `portProxyIntegration` (boolean) ### Port80Handler (AcmeOptions) - `enabled` (boolean, default true) - `port` (number, default 80) - `contactEmail` (string) - `useProduction` (boolean, default false) - `renewThresholdDays` (number, default 30) - `autoRenew` (boolean, default true) - `certificateStore` (string) - `skipConfiguredCerts` (boolean) - `domainForwards` (DomainForwardConfig[]) ### NfTablesProxy (NfTableProxySettings) - `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) ### Redirect / SslRedirect - Constructor options: `httpPort`, `httpsPort`, `sslOptions`, `rules` (RedirectRule[]) ### SmartProxy (SmartProxyOptions) - `fromPort`, `toPort` (number) - `domainConfigs` (DomainConfig[]) - Using unified forwarding configuration - `sniEnabled`, `preserveSourceIP` (booleans) - `defaultAllowedIPs`, `defaultBlockedIPs` (string[]) - Default IP allowlists/blocklists - Timeouts: `initialDataTimeout`, `socketTimeout`, `inactivityTimeout`, etc. - Socket opts: `noDelay`, `keepAlive`, `enableKeepAliveProbes` - `acme` (AcmeOptions), `certProvisionFunction` (callback) - `useNetworkProxy` (number[]), `networkProxyPort` (number) - `globalPortRanges` (Array<{ from: number; to: number }>) ## Troubleshooting ### NetworkProxy - Verify ports, certificates and `rejectUnauthorized` for TLS errors - Configure CORS or use `addDefaultHeaders` for preflight issues - Increase `maxConnections` or `connectionPoolSize` under load ### Port80Handler - Run as root or grant CAP_NET_BIND_SERVICE for port 80 - Inspect `certificate-failed` events and switch staging/production ### NfTablesProxy - Ensure `nft` is installed and run with sufficient privileges - Use `forceCleanSlate:true` to clear conflicting rules ### Redirect / SslRedirect - Check `fromHost`/`fromPath` patterns and Host headers - Validate `sslOptions` key/cert correctness ### SmartProxy & SniHandler - Increase `initialDataTimeout`/`maxPendingDataSize` for large ClientHello - Enable `enableTlsDebugLogging` to trace handshake - Ensure `allowSessionTicket` and fragmentation support for resumption - Double-check forwarding configuration to ensure correct `type` for your use case - Use helper functions like `httpOnly()`, `httpsPassthrough()`, etc. to create correct configurations - For IP filtering issues, check the `security.allowedIps` and `security.blockedIps` settings ## 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.