Skip to main content

readme.md for @push.rocks/smartvpn

A high-performance VPNΒ solution with a TypeScript control plane and a Rust data plane daemon. ManageEnterprise-ready VPNclient connectionsauthentication, withtriple clean,transport fully-support (WebSocket + QUIC + WireGuard), and a typed APIshub whileAPI allfor networkingmanaging heavyclients liftingfrom β€” encryption, tunneling, QoS, rate limiting β€” runs at native speed in Rust.code.

πŸ”’πŸ” Noise NKIK handshakemutual +authentication XChaCha20-Poly1305β€” encryptionper-client X25519 keypairs, server-side registry πŸš€ Triple transport: WebSocket (Cloudflare-friendly), raw QUIC (datagrams), and WireGuard (standard protocol) πŸ›‘οΈ ACL engineΒ β€” deny-overrides-allow IP filtering, aligned with SmartProxy conventions πŸ“Š Adaptive QoS: packetper-client classification,rate limiting, priority queues, per-clientconnection ratequality limitingtracking πŸ”„ Auto-transportHub API: triesone QUICcreateClient() first,call fallsgenerates backkeys, toassigns WebSocketIP, seamlesslyreturns both SmartVPN + WireGuard configs πŸ“‘ Real-time telemetry: RTT, jitter, loss,loss ratio, link health β€” all exposed via typed APIs πŸ›‘οΈ WireGuard mode: full userspace WireGuard via boringtunΒ β€” generate .confΒ files, manage peers live

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.

InstallΒ πŸ“¦

pnpm install @push.rocks/smartvpn
# or
npm install @push.rocks/smartvpn

The package ships with pre-compiled Rust binaries for linux/amd64Β and linux/arm64. No Rust toolchain required at runtime.

Architecture πŸ—οΈΒ Architecture

TypeScript (control plane)              Rust (data plane)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     JSON-lines IPC     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    VpnClientTypeScript /Control VpnServerPlane  β”‚ β”‚ smartvpn_daemon◄─────────────────────► β”‚     β”‚Rust └─Data VpnBridgePlane │──stdio/──▢ β”‚  β”œβ”€ management (JSON IPC)          β”‚
β”‚      └─ RustBridge       β”‚  socket    β”‚  β”œβ”€ transport_trait (abstraction)   β”‚
β”‚         (smartrust)Daemon    β”‚
β”‚                              β”‚   β”œβ”€stdio  transportor  (WebSocket/TLS)Unix sock  β”‚                               β”‚
β”‚  β”‚VpnServer β”‚/ └─ quic_transport (QUIC/UDP)VpnClient      β”‚                          β”‚  WgConfigGeneratorNoise IK handshake           β”‚
β”‚  β”œβ”€Typed wireguardIPC (boringtun WG)commands          β”‚                          β”‚  └─ .conf file outputXChaCha20-Poly1305           β”‚
β”‚  β”œβ”€Config cryptovalidation           (Noiseβ”‚                          NKβ”‚  WS + XCha20)QUIC + WireGuard        β”‚
β”‚  Hub: client management      β”‚                          β”‚  TUN device, IP pool, NAT     β”‚
β”‚  WireGuard .conf generation  β”‚                          β”‚  Rate limiting, ACLs, QoS     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚  β”œβ”€ codec (binary framing)         β”‚
                                        β”‚  β”œβ”€ keepalive (adaptive state FSM) β”‚
                                        β”‚  β”œβ”€ telemetry (RTT/jitter/loss)    β”‚
                                        β”‚  β”œβ”€ qos (classify + priority Q)    β”‚
                                        β”‚  β”œβ”€ ratelimit (token bucket)       β”‚
                                        β”‚  β”œβ”€ mtu (overhead calc + ICMP)     β”‚
                                        β”‚  β”œβ”€ tunnel (TUN device)            β”‚
                                        β”‚  β”œβ”€ network (NAT/IP pool)          β”‚
                                        β”‚  └─ reconnect (exp. backoff)       β”‚
                                        β””β”€β”€β”€β”€β”€β”˜                          β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

KeySplit-plane design decisions:β€” TypeScript handles orchestration, config, and DX; Rust handles every hot-path byte with zero-copy async I/O (tokio, mimalloc).

Quick Start πŸš€ Decision

1. ChoiceStart Whya

VPN Server (Hub)
import Transport{ VpnServer } from '@push.rocks/smartvpn';

const server = new VpnServer({ transport: { transport: 'stdio' } });
await server.start({
  listenAddr: '0.0.0.0:443',
  privateKey: '<server-noise-private-key-base64>',
  publicKey: '<server-noise-public-key-base64>',
  subnet: '10.8.0.0/24',
  transportMode: 'both', // WebSocket + QUIC +simultaneously
  WireGuardenableNat: WStrue,
  worksdns: through['1.1.1.1', Cloudflare;'8.8.8.8'],
QUIC});
gives
low

2. latencyCreate +a datagrams;Client WG(One forCall = Everything)

const bundle = await server.createClient({
  clientId: 'alice-laptop',
  tags: ['engineering'],
  security: {
    destinationAllowList: ['10.0.0.0/8'],        // can only reach internal network
    destinationBlockList: ['10.0.0.99'],           // except this host
    rateLimit: { bytesPerSec: 10_000_000, burstBytes: 20_000_000 },
  },
});

