Quick Start
Get a self-hosted BuildBase stack running in minutes with Docker Compose.
Quick Start
This guide gets you from zero to a running stack in minutes. Everything is bundled — MongoDB, Redis, tenant server, client app, and auth portal.
Prerequisites
- Docker and Docker Compose installed
- An
amd64orarm64host — images run natively on both, including Apple Silicon - A BuildBase account (console.buildbase.app)
Step 1: Create an Organization & Installation
- Log in to console.buildbase.app
- Create a new organization with Self-Hosted hosting mode
- The setup wizard will guide you to create an Installation
- Copy your Installation API Key and Installation ID
Step 2: Create your environment file
Save this as .env.selfhost:
# ═══════════════════════════════════════════════════════════════════
# Self-Hosted — Production Environment
# ═══════════════════════════════════════════════════════════════════
# ── Installation (from BuildBase dashboard) ──────────────────────
INSTALLATION_API_KEY=<INSTALLATION_API_KEY>
INSTALLATION_ID=<INSTALLATION_ID>
# ── Database (REQUIRED for production) ───────────────────────────
# The production compose uses an external MongoDB (Atlas or
# self-managed). Without this, the server falls back to localhost
# inside the container and never becomes ready.
# The quick-start compose bundles MongoDB and ignores this value.
MONGO_CONNECTION_URL=mongodb+srv://user:[email protected]/
# ── Public URLs ──────────────────────────────────────────────────
# For local testing use http://localhost:4100, :4101, :4103
CLIENT_URL=https://app.yourcompany.com
TENANT_SERVER_URL=https://api.yourcompany.com
AUTH_URL=https://auth.yourcompany.com
# ── Ports ────────────────────────────────────────────────────────
CLIENT_PORT=4100
TENANT_SERVER_PORT=4101
AUTH_PORT=4103
# ── Security (REQUIRED — run: openssl rand -hex 32) ──────────────
JWT_PASS=
DB_ENCRYPTION_KEY=
SECRET_KEY=
OAUTH2_SECRET=
# ── Optional services ────────────────────────────────────────────
# GOOGLE_AUTH_CLIENT_ID=
# GOOGLE_AUTH_CLIENT_SECRET=
# GOOGLE_STORAGE_ASSETS_BUCKET_NAME=
# MAILGUN_API_KEY=Generate all secrets at once:
for i in JWT_PASS DB_ENCRYPTION_KEY SECRET_KEY OAUTH2_SECRET; do echo "$i=$(openssl rand -hex 32)"; doneStep 3: Save the Docker Compose file
Save this as docker-compose.selfhost.yml:
# Self-Hosted: MongoDB + Redis + Server + Client + Auth
# Save as docker-compose.selfhost.yml
# Usage: docker compose -f docker-compose.selfhost.yml --env-file .env.selfhost up -d
services:
# ── Infrastructure ──────────────────────────────────────────
mongodb:
image: mongo:7.0
restart: unless-stopped
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- SETUID
- SETGID
- DAC_OVERRIDE
volumes:
- mongodb_data:/data/db
networks:
- db
healthcheck:
test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
start_period: 20s
retries: 3
deploy:
resources:
limits:
memory: 1024M
cpus: '1.0'
pids: 256
logging:
driver: json-file
options:
max-size: '100m'
max-file: '3'
redis:
image: redis:7.4-alpine
restart: unless-stopped
read_only: true
cap_drop:
- ALL
cap_add:
- SETUID
- SETGID
command: redis-server --appendonly yes --maxmemory-policy noeviction --maxmemory 256mb --requirepass ${REDIS_PASSWORD:-redispass}
tmpfs:
- /tmp
volumes:
- redis_data:/data
networks:
- db
healthcheck:
test: ['CMD', 'redis-cli', '-a', '${REDIS_PASSWORD:-redispass}', 'ping']
interval: 10s
timeout: 5s
retries: 3
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
pids: 64
logging:
driver: json-file
options:
max-size: '50m'
max-file: '3'
# ── Backend ─────────────────────────────────────────────────
tenant-server:
image: buildbaseapp/tenant-server:latest
restart: unless-stopped
read_only: true
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
tmpfs:
- /tmp
- /var/log
ports:
- '${TENANT_SERVER_PORT:-4101}:3000'
environment:
- NODE_ENV=production
- PORT=3000
# Keep the Node heap below the 1024M container limit — the image
# default is sized for larger hosts and would get OOM-killed here.
- NODE_OPTIONS=--max-old-space-size=768
- SERVER_URL=${TENANT_SERVER_URL:-http://localhost:4101}
- APPLICATION_URL=${CLIENT_URL:-http://localhost:4100}
- AUTH_SERVER_URL=${AUTH_URL:-http://localhost:4103}
- MONGO_CONNECTION_URL=mongodb://mongodb:27017/
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD:-redispass}
- INSTALLATION_API_KEY=${INSTALLATION_API_KEY:-}
- INSTALLATION_ID=${INSTALLATION_ID:-}
- JWT_PASS=${JWT_PASS:-localdev_jwt_secret_do_not_use_in_production}
- OAUTH2_SECRET=${OAUTH2_SECRET:-localdev_oauth2_secret_do_not_use_in_production}
- DB_ENCRYPTION_KEY=${DB_ENCRYPTION_KEY:-localdev_db_encryption_key_do_not_use_in_production}
- SECRET_KEY=${SECRET_KEY:-localdev_secret_key_do_not_use_in_production}
- CORS_WHITELISTED_DOMAINS=${CLIENT_URL:-http://localhost:4100},${AUTH_URL:-http://localhost:4103}
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
networks:
- db
- app
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://127.0.0.1:3000/api/ready']
interval: 15s
timeout: 5s
start_period: 45s
retries: 3
deploy:
resources:
limits:
memory: 1024M
cpus: '1.0'
pids: 256
logging:
driver: json-file
options:
max-size: '100m'
max-file: '5'
# ── Frontend ────────────────────────────────────────────────
client:
image: buildbaseapp/client:latest
restart: unless-stopped
# NOTE: read_only must NOT be set on client or auth. Their entrypoints
# rewrite __NEXT_PUBLIC_*__ URL placeholders in the JS bundles at
# startup; a read-only filesystem makes that rewrite fail silently and
# the app calls the literal placeholder string instead of your URL.
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
tmpfs:
- /tmp
- /var/cache/nginx
- /var/run
ports:
- '${CLIENT_PORT:-4100}:3000'
environment:
- NEXT_PUBLIC_SERVER_URL=${TENANT_SERVER_URL:-http://localhost:4101}
- NEXT_PUBLIC_DEFAULT_TENANT_SERVER_URL=${TENANT_SERVER_URL:-http://localhost:4101}
- NEXT_PUBLIC_INSTALLATION_ID=${INSTALLATION_ID:-}
networks:
- app
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://127.0.0.1:3000/']
interval: 15s
timeout: 5s
start_period: 30s
retries: 3
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
pids: 128
logging:
driver: json-file
options:
max-size: '50m'
max-file: '3'
auth:
image: buildbaseapp/auth:latest
restart: unless-stopped
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
tmpfs:
- /tmp
- /var/cache/nginx:uid=1001,gid=1001
- /var/run:uid=1001,gid=1001
ports:
- '${AUTH_PORT:-4103}:3000'
environment:
- NEXT_PUBLIC_SERVER_URL=${TENANT_SERVER_URL:-http://localhost:4101}
networks:
- app
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://127.0.0.1:3000/health']
interval: 15s
timeout: 5s
start_period: 30s
retries: 3
deploy:
resources:
limits:
memory: 256M
cpus: '0.5'
pids: 128
logging:
driver: json-file
options:
max-size: '50m'
max-file: '3'
volumes:
mongodb_data:
redis_data:
# Network segmentation: databases isolated from frontends.
# Only tenant-server bridges both networks.
networks:
db:
driver: bridge
internal: true
app:
driver: bridgeStep 4: Start the stack
docker compose -f docker-compose.selfhost.yml --env-file .env.selfhost up -dStep 5: Verify
# Check all services are running
docker compose -f docker-compose.selfhost.yml ps
# Server should return {"ready": true}
curl http://localhost:4101/api/readyStep 6: Connect
Go back to the setup wizard in the dashboard, enter your server URL (http://localhost:4101 for local testing), click Test Connection, then Complete Setup.
Your services are now running at:
- Client: http://localhost:4100
- Server API: http://localhost:4101
- Auth Portal: http://localhost:4103
What's Next
- Configuration reference — all environment variables
- Production deployment — SSL, custom domains, scaling