← Home

Deploy a fukura-hub

A team’s own hub takes about fifteen minutes. The binary is one container, the database is Postgres, the search index is a directory. Below is the concrete recipe. Every numbered step maps to a concrete artefact in the repo.

1Prerequisites

Docker / Compose, or a Kubernetes cluster. Postgres 15+ (separate managed DB is fine). 2 vCPU / 4 GB RAM baseline. Outbound HTTPS for OAuth (if you use GitHub / Google login). One domain for the API and one for the web UI (or a single host with path-based routing).

2Pull the image

Use the Docker Compose manifest at the repo root: a single docker compose up -d --build brings up Postgres, the Rust backend on :8080, and the Next.js frontend on :3000.
git clone https://github.com/boostbit-inc/fukura-hub
cd fukura-hub
cp backend/env.sample backend/.env
# edit .env with real values
docker compose up -d --build

3Environment variables

The hub reads its config from env. Minimum required:
  • DATABASE_URL — Postgres DSN.
  • JWT_SECRET — random 32+ byte string. Rotate on incident; every token signed with the old secret becomes invalid.
  • HOST / PORT — defaults 0.0.0.0:8080.
  • FRONTEND_URL — used for OAuth redirects.
  • SEARCH_INDEX_PATH — persistent directory for the Tantivy index. Mount a volume here.
  • Optional: GITHUB_CLIENT_ID / _SECRET, GOOGLE_CLIENT_ID / _SECRET for OAuth sign-in.

4Database migrations

The backend auto-runs all migrations on boot. First-run ordering: 001_init002_attempts 003_notes_ekp_columns 004_privacy_team_to_org 005_notes_extras. Migrations are forward-only; never edit a file that has already shipped. For zero-downtime enum work see ADR 0006.

5Search index volume

Persist /app/search_index (or whatever SEARCH_INDEX_PATH points at). Losing the directory means the search index rebuilds on next boot, which is expensive at scale.

6DNS + TLS

Point a domain at the hub. Terminate TLS at your ingress (Caddy, nginx, ALB, Cloudflare — anything). The backend expects X-Forwarded-Proto: https behind a TLS terminator so OAuth redirects stay on HTTPS.

7Bootstrap the first admin

Register through the standard /api/auth/register flow (UI or curl). The first user is the first org admin. Invite teammates through the standard UI; they land in personal context by default and switch via the Navbar dropdown (see ADR 0004).

8Point CLIs at your hub

fuku hub --url https://hub.acme.dev --token "$FUKURA_HUB_TOKEN" ping
# set once in your shell rc:
export FUKURA_HUB_URL=https://hub.acme.dev
export FUKURA_HUB_TOKEN=...
Distribute the URL (not the token) to the team via your usual channel. Each engineer runs fuku hub ping to confirm.

9Run the contract tests against your deploy

Fukura ships a contract test that exercises the entire spec surface against any hub URL. Run it against your deploy before you declare production:
git clone https://github.com/boostbit-inc/fukura
cd fukura
HUB_BASE_URL=https://hub.acme.dev HUB_TOKEN=... \
  HUB_SLICE_1=1 HUB_SLICE_2=1 HUB_SLICE_3=1 HUB_SLICE_4=1 HUB_SLICE_5=1 \
  cargo test --test hub_http_client -- --nocapture
A green run is the guarantee that your hub is spec-conformant.

10Upgrades

docker compose pull && docker compose up -d is the happy path. For enum / schema changes that the hub flags as stage-gated, follow the three-stage pattern in ADR 0006. Never skip stages even if production is quiet.

11Backups and observability

Postgres: daily logical dump, weekly physical snapshot. Search index: daily directory snapshot is fine (worst case, rebuild from Postgres). Metrics: backend exposes /health (unauth) and /v1/health with version + hub_id, plus structured tracing that speaks the standard Rust RUST_LOG filter.

Self-hosting stays free

The repo is source-available: you can run the exact image we run. Commercial support and SAML / SCIM / audit / federation live in the paid tiers (see pricing). If your team outgrows the Free tier in features, not capacity, that is the conversation to have with us.