Skip to main content
Understand the hub-and-spoke architecture that powers Private Connect’s secure service mesh.

Overview

Private Connect uses a hub-and-spoke architecture where agents connect to a central coordination layer (the Hub). Services are exposed from one machine and accessed from another through encrypted tunnels.
┌─────────────────┐         ┌───────┐         ┌─────────────────┐
│   Your Server   │────────▶│  Hub  │◀────────│   Your Laptop   │
│                 │         └───────┘         │                 │
│ connect :5432   │                           │ connect prod-db │
└─────────────────┘                           └─────────────────┘

Agents

Lightweight CLI running on each machine, managing connections

Hub

Central coordination layer for routing and metadata

Services

Exposed endpoints accessible by name across your workspace

Workspace

Isolated environment where all your services and agents live

Core Components

Agents

An agent runs on each machine where you want to expose or access services. Agents are responsible for:
  • Establishing secure WebSocket connections to the Hub
  • Exposing local services to the workspace
  • Creating tunnels to remote services
  • Maintaining stable port mappings
  • Reporting health and connectivity status
# Start an agent
connect up

# Expose a service
connect expose localhost:5432 --name prod-db

# Access a service
connect reach prod-db

The Hub

The Hub is the central coordination service that:
  • Authenticates agents and maintains workspace isolation
  • Stores service metadata (names, targets, ownership)
  • Routes traffic between agents as an opaque relay
  • Tracks connection metadata for audit logging
  • Enforces access controls and permissions
The Hub sees metadata (service names, connection times) but does not inspect payload data. All traffic passes through as base64-encoded packets.

Services

Services are exposed endpoints that can be accessed by name:
# Service = name + target
connect expose localhost:5432 --name prod-db
#                ^^^^^^^^^^^^^^       ^^^^^^^^
#                   target              name
Services are:
  • Workspace-scoped: Only accessible within your workspace
  • Name-based: Access by name, not IP or port
  • Stable: Same service always maps to the same local port
  • Private by default: Not accessible outside your workspace unless explicitly shared

Data Flow

Here’s how traffic flows when Agent B reaches a service exposed by Agent A:
┌─────────────────┐                              ┌─────────────────┐
│   Agent A       │                              │   Agent B       │
│   (Exposing)    │                              │   (Reaching)    │
│                 │      ┌──────────────┐        │                 │
│  localhost:5432 │◀────▶│     Hub      │◀──────▶│  localhost:5432 │
│                 │      │              │        │                 │
└─────────────────┘      │  Metadata    │        └─────────────────┘
                         │  + Relay     │
                         └──────────────┘

Step-by-Step Flow

1

Service Discovery

Agent B queries the Hub: “Where is prod-db?”Hub responds: “Agent A is exposing prod-db at localhost:5432”
2

Tunnel Establishment

Agent B creates a local listener on localhost:5432Agent B opens a WebSocket tunnel to the Hub, tagged for Agent A
3

Data Transfer

Client connects to localhost:5432 on Agent B’s machineAgent B base64-encodes packets and sends to HubHub relays packets to Agent A without inspectionAgent A decodes packets and forwards to localhost:5432Responses flow back the same way
If Agent A disconnects, the tunnel breaks. Active connections will fail and Agent B will attempt to reconnect with exponential backoff.

What the Hub Sees

DataVisibilityNotes
Agent identity✓ VisibleAgent ID, label, workspace
Service names✓ Visiblee.g., “prod-db”, “redis”
Target host:port✓ Visiblee.g., “localhost:5432”
Connection metadata✓ VisibleWhen connections are made, duration
IP addresses✓ VisibleFor audit logging (masked in logs)
Payload dataOpaque relayBase64-encoded, not inspected

Payload Handling

When data flows through the Hub:
  1. Agent B sends data as base64-encoded packets
  2. Hub forwards packets to Agent A without inspection
  3. Agent A decodes and forwards to the target service
  4. Responses flow back the same way
The Hub does not:
  • Decrypt or inspect payload contents
  • Store payload data
  • Log payload contents

Workspace Isolation

Every resource belongs to exactly one workspace:
Workspace
├── Agents (machines running the connect CLI)
├── Services (exposed endpoints)
├── API Keys (for programmatic access)
└── Shares (environment sharing codes)

Isolation Guarantees

PostgreSQL Row Level Security (RLS) enforces workspace isolation at the database layer. All workspace-scoped tables have RLS policies that only allow access to rows matching the current workspace context.
All queries are additionally scoped by workspaceId in the application code (defense-in-depth).
Guards validate workspace ownership before any operation.
WebSocket rooms are isolated by workspace (workspace:{id}).
Agents can only access services within their workspace.

Who Can Access My Services?

Only authenticated members of your workspace. By default, exposed services are completely private.
# On your server (workspace: acme-corp)
connect up
connect expose localhost:5432 --name prod-db

# On your laptop (same workspace: acme-corp)  
connect up
connect reach prod-db          # ✓ Works

