Docker Compose
Run the full Hyperbolic stack — API server, web app, Postgres — on your own infrastructure with one command.
Hyperbolic is designed to self-host cleanly. The public beta at hyperbolic.sh runs on Railway + Vercel + Neon, but everything you see there is fully reproducible on your own hardware.
Prerequisites#
- Node.js ≥ 20
- pnpm ≥ 9
- PostgreSQL ≥ 15 (Neon, Supabase, or self-hosted)
- Docker & Docker Compose (recommended)
Quickstart#
git clone https://github.com/jdgmnt33/hyperbolic
cd hyperbolic
cp .env.production.example .env
# edit .env — see the env page
docker compose up -d --build
curl http://localhost:3111/api/healthThe compose file exposes:
- API server on
${PORT:-3111} - Web dashboard on
${WEB_PORT:-3222}
Both run as non-root user appuser (UID 1001).
Updating#
git pull
docker compose up -d --buildDatabase schema#
First-time setup requires pushing the Drizzle schema:
cd apps/server
DATABASE_URL="postgres://…" npx drizzle-kit pushRe-run this whenever you upgrade to a version that adds tables or columns.
Direct Node deployment#
If you prefer no Docker:
pnpm install
pnpm build
# Schema push (first deploy only)
cd apps/server && DATABASE_URL="…" npx drizzle-kit push && cd ../..
# Start both processes (or use your process manager of choice)
cd apps/server && node dist/index.js &
cd apps/web && node .next/standalone/server.js &Reverse proxy#
SSE requires careful proxy configuration. The short version: disable response buffering on the API path.
Caddy#
api.example.com {
reverse_proxy localhost:3111 {
flush_interval -1
}
}
app.example.com {
reverse_proxy localhost:3222
}nginx#
server {
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3111;
proxy_set_header Host $host;
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 86400s;
proxy_http_version 1.1;
chunked_transfer_encoding off;
}
listen 443 ssl;
}Cloudflare#
If you proxy through Cloudflare, enable "Grey cloud" (DNS-only) for the API subdomain, or the streaming connection will be buffered. The web subdomain is fine under the orange cloud.
Health and monitoring#
| Endpoint | Purpose |
|---|---|
| GET /api/health | Server health, uptime, active SSE count |
| GET /api/ping | Lightweight connectivity check |
| /health (web) | Dashboard health page |
Point an uptime monitor (UptimeRobot, Better Stack, etc.) at /api/health.
Common pitfalls#
nginx, Cloudflare, and many CDNs buffer streaming responses by default. If SSE "appears stuck", disable buffering on the API path.
Changing NEXT_PUBLIC_API_URL or NEXT_PUBLIC_SSE_URL requires rebuilding the web image. They can't be changed at runtime.
CORS_ORIGINS must exactly match the browser's origin (protocol + host + port). No trailing slashes.