2022-07-29 01:52:34 +02:00
2019-08-20 17:50:17 +02:00
2026-02-16 03:00:39 +00:00

@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.

📦 Installation

npm install @push.rocks/smartproxy
# or
pnpm add @push.rocks/smartproxy

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.

🎯 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.

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.

Key Features

Feature Description
🦀 Rust-Powered Engine All networking handled by a high-performance Rust binary via IPC
🔀 Unified Route-Based Config Clean match/action patterns for intuitive traffic routing
🔒 Automatic SSL/TLS Zero-config HTTPS with Let's Encrypt ACME integration
🎯 Flexible Matching Route by port, domain, path, client IP, TLS version, headers, or custom logic
🚄 High-Performance Choose between user-space or kernel-level (NFTables) forwarding
⚖️ 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
🔧 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

🚀 Quick Start

Get up and running in 30 seconds:

import { SmartProxy, createCompleteHttpsServer } from '@push.rocks/smartproxy';

// Create a proxy with automatic HTTPS
const proxy = new SmartProxy({
  acme: {
    email: 'ssl@yourdomain.com',
    useProduction: true
  },
  routes: [
    // Complete HTTPS setup in one call! ✨
    ...createCompleteHttpsServer('app.example.com', {
      host: 'localhost',
      port: 3000
    }, {
      certificate: 'auto'  // Automatic Let's Encrypt cert 🎩
    })
  ]
});

await proxy.start();
console.log('🚀 Proxy running with automatic HTTPS!');

📚 Core Concepts

🏗️ Route-Based Architecture

SmartProxy uses a powerful match/action pattern that makes routing predictable and maintainable:

{
  name: 'api-route',
  match: {
    ports: 443,
    domains: 'api.example.com',
    path: '/v1/*'
  },
  action: {
    type: 'forward',
    targets: [{ host: 'backend', port: 8080 }],
    tls: { mode: 'terminate', certificate: 'auto' }
  }
}

