Self-Hosting
Overview
Section titled “Overview”Self-hosting Rebase means running two things: a Postgres database, and the
official rebasepro/server image with your project’s bundle mounted into it.
There is no application image to build. Your project travels as a bundle, the runtime is published, and upgrading Rebase is a tag change rather than a rebuild. See Runtime and bundles for why it is split that way.
Docker Compose
Section titled “Docker Compose”rebase build # produces ./dist-bundledocker compose up -d db # start Postgresrebase db push # create the collection tables, oncedocker compose up # start the runtimeA minimal docker-compose.yml:
services: db: image: postgres:18-alpine environment: POSTGRES_USER: rebase_app POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: rebase volumes: - db-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U rebase -d rebase"] interval: 5s retries: 12
api: image: rebasepro/server:latest depends_on: db: { condition: service_healthy } environment: DATABASE_URL: postgres://rebase:${POSTGRES_PASSWORD}@db:5432/rebase JWT_SECRET: ${JWT_SECRET} REBASE_SERVICE_KEY: ${REBASE_SERVICE_KEY} CORS_ORIGINS: ${CORS_ORIGINS} volumes: # Writable: the container installs the bundle's declared dependencies into # it on first start. See "Dependencies" below for the read-only variant. - ./dist-bundle:/bundle ports: - "8080:8080"
volumes: db-data:Dependencies
Section titled “Dependencies”rebase build writes a package.json next to your bundle listing the
dependencies your project declared. The container installs them on first start,
which is why the mount above is writable.
To mount read-only instead — worth doing, because a compromised hook then cannot rewrite the code that runs after the next restart — install them first:
npm install --omit=dev --prefix dist-bundle volumes: - ./dist-bundle:/bundle:roFor a real deployment, prefer baking both into an image, which also pins exactly what runs:
FROM rebasepro/server:0.11.0COPY dist-bundle /bundleCreating the schema
Section titled “Creating the schema”The runtime creates its own auth tables at boot. Collection tables are a separate, deliberate step, and the runtime image does not do it — a container restart must not be able to change a schema as a side effect of a deploy.
rebase db pushRun it from a checkout or a CI job, pointed at the deployment’s database. It dry-runs the change first, refuses destructive ones without explicit confirmation, and can take a backup before applying.
REBASE_MIGRATE_ON_BOOT accepts ensure (the default — auth tables only) and
none.
Other platforms
Section titled “Other platforms”The runtime is an ordinary container listening on $PORT, so anything that runs
containers works. Two things to get right everywhere:
- The bundle must be present at
/bundle(or whereverREBASE_BUNDLEpoints), with its dependencies installed beside it — see Dependencies. - Set
CORS_ORIGINS,JWT_SECRETandDATABASE_URL. The runtime refuses to start in production without them rather than guessing.
Fly.io
Section titled “Fly.io”[build] image = "rebasepro/server:0.11.0"
[http_service] internal_port = 8080
[[http_service.checks]] path = "/livez"Use the derived-image form above so the bundle ships with the app, then
fly deploy.
Railway / Render
Section titled “Railway / Render”Point the service at the derived image, set the environment variables, and set
the health check path to /livez.
A plain VPS
Section titled “A plain VPS”npm install -g @rebasepro/server @rebasepro/server-postgresrebase-server /srv/myapp/dist-bundleRun it under systemd, with Environment= lines for the variables above.
Health checks
Section titled “Health checks”| Path | Use for |
|---|---|
/livez |
Liveness. Answers “is this process alive” without touching the database. |
/health |
Readiness. Performs a database round-trip and reports latency. |
Point liveness probes at /livez. A liveness probe on /health restarts a
perfectly healthy process during a brief database hiccup, which is the opposite
of what it is for.
Metrics
Section titled “Metrics”REBASE_METRICS=trueREBASE_METRICS_TOKEN=<random string>Exposes Prometheus metrics at /metrics: request counts and latency histograms
broken down by API surface (data, auth, storage, functions) and collection, plus
process gauges. Without a token the endpoint is readable by anyone who can reach
the port, so set one unless it is on a private network.
Upgrading
Section titled “Upgrading”image: rebasepro/server:0.12.0Restart. Your bundle is unchanged. Within a runtime contract major, a bundle that validated keeps working — see Compatibility.