// bundle.smartvpnConfig  β†’ typed IVpnClientConfig, ready to use
// bundle.wireguardConfig β†’ standard protocolWireGuard interop
.conf string // Auto-transportbundle.secrets QUICβ†’ first,{ WSnoisePrivateKey, fallbackwgPrivateKey Best performance when QUIC is available, graceful degradation when it's not WireGuard Userspace via boringtun No kernel module needed, runs on any platform, full peer management via IPC Encryption Noise NK + XChaCha20-Poly1305 Strong forward secrecy, large nonce space (no counter sync needed) QUIC auth Certificate hash pinning WireGuard-style trust model} β€” noshown CAONCE needed, just pin the server cert hash Keepalive Adaptive app-level pings Cloudflare drops WS pings; interval adapts to link health (10–60s) QoS Packet classification + priority queues DNS/SSH/ICMP always drain first; bulk flows get deprioritized Rate limiting Per-client token bucket Byte-granular, dynamically reconfigurable via IPC IPC JSON lines over stdio / Unix socket stdioΒ for dev, socketΒ for production (daemon stays alive) Binary protocol [type:1B][length:4B][payload:NB] Minimal overhead, easy to parse at wire speed

πŸš€ Quick Start

VPN3. Connect a Client

import { VpnClient } from '@push.rocks/smartvpn';

const client = new VpnClient({ transport: { transport: 'stdio' }, });
await client.start();

const { assignedIp } = await client.connect({
  serverUrl: 'wss://vpn.example.com/tunnel',
  serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
  dns: ['1.1.1.1', '8.8.8.8'],
  mtu: 1420,
  keepaliveIntervalSecs: 30,
})bundle.smartvpnConfig);
console.log(`Connected! AssignedVPN IP: ${assignedIp}`);

Features ✨

πŸ” Enterprise Authentication (Noise IK)