Every route consists of:

  • Match — What traffic to capture (ports, domains, paths, 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
  • Name/Priority (optional) — For identification and ordering

🔄 TLS Modes

SmartProxy supports three TLS handling modes:

Mode Description Use Case
passthrough Forward encrypted traffic as-is (SNI-based routing) Backend handles TLS
terminate Decrypt at proxy, forward plain HTTP to backend Standard reverse proxy
terminate-and-reencrypt Decrypt, then re-encrypt to backend Zero-trust environments

💡 Common Use Cases

🌐 HTTP to HTTPS Redirect

import { SmartProxy, createHttpToHttpsRedirect } from '@push.rocks/smartproxy';

const proxy = new SmartProxy({
  routes: [
    createHttpToHttpsRedirect(['example.com', '*.example.com'])
  ]
});

⚖️ Load Balancer with Health Checks

import { SmartProxy, createLoadBalancerRoute } from '@push.rocks/smartproxy';

const proxy = new SmartProxy({
  routes: [
    createLoadBalancerRoute(
      'app.example.com',
      [
        { host: 'server1.internal', port: 8080 },
        { host: 'server2.internal', port: 8080 },
        { host: 'server3.internal', port: 8080 }
      ],
      {
        tls: { mode: 'terminate', certificate: 'auto' },
        loadBalancing: {
          algorithm: 'round-robin',
          healthCheck: {
            path: '/health',
            interval: 30000,
            timeout: 5000
          }
        }
      }
    )
  ]
});

🔌 WebSocket Proxy

import { SmartProxy, createWebSocketRoute } from '@push.rocks/smartproxy';

const proxy = new SmartProxy({
  routes: [
    createWebSocketRoute(
      'ws.example.com',
      { host: 'websocket-server', port: 8080 },
      {
        path: '/socket',
        useTls: true,
        certificate: 'auto',
        pingInterval: 30000,
        pingTimeout: 10000
      }
    )
  ]
});

🚦 API Gateway with Rate Limiting

import { SmartProxy, createApiGatewayRoute, addRateLimiting } from '@push.rocks/smartproxy';

let apiRoute = createApiGatewayRoute(
  'api.example.com',
  '/api',
  { host: 'api-backend', port: 8080 },
  {
    useTls: true,
    certificate: 'auto',
    addCorsHeaders: true
  }
);

// Add rate limiting — 100 requests per minute per IP
apiRoute = addRateLimiting(apiRoute, {
  maxRequests: 100,
  window: 60,
  keyBy: 'ip'
});

const proxy = new SmartProxy({ routes: [apiRoute] });

🎮 Custom Protocol Handler

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:

import { SmartProxy, createSocketHandlerRoute, SocketHandlers } from '@push.rocks/smartproxy';

// Use pre-built handlers
const echoRoute = createSocketHandlerRoute(
  'echo.example.com',
  7777,
  SocketHandlers.echo
);

// Or create your own custom protocol
const customRoute = createSocketHandlerRoute(
  'custom.example.com',
  9999,
  async (socket) => {
    console.log(`New connection on custom protocol`);
    socket.write('Welcome to my custom protocol!\n');

    socket.on('data', (data) => {
      const command = data.toString().trim();
      switch (command) {
        case 'PING': socket.write('PONG\n'); break;
        case 'TIME': socket.write(`${new Date().toISOString()}\n`); break;
        case 'QUIT': socket.end('Goodbye!\n'); break;
        default: socket.write(`Unknown: ${command}\n`);
      }
    });
  }
);

const proxy = new SmartProxy({ routes: [echoRoute, customRoute] });

Pre-built Socket Handlers:

Handler Description
SocketHandlers.echo Echo server — returns everything sent
SocketHandlers.proxy(host, port) TCP proxy to another server
SocketHandlers.lineProtocol(handler) Line-based text protocol
SocketHandlers.httpResponse(code, body) Simple HTTP response
SocketHandlers.httpRedirect(url, code) HTTP redirect with template variables ({domain}, {path}, {port}, {clientIp})
SocketHandlers.httpServer(handler) Full HTTP request/response handling
SocketHandlers.httpBlock(status, message) HTTP block response
SocketHandlers.block(message) Block with optional message

High-Performance NFTables Forwarding

For ultra-low latency on Linux, use kernel-level forwarding (requires root):

import { SmartProxy, createNfTablesTerminateRoute } from '@push.rocks/smartproxy';

const proxy = new SmartProxy({
  routes: [
    createNfTablesTerminateRoute(
      'fast.example.com',
      { host: 'backend', port: 8080 },
      {
        ports: 443,
        certificate: 'auto',
        preserveSourceIP: true  // Backend sees real client IP
      }
    )
  ]
});

🔒 SNI Passthrough (TLS Passthrough)

Forward encrypted traffic to backends without terminating TLS — the proxy routes based on the SNI hostname alone:

import { SmartProxy, createHttpsPassthroughRoute } from '@push.rocks/smartproxy';

const proxy = new SmartProxy({
  routes: [
    createHttpsPassthroughRoute('secure.example.com', {
      host: 'backend-that-handles-tls',
      port: 8443
    })
  ]
});

🔧 Advanced Features

🎯 Dynamic Routing

Route traffic based on runtime conditions using function-based host/port resolution:

const proxy = new SmartProxy({
  routes: [{
    name: 'dynamic-backend',
    match: {
      ports: 443,
      domains: 'app.example.com'
    },
    action: {
      type: 'forward',
      targets: [{
        host: (context) => {
          return context.path?.startsWith('/premium')
            ? 'premium-backend'
            : 'standard-backend';
        },
        port: 8080
      }],
      tls: { mode: 'terminate', certificate: 'auto' }
    }
  }]
});

Note: Routes with dynamic functions (host/port callbacks) are automatically relayed through the TypeScript socket handler server, since JavaScript functions can't be serialized to Rust.

🔒 Security Controls

Comprehensive per-route security options:

{
  name: 'secure-api',
  match: { ports: 443, domains: 'api.example.com' },
  action: {
    type: 'forward',
    targets: [{ host: 'api-backend', port: 8080 }],
    tls: { mode: 'terminate', certificate: 'auto' }
  },
  security: {
    // IP-based access control
    ipAllowList: ['10.0.0.0/8', '192.168.*'],
    ipBlockList: ['192.168.1.100'],

    // Connection limits
    maxConnections: 1000,

    // Rate limiting
    rateLimit: {
      enabled: true,
      maxRequests: 100,
      window: 60
    },

    // Authentication
    basicAuth: { users: [{ username: 'admin', password: 'secret' }] },
    jwtAuth: { secret: 'your-jwt-secret', algorithm: 'HS256' }
  }
}

Security modifier helpers let you add security to any existing route:

import { addRateLimiting, addBasicAuth, addJwtAuth } from '@push.rocks/smartproxy';

let route = createHttpsTerminateRoute('api.example.com', { host: 'backend', port: 8080 });
route = addRateLimiting(route, { maxRequests: 100, window: 60, keyBy: 'ip' });
route = addBasicAuth(route, { users: [{ username: 'admin', password: 'secret' }] });

📊 Runtime Management

Control your proxy without restarts:

// Dynamic port management
await proxy.addListeningPort(8443);
await proxy.removeListeningPort(8080);
const ports = await proxy.getListeningPorts();

// Update routes on the fly (atomic, mutex-locked)
await proxy.updateRoutes([...newRoutes]);

// Get real-time metrics
const metrics = proxy.getMetrics();
console.log(`Active connections: ${metrics.connections.active()}`);
console.log(`Bytes in: ${metrics.totals.bytesIn()}`);
console.log(`Requests/sec: ${metrics.requests.perSecond()}`);
console.log(`Throughput in: ${metrics.throughput.instant().in} bytes/sec`);

// Get detailed statistics from the Rust engine
const stats = await proxy.getStatistics();

// Certificate management
await proxy.provisionCertificate('my-route-name');
await proxy.renewCertificate('my-route-name');
const certStatus = await proxy.getCertificateStatus('my-route-name');

// NFTables status
const nftStatus = await proxy.getNfTablesStatus();

🔄 Header Manipulation

Transform requests and responses with template variables:

{
  action: {
    type: 'forward',
    targets: [{ host: 'backend', port: 8080 }]
  },
  headers: {
    request: {
      'X-Real-IP': '{clientIp}',
      'X-Request-ID': '{uuid}',
      'X-Forwarded-Proto': 'https'
    },
    response: {
      'Strict-Transport-Security': 'max-age=31536000',
      'X-Frame-Options': 'DENY'
    }
  }
}

🔀 PROXY Protocol Support

Preserve original client information through proxy chains:

const proxy = new SmartProxy({
  // Accept PROXY protocol from trusted load balancers
  acceptProxyProtocol: true,
  proxyIPs: ['10.0.0.1', '10.0.0.2'],

  // Forward PROXY protocol to backends
  sendProxyProtocol: true,

  routes: [...]
});

🏗️ Custom Certificate Provisioning

Supply your own certificates or integrate with external certificate providers:

const proxy = new SmartProxy({
  certProvisionFunction: async (domain: string) => {
    // Return 'http01' to let the built-in ACME handle it
    if (domain.endsWith('.example.com')) return 'http01';

    // Or return a static certificate object
    return {
      publicKey: myPemCert,
      privateKey: myPemKey,
    };
  },
  certProvisionFallbackToAcme: true,  // Fall back to ACME if callback fails
  routes: [...]
});

💾 Consumer-Managed Certificate Storage

SmartProxy never writes certificates to disk. Instead, you own all persistence through the certStore interface. This gives you full control — store certs in a database, cloud KMS, encrypted vault, or wherever makes sense for your infrastructure:

const proxy = new SmartProxy({
  routes: [...],

  certProvisionFunction: async (domain) => myAcme.provision(domain),

  // Your persistence layer — SmartProxy calls these hooks
  certStore: {
    // Called once on startup to pre-load persisted certs
    loadAll: async () => {
      const certs = await myDb.getAllCerts();
      return certs.map(c => ({
        domain: c.domain,
        publicKey: c.certPem,
        privateKey: c.keyPem,
        ca: c.caPem,      // optional
      }));
    },

    // Called after each successful cert provision
    save: async (domain, publicKey, privateKey, ca) => {
      await myDb.upsertCert({ domain, certPem: publicKey, keyPem: privateKey, caPem: ca });
    },

    // Optional: called when a cert should be removed
    remove: async (domain) => {
      await myDb.deleteCert(domain);
    },
  },
});

Startup flow:

  1. Rust engine starts
  2. Default self-signed * fallback cert is loaded (unless disableDefaultCert: true)
  3. certStore.loadAll() is called → all returned certs are loaded into the Rust TLS stack
  4. certProvisionFunction runs for any remaining certificate: 'auto' routes (skipping domains already loaded from the store)
  5. After each successful provision, certStore.save() is called

This means your second startup is instant — no re-provisioning needed for domains that already have valid certs in your store.

🏛️ Architecture

SmartProxy uses a hybrid Rust + TypeScript architecture:

┌─────────────────────────────────────────────────────┐
│                  Your Application                    │
│     (TypeScript — routes, config, socket handlers)   │
└──────────────────┬──────────────────────────────────┘
                   │  IPC (JSON over stdin/stdout)
┌──────────────────▼──────────────────────────────────┐
│              Rust Proxy Engine                        │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐  │
│  │ TCP/TLS │ │  HTTP    │ │  Route  │ │  ACME    │  │
│  │ Listener│ │ Reverse  │ │ Matcher │ │ Cert Mgr │  │
│  │         │ │  Proxy   │ │         │ │          │  │
│  └─────────┘ └─────────┘ └─────────┘ └──────────┘  │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐  │
│  │ Security│ │ Metrics  │ │ Connec- │ │ NFTables │  │
│  │ Enforce │ │ Collect  │ │  tion   │ │  Mgr     │  │
│  │         │ │          │ │ Tracker │ │          │  │
│  └─────────┘ └─────────┘ └─────────┘ └──────────┘  │
└──────────────────┬──────────────────────────────────┘
                   │  Unix Socket Relay
┌──────────────────▼──────────────────────────────────┐
│       TypeScript Socket Handler Server               │
│  (for JS-defined socket handlers & 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
  • 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)

🎯 Route Configuration Reference

Match Criteria

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']
  headers?: Record<string, string | RegExp>;  // Match by HTTP headers
}

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

