Realtime SDK

Self-Hosting

Self-Hosting

Run the Realtime server on your own infrastructure with full control over data and compliance.

Docker

The easiest way to self-host:

docker run -d \
  -p 8080:8080 \
  -e JWT_SECRET=your-secret-key \
  -e DATABASE_URL=postgres://user:pass@host:5432/realtime \
  ghcr.io/actadv/realtime-server:latest

Docker Compose

For production with PostgreSQL and Redis:

# docker-compose.yml
version: '3.8'
 
services:
  realtime:
    image: ghcr.io/actadv/realtime-server:latest
    ports:
      - "8080:8080"
    environment:
      - JWT_SECRET=${JWT_SECRET}
      - DATABASE_URL=postgres://postgres:postgres@db:5432/realtime
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis
 
  db:
    image: postgres:16-alpine
    environment:
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=realtime
    volumes:
      - postgres_data:/var/lib/postgresql/data
 
  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
 
volumes:
  postgres_data:
  redis_data:

Environment Variables

VariableRequiredDefaultDescription
JWT_SECRETYes-Secret for JWT verification
DATABASE_URLNo-PostgreSQL connection string
REDIS_URLNo-Redis for horizontal scaling
PORTNo8080Server port
HOSTNo0.0.0.0Bind address
JWT_ISSUERNo-Expected JWT issuer
JWT_AUDIENCENo-Expected JWT audience

Webhook Runtime Configuration

The server can source webhook endpoint configuration from the database, environment, or both.

VariableDefaultDescription
WEBHOOK_MODEdbdisabled, db, env, or hybrid
WEBHOOK_ENV_CONFIG_JSON-JSON array of static webhook endpoints (used by env/hybrid)
WEBHOOK_TIMEOUT_MS30000HTTP delivery timeout per attempt
WEBHOOK_RETRY_MAX_ATTEMPTS5Maximum attempts including initial delivery
WEBHOOK_RETRY_BASE_DELAY_MS1000Retry base backoff delay
WEBHOOK_RETRY_MAX_DELAY_MS3600000Retry max backoff delay
WEBHOOK_RETRY_JITTER_FACTOR0.2Retry jitter ratio

Mode behavior:

  • disabled: webhook dispatcher is not created.
  • db: webhook subscriptions are read from the webhooks table.
  • env: webhook subscriptions come only from WEBHOOK_ENV_CONFIG_JSON.
  • hybrid: subscriptions come from both DB and env configuration.

WEBHOOK_ENV_CONFIG_JSON example:

[
  {
    "customerId": "cust_123",
    "url": "https://example.com/realtime-webhooks",
    "secret": "whsec_live_123",
    "events": ["room:join", "room:leave", "document:update"],
    "enabled": true
  }
]

Failure handling expectations:

  • If dispatcher startup config is invalid in env mode, webhook runtime is disabled (fail closed).
  • If env config is invalid in hybrid mode, the server logs an error and continues with DB-backed webhooks (fail open).
  • If webhook target lookup fails for an event, dispatch for that event is skipped and logged; room operations continue.
  • If delivery log persistence fails, delivery attempts still proceed and failures are logged.

Database Setup

Run migrations to create the required tables:

# Using the Docker image
docker run --rm \
  -e DATABASE_URL=postgres://... \
  ghcr.io/actadv/realtime-server:latest \
  pnpm db:migrate

Or create tables manually:

CREATE TABLE documents (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  room_id TEXT NOT NULL,
  doc_id TEXT NOT NULL,
  state BYTEA NOT NULL,
  updated_at TIMESTAMPTZ DEFAULT now(),
  created_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(room_id, doc_id)
);
 
CREATE INDEX idx_documents_room_doc ON documents(room_id, doc_id);

Horizontal Scaling

For multiple server instances, configure Redis for pub/sub:

REDIS_URL=redis://your-redis-host:6379

All instances will sync presence, cursors, and document updates through Redis.

AWS Deployment

See the CDK infrastructure for production AWS deployment including:

  • ECS Fargate for the server
  • Aurora Serverless v2 for PostgreSQL
  • ElastiCache for Redis
  • NLB with TLS termination
  • Global Accelerator for anycast IPs

Health Checks

The server exposes a health endpoint:

GET /health

{
  "status": "ok",
  "connections": 42,
  "rooms": 10,
  "members": 85
}

Client Configuration

Point your client to your self-hosted server:

<RealtimeProvider
  endpoint="wss://realtime.yourdomain.com"
  authToken={getToken}
>
  {children}
</RealtimeProvider>

On this page