Self-Hosting
Overview
BriefGate cloud (app.briefgate.dev) is the recommended path for most users — no infrastructure to manage, EU data residency included, and you can be up in 5 minutes.
Self-hosting is available if you need data sovereignty on your own infrastructure, on-premises deployment, compliance requirements that cloud does not satisfy, or custom integrations at the server level. The BriefGate server is MIT licensed.
Requirements
| Component | Minimum version |
|---|---|
| Node.js | 22+ |
| PostgreSQL | 16+ |
| Redis | 7+ |
| S3-compatible storage | Optional (Cloudflare R2, MinIO, AWS S3) — defaults to local disk |
| Resend API key | Recommended — without it, chase emails are no-ops |
Quick start with Docker Compose
git clone https://github.com/briefgate/briefgate
cd briefgate
cp .env.example .env
# Edit .env — minimum required variables:
# DATABASE_URL, REDIS_URL, BASE_URL, PORTAL_URL,
# SECRETS_PUBLIC_KEY, SECRETS_PRIVATE_KEY
docker compose up -dThe compose file starts Postgres, Redis, and the BriefGate server. For production, run Postgres and Redis on separate managed instances and point DATABASE_URL and REDIS_URL at them.
Generating the secrets key pair
The secrets vault requires a libsodium keypair. Generate one before first run:
import libsodium from 'libsodium-wrappers';
await libsodium.ready;
const { publicKey, privateKey } = libsodium.crypto_box_keypair();
console.log('SECRETS_PUBLIC_KEY=' + Buffer.from(publicKey).toString('base64'));
console.log('SECRETS_PRIVATE_KEY=' + Buffer.from(privateKey).toString('base64'));Store the private key in your secrets manager (Vault, AWS Secrets Manager, 1Password Secrets Automation, etc.). Never commit either key to git.
The public key encrypts values in the client's browser. The private key decrypts on the server. If you rotate the keypair, existing unrevealed secrets cannot be decrypted — rotate only when you intend to start fresh, and only after ensuring all existing secrets have been revealed.
Environment variables
| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string (e.g. postgres://user:pass@host:5432/briefgate) |
REDIS_URL |
Yes | Redis connection string (e.g. redis://localhost:6379) |
BASE_URL |
Yes | Public API URL (e.g. https://api.yourdomain.com) |
PORTAL_URL |
Yes | Public portal URL (e.g. https://p.yourdomain.com) |
SECRETS_PUBLIC_KEY |
Yes | libsodium public key, base64-encoded |
SECRETS_PRIVATE_KEY |
Yes | libsodium private key, base64-encoded. Keep in secrets manager, not .env file in git. |
RESEND_API_KEY |
Recommended | Email delivery via Resend. Without it, chase emails and portal invitation emails are no-ops. |
ALLOW_SIGNUP |
First run | Set to true to allow account creation. Set to false after creating your account. |
STRIPE_SECRET_KEY |
Optional | Billing integration. Without it, all tier limits are disabled (everyone gets Agency-equivalent access). |
R2_ENDPOINT |
Optional | S3-compatible endpoint (e.g. https://<account>.r2.cloudflarestorage.com) |
R2_ACCESS_KEY_ID |
Optional | S3 access key |
R2_SECRET_ACCESS_KEY |
Optional | S3 secret key |
R2_BUCKET |
Optional | Bucket name for file storage |
STORAGE_LOCAL_DIR |
Optional | Local disk path for file storage when R2 is not configured (default: ./storage) |
SECRETS_TTL_DAYS |
Optional | Default secret token expiry in days (default: 30) |
TRUST_PROXY |
Behind a proxy | Number of proxy hops in front of the API — 1 behind a single reverse proxy. Default 0 (use the socket address). See the warning below. |
CORS_ORIGIN |
If the portal is on another origin | Comma-separated origins allowed to call the API from a browser. Unset = same-origin only. |
COOKIE_SECURE |
Production | true to mark session cookies Secure. Defaults to on when NODE_ENV=production. |
CLAMAV_HOST |
Recommended | clamd host for virus scanning uploads. Without it uploads are marked skipped and served unscanned. |
CLAMAV_TIMEOUT_MS |
Optional | Scan timeout (default: 30000). A timeout marks the file error, and errored files are never served. |
SESSION_COOKIE_NAME / PORTAL_COOKIE_NAME |
Optional | Cookie names for the dashboard and client portal sessions (defaults bg_session / bg_portal). Change if you host something else on the same domain. |
LOG_LEVEL |
Optional | debug, info, warn, error (default: info) |
A warning about TRUST_PROXY
Set it to the number of proxies actually in front of the API, and never to
true on a public listener. true means "believe X-Forwarded-For from
anyone", which lets a caller choose their own request.ip: they rotate the
header to walk around the per-IP brute-force limit on login, and every audit
entry records an address of their choosing.
Leaving it at 0 behind a proxy has the opposite failure: every request appears
to come from the proxy, so the per-IP limit becomes one global bucket and one
noisy client locks out everyone.
Health checks
| Endpoint | Type | Description |
|---|---|---|
GET /healthz |
Liveness | Returns 200 if the process is running |
GET /readyz |
Readiness | Returns 200 only if DB and Redis are reachable |
Configure your load balancer or orchestrator to use /readyz for routing decisions. Use /healthz for restart policies (a healthy process that cannot reach its DB should not receive traffic but should not be killed).
First login
After docker compose up:
- Set
ALLOW_SIGNUP=truein your.envand restart (or set it before the first start) - Create your account:
curl -X POST https://api.yourdomain.com/v1/auth/signup \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"...","name":"Your Name"}'- Set
ALLOW_SIGNUP=falseand restart to prevent additional registrations
If you need multiple accounts (e.g. for a team), create them all while ALLOW_SIGNUP=true, then disable it.
Connecting the MCP package to your instance
The @briefgate/mcp package works with self-hosted deployments. Set the base URL:
# Via environment variable
BRIEFGATE_BASE_URL=https://api.yourdomain.com briefgate-mcp --api-key bg_live_xxxxx# Via CLI flag
briefgate-mcp --api-key bg_live_xxxxx --base-url https://api.yourdomain.comOr in your Claude Code MCP config:
claude mcp add briefgate -- briefgate-mcp \
--api-key bg_live_xxxxx \
--base-url https://api.yourdomain.comThe portal URL is served from PORTAL_URL — your clients will receive portal links pointing to your domain.