Target Options

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)
  websocket?: IRouteWebSocket;
  loadBalancing?: IRouteLoadBalancing;
  sendProxyProtocol?: boolean;
  headers?: IRouteHeaders;
  advanced?: IRouteAdvanced;
}

TLS Options

interface IRouteTls {
  mode: 'passthrough' | 'terminate' | 'terminate-and-reencrypt';
  certificate?: 'auto' | {
    key: string;
    cert: string;
    ca?: string;
    keyFile?: string;
    certFile?: string;
  };
  acme?: {
    email: string;
    useProduction?: boolean;
    challengePort?: number;
    renewBeforeDays?: number;
  };
  versions?: string[];
  ciphers?: string;
  honorCipherOrder?: boolean;
  sessionTimeout?: number;
}

WebSocket Options

interface IRouteWebSocket {
  enabled: boolean;
  pingInterval?: number;     // ms between pings
  pingTimeout?: number;      // ms to wait for pong
  maxPayloadSize?: number;   // Maximum frame payload
  subprotocols?: string[];   // Allowed subprotocols
  allowedOrigins?: string[]; // CORS origins
}

Load Balancing Options

interface IRouteLoadBalancing {
  algorithm: 'round-robin' | 'least-connections' | 'ip-hash';
  healthCheck?: {
    path: string;
    interval: number;        // ms
    timeout: number;         // ms
    unhealthyThreshold: number;
    healthyThreshold: number;
  };
}

