Docs
Self-host Headquarters
Run the full CRM on your own machine or VPS. Start locally in minutes, then harden for always-on production when you’re ready.
Prerequisites
Install these before you clone the repo:
- Docker (daemon running)
- Node.js 22+
- pnpm 10 —
corepack enable && corepack prepare pnpm@10 --activate - Supabase CLI ~2.111
Quick start
The fastest path is the bootstrap script. It starts the Supabase Docker stack, applies migrations, writes public env keys, serves the API, and runs the app.
- Clone the repo
git clone https://github.com/JTCorrin/Headquarters.git cd Headquarters - Start the stack
./scripts/dev-up.shSame as
pnpm dev:stack. First run applies migrations. Usepnpm dev:stack:resetwhen you want a clean database. - Open the app at http://127.0.0.1:5173, sign up, and create an organisation through onboarding.
Useful helpers:
./scripts/dev-status.sh # URLs and public key summary
./scripts/dev-down.sh # stop api-v1 serve + supabase stop Backend only (no Vite): ./scripts/dev-up.sh --no-app, then pnpm dev in another terminal.
| Service | URL |
|---|---|
| App | http://127.0.0.1:5173 |
| Supabase API | http://127.0.0.1:54321 |
| Studio | http://127.0.0.1:54323 |
Production (always-on VPS)
Self-hosting for real use means a durable host with Docker, Node 22+, pnpm, and the Supabase CLI — plus a reverse proxy with TLS in front of the Node app. There is no first-party Docker Compose file today; the app process is Node, and Supabase runs via the CLI’s Docker stack.
- Provision the host with Docker (daemon up), Node.js 22+, pnpm 10, Supabase CLI ~2.111, git, and a reverse proxy (Caddy, nginx, or Traefik).
- Clone and install
git clone https://github.com/JTCorrin/Headquarters.git cd Headquarters pnpm install --frozen-lockfile - Point Auth at your public origin in
supabase/config.toml: setsite_url,additional_redirect_urls(includehttps://your.domain/auth/callback), and ensure auth email/SMTP settings match how you want signup confirmation to work. - Start Supabase and load edge secrets
supabase startWrite
supabase/functions/.env(Edge loads these on container create). At minimum pin CORS and cron secrets — generate strong random values and keep them offline:API_CORS_ORIGIN=https://your.domain APP_BASE_URL=https://your.domain PUBLIC_SUPABASE_URL=https://supabase.your.domain MAILBOX_SYNC_SECRET=… RECURRING_INVOICES_CRON_SECRET=… PLAYBOOKS_CRON_SECRET=…PUBLIC_SUPABASE_URLhere must be the browser-reachable Kong/API URL (not only loopback), so Auth and signed Storage URLs work for users. After writingfunctions/.env, bounce the stack withsupabase stopthensupabase startso Edge picks up secrets. Do not remove the edge-runtime container alone. - Configure the app
.envPUBLIC_SUPABASE_URL=https://supabase.your.domain PUBLIC_SUPABASE_ANON_KEY=… # from `supabase status` PUBLIC_API_BASE_URL= # leave empty — same-origin /api/v1 proxy APP_BASE_URL=https://your.domainLeave
PUBLIC_HOSTED_BILLING,PUBLIC_BILLING_API_URL,PUBLIC_LANDING_URL, andBILLING_CLAIM_SECRETunset. Those are for the hosted SaaS product only. - Build and run the Node app
pnpm build pnpm startpnpm startrunsnode build/index.js(adapter-node). Put it behind systemd (or similar) and reverse-proxy HTTPS to that process. Prefer emptyPUBLIC_API_BASE_URLso browsers only call/api/v1on your app origin. - Schedule background jobs with host cron (or another scheduler). Hit the
Edge function URLs with the matching secret headers — for example every minute for mailbox
sync and every few minutes for recurring invoices and playbooks:
mailbox-sync— headerx-mailbox-sync-secretjobs-recurring-invoices— headerx-recurring-invoices-cron-secretjobs-playbooks— headerx-playbooks-cron-secret
Keep secrets out of process argv (use a small wrapper script that reads a file). Protect these endpoints with network isolation; they use shared secrets rather than end-user JWTs.
Core CRM works without OAuth or mailbox providers. Invite email goes through the inviter’s personal mailbox SMTP (Settings → Mail), not a platform SMTP env var.
Optional integrations
Copy values into .env / edge env using the repo’s .env.example as the guide. Common optional pieces:
- Google / Azure login (Supabase Auth external providers +
config.toml) - Mailbox Microsoft / Google OAuth (separate from login)
- Google Calendar OAuth
- Cron secrets for mailbox sync, recurring invoices, and playbooks
Bootstrap scripts do not overwrite secrets you have already set. Org AI providers use user-stored vault keys, not platform env vars.
License
Headquarters is source-available under the Elastic License 2.0 (not OSI “open source”).
- Allowed: use, modify, and self-host — including for your own internal business operations — as long as you keep copyright and license notices.
- Not allowed: offering Headquarters (or a substantial set of its features) to third parties as a hosted or managed service without a separate license.
Help
Source, issues, and deeper backend notes live in the GitHub repository. Prefer issues for bugs and self-host snags so others can find the same fix.