|
|
|
@ -1,12 +1,13 @@
|
|
|
|
|
# @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
|
|
|
|
|
A unified high-performance proxy toolkit for Node.js, with **SmartProxy** as the central API to handle all your proxy needs:
|
|
|
|
|
|
|
|
|
|
- **Unified Configuration API**: One consistent way to configure various proxy types
|
|
|
|
|
- **SSL/TLS Support**: Automatic HTTPS with Let's Encrypt certificate provisioning
|
|
|
|
|
- **Simplified Domain Management**: Easy routing based on domain names with wildcard support
|
|
|
|
|
- **Advanced SNI Handling**: Smart TCP/SNI-based forwarding with IP filtering
|
|
|
|
|
- **Multiple Forwarding Types**: HTTP-only, HTTPS passthrough, TLS termination options
|
|
|
|
|
- **Security Features**: IP allowlists, connection limits, timeouts, and more
|
|
|
|
|
|
|
|
|
|
## Project Architecture Overview
|
|
|
|
|
|
|
|
|
@ -51,34 +52,52 @@ SmartProxy has been restructured using a modern, modular architecture to improve
|
|
|
|
|
└── /redirects # Redirect handlers
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Exports
|
|
|
|
|
The following classes and interfaces are provided:
|
|
|
|
|
## Main Components
|
|
|
|
|
|
|
|
|
|
### Primary API (Recommended)
|
|
|
|
|
|
|
|
|
|
- **SmartProxy** (`ts/proxies/smart-proxy/smart-proxy.ts`)
|
|
|
|
|
The central unified API for all proxy needs, featuring:
|
|
|
|
|
- Domain-based routing with SNI inspection
|
|
|
|
|
- Automatic certificate management
|
|
|
|
|
- Multiple forwarding types in one configuration
|
|
|
|
|
- Advanced security controls
|
|
|
|
|
- Flexible backend targeting options
|
|
|
|
|
|
|
|
|
|
### Helper Functions
|
|
|
|
|
|
|
|
|
|
- **createDomainConfig**
|
|
|
|
|
Create domain configuration with clean syntax
|
|
|
|
|
- **httpOnly**, **httpsPassthrough**, **tlsTerminateToHttp**, **tlsTerminateToHttps**
|
|
|
|
|
Helper functions to create different forwarding configurations
|
|
|
|
|
|
|
|
|
|
### Specialized Components
|
|
|
|
|
|
|
|
|
|
- **NetworkProxy** (`ts/proxies/network-proxy/network-proxy.ts`)
|
|
|
|
|
HTTP/HTTPS reverse proxy with TLS termination, WebSocket support,
|
|
|
|
|
connection pooling, and optional ACME integration.
|
|
|
|
|
HTTP/HTTPS reverse proxy with TLS termination and WebSocket support
|
|
|
|
|
- **Port80Handler** (`ts/http/port80/port80-handler.ts`)
|
|
|
|
|
ACME HTTP-01 challenge handler and certificate manager.
|
|
|
|
|
ACME HTTP-01 challenge handler for Let's Encrypt certificates
|
|
|
|
|
- **NfTablesProxy** (`ts/proxies/nftables-proxy/nftables-proxy.ts`)
|
|
|
|
|
Low-level port forwarding using nftables NAT rules.
|
|
|
|
|
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.
|
|
|
|
|
HTTP-to-HTTPS redirects with customizable rules
|
|
|
|
|
- **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
|
|
|
|
|
Utilities for SNI extraction from TLS handshakes
|
|
|
|
|
|
|
|
|
|
- **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`)
|
|
|
|
|
### 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
|
|
|
|
|
|
|
|
|
|
- `ISmartProxyOptions`, `IDomainConfig` (`ts/proxies/smart-proxy/models/interfaces.ts`)
|
|
|
|
|
- `IForwardConfig`, `TForwardingType` (`ts/forwarding/config/forwarding-types.ts`)
|
|
|
|
|
- `INetworkProxyOptions` (`ts/proxies/network-proxy/models/types.ts`)
|
|
|
|
|
- `IAcmeOptions`, `IDomainOptions` (`ts/certificate/models/certificate-types.ts`)
|
|
|
|
|
- `INfTableProxySettings` (`ts/proxies/nftables-proxy/models/interfaces.ts`)
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
Install via npm:
|
|
|
|
@ -86,15 +105,142 @@ Install via npm:
|
|
|
|
|
npm install @push.rocks/smartproxy
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
## Quick Start with SmartProxy
|
|
|
|
|
|
|
|
|
|
SmartProxy is the recommended way to use this library, providing a unified API for all proxy scenarios.
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, httpOnly, tlsTerminateToHttp, httpsPassthrough } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
// Create a new SmartProxy instance with all your domain configurations in one place
|
|
|
|
|
const proxy = new SmartProxy({
|
|
|
|
|
// Listen on port 443 for incoming connections
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
|
|
|
|
|
// Configure domains and their forwarding rules
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
// Basic HTTP forwarding for api.example.com
|
|
|
|
|
createDomainConfig('api.example.com', httpOnly({
|
|
|
|
|
target: { host: 'localhost', port: 3000 }
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// HTTPS termination with automatic Let's Encrypt certificates
|
|
|
|
|
createDomainConfig('secure.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'localhost', port: 8080 },
|
|
|
|
|
acme: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
production: true
|
|
|
|
|
}
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// Multiple domains with wildcard support
|
|
|
|
|
createDomainConfig(['example.com', '*.example.com'], httpsPassthrough({
|
|
|
|
|
target: {
|
|
|
|
|
// Load balancing across multiple backend servers
|
|
|
|
|
host: ['192.168.1.10', '192.168.1.11'],
|
|
|
|
|
port: 443
|
|
|
|
|
},
|
|
|
|
|
security: {
|
|
|
|
|
// IP filtering for enhanced security
|
|
|
|
|
allowedIps: ['10.0.0.*', '192.168.1.*'],
|
|
|
|
|
blockedIps: ['1.2.3.4']
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
// Enable SNI-based routing
|
|
|
|
|
sniEnabled: true,
|
|
|
|
|
|
|
|
|
|
// Automatic Let's Encrypt integration
|
|
|
|
|
acme: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
contactEmail: 'admin@example.com',
|
|
|
|
|
useProduction: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Listen for certificate events
|
|
|
|
|
proxy.on('certificate', evt => {
|
|
|
|
|
console.log(`Certificate for ${evt.domain} ready, expires: ${evt.expiryDate}`);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Start the proxy
|
|
|
|
|
await proxy.start();
|
|
|
|
|
|
|
|
|
|
// Dynamically add or update domain configurations later
|
|
|
|
|
await proxy.updateDomainConfigs([
|
|
|
|
|
createDomainConfig('new-domain.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'localhost', port: 9000 }
|
|
|
|
|
}))
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Later, gracefully shut down
|
|
|
|
|
await proxy.stop();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### What You Can Do with SmartProxy
|
|
|
|
|
|
|
|
|
|
1. **Domain-Based Routing**
|
|
|
|
|
```typescript
|
|
|
|
|
// Route requests for different domains to different backend servers
|
|
|
|
|
createDomainConfig('api.example.com', httpOnly({
|
|
|
|
|
target: { host: 'api-server', port: 3000 }
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2. **Automatic SSL with Let's Encrypt**
|
|
|
|
|
```typescript
|
|
|
|
|
// Get and automatically renew certificates
|
|
|
|
|
createDomainConfig('secure.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'localhost', port: 8080 },
|
|
|
|
|
acme: { enabled: true, production: true }
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
3. **Load Balancing**
|
|
|
|
|
```typescript
|
|
|
|
|
// Distribute traffic across multiple backend servers
|
|
|
|
|
createDomainConfig('app.example.com', httpOnly({
|
|
|
|
|
target: {
|
|
|
|
|
host: ['10.0.0.1', '10.0.0.2', '10.0.0.3'],
|
|
|
|
|
port: 8080
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. **Security Controls**
|
|
|
|
|
```typescript
|
|
|
|
|
// Restrict access based on IP addresses
|
|
|
|
|
createDomainConfig('admin.example.com', httpOnly({
|
|
|
|
|
target: { host: 'localhost', port: 8080 },
|
|
|
|
|
security: {
|
|
|
|
|
allowedIps: ['10.0.0.*', '192.168.1.*'],
|
|
|
|
|
maxConnections: 100
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
5. **Wildcard Domains**
|
|
|
|
|
```typescript
|
|
|
|
|
// Handle all subdomains with one config
|
|
|
|
|
createDomainConfig(['example.com', '*.example.com'], httpsPassthrough({
|
|
|
|
|
target: { host: 'backend-server', port: 443 }
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Other Components
|
|
|
|
|
|
|
|
|
|
While SmartProxy provides a unified API for most needs, you can also use individual components:
|
|
|
|
|
|
|
|
|
|
### NetworkProxy
|
|
|
|
|
For HTTP/HTTPS reverse proxy with TLS termination and WebSocket support:
|
|
|
|
|
|
|
|
|
|
### 1. HTTP(S) Reverse Proxy (NetworkProxy)
|
|
|
|
|
```typescript
|
|
|
|
|
import { NetworkProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
import * as fs from 'fs';
|
|
|
|
|
|
|
|
|
|
const proxy = new NetworkProxy({ port: 443 });
|
|
|
|
|
await proxy.start();
|
|
|
|
|
|
|
|
|
|
await proxy.updateProxyConfigs([
|
|
|
|
|
{
|
|
|
|
|
hostName: 'example.com',
|
|
|
|
@ -104,163 +250,56 @@ await proxy.updateProxyConfigs([
|
|
|
|
|
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';
|
|
|
|
|
### Port80Handler
|
|
|
|
|
For standalone ACME certificate management:
|
|
|
|
|
|
|
|
|
|
// 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}`);
|
|
|
|
|
useProduction: true
|
|
|
|
|
});
|
|
|
|
|
acme.on('certificate-issued', evt => console.log(`Certificate ready: ${evt.domain}`));
|
|
|
|
|
await acme.start();
|
|
|
|
|
acme.addDomain({
|
|
|
|
|
domainName: 'example.com',
|
|
|
|
|
sslRedirect: true,
|
|
|
|
|
acmeMaintenance: true
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4. Low-Level Port Forwarding (NfTablesProxy)
|
|
|
|
|
### NfTablesProxy
|
|
|
|
|
For low-level port forwarding using nftables:
|
|
|
|
|
|
|
|
|
|
```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
|
|
|
|
|
preserveSourceIP: true
|
|
|
|
|
});
|
|
|
|
|
await nft.start();
|
|
|
|
|
// ...
|
|
|
|
|
await nft.stop();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5. TCP/SNI Proxy (SmartProxy)
|
|
|
|
|
### Redirect / SslRedirect
|
|
|
|
|
For HTTP-to-HTTPS redirects:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy } from '@push.rocks/smartproxy';
|
|
|
|
|
import { createDomainConfig, httpOnly, tlsTerminateToHttp, httpsPassthrough } from '@push.rocks/smartproxy';
|
|
|
|
|
import { SslRedirect } 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');
|
|
|
|
|
// Quick HTTP→HTTPS helper on port 80
|
|
|
|
|
const redirect = new SslRedirect(80);
|
|
|
|
|
await redirect.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 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`)
|
|
|
|
|
- `INetworkProxyOptions` (`ts/proxies/network-proxy/models/types.ts`)
|
|
|
|
|
- `IAcmeOptions`, `IDomainOptions` (`ts/certificate/models/certificate-types.ts`)
|
|
|
|
|
- `IForwardConfig` (`ts/forwarding/config/forwarding-types.ts`)
|
|
|
|
|
- `INfTableProxySettings` (`ts/proxies/nftables-proxy/models/interfaces.ts`)
|
|
|
|
|
- `ISmartProxyOptions`, `IDomainConfig` (`ts/proxies/smart-proxy/models/interfaces.ts`)
|
|
|
|
|
|
|
|
|
|
## Architecture & Flow Diagrams
|
|
|
|
|
|
|
|
|
@ -479,118 +518,290 @@ Listen for certificate events via EventEmitter:
|
|
|
|
|
|
|
|
|
|
Provide a `certProvisionFunction(domain)` in SmartProxy settings to supply static certs or return `'http01'`.
|
|
|
|
|
|
|
|
|
|
## Unified Forwarding System
|
|
|
|
|
## SmartProxy: Common Use Cases
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
The SmartProxy component offers a clean, unified approach to handle virtually any proxy scenario.
|
|
|
|
|
|
|
|
|
|
### Forwarding Types
|
|
|
|
|
### 1. API Gateway / Backend Routing
|
|
|
|
|
|
|
|
|
|
The system supports four primary forwarding types:
|
|
|
|
|
Create a flexible API gateway to route traffic to different microservices based on domain:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, httpOnly, tlsTerminateToHttp } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const apiGateway = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
// Users API
|
|
|
|
|
createDomainConfig('users.api.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'users-service', port: 3000 },
|
|
|
|
|
acme: { enabled: true, production: true }
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// Products API
|
|
|
|
|
createDomainConfig('products.api.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'products-service', port: 3001 },
|
|
|
|
|
acme: { enabled: true, production: true }
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// Admin dashboard gets extra security
|
|
|
|
|
createDomainConfig('admin.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'admin-dashboard', port: 8080 },
|
|
|
|
|
security: {
|
|
|
|
|
allowedIps: ['10.0.0.*', '192.168.1.*'] // Only allow internal network
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
],
|
|
|
|
|
sniEnabled: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await apiGateway.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 2. Automatic HTTPS for Development
|
|
|
|
|
|
|
|
|
|
Easily add HTTPS to your local development environment with automatic certificates:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, tlsTerminateToHttp } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const devProxy = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
createDomainConfig('dev.local', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'localhost', port: 3000 },
|
|
|
|
|
// For development, use self-signed or existing certificates
|
|
|
|
|
https: {
|
|
|
|
|
customCert: {
|
|
|
|
|
key: fs.readFileSync('dev-cert.key', 'utf8'),
|
|
|
|
|
cert: fs.readFileSync('dev-cert.pem', 'utf8')
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
// Auto-redirect HTTP to HTTPS
|
|
|
|
|
http: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
redirectToHttps: true
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await devProxy.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3. Load Balancing Multiple Servers
|
|
|
|
|
|
|
|
|
|
Distribute traffic across multiple backend servers with round-robin load balancing:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, tlsTerminateToHttp } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const loadBalancer = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
createDomainConfig('app.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: {
|
|
|
|
|
// Round-robin across multiple servers
|
|
|
|
|
host: [
|
|
|
|
|
'10.0.0.10',
|
|
|
|
|
'10.0.0.11',
|
|
|
|
|
'10.0.0.12'
|
|
|
|
|
],
|
|
|
|
|
port: 8080
|
|
|
|
|
},
|
|
|
|
|
acme: { enabled: true, production: true }
|
|
|
|
|
}))
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await loadBalancer.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 4. Wildcard Subdomain Handling
|
|
|
|
|
|
|
|
|
|
Support multiple or dynamically created subdomains with one configuration:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, tlsTerminateToHttp } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const multiTenantProxy = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
// Handle all customer subdomains with one config
|
|
|
|
|
createDomainConfig('*.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'tenant-router', port: 8080 },
|
|
|
|
|
acme: { enabled: true, production: true },
|
|
|
|
|
// Pass original hostname to backend for tenant identification
|
|
|
|
|
advanced: {
|
|
|
|
|
headers: {
|
|
|
|
|
'X-Original-Host': '{sni}'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
],
|
|
|
|
|
sniEnabled: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await multiTenantProxy.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5. Comprehensive Proxy Server
|
|
|
|
|
|
|
|
|
|
Create a complete proxy solution with multiple services on a single server:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SmartProxy, createDomainConfig, httpOnly, tlsTerminateToHttp, tlsTerminateToHttps, httpsPassthrough } from '@push.rocks/smartproxy';
|
|
|
|
|
|
|
|
|
|
const enterpriseProxy = new SmartProxy({
|
|
|
|
|
fromPort: 443,
|
|
|
|
|
domainConfigs: [
|
|
|
|
|
// Web application with automatic HTTPS
|
|
|
|
|
createDomainConfig('app.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'web-app', port: 8080 },
|
|
|
|
|
acme: { enabled: true, production: true },
|
|
|
|
|
http: { enabled: true, redirectToHttps: true }
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// Legacy system that needs HTTPS passthrough
|
|
|
|
|
createDomainConfig('legacy.example.com', httpsPassthrough({
|
|
|
|
|
target: { host: 'legacy-server', port: 443 }
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// Internal APIs with IP restrictions
|
|
|
|
|
createDomainConfig('api.internal.example.com', tlsTerminateToHttp({
|
|
|
|
|
target: { host: 'api-gateway', port: 3000 },
|
|
|
|
|
security: {
|
|
|
|
|
allowedIps: ['10.0.0.0/16', '192.168.0.0/16'],
|
|
|
|
|
maxConnections: 500
|
|
|
|
|
}
|
|
|
|
|
})),
|
|
|
|
|
|
|
|
|
|
// External services with customer certificate
|
|
|
|
|
createDomainConfig('external.example.com', tlsTerminateToHttps({
|
|
|
|
|
target: { host: 'external-service', port: 8443 },
|
|
|
|
|
https: {
|
|
|
|
|
customCert: {
|
|
|
|
|
key: fs.readFileSync('external-key.pem', 'utf8'),
|
|
|
|
|
cert: fs.readFileSync('external-cert.pem', 'utf8')
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
],
|
|
|
|
|
sniEnabled: true,
|
|
|
|
|
// Enable connection timeouts for security
|
|
|
|
|
inactivityTimeout: 30000,
|
|
|
|
|
// Using global certificate management
|
|
|
|
|
acme: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
contactEmail: 'admin@example.com',
|
|
|
|
|
useProduction: true,
|
|
|
|
|
renewThresholdDays: 30
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
await enterpriseProxy.start();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Unified Forwarding System Details
|
|
|
|
|
|
|
|
|
|
SmartProxy's unified forwarding 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
|
|
|
|
|
### Configuration Format
|
|
|
|
|
|
|
|
|
|
Each domain is configured with a forwarding type and target:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
{
|
|
|
|
|
domains: ['example.com'],
|
|
|
|
|
domains: ['example.com'], // Single domain or array of domains (with wildcard support)
|
|
|
|
|
forwarding: {
|
|
|
|
|
type: 'http-only',
|
|
|
|
|
type: 'http-only', // One of the four forwarding types
|
|
|
|
|
target: {
|
|
|
|
|
host: 'localhost',
|
|
|
|
|
port: 3000
|
|
|
|
|
host: 'localhost', // Backend server (string or array for load balancing)
|
|
|
|
|
port: 3000 // Backend port
|
|
|
|
|
}
|
|
|
|
|
// Additional options as needed
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Helper Functions
|
|
|
|
|
|
|
|
|
|
Helper functions are provided for common configurations:
|
|
|
|
|
Helper functions provide a cleaner syntax for creating configurations:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { createDomainConfig, httpOnly, tlsTerminateToHttp,
|
|
|
|
|
tlsTerminateToHttps, httpsPassthrough } from '@push.rocks/smartproxy';
|
|
|
|
|
// Instead of manually specifying the type and format
|
|
|
|
|
const config = createDomainConfig('example.com', httpOnly({
|
|
|
|
|
target: { host: 'localhost', port: 3000 }
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// 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 }
|
|
|
|
|
}))
|
|
|
|
|
);
|
|
|
|
|
// Available helper functions:
|
|
|
|
|
// - httpOnly() - For HTTP-only traffic
|
|
|
|
|
// - httpsPassthrough() - For SNI-based passthrough
|
|
|
|
|
// - tlsTerminateToHttp() - For HTTPS termination to HTTP
|
|
|
|
|
// - tlsTerminateToHttps() - For HTTPS termination to HTTPS
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Advanced Configuration
|
|
|
|
|
### Advanced Configuration Options
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
createDomainConfig('api.example.com', tlsTerminateToHttps({
|
|
|
|
|
// Target configuration with load balancing
|
|
|
|
|
target: {
|
|
|
|
|
host: ['10.0.0.10', '10.0.0.11'], // Round-robin load balancing
|
|
|
|
|
port: 8443
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// HTTP options
|
|
|
|
|
http: {
|
|
|
|
|
enabled: true, // Listen on HTTP port
|
|
|
|
|
redirectToHttps: true // Automatically redirect to HTTPS
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// HTTPS/TLS options
|
|
|
|
|
https: {
|
|
|
|
|
customCert: { // Provide your own certificate
|
|
|
|
|
key: '-----BEGIN PRIVATE KEY-----\n...',
|
|
|
|
|
cert: '-----BEGIN CERTIFICATE-----\n...'
|
|
|
|
|
},
|
|
|
|
|
http: {
|
|
|
|
|
enabled: true,
|
|
|
|
|
redirectToHttps: true
|
|
|
|
|
forwardSni: true // Forward original SNI to backend
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Let's Encrypt ACME integration
|
|
|
|
|
acme: {
|
|
|
|
|
enabled: true, // Enable automatic certificates
|
|
|
|
|
production: true, // Use production Let's Encrypt
|
|
|
|
|
maintenance: true // Auto-renew certificates
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Security settings
|
|
|
|
|
security: {
|
|
|
|
|
allowedIps: ['10.0.0.*'], // IP allowlist (glob patterns)
|
|
|
|
|
blockedIps: ['1.2.3.4'], // IP blocklist
|
|
|
|
|
maxConnections: 100 // Connection limits
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// Advanced settings
|
|
|
|
|
advanced: {
|
|
|
|
|
timeout: 30000, // Connection timeout in ms
|
|
|
|
|
headers: { // Custom headers to backend
|
|
|
|
|
'X-Forwarded-For': '{clientIp}',
|
|
|
|
|
'X-Original-Host': '{sni}' // Template variables available
|
|
|
|
|
},
|
|
|
|
|
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}'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
keepAlive: true // Keep connections alive
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}))
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Extended Configuration Options
|
|
|
|
|
|
|
|
|
|
#### ForwardConfig
|
|
|
|
|
#### IForwardConfig
|
|
|
|
|
- `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<string, string> }
|
|
|
|
@ -601,7 +812,7 @@ For more complex scenarios, additional options can be specified:
|
|
|
|
|
|
|
|
|
|
## Configuration Options
|
|
|
|
|
|
|
|
|
|
### NetworkProxy (NetworkProxyOptions)
|
|
|
|
|
### NetworkProxy (INetworkProxyOptions)
|
|
|
|
|
- `port` (number, required)
|
|
|
|
|
- `backendProtocol` ('http1'|'http2', default 'http1')
|
|
|
|
|
- `maxConnections` (number, default 10000)
|
|
|
|
@ -610,11 +821,11 @@ For more complex scenarios, additional options can be specified:
|
|
|
|
|
- `cors` (object)
|
|
|
|
|
- `connectionPoolSize` (number, default 50)
|
|
|
|
|
- `logLevel` ('error'|'warn'|'info'|'debug')
|
|
|
|
|
- `acme` (AcmeOptions)
|
|
|
|
|
- `acme` (IAcmeOptions)
|
|
|
|
|
- `useExternalPort80Handler` (boolean)
|
|
|
|
|
- `portProxyIntegration` (boolean)
|
|
|
|
|
|
|
|
|
|
### Port80Handler (AcmeOptions)
|
|
|
|
|
### Port80Handler (IAcmeOptions)
|
|
|
|
|
- `enabled` (boolean, default true)
|
|
|
|
|
- `port` (number, default 80)
|
|
|
|
|
- `contactEmail` (string)
|
|
|
|
@ -623,9 +834,9 @@ For more complex scenarios, additional options can be specified:
|
|
|
|
|
- `autoRenew` (boolean, default true)
|
|
|
|
|
- `certificateStore` (string)
|
|
|
|
|
- `skipConfiguredCerts` (boolean)
|
|
|
|
|
- `domainForwards` (DomainForwardConfig[])
|
|
|
|
|
- `domainForwards` (IDomainForwardConfig[])
|
|
|
|
|
|
|
|
|
|
### NfTablesProxy (NfTableProxySettings)
|
|
|
|
|
### NfTablesProxy (INfTableProxySettings)
|
|
|
|
|
- `fromPort` / `toPort` (number|range|array)
|
|
|
|
|
- `toHost` (string, default 'localhost')
|
|
|
|
|
- `preserveSourceIP`, `deleteOnExit`, `protocol`, `enableLogging`, `ipv6Support` (booleans)
|
|
|
|
@ -634,16 +845,16 @@ For more complex scenarios, additional options can be specified:
|
|
|
|
|
- `qos`, `netProxyIntegration` (objects)
|
|
|
|
|
|
|
|
|
|
### Redirect / SslRedirect
|
|
|
|
|
- Constructor options: `httpPort`, `httpsPort`, `sslOptions`, `rules` (RedirectRule[])
|
|
|
|
|
- Constructor options: `httpPort`, `httpsPort`, `sslOptions`, `rules` (IRedirectRule[])
|
|
|
|
|
|
|
|
|
|
### SmartProxy (SmartProxyOptions)
|
|
|
|
|
### SmartProxy (ISmartProxyOptions)
|
|
|
|
|
- `fromPort`, `toPort` (number)
|
|
|
|
|
- `domainConfigs` (DomainConfig[]) - Using unified forwarding configuration
|
|
|
|
|
- `domainConfigs` (IDomainConfig[]) - 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)
|
|
|
|
|
- `acme` (IAcmeOptions), `certProvisionFunction` (callback)
|
|
|
|
|
- `useNetworkProxy` (number[]), `networkProxyPort` (number)
|
|
|
|
|
- `globalPortRanges` (Array<{ from: number; to: number }>)
|
|
|
|
|
|
|
|
|
|