🛠️ Helper Functions Reference

All helpers are fully typed and return IRouteConfig or IRouteConfig[]:

import {
  // HTTP/HTTPS
  createHttpRoute,                 // Plain HTTP route
  createHttpsTerminateRoute,       // HTTPS with TLS termination
  createHttpsPassthroughRoute,     // SNI passthrough (no termination)
  createHttpToHttpsRedirect,       // HTTP → HTTPS redirect
  createCompleteHttpsServer,       // HTTPS + redirect combo (returns IRouteConfig[])

  // Load Balancing
  createLoadBalancerRoute,         // Multi-backend with health checks
  createSmartLoadBalancer,         // Dynamic domain-based backend selection

  // API & WebSocket
  createApiRoute,                  // API route with path matching
  createApiGatewayRoute,           // API gateway with CORS
  createWebSocketRoute,            // WebSocket-enabled route

  // Custom Protocols
  createSocketHandlerRoute,        // Custom socket handler
  SocketHandlers,                  // Pre-built handlers (echo, proxy, block, etc.)

  // NFTables (Linux, requires root)
  createNfTablesRoute,             // Kernel-level packet forwarding
  createNfTablesTerminateRoute,    // NFTables + TLS termination
  createCompleteNfTablesHttpsServer, // NFTables HTTPS + redirect combo

  // Dynamic Routing
  createPortMappingRoute,          // Port mapping with context
  createOffsetPortMappingRoute,    // Simple port offset
  createDynamicRoute,              // Dynamic host/port via functions
  createPortOffset,                // Port offset factory

  // Security Modifiers
  addRateLimiting,                 // Add rate limiting to any route
  addBasicAuth,                    // Add basic auth to any route
  addJwtAuth,                      // Add JWT auth to any route

  // Route Utilities
  mergeRouteConfigs,               // Deep-merge two route configs
  findMatchingRoutes,              // Find routes matching criteria
  findBestMatchingRoute,           // Find best matching route
  cloneRoute,                      // Deep-clone a route
  generateRouteId,                 // Generate deterministic route ID
  RouteValidator,                  // Validate route configurations
} from '@push.rocks/smartproxy';

