Self-Hosting Guide
Overview
Section titled “Overview”The HARP relay is a zero-knowledge dumb pipe that routes encrypted envelopes. While the managed relay at relay.humanauth.ai is the easiest option, teams with strict data residency or compliance requirements can self-host the relay.
The relay package ships with two entry points:
- Cloudflare Workers — used by the managed service (Durable Objects for state)
- Node.js — for self-hosting (in-memory store, single-process)
This guide covers the Node.js self-hosting path.
Quick Start with Docker
Section titled “Quick Start with Docker”Dockerfile
Section titled “Dockerfile”FROM node:22-alpine AS buildWORKDIR /appRUN npm install -g pnpm@9COPY . .RUN pnpm install --frozen-lockfileRUN pnpm --filter @humanauth/relay build
FROM node:22-alpineWORKDIR /appCOPY --from=build /app/packages/relay/dist ./distCOPY --from=build /app/packages/relay/package.json .COPY --from=build /app/node_modules ./node_modulesEXPOSE 8787CMD ["node", "dist/index.js"]Build and Run
Section titled “Build and Run”docker build -t harp-relay .docker run -p 8787:8787 harp-relayThe relay is now running at http://localhost:8787.
Verify
Section titled “Verify”curl http://localhost:8787/health# {"status":"ok"}Configuration
Section titled “Configuration”Environment Variables
Section titled “Environment Variables”| Variable | Default | Description |
|---|---|---|
PORT | 8787 | HTTP port |
HOST | 0.0.0.0 | Bind address |
Reverse Proxy (nginx)
Section titled “Reverse Proxy (nginx)”For production, place the relay behind a reverse proxy with TLS:
server { listen 443 ssl; server_name relay.yourcompany.com;
ssl_certificate /etc/ssl/certs/relay.crt; ssl_certificate_key /etc/ssl/private/relay.key;
location / { proxy_pass http://127.0.0.1:8787; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
# Long polling support proxy_read_timeout 600s; proxy_send_timeout 600s; }}Using Your Self-Hosted Relay
Section titled “Using Your Self-Hosted Relay”Point the CLI and MCP server to your relay:
# Pairinghumanauth pair --name "my-agent" --relay https://relay.yourcompany.com
# The relay URL is saved in the pairing file, so all subsequent# requests automatically route through your self-hosted relay.Docker Compose
Section titled “Docker Compose”For a complete setup with nginx and auto-renewing TLS via certbot:
version: "3.8"services: relay: build: . restart: unless-stopped environment: - PORT=8787 expose: - "8787"
nginx: image: nginx:alpine restart: unless-stopped ports: - "443:443" - "80:80" volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf - ./certs:/etc/ssl depends_on: - relayLimitations of Self-Hosting
Section titled “Limitations of Self-Hosting”The Node.js relay uses an in-memory store. This means:
- State is lost on restart — active pairing sessions and pending requests are cleared
- Single process — no horizontal scaling (all state is in one process)
- No push notifications — the self-hosted relay does not send push notifications. The app must poll for pending requests.
For production workloads that require persistence, high availability, and push notifications, use the managed relay at relay.humanauth.ai or deploy the Cloudflare Workers version with Durable Objects.
Security Considerations
Section titled “Security Considerations”- Always use TLS in production. The relay handles encrypted blobs, but TLS protects metadata (pair_ids, request_ids, timing).
- The relay stores only routing data (
pair_id -> device_id -> push_token). It never sees plaintext. - Rate limit incoming requests to prevent abuse (10 requests/minute per
pair_id, 100/minute per IP). - Monitor relay logs for unusual traffic patterns.