feat(readme): document UDP, QUIC, and HTTP/3 support in the README
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-03-19 - 25.15.0 - feat(readme)
|
||||
document UDP, QUIC, and HTTP/3 support in the README
|
||||
|
||||
- Adds README examples for UDP datagram handlers, QUIC/HTTP3 forwarding, and dual-stack TCP/UDP routes
|
||||
- Expands configuration and API reference sections to cover transport matching, UDP/QUIC options, backend transport selection, and UDP metrics
|
||||
- Updates architecture and feature descriptions to reflect UDP, QUIC, HTTP/3, and datagram handler capabilities
|
||||
|
||||
## 2026-03-19 - 25.14.1 - fix(deps)
|
||||
update build and runtime dependencies and align route validation test expectations
|
||||
|
||||
|
||||
211
readme.md
211
readme.md
@@ -1,6 +1,6 @@
|
||||
# @push.rocks/smartproxy 🚀
|
||||
|
||||
**A high-performance, Rust-powered proxy toolkit for Node.js** — unified route-based configuration for SSL/TLS termination, HTTP/HTTPS reverse proxying, WebSocket support, load balancing, custom protocol handlers, and kernel-level NFTables forwarding.
|
||||
**A high-performance, Rust-powered proxy toolkit for Node.js** — unified route-based configuration for SSL/TLS termination, HTTP/HTTPS reverse proxying, WebSocket support, UDP/QUIC/HTTP3, load balancing, custom protocol handlers, and kernel-level NFTables forwarding.
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
@@ -16,9 +16,9 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
|
||||
## 🎯 What is SmartProxy?
|
||||
|
||||
SmartProxy is a production-ready proxy solution that takes the complexity out of traffic management. Under the hood, all networking — TCP, TLS, HTTP reverse proxy, connection tracking, security enforcement, and NFTables — is handled by a **Rust engine** for maximum performance, while you configure everything through a clean TypeScript API with full type safety.
|
||||
SmartProxy is a production-ready proxy solution that takes the complexity out of traffic management. Under the hood, all networking — TCP, UDP, TLS, HTTP reverse proxy, QUIC/HTTP3, connection tracking, security enforcement, and NFTables — is handled by a **Rust engine** for maximum performance, while you configure everything through a clean TypeScript API with full type safety.
|
||||
|
||||
Whether you're building microservices, deploying edge infrastructure, or need a battle-tested reverse proxy with automatic Let's Encrypt certificates, SmartProxy has you covered.
|
||||
Whether you're building microservices, deploying edge infrastructure, proxying UDP-based protocols, or need a battle-tested reverse proxy with automatic Let's Encrypt certificates, SmartProxy has you covered.
|
||||
|
||||
### ⚡ Key Features
|
||||
|
||||
@@ -29,11 +29,12 @@ Whether you're building microservices, deploying edge infrastructure, or need a
|
||||
| 🔒 **Automatic SSL/TLS** | Zero-config HTTPS with Let's Encrypt ACME integration |
|
||||
| 🎯 **Flexible Matching** | Route by port, domain, path, protocol, client IP, TLS version, headers, or custom logic |
|
||||
| 🚄 **High-Performance** | Choose between user-space or kernel-level (NFTables) forwarding |
|
||||
| 📡 **UDP & QUIC/HTTP3** | First-class UDP transport, datagram handlers, QUIC tunneling, and HTTP/3 support |
|
||||
| ⚖️ **Load Balancing** | Round-robin, least-connections, IP-hash with health checks |
|
||||
| 🛡️ **Enterprise Security** | IP filtering, rate limiting, basic auth, JWT auth, connection limits |
|
||||
| 🔌 **WebSocket Support** | First-class WebSocket proxying with ping/pong keep-alive |
|
||||
| 🎮 **Custom Protocols** | Socket handlers for implementing any protocol in TypeScript |
|
||||
| 📊 **Live Metrics** | Real-time throughput, connection counts, and performance data |
|
||||
| 🎮 **Custom Protocols** | Socket and datagram handlers for implementing any protocol in TypeScript |
|
||||
| 📊 **Live Metrics** | Real-time throughput, connection counts, UDP sessions, and performance data |
|
||||
| 🔧 **Dynamic Management** | Add/remove ports and routes at runtime without restarts |
|
||||
| 🔄 **PROXY Protocol** | Full PROXY protocol v1/v2 support for preserving client information |
|
||||
| 💾 **Consumer Cert Storage** | Bring your own persistence — SmartProxy never writes certs to disk |
|
||||
@@ -89,7 +90,7 @@ SmartProxy uses a powerful **match/action** pattern that makes routing predictab
|
||||
```
|
||||
|
||||
Every route consists of:
|
||||
- **Match** — What traffic to capture (ports, domains, paths, protocol, IPs, headers)
|
||||
- **Match** — What traffic to capture (ports, domains, paths, transport, protocol, IPs, headers)
|
||||
- **Action** — What to do with it (`forward` or `socket-handler`)
|
||||
- **Security** (optional) — IP allow/block lists, rate limits, authentication
|
||||
- **Headers** (optional) — Request/response header manipulation with template variables
|
||||
@@ -197,7 +198,7 @@ apiRoute = addRateLimiting(apiRoute, {
|
||||
const proxy = new SmartProxy({ routes: [apiRoute] });
|
||||
```
|
||||
|
||||
### 🎮 Custom Protocol Handler
|
||||
### 🎮 Custom Protocol Handler (TCP)
|
||||
|
||||
SmartProxy lets you implement any protocol with full socket control. Routes with JavaScript socket handlers are automatically relayed from the Rust engine back to your TypeScript code:
|
||||
|
||||
@@ -247,6 +248,98 @@ const proxy = new SmartProxy({ routes: [echoRoute, customRoute] });
|
||||
| `SocketHandlers.httpBlock(status, message)` | HTTP block response |
|
||||
| `SocketHandlers.block(message)` | Block with optional message |
|
||||
|
||||
### 📡 UDP Datagram Handler
|
||||
|
||||
Handle raw UDP datagrams with custom TypeScript logic — perfect for DNS, game servers, IoT protocols, or any UDP-based service:
|
||||
|
||||
```typescript
|
||||
import { SmartProxy } from '@push.rocks/smartproxy';
|
||||
import type { IRouteConfig, TDatagramHandler, IDatagramInfo } from '@push.rocks/smartproxy';
|
||||
|
||||
// Custom UDP echo handler
|
||||
const udpHandler: TDatagramHandler = (datagram, info, reply) => {
|
||||
console.log(`UDP from ${info.sourceIp}:${info.sourcePort} on port ${info.destPort}`);
|
||||
reply(datagram); // Echo it back
|
||||
};
|
||||
|
||||
const proxy = new SmartProxy({
|
||||
routes: [{
|
||||
name: 'udp-echo',
|
||||
match: {
|
||||
ports: 5353,
|
||||
transport: 'udp' // 👈 Listen for UDP datagrams
|
||||
},
|
||||
action: {
|
||||
type: 'socket-handler',
|
||||
datagramHandler: udpHandler, // 👈 Process each datagram
|
||||
udp: {
|
||||
sessionTimeout: 60000, // Session idle timeout (ms)
|
||||
maxSessionsPerIP: 100,
|
||||
maxDatagramSize: 65535
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
await proxy.start();
|
||||
```
|
||||
|
||||
### 📡 QUIC / HTTP3 Forwarding
|
||||
|
||||
Forward QUIC traffic to backends with optional protocol translation (e.g., receive QUIC, forward as TCP/HTTP1):
|
||||
|
||||
```typescript
|
||||
import { SmartProxy } from '@push.rocks/smartproxy';
|
||||
import type { IRouteConfig } from '@push.rocks/smartproxy';
|
||||
|
||||
const quicRoute: IRouteConfig = {
|
||||
name: 'quic-to-backend',
|
||||
match: {
|
||||
ports: 443,
|
||||
transport: 'udp',
|
||||
protocol: 'quic' // 👈 Match QUIC protocol
|
||||
},
|
||||
action: {
|
||||
type: 'forward',
|
||||
targets: [{
|
||||
host: 'backend-server',
|
||||
port: 8443,
|
||||
backendTransport: 'tcp' // 👈 Translate QUIC → TCP for backend
|
||||
}],
|
||||
udp: {
|
||||
quic: {
|
||||
enableHttp3: true,
|
||||
maxIdleTimeout: 30000,
|
||||
maxConcurrentBidiStreams: 100,
|
||||
altSvcPort: 443, // Advertise in Alt-Svc header
|
||||
altSvcMaxAge: 86400
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const proxy = new SmartProxy({ routes: [quicRoute] });
|
||||
```
|
||||
|
||||
### 🔁 Dual-Stack TCP + UDP Route
|
||||
|
||||
Listen on both TCP and UDP with a single route — handle each transport with its own handler:
|
||||
|
||||
```typescript
|
||||
const dualStackRoute: IRouteConfig = {
|
||||
name: 'dual-stack-dns',
|
||||
match: {
|
||||
ports: 53,
|
||||
transport: 'all' // 👈 Listen on both TCP and UDP
|
||||
},
|
||||
action: {
|
||||
type: 'socket-handler',
|
||||
socketHandler: handleTcpDns, // 👈 TCP connections
|
||||
datagramHandler: handleUdpDns, // 👈 UDP datagrams
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### ⚡ High-Performance NFTables Forwarding
|
||||
|
||||
For ultra-low latency on Linux, use kernel-level forwarding (requires root):
|
||||
@@ -419,6 +512,10 @@ console.log(`Bytes in: ${metrics.totals.bytesIn()}`);
|
||||
console.log(`Requests/sec: ${metrics.requests.perSecond()}`);
|
||||
console.log(`Throughput in: ${metrics.throughput.instant().in} bytes/sec`);
|
||||
|
||||
// UDP metrics
|
||||
console.log(`UDP sessions: ${metrics.udp.activeSessions()}`);
|
||||
console.log(`Datagrams in: ${metrics.udp.datagramsIn()}`);
|
||||
|
||||
// Get detailed statistics from the Rust engine
|
||||
const stats = await proxy.getStatistics();
|
||||
|
||||
@@ -545,7 +642,7 @@ SmartProxy uses a hybrid **Rust + TypeScript** architecture:
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Your Application │
|
||||
│ (TypeScript — routes, config, socket handlers) │
|
||||
│ (TypeScript — routes, config, handlers) │
|
||||
└──────────────────┬──────────────────────────────────┘
|
||||
│ IPC (JSON over stdin/stdout)
|
||||
┌──────────────────▼──────────────────────────────────┐
|
||||
@@ -556,22 +653,23 @@ SmartProxy uses a hybrid **Rust + TypeScript** architecture:
|
||||
│ │ │ │ Proxy │ │ │ │ │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
|
||||
│ │ Security│ │ Metrics │ │ Connec- │ │ NFTables │ │
|
||||
│ │ Enforce │ │ Collect │ │ tion │ │ Mgr │ │
|
||||
│ │ │ │ │ │ Tracker │ │ │ │
|
||||
│ │ UDP │ │ Security│ │ Metrics │ │ NFTables │ │
|
||||
│ │ QUIC │ │ Enforce │ │ Collect │ │ Mgr │ │
|
||||
│ │ HTTP/3 │ │ │ │ │ │ │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └──────────┘ │
|
||||
└──────────────────┬──────────────────────────────────┘
|
||||
│ Unix Socket Relay
|
||||
┌──────────────────▼──────────────────────────────────┐
|
||||
│ TypeScript Socket Handler Server │
|
||||
│ (for JS-defined socket handlers & dynamic routes) │
|
||||
│ TypeScript Socket & Datagram Handler Servers │
|
||||
│ (for JS socket handlers, datagram handlers, │
|
||||
│ and dynamic routes) │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Rust Engine** handles all networking, TLS, HTTP proxying, connection management, security, and metrics
|
||||
- **TypeScript** provides the npm API, configuration types, route helpers, validation, and socket handler callbacks
|
||||
- **Rust Engine** handles all networking: TCP, UDP, TLS, QUIC, HTTP proxying, connection management, security, and metrics
|
||||
- **TypeScript** provides the npm API, configuration types, route helpers, validation, and handler callbacks
|
||||
- **IPC** — The TypeScript wrapper uses JSON commands/events over stdin/stdout to communicate with the Rust binary
|
||||
- **Socket Relay** — A Unix domain socket server for routes requiring TypeScript-side handling (socket handlers, dynamic host/port functions)
|
||||
- **Socket/Datagram Relay** — Unix domain socket servers for routes requiring TypeScript-side handling (socket handlers, datagram handlers, dynamic host/port functions)
|
||||
|
||||
## 🎯 Route Configuration Reference
|
||||
|
||||
@@ -579,22 +677,26 @@ SmartProxy uses a hybrid **Rust + TypeScript** architecture:
|
||||
|
||||
```typescript
|
||||
interface IRouteMatch {
|
||||
ports: number | number[] | Array<{ from: number; to: number }>; // Required — port(s) to listen on
|
||||
domains?: string | string[]; // 'example.com', '*.example.com'
|
||||
path?: string; // '/api/*', '/users/:id'
|
||||
clientIp?: string[]; // ['10.0.0.0/8', '192.168.*']
|
||||
tlsVersion?: string[]; // ['TLSv1.2', 'TLSv1.3']
|
||||
ports: TPortRange; // Required — port(s) to listen on
|
||||
transport?: 'tcp' | 'udp' | 'all'; // Transport protocol (default: 'tcp')
|
||||
domains?: string | string[]; // 'example.com', '*.example.com'
|
||||
path?: string; // '/api/*', '/users/:id'
|
||||
clientIp?: string[]; // ['10.0.0.0/8', '192.168.*']
|
||||
tlsVersion?: string[]; // ['TLSv1.2', 'TLSv1.3']
|
||||
headers?: Record<string, string | RegExp>; // Match by HTTP headers
|
||||
protocol?: 'http' | 'tcp'; // Match specific protocol ('http' includes h2 + WebSocket upgrades)
|
||||
protocol?: 'http' | 'tcp' | 'udp' | 'quic' | 'http3'; // Application-layer protocol
|
||||
}
|
||||
|
||||
// Port range supports single numbers, arrays, and ranges
|
||||
type TPortRange = number | Array<number | { from: number; to: number }>;
|
||||
```
|
||||
|
||||
### Action Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `forward` | Proxy to one or more backend targets (with optional TLS, WebSocket, load balancing) |
|
||||
| `socket-handler` | Custom socket handling function in TypeScript |
|
||||
| `forward` | Proxy to one or more backend targets (with optional TLS, WebSocket, load balancing, UDP/QUIC) |
|
||||
| `socket-handler` | Custom socket/datagram handling function in TypeScript |
|
||||
|
||||
### Target Options
|
||||
|
||||
@@ -602,14 +704,15 @@ interface IRouteMatch {
|
||||
interface IRouteTarget {
|
||||
host: string | string[] | ((context: IRouteContext) => string | string[]);
|
||||
port: number | 'preserve' | ((context: IRouteContext) => number);
|
||||
tls?: IRouteTls; // Per-target TLS override
|
||||
priority?: number; // Target priority
|
||||
match?: ITargetMatch; // Sub-match within a route (by port, path, headers, method)
|
||||
tls?: IRouteTls; // Per-target TLS override
|
||||
priority?: number; // Target priority
|
||||
match?: ITargetMatch; // Sub-match within a route (by port, path, headers, method)
|
||||
websocket?: IRouteWebSocket;
|
||||
loadBalancing?: IRouteLoadBalancing;
|
||||
sendProxyProtocol?: boolean;
|
||||
headers?: IRouteHeaders;
|
||||
advanced?: IRouteAdvanced;
|
||||
backendTransport?: 'tcp' | 'udp'; // Backend transport (e.g., receive QUIC, forward as TCP)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -666,6 +769,27 @@ interface IRouteLoadBalancing {
|
||||
}
|
||||
```
|
||||
|
||||
### UDP & QUIC Options
|
||||
|
||||
```typescript
|
||||
interface IRouteUdp {
|
||||
sessionTimeout?: number; // Idle timeout per UDP session (ms, default: 60000)
|
||||
maxSessionsPerIP?: number; // Max concurrent sessions per IP (default: 1000)
|
||||
maxDatagramSize?: number; // Max datagram size in bytes (default: 65535)
|
||||
quic?: IRouteQuic;
|
||||
}
|
||||
|
||||
interface IRouteQuic {
|
||||
maxIdleTimeout?: number; // QUIC idle timeout (ms, default: 30000)
|
||||
maxConcurrentBidiStreams?: number; // Max bidi streams (default: 100)
|
||||
maxConcurrentUniStreams?: number; // Max uni streams (default: 100)
|
||||
enableHttp3?: boolean; // Enable HTTP/3 (default: false)
|
||||
altSvcPort?: number; // Port for Alt-Svc header
|
||||
altSvcMaxAge?: number; // Alt-Svc max age in seconds (default: 86400)
|
||||
initialCongestionWindow?: number; // Initial congestion window (bytes)
|
||||
}
|
||||
```
|
||||
|
||||
## 🛠️ Helper Functions Reference
|
||||
|
||||
All helpers are fully typed and return `IRouteConfig` or `IRouteConfig[]`:
|
||||
@@ -689,7 +813,7 @@ import {
|
||||
createWebSocketRoute, // WebSocket-enabled route
|
||||
|
||||
// Custom Protocols
|
||||
createSocketHandlerRoute, // Custom socket handler
|
||||
createSocketHandlerRoute, // Custom TCP socket handler
|
||||
SocketHandlers, // Pre-built handlers (echo, proxy, block, etc.)
|
||||
|
||||
// NFTables (Linux, requires root)
|
||||
@@ -718,6 +842,8 @@ import {
|
||||
} from '@push.rocks/smartproxy';
|
||||
```
|
||||
|
||||
> **Tip:** For UDP datagram handler routes or QUIC/HTTP3 routes, construct `IRouteConfig` objects directly — there are no helper functions for these yet. See the [UDP Datagram Handler](#-udp-datagram-handler) and [QUIC / HTTP3 Forwarding](#-quic--http3-forwarding) examples above.
|
||||
|
||||
## 📖 API Documentation
|
||||
|
||||
### SmartProxy Class
|
||||
@@ -753,6 +879,8 @@ class SmartProxy extends EventEmitter {
|
||||
|
||||
// Events
|
||||
on(event: 'error', handler: (err: Error) => void): this;
|
||||
on(event: 'certificate-issued', handler: (ev: ICertificateIssuedEvent) => void): this;
|
||||
on(event: 'certificate-failed', handler: (ev: ICertificateFailedEvent) => void): this;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -775,6 +903,8 @@ interface ISmartProxyOptions {
|
||||
// Custom certificate provisioning
|
||||
certProvisionFunction?: (domain: string) => Promise<ICert | 'http01'>;
|
||||
certProvisionFallbackToAcme?: boolean; // Fall back to ACME on failure (default: true)
|
||||
certProvisionTimeout?: number; // Timeout per provision call (ms)
|
||||
certProvisionConcurrency?: number; // Max concurrent provisions
|
||||
|
||||
// Consumer-managed certificate persistence (see "Consumer-Managed Certificate Storage")
|
||||
certStore?: ISmartProxyCertStore;
|
||||
@@ -782,6 +912,9 @@ interface ISmartProxyOptions {
|
||||
// Self-signed fallback
|
||||
disableDefaultCert?: boolean; // Disable '*' self-signed fallback (default: false)
|
||||
|
||||
// Rust binary path override
|
||||
rustBinaryPath?: string; // Custom path to the Rust proxy binary
|
||||
|
||||
// Global defaults
|
||||
defaults?: {
|
||||
target?: { host: string; port: number };
|
||||
@@ -868,11 +1001,22 @@ metrics.requests.perSecond(); // Requests per second
|
||||
metrics.requests.perMinute(); // Requests per minute
|
||||
metrics.requests.total(); // Total requests
|
||||
|
||||
// UDP metrics
|
||||
metrics.udp.activeSessions(); // Current active UDP sessions
|
||||
metrics.udp.totalSessions(); // Total UDP sessions since start
|
||||
metrics.udp.datagramsIn(); // Datagrams received
|
||||
metrics.udp.datagramsOut(); // Datagrams sent
|
||||
|
||||
// Cumulative totals
|
||||
metrics.totals.bytesIn(); // Total bytes received
|
||||
metrics.totals.bytesOut(); // Total bytes sent
|
||||
metrics.totals.connections(); // Total connections
|
||||
|
||||
// Backend metrics
|
||||
metrics.backends.byBackend(); // Map<backend, IBackendMetrics>
|
||||
metrics.backends.protocols(); // Map<backend, protocol>
|
||||
metrics.backends.topByErrors(10); // Top N error-prone backends
|
||||
|
||||
// Percentiles
|
||||
metrics.percentiles.connectionDuration(); // { p50, p95, p99 }
|
||||
metrics.percentiles.bytesTransferred(); // { in: { p50, p95, p99 }, out: { p50, p95, p99 } }
|
||||
@@ -896,11 +1040,12 @@ metrics.percentiles.bytesTransferred(); // { in: { p50, p95, p99 }, out: { p5
|
||||
### Rust Binary Not Found
|
||||
|
||||
SmartProxy searches for the Rust binary in this order:
|
||||
1. `SMARTPROXY_RUST_BINARY` environment variable
|
||||
2. Platform-specific npm package (`@push.rocks/smartproxy-linux-x64`, etc.)
|
||||
3. `dist_rust/rustproxy` relative to the package root (built by `tsrust`)
|
||||
4. Local dev build (`./rust/target/release/rustproxy`)
|
||||
5. System PATH (`rustproxy`)
|
||||
1. `rustBinaryPath` option in `ISmartProxyOptions`
|
||||
2. `SMARTPROXY_RUST_BINARY` environment variable
|
||||
3. Platform-specific npm package (`@push.rocks/smartproxy-linux-x64`, etc.)
|
||||
4. `dist_rust/rustproxy` relative to the package root (built by `tsrust`)
|
||||
5. Local dev build (`./rust/target/release/rustproxy`)
|
||||
6. System PATH (`rustproxy`)
|
||||
|
||||
### Performance Tuning
|
||||
- ✅ Use NFTables forwarding for high-traffic routes (Linux only)
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartproxy',
|
||||
version: '25.14.1',
|
||||
version: '25.15.0',
|
||||
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user