📖 API Documentation

SmartProxy Class

class SmartProxy extends EventEmitter {
  constructor(options: ISmartProxyOptions);

  // Lifecycle
  start(): Promise<void>;
  stop(): Promise<void>;

  // Route Management (atomic, mutex-locked)
  updateRoutes(routes: IRouteConfig[]): Promise<void>;

  // Port Management
  addListeningPort(port: number): Promise<void>;
  removeListeningPort(port: number): Promise<void>;
  getListeningPorts(): Promise<number[]>;

  // Monitoring & Metrics
  getMetrics(): IMetrics;              // Sync — returns cached metrics adapter
  getStatistics(): Promise<any>;       // Async — queries Rust engine

  // Certificate Management
  provisionCertificate(routeName: string): Promise<void>;
  renewCertificate(routeName: string): Promise<void>;
  getCertificateStatus(routeName: string): Promise<any>;
  getEligibleDomainsForCertificates(): string[];

  // NFTables
  getNfTablesStatus(): Promise<Record<string, any>>;

  // Events
  on(event: 'error', handler: (err: Error) => void): this;
}

Configuration Options

interface ISmartProxyOptions {
  routes: IRouteConfig[];                   // Required: array of route configs

  // ACME/Let's Encrypt
  acme?: {
    email: string;                          // Contact email for Let's Encrypt
    useProduction?: boolean;                // Use production servers (default: false)
    port?: number;                          // HTTP-01 challenge port (default: 80)
    renewThresholdDays?: number;            // Days before expiry to renew (default: 30)
    autoRenew?: boolean;                    // Enable auto-renewal (default: true)
    renewCheckIntervalHours?: number;       // Renewal check interval (default: 24)
  };

  // Custom certificate provisioning
  certProvisionFunction?: (domain: string) => Promise<ICert | 'http01'>;
  certProvisionFallbackToAcme?: boolean;    // Fall back to ACME on failure (default: true)

  // Consumer-managed certificate persistence (see "Consumer-Managed Certificate Storage")
  certStore?: ISmartProxyCertStore;

  // Self-signed fallback
  disableDefaultCert?: boolean;             // Disable '*' self-signed fallback (default: false)

  // Global defaults
  defaults?: {
    target?: { host: string; port: number };
    security?: { ipAllowList?: string[]; ipBlockList?: string[]; maxConnections?: number };
  };

  // PROXY protocol
  proxyIPs?: string[];                      // Trusted proxy IPs
  acceptProxyProtocol?: boolean;            // Accept PROXY protocol headers
  sendProxyProtocol?: boolean;              // Send PROXY protocol to targets

  // Timeouts
  connectionTimeout?: number;               // Backend connection timeout (default: 30s)
  initialDataTimeout?: number;              // Initial data/SNI timeout (default: 120s)
  socketTimeout?: number;                   // Socket inactivity timeout (default: 1h)
  maxConnectionLifetime?: number;           // Max connection lifetime (default: 24h)
  inactivityTimeout?: number;               // Inactivity timeout (default: 4h)
  gracefulShutdownTimeout?: number;         // Shutdown grace period (default: 30s)

  // Connection limits
  maxConnectionsPerIP?: number;             // Per-IP connection limit (default: 100)
  connectionRateLimitPerMinute?: number;    // Per-IP rate limit (default: 300/min)

