Hub Setup
What is the Hub?
Section titled “What is the Hub?”xNet works fully peer-to-peer — no server required. A Hub improves availability and adds services that are hard on mobile devices:
| Without Hub | With Hub |
|---|---|
| Sync only when both peers are online | Sync anytime — Hub bridges the gap |
| No backup | Encrypted backup (zero-knowledge) |
| No full-text search across devices | Server-side FTS5 search |
| P2P only | P2P when possible, Hub when not |
The Hub never sees your plaintext data. It stores encrypted updates and relays them to your devices.
flowchart LR A[Device A] <-->|P2P| B[Device B] A <-->|Hub Relay| H[Hub] B <-->|Hub Relay| H
Quick Start: Deploy on Railway
Section titled “Quick Start: Deploy on Railway”The fastest way to get a Hub running. No Docker, no SSH, no TLS setup.
What happens:
- Railway clones the xNet repo
- Builds the Hub from its Dockerfile
- Creates a persistent volume for SQLite + blobs
- Gives you a URL:
hub-xyz.up.railway.app
Cost: $0-2/month for a personal Hub (covered by Railway’s $5 Hobby credit).
After Deploying
Section titled “After Deploying”Your Hub is live. Copy the URL and configure your app:
<XNetProvider config={{ hubUrl: 'wss://hub-xyz.up.railway.app', }}/>Platform Comparison
Section titled “Platform Comparison”| Platform | Best for | Typical cost | Notes |
|---|---|---|---|
| Railway | One-click, lowest friction | $0-2/mo | Ideal default for personal Hubs |
| Fly.io | Auto-suspend, global edge | $2-6/mo | Suspend/resume adds ~2s wake |
| VPS | Full control | $4-5/mo | You manage TLS + upgrades |
Alternative Deployments
Section titled “Alternative Deployments”Best for auto-suspend cost savings or multi-region experiments.
# Install Fly CLIcurl -L https://fly.io/install.sh | shfly auth login
# Deploycd packages/hubfly launch --no-deployfly volumes create xnet_hub_data --size 1 --region sjcfly deployCost: ~$2-6/month depending on usage. Machines can auto-suspend when idle.
For multi-region (future), add additional regions and volumes, then enable hub federation for query routing.
Best for full control or predictable cost.
docker run -d \ --name xnet-hub \ -p 4444:4444 \ -v xnet-hub-data:/data \ --restart unless-stopped \ ghcr.io/crs48/xnet-hub:latestYou’ll need to configure TLS yourself (Caddy, nginx, or Cloudflare Tunnel).
Cost: $4-5/month for a basic VPS (Hetzner, DigitalOcean).
Best for development and testing.
npx @xnet/hub --port 4444 --data ~/.xnet-hubNo TLS, no persistence guarantees. Use for local development only.
Configuration
Section titled “Configuration”Environment Variables
Section titled “Environment Variables”| Variable | Default | Description |
|---|---|---|
PORT | 4444 | Listen port (Railway injects this) |
HUB_DATA_DIR | ./xnet-hub-data | SQLite + blob storage directory |
HUB_LOG_LEVEL | info | Log verbosity: debug, info, warn, error |
HUB_PUBLIC_URL | — | Public URL for discovery + federation |
RAILWAY_VOLUME_MOUNT_PATH | — | Auto-set by Railway when a volume is attached |
CLI Flags
Section titled “CLI Flags”| Flag | Description |
|---|---|
--port | Listen port |
--data | Data directory |
--no-auth | Disable UCAN authentication |
--storage | Storage backend: sqlite, memory |
--public-url | Public hub URL for discovery |
--max-connections | Max concurrent WebSocket clients |
--max-blob-size | Max backup blob size |
--awareness-ttl | Awareness TTL in ms |
--discovery-ttl | Peer discovery TTL in ms |
Connect Your App
Section titled “Connect Your App”React (Renderer)
Section titled “React (Renderer)”<XNetProvider config={{ hubUrl: 'wss://your-hub.example.com', }}/>Electron (Main)
Section titled “Electron (Main)”const manager = new SyncManager({ hubUrl: 'wss://your-hub.example.com',})Operations
Section titled “Operations”Health & Metrics
Section titled “Health & Metrics”| Endpoint | Purpose |
|---|---|
GET /health | JSON status, uptime, platform metadata |
GET /metrics | Prometheus metrics |
Core Endpoints
Section titled “Core Endpoints”| Endpoint | Purpose |
|---|---|
PUT /backup/:docId | Upload encrypted backup |
GET /backup/:docId | Download encrypted backup |
GET /backup | List backups for your DID |
PUT /files/:cid | Upload content-addressed file |
GET /files/:cid | Download file |
POST /schemas | Publish schema |
GET /schemas/resolve/:iri | Resolve schema |
POST /dids/register | Register peer discovery |
GET /dids/:did | Resolve peer |
Backups
Section titled “Backups”The Hub stores encrypted blobs. Your app encrypts before upload.
| Endpoint | Purpose |
|---|---|
PUT /backup/:docId | Upload encrypted backup |
GET /backup/:docId | Download encrypted backup |
GET /backup | List backups for your DID |
Query + Search
Section titled “Query + Search”Queries run locally first, with Hub results filling in the gaps:
const results = await queryClient.search('budget', { federate: true, limit: 20,})Migration
Section titled “Migration”Moving between platforms is straightforward:
- Stop the old Hub (
SIGTERMflushes SQLite) - Copy the data directory (
/dataor yourHUB_DATA_DIR) - Start the new Hub with the same data dir
- Update your app’s
hubUrl
Railway → VPS/Fly.io is just a volume export + upload. Fly.io → Railway is the same process in reverse.