Every client authenticates with a Noise IK handshakeΒ (Noise_IK_25519_ChaChaPoly_BLAKE2s). The server verifies the client's static public key against its registry β€” unauthorized clients are rejected before any data flows.

    Per-client X25519 keypair generated server-side Client registry with enable/disable, expiry, tags Key rotation with rotateClientKey()Β β€” generates new keys, returns fresh config bundle, disconnects old session

    🌐 Triple Transport

    Transport Protocol Best For WebSocket TLS over TCP Firewall-friendly, Cloudflare compatible QUIC UDP (via quinn) Low latency, datagram support for IP packets WireGuard UDP (via boringtun) Standard WG clients (iOS, Android, wg-quick)

    The server can run all three simultaneouslyΒ with transportMode: 'both'Β (WS + QUIC) or 'wireguard'. Clients auto-negotiate with transport: 'auto'Β (tries QUIC first, falls back to WS).

    πŸ›‘οΈ ACL Engine (SmartProxy-Aligned)

    Security policies per client, using the same ipAllowListΒ / ipBlockListΒ naming convention as @push.rocks/smartproxy:

    security: {
      ipAllowList: ['192.168.1.0/24'],          // source IPs allowed to connect
      ipBlockList: ['192.168.1.100'],            // deny overrides allow
      destinationAllowList: ['10.0.0.0/8'],      // VPN destinations permitted
      destinationBlockList: ['10.0.0.99'],        // deny overrides allow
      maxConnections: 5,
      rateLimit: { bytesPerSec: 1_000_000, burstBytes: 2_000_000 },
    }
    

    Supports exact IPs, CIDR, wildcards (192.168.1.*), and ranges (1.1.1.1-1.1.1.100).

    πŸ“Š Telemetry & QoS

      Connection quality: Smoothed RTT, jitter, min/max RTT, loss ratio, link health (adaptivehealthy keepalive/ +degraded telemetry)/ critical) Adaptive keepalives: Interval adjusts based on link health (60s β†’ 30s β†’ 10s) Per-client rate limiting: Token bucket with configurable bytes/sec and burst Dead-peer detection: 180s inactivity timeout MTU management: Automatic overhead calculation (IP+TCP+WS+Noise = 79 bytes)

      πŸ”„ Hub Client Management

      The server acts as a hubΒ β€” one API to manage all clients:

      // Create (generates keys, assigns IP, returns config bundle)
      const qualitybundle = await client.getConnectionQuality();
      console.log(quality);
      // server.createClient({ //   srttMs: 42.5, jitterMs: 3.2, minRttMs: 38.0, maxRttMs: 67.0,
      //   lossRatio: 0.0, consecutiveTimeouts: 0,
      //   linkHealth:clientId: 'healthy', currentKeepaliveIntervalSecs: 60
      // }
      
      // MTU info
      const mtu = await client.getMtuInfo();
      console.log(mtu);
      // { tunMtu: 1420, effectiveMtu: 1421, linkMtu: 1500, overheadBytes: 79, ... }
      
      // Traffic stats (includes quality snapshot)
      const stats = await client.getStatistics();
      
      await client.disconnect();
      client.stop();
      

      VPN Client with QUIC

      import { VpnClient } from '@push.rocks/smartvpn';
      
      // Explicit QUIC β€” serverUrl is host:port, pinned by cert hash
      const quicClient = new VpnClient({
        transport: { transport: 'stdio' },
      });
      
      await quicClient.start();
      
      const { assignedIp } = await quicClient.connect({
        serverUrl: 'vpn.example.com:443',
        serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
        transport: 'quic',
        serverCertHash: 'BASE64_SHA256_CERT_HASH', // printed by server on startupbob-phone' });
      
      // Or use auto-transport: tries QUIC first (3s timeout), falls back to WSRead
      const autoCliententry = new VpnClient({
        transport: { transport: 'stdio' },
      });
      
      await autoClient.start();
      
      await autoClient.connect({
        serverUrl: server.getClient('wss://vpn.example.com/tunnel', // WS URL β€” host:port extracted for QUIC attempt
        serverPublicKey: 'BASE64_SERVER_PUBLIC_KEY',
        transport: 'auto', // default β€” QUIC first, then WS
      });
      

      VPN Client with WireGuard

      import { VpnClient } from '@push.rocks/smartvpn';
      
      const wgClient = new VpnClient({
        transport: { transport: 'stdio' },
      });
      
      await wgClient.start(bob-phone');
      const { assignedIp }all   = await wgClient.connect({
        serverPublicKey: 'BASE64_SERVER_WG_PUBLIC_KEY',
        serverUrl: '',server.listRegisteredClients();
      
      // notUpdate used(ACLs, fortags, WireGuarddescription, transport:rate limits...)
      await server.updateClient('wireguard'bob-phone', wgPrivateKey:{
        'BASE64_CLIENT_PRIVATE_KEY',security: wgAddress:{ '10.8.0.2',
        wgAddressPrefix: 24,
        wgEndpoint: 'vpn.example.com:51820',
        wgAllowedIps:destinationAllowList: ['0.0.0.0/0']Β },
        // route all traffic
        wgPersistentKeepalive: 25,
        wgPresharedKey: 'OPTIONAL_PSK',     // optional extra layer
        dns:tags: ['1.1.1.1']mobile', mtu: 1420,
      });
      
      console.log(`WireGuard connected! IP: ${assignedIp}`);
      await wgClient.disconnect();
      wgClient.stop();
      

      VPN Server

      import { VpnServer } from '@push.rocks/smartvpn';
      
      const server = new VpnServer({
        transport: { transport: 'stdio' }field-ops'],
      });
      
      // GenerateEnable a/ Noise keypair firstDisable
      await server.start(disableClient('bob-phone'); // disconnects + blocks reconnection
      await server.enableClient('bob-phone');
      
      // Key rotation
      const keypairnewBundle = await server.generateKeypair(rotateClientKey('bob-phone');
      
      // StartExport theconfig VPN(without listenersecrets)
      const wgConf = await server.start({
        listenAddr: exportClientConfig('0.0.0.0:443',
        privateKey: keypair.privateKey,
        publicKey: keypair.publicKey,
        subnet: '10.8.0.0/24',
        dns: ['1.1.1.1'],
        mtu: 1420,
        enableNat: true,
        // Transport mode: 'websocket'bob-phone', 'quic', 'both', or 'wireguard'
        transportMode: 'both',
        // Optional: separate QUIC listen address
        quicListenAddr: '0.0.0.0:4433',
        // Optional: QUIC idle timeout
        quicIdleTimeoutSecs: 30,
        // Optional: default rate limit for all new clients
        defaultRateLimitBytesPerSec: 10_000_000, // 10 MB/s
        defaultBurstBytes: 20_000_000,           // 20 MB burst
      });
      
      // List connected clients
      const clients =Remove
      await server.listClients();
      
      // Per-client rate limiting (live, no reconnect needed)
      await server.setClientRateLimit(removeClient('client-id', 5_000_000, 10_000_000);
      await server.removeClientRateLimit('client-id'); // unlimited
      
      // Per-client telemetry
      const telemetry = await server.getClientTelemetry('client-id');
      console.log(telemetry);
      // {
      //   clientId, assignedIp, lastKeepaliveAt, keepalivesReceived,
      //   packetsDropped, bytesDropped, bytesReceived, bytesSent,
      //   rateLimitBytesPerSec, burstBytes
      // }
      
      // Kick a client
      await server.disconnectClient('client-id');
      
      await server.stopServer();
      server.stop(bob-phone');
      

      WireGuard Server Mode

      import { VpnServer } from '@push.rocks/smartvpn';
      
      const wgServer = new VpnServer({
        transport: { transport: 'stdio' },
      });
      
      // Generate aπŸ“ WireGuard X25519Config keypair
      await wgServer.start();
      const keypair = await wgServer.generateWgKeypair();
      console.log(`Server public key: ${keypair.publicKey}`);
      
      // Start in WireGuard mode
      await wgServer.start({
        listenAddr: '0.0.0.0:51820',
        privateKey: keypair.privateKey,
        publicKey: keypair.publicKey,
        subnet: '10.8.0.0/24',
        transportMode: 'wireguard',
        wgListenPort: 51820,
        wgPeers: [
          {
            publicKey: 'CLIENT_PUBLIC_KEY_BASE64',
            allowedIps: ['10.8.0.2/32'],
            persistentKeepalive: 25,
          },
        ],
        enableNat: true,
        dns: ['1.1.1.1'],
        mtu: 1420,
      });
      
      // Live peer management β€” add/remove peers without restart
      await wgServer.addWgPeer({
        publicKey: 'NEW_CLIENT_PUBLIC_KEY',
        allowedIps: ['10.8.0.3/32'],
        persistentKeepalive: 25,
      });
      
      // List peers with live stats
      const peers = await wgServer.listWgPeers();
      for (const peer of peers) {
        console.log(`${peer.publicKey}: ↑${peer.bytesSent} ↓${peer.bytesReceived}`);
      }
      
      // Remove a peer by public key
      await wgServer.removeWgPeer('CLIENT_PUBLIC_KEY_BASE64');
      
      await wgServer.stopServer();
      wgServer.stop();
      

      Generating WireGuard .conf FilesGeneration

      The WgConfigGeneratorΒ createsGenerate standardΒ WireGuard .conf files compatiblefor with wg-quick, iOS/Android apps, and all standardany WireGuard clients:client:

      import { WgConfigGenerator } from '@push.rocks/smartvpn';
      
      // Client config (for wg-quick or mobile apps)
      const clientConfconf = WgConfigGenerator.generateClientConfig({
        privateKey: 'CLIENT_PRIVATE_KEY_BASE64'<client-wg-private-key>',
        address: '10.8.0.2/24',
        dns: ['1.1.1.1', '8.8.8.8'],
        mtu: 1420,
        peer: {
          publicKey: 'SERVER_PUBLIC_KEY_BASE64'<server-wg-public-key>',
          endpoint: 'vpn.example.com:51820',
          allowedIps: ['0.0.0.0/0', '::/0'],
          persistentKeepalive: 25,
          presharedKey: 'OPTIONAL_PSK_BASE64',
        },
      });
      // Server→ configstandard (forWireGuard .conf compatible with wg-quick)quick, iOS, Android
      

      πŸ–₯️ System Service Installation

      import { VpnInstaller } from '@push.rocks/smartvpn';
      
      const serverConfunit = WgConfigGenerator.generateServerConfig(VpnInstaller.generateServiceUnit({
        privateKey:mode: 'SERVER_PRIVATE_KEY_BASE64'server',
        address:configPath: '10.8.0.1/24',
        listenPort: 51820,
        dns: ['1.1.1.1'],
        mtu: 1420,
        enableNat: true,
        natInterface: 'eth0', // auto-detected if omitted
        peers: [
          {
            publicKey: 'CLIENT_PUBLIC_KEY_BASE64',
            allowedIps: ['10.8.0.2/32'],
            persistentKeepalive: 25,
          },
        ]etc/smartvpn/server.json',
      });
      // Writeunit.platform  to disk
      import * as fs from→ 'fs';linux' fs.writeFileSync(| 'macos'
      // unit.content   β†’ systemd unit file or launchd plist
      // unit.installPath β†’ /etc/wireguard/wg0.conf', serverConf);systemd/system/smartvpn-server.service
      
      Example output: client .conf
      [Interface]
      PrivateKey = CLIENT_PRIVATE_KEY_BASE64
      Address = 10.8.0.2/24
      DNS = 1.1.1.1, 8.8.8.8
      MTU = 1420
      
      [Peer]
      PublicKey = SERVER_PUBLIC_KEY_BASE64
      PresharedKey = OPTIONAL_PSK_BASE64
      Endpoint = vpn.example.com:51820
      AllowedIPs = 0.0.0.0/0, ::/0
      PersistentKeepalive = 25
      

      Production: Socket Transport

      In production, the daemon runs as a system service and you connect over a Unix socket:

      const client = new VpnClient({
        transport: {
          transport: 'socket',
          socketPath: '/var/run/smartvpn.sock',
          autoReconnect: true,
          reconnectBaseDelayMs: 100,
          reconnectMaxDelayMs: 30000,
          maxReconnectAttempts: 10,
        },
      });
      
      await client.start(); // connects to existing daemon (does not spawn)
      

      When using socket transport, client.stop()Β closes the socket but does not kill the daemonΒ β€” exactly what you want in production.

      πŸ“‹ API ReferenceΒ πŸ“–

      VpnClientClasses

      Method
      ReturnsClass Description start()VpnServer Promise<boolean> StartManages the Rust daemon bridgein (spawnserver ormode. connect)Hub methods for client CRUD. connect(config?)VpnClient Promise<{Manages assignedIpthe }>Rust Connectdaemon toin VPNclient servermode. (WS,Connect, QUIC,disconnect, or WireGuard)telemetry. disconnect() PromiseVpnBridge<voidT> DisconnectLow-level fromtyped VPNIPC bridge (stdio or Unix socket). getStatus(VpnConfig Static config validation and file I/O. VpnInstaller Generates systemd/launchd service files. WgConfigGenerator Generates standard WireGuard .confΒ files.

      Key Interfaces

      Interface Purpose IVpnServerConfig Server configuration (listen addr, keys, subnet, transport mode, clients) IVpnClientConfig Client configuration (server URL, keys, transport, WG options) IClientEntry Server-side client definition (ID, keys, security, priority, tags, expiry) IClientSecurity Per-client ACLs and rate limits (SmartProxy-aligned naming) IClientRateLimit Rate limiting config (bytesPerSec, burstBytes) IClientConfigBundle Full config bundle returned by createClient() Promise<IVpnStatus>IVpnClientInfo CurrentConnected connectionclient info (IP, stats, authenticated key) IVpnConnectionQuality RTT, jitter, loss ratio, link health IVpnKeypair Base64-encoded public/private key pair

      Server IPC Commands

      Command Description startΒ / stop Start/stop the VPN listener createClient Generate keys, assign IP, return config bundle removeClientΒ / getClientΒ / listRegisteredClients Client registry CRUD updateClientΒ / enableClientΒ / disableClient Modify client state getStatistics()rotateClientKey Promise<IVpnStatistics>Fresh Traffic statskeypairs + connectionnew qualityconfig bundle getConnectionQuality()exportClientConfig Re-export as SmartVPN config or WireGuard Promise<IVpnConnectionQuality>.conf listClientsΒ / disconnectClient Manage live connections setClientRateLimitΒ / removeClientRateLimit Runtime rate limit adjustments getStatusΒ / getStatisticsΒ / getClientTelemetry Monitoring generateKeypairΒ / generateWgKeypairΒ / generateClientKeypair Key generation addWgPeerΒ / removeWgPeerΒ / listWgPeers WireGuard peer management

      Client IPC Commands

      Command Description connectΒ / disconnect Manage the tunnel getStatusΒ / getStatistics Connection state and traffic stats getConnectionQuality RTT, jitter, loss, link health getMtuInfo() Promise<IVpnMtuInfo>getMtuInfo MTU info and overhead breakdown stop() void Kill/close the daemon bridge running boolean Whether bridge is activedetails

      Transport Modes πŸ”€

      Server Configuration

      VpnServer// WebSocket only
      { transportMode: 'websocket', listenAddr: '0.0.0.0:443' }
      
      // QUIC only
      { transportMode: 'quic', listenAddr: '0.0.0.0:443' }
      
      // Both (WS + QUIC on same or different ports)
      { transportMode: 'both', listenAddr: '0.0.0.0:443', quicListenAddr: '0.0.0.0:4433' }
      
      // WireGuard
      { transportMode: 'wireguard', wgListenPort: 51820, wgPeers: [...] }
      

      Client Configuration

      // Auto (tries QUIC first, falls back to WS)
      { transport: 'auto', serverUrl: 'wss://vpn.example.com' }
      
      // Explicit QUIC with certificate pinning
      { transport: 'quic', serverUrl: '1.2.3.4:4433', serverCertHash: '<sha256-base64>' }
      
      // WireGuard
      { transport: 'wireguard', wgPrivateKey: '...', wgEndpoint: 'vpn.example.com:51820', ... }
      

      Cryptography πŸ”‘

      MethodLayer ReturnsAlgorithm
      Purpose Handshake Noise IK (X25519 + ChaChaPoly + BLAKE2s) Mutual authentication + key exchange Transport Noise transport state (ChaChaPoly) All post-handshake data encryption Additional XChaCha20-Poly1305 Extended nonce space for data-at-rest WireGuard X25519 + ChaCha20-Poly1305 (via boringtun) Standard WireGuard crypto

      Binary Protocol πŸ“‘

      All frames use [type:1B][length:4B][payload:NB]Β with a 64KB max payload:

      Type Hex Direction Description start(config?) Promise<void> Start daemon + VPN server stopServer() Promise<void> Stop the VPN server getStatus() Promise<IVpnStatus> Server connection state getStatistics() Promise<IVpnServerStatistics> Server stats (includes client counts) listClients() Promise<IVpnClientInfo[]> Connected clients with QoS stats disconnectClient(id) Promise<void> Kick a client generateKeypair() Promise<IVpnKeypair> Generate Noise NK keypair setClientRateLimit(id, rate, burst) Promise<void> Set per-client rate limit (bytes/sec) removeClientRateLimit(id) Promise<void> Remove rate limit (unlimited) getClientTelemetry(id) Promise<IVpnClientTelemetry> Per-client telemetry + drop stats generateWgKeypair() Promise<IVpnKeypair> Generate WireGuard X25519 keypair addWgPeer(peer) Promise<void> Add a WireGuard peer at runtime removeWgPeer(publicKey) Promise<void> Remove a WireGuard peer by key listWgPeers() Promise<IWgPeerInfo[]> List WG peers with traffic stats stop() void Kill/close the daemon bridge

      VpnConfig

      Static utility class for config validation and file I/O:

      import { VpnConfig } from '@push.rocks/smartvpn';
      
      // Validate (throws on invalid)
      VpnConfig.validateClientConfig(config);
      VpnConfig.validateServerConfig(config);
      
      // Load/save JSON configs
      const config = await VpnConfig.loadFromFile<IVpnClientConfig>('/etc/smartvpn/client.json');
      await VpnConfig.saveToFile('/etc/smartvpn/client.json', config);
      

      Validation covers both smartvpn-native configs and WireGuard configs β€” base64 key format, CIDR ranges, port ranges, and required fields are all checked.

      WgConfigGenerator

      Static generator for standard WireGuard .confΒ files:

      Method Returns Description generateClientConfig(opts) string Generate a wg-quickΒ compatible client .conf generateServerConfig(opts) string Generate a wg-quickΒ compatible server .confΒ with NAT rules

      Output is compatible with wg-quick, WireGuard iOS/Android apps, and any standard WireGuard implementation.

      VpnInstaller

      Generate system service units for the daemon:

      import { VpnInstaller } from '@push.rocks/smartvpn';
      
      const platform = VpnInstaller.detectPlatform(); // 'linux' | 'macos' | 'windows' | 'unknown'
      
      // Linux (systemd)
      const unit = VpnInstaller.generateSystemdUnit({
        binaryPath: '/usr/local/bin/smartvpn_daemon',
        socketPath: '/var/run/smartvpn.sock',
        mode: 'server',
      });
      
      // macOS (launchd)
      const plist = VpnInstaller.generateLaunchdPlist({
        binaryPath: '/usr/local/bin/smartvpn_daemon',
        socketPath: '/var/run/smartvpn.sock',
        mode: 'client',
      });
      
      // Auto-detect platform
      const serviceUnit = VpnInstaller.generateServiceUnit({
        binaryPath: '/usr/local/bin/smartvpn_daemon',
        socketPath: '/var/run/smartvpn.sock',
        mode: 'server',
      });
      

      Events

      Both VpnClientΒ and VpnServerΒ extend EventEmitter:

      client.on('exit', ({ code, signal }) => { /* daemon exited */ });
      client.on('reconnected', () => { /* socket reconnected */ });
      client.on('status', (status) => { /* IVpnStatus update */ });
      client.on('error', (error) => { /* error from daemon */ });
      
      server.on('client-connected', (info) => { /* IVpnClientInfo */ });
      server.on('client-disconnected', ({ clientId, reason }) => { /* ... */ });
      server.on('started', () => { /* server listener started */ });
      server.on('stopped', () => { /* server listener stopped */ });
      

      🌐 Transport Modes

      smartvpn supports three transport protocols. The smartvpn-native transports (WebSocket + QUIC) share the same encryption, framing, and QoS pipeline. WireGuard mode uses the standard WireGuard protocol for broad interoperability.

      WebSocket (default for smartvpn-native)

        Works through Cloudflare, reverse proxies, and HTTP load balancers Reliable delivery only (no datagram support) URL format: wss://host/pathΒ or ws://host:port/path

        QUIC

          Lower latency, built-in multiplexing, 0-RTT connection establishment Supports unreliable datagramsΒ for IP packets (with automatic fallback to reliable if oversized) Certificate hash pinning β€” no CA chain needed, WireGuard-style trust URL format: host:port ALPN protocol: smartvpn

          WireGuard

            Standard WireGuard protocol via boringtunΒ (userspace, no kernel module) Compatible with all WireGuard clientsΒ β€” iOS, Android, macOS, Windows, Linux, routers X25519 key exchange, ChaCha20-Poly1305 encryption Dynamic peer management at runtime (add/remove without restart) Optional preshared keys for post-quantum defense-in-depth Generate .confΒ files for standard clients via WgConfigGenerator Default port: 51820/UDP

            Auto-Transport (Recommended for smartvpn-native)

            The default transport: 'auto'Β mode gives you the best of both worlds:

              Extract host:portΒ from the WebSocket URL Attempt QUIC connection (3-second timeout) If QUIC fails or times out β†’ fall back to WebSocket Completely transparent to the application
              await client.connect({
                serverUrl: 'wss://vpn.example.com/tunnel',
                serverPublicKey: '...',
                transport: 'auto', // default β€” QUIC first, WS fallback
              });
              

              Server Dual-Mode / Multi-Mode

              The server can listen on multiple transports simultaneously:

              // WebSocket + QUIC (dual mode)
              await server.start({
                listenAddr: '0.0.0.0:443',         // WebSocket listener
                quicListenAddr: '0.0.0.0:4433',    // QUIC listener (optional, defaults to listenAddr)
                transportMode: 'both',             // 'websocket' | 'quic' | 'both' | 'wireguard'
                quicIdleTimeoutSecs: 30,
                // ... other config
              });
              
              // WireGuard standalone
              await server.start({
                listenAddr: '0.0.0.0:51820',
                transportMode: 'wireguard',
                wgListenPort: 51820,
                wgPeers: [{ publicKey: '...', allowedIps: ['10.8.0.2/32'] }],
                // ... other config
              });
              

              When using 'both'Β mode, the server logs the QUIC certificate hash on startup β€” share this with clients for cert pinning.

              πŸ“Š QoS System

              The Rust daemon includes a full QoS stack that operates on decrypted IP packets:

              Adaptive Keepalive

              The keepalive system automatically adjusts its interval based on connection quality:

              Link Health Keepalive Interval Triggered When 🟒 Healthy 60s Jitter < 30ms, loss < 2%, no timeouts 🟑 Degraded 30s Jitter > 50ms, loss > 5%, or 1+ timeout πŸ”΄ Critical 10s Loss > 20% or 2+ consecutive timeouts

              State transitions include hysteresis (3 consecutive good checks to upgrade, 2 to recover) to prevent flapping. Dead peer detection fires after 3 consecutive timeouts in Critical state.

              Packet Classification

              IP packets are classified into three priority levels by inspecting headers (no deep packet inspection):

              Priority Traffic High ICMP, DNS (port 53), SSH (port 22), small packets (< 128 bytes) Normal Everything else Low Bulk flows exceeding 1 MB within a 60s window

              Priority channels drain with biased tokio::select!Β β€” high-priority packets always go first.

              Smart Packet Dropping

              Under backpressure, packets are dropped intelligently:

                LowΒ queue full β†’ drop silently NormalΒ queue full β†’ drop HighΒ queue full β†’ wait 5ms, then drop as last resort

                Drop statistics are tracked per priority level and exposed via telemetry.

                Per-Client Rate Limiting

                Token bucket algorithm with byte granularity:

                // Set: 10 MB/s sustained, 20 MB burst
                await server.setClientRateLimit('client-id', 10_000_000, 20_000_000);
                
                // Check drops via telemetry
                const t = await server.getClientTelemetry('client-id');
                console.log(`Dropped: ${t.packetsDropped} packets, ${t.bytesDropped} bytes`);
                
                // Remove limit
                await server.removeClientRateLimit('client-id');
                

                Rate limits can be changed live without disconnecting the client.

                Path MTU

                Tunnel overhead is calculated precisely:

                Layer Bytes IP header 20 TCP header (with timestamps) 32 WebSocket framing 6 VPN frame header 5 Noise AEAD tag 16 Total overhead 79

                For a standard 1500-byte Ethernet link, effective TUN MTU = 1421 bytes. The default TUN MTU of 1420 is conservative and correct. Oversized packets get an ICMP "Fragmentation Needed" (Type 3, Code 4) written back into the TUN, so the source TCP adjusts its MSS automatically.

                πŸ” Security Model

                smartvpn-native (WebSocket / QUIC)

                The VPN uses a Noise NKΒ handshake pattern:

                  NKΒ = client does Not authenticate, but Knows the server's static public key The client generates an ephemeral keypair, performs e, esΒ (DH with server's static key) Server responds with e, eeΒ (DH with both ephemeral keys) Result: forward-secret transport keys derived from both DH operations

                  Post-handshake, all IP packets are encrypted with XChaCha20-Poly1305:

                    24-byte random nonces (no counter synchronization needed) 16-byte authentication tags Wire format: [nonce:24B][ciphertext:var][tag:16B]

                    WireGuard Mode

                    Uses the standard Noise IKpsk2Β handshake:

                      X25519Β key exchange (Curve25519 Diffie-Hellman) ChaCha20-Poly1305Β AEAD encryption Optional preshared keysΒ for post-quantum defense-in-depth Implemented via boringtunΒ β€” Cloudflare's userspace WireGuard in Rust

                      QUIC Certificate Pinning

                      When using QUIC transport, the server generates a self-signed TLS certificate (or uses a configured PEM). Instead of relying on a CA chain, clients pin the server's certificate by its SHA-256 hashΒ (base64-encoded) β€” a WireGuard-inspired trust model:

                      // Server logs the cert hash on startup:
                      // "QUIC cert hash: <BASE64_HASH>"
                      
                      // Client pins it:
                      await client.connect({
                        serverUrl: 'vpn.example.com:443',
                        transport: 'quic',
                        serverCertHash: '<BASE64_HASH>',
                        serverPublicKey: '...',
                      });
                      

                      πŸ“¦ Binary Protocol

                      Inside the tunnel (both WebSocket and QUIC reliable channels), packets use a simple binary framing:

                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚ Type (1B)β”‚ Len (4B) β”‚ Payload (variable) β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      
                      Type Value Description HandshakeInit 0x01 Client → Server handshakeNoise IK first message HandshakeResp 0x02 Server → Client handshakeNoise IK response IpPacket 0x10 Bidirectional Encrypted IPtunnel packetdata Keepalive 0x20 Client → Server App-level pingkeepalive (8-bytenot timestampWS payload)ping) KeepaliveAck 0x21 App-levelServer pong→ (echoesClient timestampKeepalive forresponse RTT)with RTT payload SessionResume 0x30 Resume a dropped session SessionResumeOk 0x31 Resume accepted SessionResumeErr 0x32 Resume rejected Disconnect 0x3F Bidirectional Graceful disconnect

                      When

                      Development QUIC datagrams are available, IP packets can optionally be sent via the unreliable datagram channel for lower latency. Packets that exceed the max datagram size automatically fall back to the reliable stream.

                      Note:Β WireGuard mode uses the standard WireGuard wire protocol, not this binary framing.

                      πŸ› οΈΒ Rust Daemon CLI

                      # Development: stdio management (JSON lines on stdin/stdout)
                      smartvpn_daemon --management --mode client
                      smartvpn_daemon --management --mode server
                      
                      # Production: Unix socket management
                      smartvpn_daemon --management-socket /var/run/smartvpn.sock --mode server
                      
                      # Generate a Noise keypair
                      smartvpn_daemon --generate-keypair
                      

                      πŸ”§ Building from Source

                      # Install dependencies
                      pnpm install
                      
                      # Build (TypeScript + cross-compile Rust (amd64 + arm64)cross-compile)
                      pnpmΒ build
                      
                      # Build Rust only (debug)
                      cd rust && cargo build
                      
                      # Run all tests (9379 TS + 121 Rust += 77200 TypeScript)tests)
                      pnpm test
                      
                      # Run Rust tests directly
                      cd rust && cargo test
                      
                      pnpm# Run a specific TS test
                      tstest test/test.flowcontrol.node.ts --verbose
                      

                      πŸ“˜

                      Project Structure

                      smartvpn/
                      β”œβ”€β”€ ts/                         # TypeScript Interfaces
                      control
                      Clickβ”‚ toβ”œβ”€β”€ expandindex.ts full# typeAll definitionsplane exports
                      //β”‚   Transportβ”œβ”€β”€ optionssmartvpn.interfaces.ts  type# TVpnTransportOptionsInterfaces, =types, |IPC {command transport:maps
                      'stdio'β”‚   }β”œβ”€β”€ |smartvpn.classes.vpnserver.ts
                      {β”‚   transport:β”œβ”€β”€ 'socket';smartvpn.classes.vpnclient.ts
                      socketPath:β”‚   string;β”œβ”€β”€ autoReconnect?:smartvpn.classes.vpnbridge.ts
                      boolean;β”‚   reconnectBaseDelayMs?:β”œβ”€β”€ number;smartvpn.classes.vpnconfig.ts
                      reconnectMaxDelayMs?:β”‚   number;β”œβ”€β”€ maxReconnectAttempts?:smartvpn.classes.vpninstaller.ts
                      number;β”‚   };└── //smartvpn.classes.wgconfig.ts
                      β”œβ”€β”€ rust/                       # Rust data plane daemon
                      β”‚   └── src/
                      β”‚       β”œβ”€β”€ main.rs             # CLI entry point
                      β”‚       β”œβ”€β”€ server.rs           # VPN server + hub methods
                      β”‚       β”œβ”€β”€ client.rs           # VPN client
                      β”‚       β”œβ”€β”€ crypto.rs           # Noise IK + XChaCha20
                      β”‚       β”œβ”€β”€ client_registry.rs  # Client configdatabase
                      interfaceβ”‚       IVpnClientConfigβ”œβ”€β”€ {acl.rs              serverUrl:# string;ACL //engine
                      WS:β”‚       'wss://host/path'β”œβ”€β”€ |management.rs       QUIC:# 'host:port'JSON-lines serverPublicKey:IPC
                      string;β”‚       //β”œβ”€β”€ Base64-encodedtransport.rs        Noise# staticWebSocket keytransport
                      (orβ”‚       WGβ”œβ”€β”€ publicquic_transport.rs   key)
                        transport?: 'auto' | 'websocket' | 'quic' | 'wireguard'; // Default: 'auto'
                        serverCertHash?: string;                // SHA-256 cert hash (base64) for# QUIC pinningtransport
                      dns?:β”‚       string[];β”œβ”€β”€ mtu?:wireguard.rs        number;
                        keepaliveIntervalSecs?: number;
                        // WireGuard-specific
                        wgPrivateKey?: string;                  // Client private key (base64, X25519)
                        wgAddress?: string;                     // Client TUN address (e.g. 10.8.0.2)
                        wgAddressPrefix?: number;              // Address prefix length (default: 24)
                        wgPresharedKey?: string;               // Optional preshared key (base64)
                        wgPersistentKeepalive?: number;        // Persistent keepalive interval (seconds)
                        wgEndpoint?: string;                   // Server endpoint (host:port)
                        wgAllowedIps?: string[];              // Allowed IPs (CIDR strings)
                      }
                      
                      // Server config
                      interface IVpnServerConfig {
                        listenAddr: string;
                        privateKey: string;
                        publicKey: string;
                        subnet: string;
                        tlsCert?: string;
                        tlsKey?: string;
                        dns?: string[];
                        mtu?: number;
                        keepaliveIntervalSecs?: number;
                        enableNat?: boolean;
                        transportMode?: 'websocket' | 'quic' | 'both' | 'wireguard';
                        quicListenAddr?: string;
                        quicIdleTimeoutSecs?: number;
                        defaultRateLimitBytesPerSec?: number;
                        defaultBurstBytes?: number;
                        // WireGuard-specific
                        wgListenPort?: number;                 // UDP port (default: 51820)
                        wgPeers?: IWgPeerConfig[];            // Initial peers
                      }
                      
                      //# WireGuard peer(boringtun)
                      configβ”‚       interfaceβ”œβ”€β”€ IWgPeerConfigcodec.rs            {# publicKey:Binary string;frame //protocol
                      Peer'sβ”‚       X25519β”œβ”€β”€ publickeepalive.rs        key# Adaptive keepalives
                      β”‚       β”œβ”€β”€ ratelimit.rs        # Token bucket
                      β”‚       └── ...                 # tunnel, network, telemetry, qos, mtu, reconnect
                      β”œβ”€β”€ test/                       # 9 test files (base64)79 presharedKey?:tests)
                      string;β”œβ”€β”€ //dist_ts/                    Optional# presharedCompiled keyTypeScript
                      └── dist_rust/                  # Cross-compiled binaries (base64)linux allowedIps:amd64 string[];+ // Allowed IP ranges (CIDR)
                        endpoint?: string;                     // Peer endpoint (host:port)
                        persistentKeepalive?: number;          // Keepalive interval (seconds)
                      }
                      
                      // WireGuard peer info (with live stats)
                      interface IWgPeerInfo {
                        publicKey: string;
                        allowedIps: string[];
                        endpoint?: string;
                        persistentKeepalive?: number;
                        bytesSent: number;
                        bytesReceived: number;
                        packetsSent: number;
                        packetsReceived: number;
                        lastHandshakeTime?: string;
                      }
                      
                      // Status
                      type TVpnConnectionState = 'disconnected' | 'connecting' | 'handshaking'
                                               | 'connected' | 'reconnecting' | 'error';
                      
                      interface IVpnStatus {
                        state: TVpnConnectionState;
                        assignedIp?: string;
                        serverAddr?: string;
                        connectedSince?: string;
                        lastError?: string;
                      }
                      
                      // Statistics
                      interface IVpnStatistics {
                        bytesSent: number;
                        bytesReceived: number;
                        packetsSent: number;
                        packetsReceived: number;
                        keepalivesSent: number;
                        keepalivesReceived: number;
                        uptimeSeconds: number;
                        quality?: IVpnConnectionQuality;
                      }
                      
                      interface IVpnServerStatistics extends IVpnStatistics {
                        activeClients: number;
                        totalConnections: number;
                      }
                      
                      // Connection quality (QoS)
                      type TVpnLinkHealth = 'healthy' | 'degraded' | 'critical';
                      
                      interface IVpnConnectionQuality {
                        srttMs: number;
                        jitterMs: number;
                        minRttMs: number;
                        maxRttMs: number;
                        lossRatio: number;
                        consecutiveTimeouts: number;
                        linkHealth: TVpnLinkHealth;
                        currentKeepaliveIntervalSecs: number;
                      }
                      
                      // MTU info
                      interface IVpnMtuInfo {
                        tunMtu: number;
                        effectiveMtu: number;
                        linkMtu: number;
                        overheadBytes: number;
                        oversizedPacketsDropped: number;
                        icmpTooBigSent: number;
                      }
                      
                      // Client info (with QoS fields)
                      interface IVpnClientInfo {
                        clientId: string;
                        assignedIp: string;
                        connectedSince: string;
                        bytesSent: number;
                        bytesReceived: number;
                        packetsDropped: number;
                        bytesDropped: number;
                        lastKeepaliveAt?: string;
                        keepalivesReceived: number;
                        rateLimitBytesPerSec?: number;
                        burstBytes?: number;
                      }
                      
                      // Per-client telemetry
                      interface IVpnClientTelemetry {
                        clientId: string;
                        assignedIp: string;
                        lastKeepaliveAt?: string;
                        keepalivesReceived: number;
                        packetsDropped: number;
                        bytesDropped: number;
                        bytesReceived: number;
                        bytesSent: number;
                        rateLimitBytesPerSec?: number;
                        burstBytes?: number;
                      }
                      
                      interface IVpnKeypair {
                        publicKey: string;
                        privateKey: string;
                      }arm64)
                      

                      This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the LICENSElicense 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

                      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.