  // Keep-alive
  keepAliveTreatment?: 'standard' | 'extended' | 'immortal';
  keepAliveInactivityMultiplier?: number;   // (default: 6)
  extendedKeepAliveLifetime?: number;       // (default: 7 days)

  // Metrics
  metrics?: {
    enabled?: boolean;
    sampleIntervalMs?: number;
    retentionSeconds?: number;
  };

  // Behavior
  enableDetailedLogging?: boolean;          // Verbose connection logging
  enableTlsDebugLogging?: boolean;          // TLS handshake debug logging
}

ISmartProxyCertStore Interface

interface ISmartProxyCertStore {
  /** Called once on startup to pre-load persisted certs */
  loadAll: () => Promise<Array<{
    domain: string;
    publicKey: string;
    privateKey: string;
    ca?: string;
  }>>;

  /** Called after each successful cert provision */
  save: (domain: string, publicKey: string, privateKey: string, ca?: string) => Promise<void>;

  /** Optional: remove a cert from storage */
  remove?: (domain: string) => Promise<void>;
}

IMetrics Interface

The getMetrics() method returns a cached metrics adapter that polls the Rust engine:

const metrics = proxy.getMetrics();

// Connection metrics
metrics.connections.active();              // Current active connections
metrics.connections.total();               // Total connections since start
metrics.connections.byRoute();             // Map<routeName, activeCount>
metrics.connections.byIP();                // Map<ip, activeCount>
metrics.connections.topIPs(10);            // Top N IPs by connection count

// Throughput (bytes/sec)
metrics.throughput.instant();              // { in: number, out: number }
metrics.throughput.recent();               // Recent average
metrics.throughput.average();              // Overall average
metrics.throughput.byRoute();              // Map<routeName, { in, out }>

// Request rates
metrics.requests.perSecond();              // Requests per second
metrics.requests.perMinute();              // Requests per minute
metrics.requests.total();                  // Total requests

// Cumulative totals
metrics.totals.bytesIn();                  // Total bytes received
metrics.totals.bytesOut();                 // Total bytes sent
metrics.totals.connections();              // Total connections

// Percentiles
metrics.percentiles.connectionDuration();  // { p50, p95, p99 }
metrics.percentiles.bytesTransferred();    // { in: { p50, p95, p99 }, out: { p50, p95, p99 } }

🐛 Troubleshooting

Certificate Issues

  • Ensure domain DNS points to your server
  • Port 80 must be accessible for ACME HTTP-01 challenges
  • Check DNS propagation with dig or nslookup
  • Verify the email in ACME configuration is valid
  • Use getCertificateStatus('route-name') to check cert state

Connection Problems

  • Check route priorities (higher number = matched first)
  • Verify security rules aren't blocking legitimate traffic
  • Test with curl -v for detailed connection output
  • Enable debug logging with enableDetailedLogging: true

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)

Performance Tuning

  • Use NFTables forwarding for high-traffic routes (Linux only)
  • Enable connection keep-alive where appropriate
  • Use getMetrics() and getStatistics() to identify bottlenecks
  • Adjust maxConnectionsPerIP and connectionRateLimitPerMinute based on your workload
  • Use passthrough TLS mode when backend can handle TLS directly

🏆 Best Practices

  1. 📝 Use Helper Functions — They provide sensible defaults and prevent common mistakes
  2. 🎯 Set Route Priorities — More specific routes should have higher priority values
  3. 🔒 Enable Security — Always use IP filtering and rate limiting for public-facing services
  4. 📊 Monitor Metrics — Use the built-in metrics to catch issues early
  5. 🔄 Certificate Monitoring — Set up alerts before certificates expire
  6. 🛑 Graceful Shutdown — Always call proxy.stop() for clean connection termination
  7. Validate Routes — Use RouteValidator.validateRoutes() to catch config errors before deployment
  8. 🔀 Atomic Updates — Use updateRoutes() for hot-reloading routes (mutex-locked, no downtime)
  9. 🎮 Use Socket Handlers — For protocols beyond HTTP, implement custom socket handlers instead of fighting the proxy model
  10. 💾 Use certStore — Persist certs in your own storage to avoid re-provisioning on every restart

This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the LICENSE file.

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 or third parties, 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 or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or 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.

Description
a proxy for handling high workloads of proxying, internally using rust for performance.
Readme 5.7 MiB
Languages
TypeScript 60.2%
Rust 39.8%