# Random person (different workspace)
connect reach prod-db          # ❌ "Service not found"
Outsiders cannot:
  • Discover that your services exist
  • List services in your workspace
  • Connect to any of your services
The workspace IS the access boundary — think of it like a private Tailnet in Tailscale.

Cross-Workspace Access

Services can be shared across workspace boundaries via:

Service Shares

Token-based access with permissions:
connect share --expires 7d --name "acme-contractor"
# → Share code: p4r7n3r
Features:
  • Time-limited access
  • Instant revocation
  • Audit logging
  • Per-service permissions
Time-limited URLs with configurable restrictions:
connect link api --expires 30d --methods GET --paths /api/v1
# → https://abc123xyz.privateconnect.co
Features:
  • No authentication required
  • Rate limiting
  • Method and path restrictions
  • Automatic expiration
Both methods are opt-in and create audit logs. Services remain private unless explicitly shared.

Encryption

In Transit

ConnectionEncryption
Agent ↔ HubTLS 1.2+ required (enforced for non-localhost)
Hub ↔ DatabaseTLS (when using managed PostgreSQL)
Web UI ↔ APIHTTPS
HTTPS enforcement can be bypassed for local development only:
CONNECT_ALLOW_INSECURE=true connect up --hub http://localhost:3001

At Rest

  • Database: Encryption depends on your PostgreSQL provider
  • Hosted version: Uses Railway’s managed PostgreSQL with encryption at rest
  • Self-hosted: Configure your database provider’s encryption settings

End-to-End Encryption (Future)

Currently, payload data passes through the Hub as an opaque relay. For environments requiring zero-knowledge relay, we’re considering optional agent-to-agent encryption where:
  • Agents negotiate keys directly
  • Hub relays encrypted packets it cannot read
  • Perfect forward secrecy via ephemeral keys

Deployment Options

The production Hub at api.privateconnect.co runs on:
ComponentProviderRegion
API ServerRailwayUS (Oregon)
DatabaseRailway PostgreSQLUS (Oregon)
Web FrontendRailwayUS (Oregon)
Data Residency:
  • All data resides in US (Oregon) region
  • No data replication to other regions
  • For EU data residency requirements, self-host in your preferred region

Agent Features

Stable Port Mapping

The same service always gets the same local port across restarts:
# First time
connect reach prod-db
# → localhost:5432

# After restart
connect reach prod-db
# → localhost:5432 (same port)
Port mappings are stored locally in ~/.connect/ports.json.

Always-On Mode

Run as a daemon for persistent connections:
# Install daemon (systemd/launchd)
connect daemon install

# Services stay connected across reboots
connect expose localhost:5432 --name prod-db

Health Checks

Agents report health and connectivity:
connect reach grafana --check
# ✓ DNS OK
# ✓ TCP OK  
# ✓ TLS OK
# ✓ HTTP 200 OK
# ✓ Latency: 45ms

Auto-Discovery

Agents can auto-name services based on port:
connect localhost:5432    # Auto-named "postgres"
connect localhost:6379    # Auto-named "redis"
connect localhost:3306    # Auto-named "mysql"

Multi-Region Support (Future)

Currently, agents connect to a single Hub. Multi-region Hub federation is on the roadmap for:
  • High availability deployments
  • Reduced latency by connecting to nearest Hub
  • Automatic failover between regions
  • Cross-region service access

Performance Characteristics

Latency

  • Hub overhead: ~1-2ms per request for relay
  • Total latency: Hub overhead + network distance to Hub + network distance from Hub
  • Debug mode: Additional ~1-2ms for packet capture

Throughput

  • Limited by WebSocket connection bandwidth
  • Typical throughput: 100+ MB/s for sustained transfers
  • No artificial rate limiting at the Hub level

Connection Limits

  • No hard limit on number of services per workspace
  • No hard limit on concurrent tunnels
  • Rate limiting recommended at load balancer level for self-hosted deployments

High Availability

What Happens if the Hub Goes Down?

  • Existing TCP connections through the Hub will fail
  • Agents will attempt to reconnect with exponential backoff
  • No data is lost—the Hub doesn’t store payload data
  • Service metadata is persisted in the database

Recommendations for Production

1

Database Backups

Configure automated backups for your PostgreSQL database
2

Health Monitoring

Set up monitoring and alerting for Hub availability
3

Load Balancing

Run multiple Hub instances behind a load balancer (self-hosted)
4

Rate Limiting

Configure rate limiting at the load balancer level

Open Source

The entire stack is open source under FSL-1.1-MIT license:
  • Agent: Go binary, built with Cobra CLI framework
  • API Server: NestJS (TypeScript), PostgreSQL, WebSockets
  • Web UI: Next.js, React, Tailwind CSS
  • SDK: TypeScript library for programmatic access

GitHub Repository

View the source code, contribute, or self-host

Build docs developers (and LLMs) love