Files
beardrive/docs/self-hosting.md
T
Snow LeeandClaude Opus 4.8 5c6099177b feat: bdrive skill install + one-paste Codex/Hermes setup guide
The hub's install guide told Codex and Hermes users to run four CLI
commands by hand, and the one people skipped — `bdrive hooks install` —
is exactly the one that makes files sync at turn boundaries. Hand the
setup to the agent instead, the way the Claude tab hands it to the
plugin.

- `bdrive skill install` (internal/agentskills, plugin/embed.go): the
  binary now carries the beardrive skill and writes it to any agent that
  reads SKILL.md — ~/.{claude,codex,gemini,hermes}/skills/beardrive/.
  User-level on purpose: the skill is about the CLI, not one folder, and
  a synced project folder should never carry it. Idempotent; refreshes a
  stale copy after a CLI upgrade. Bare `bdrive skill` prints the table,
  mirroring `bdrive hooks`.
- Guide's Codex/Hermes tabs are now a single paste, no terminal: the
  prompt has the agent install the CLI, keep the skill, sign in, init,
  and register hooks. The commands ride inside the prompt because these
  agents ship no BearDrive knowledge (Claude's tab is terse only because
  the plugin carries it). `login --device` there — a browser-callback
  sign-in is invisible to an agent mid-turn, while the device flow gives
  it a code and URL to relay. Plain commands live on in an "or run it
  yourself" fallback.
- Docs realigned: README, SKILL.md, /beardrive:install, self-hosting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 14:30:06 -07:00

7.5 KiB

Self-hosting a BearDrive hub in ~10 minutes

Until BearDrive Cloud launches, self-hosting is the way to run a team hub — and it stays a first-class, fully-supported path forever (AGPL, no features held back). One static Go binary, one config file, any object store (or a plain directory).

1. Install the binary

brew install runbear-io/tap/beardrive     # macOS / Linuxbrew
# or: go install github.com/runbear-io/beardrive/cmd/bdrive@latest
# or: grab a release tarball — https://github.com/runbear-io/beardrive/releases

2. Pick storage

Any of: s3://bucket/prefix, gs://bucket/prefix, an S3-compatible endpoint, or — simplest for a first run — a plain directory (file:///var/lib/bdrive/storage). Files and change journals live there; hub metadata (accounts, projects, orgs) lives in the database you pick in step 3. Clients never see this storage — they sync through the hub over HTTPS.

3. Write config.json

{
  "remote": "file:///var/lib/bdrive/storage",
  "addr": ":4173",
  "upload": true,
  "auth": {
    // Signup is invite-only by default — the safe posture for a public
    // URL. Your first account: start once with signup gated (or use an
    // org invite), then invite teammates from the web UI.
    "admins": ["you@example.com"],
    "users_db": "/var/lib/bdrive/auth.json"
  },
  "reads": { "enabled": true },              // agent read analytics (Insights)
  "database": { "driver": "sqlite", "dsn": "/var/lib/bdrive/hub.db" }
}

Full knob reference for auth and databases: the sections below; share-link rate limits and upload TTLs: the README's web-server section.

4. Run it

bdrive web -c config.json

Put TLS in front (Caddy/nginx/your platform's LB) — device tokens travel as bearer tokens. For containers, the repo ships a Dockerfile (distroless, CGO-free) with a Cloud Run recipe in deploy/ — any container platform works the same way.

5. First sign-in and first project

  1. Open https://your-hub/ → create your account (first run: use the signup posture you configured; hub admins are the admins emails).
  2. On any machine: bdrive login https://your-hub (browser flow), then in the folder you want synced: bdrive init --name wiki --yes — or --shared docs inside a repo to sync only that subfolder.
  3. Invite a teammate: sidebar footer → ManageNew invite — the join link both creates their account and adds them to your org.
  4. Connect agents: the project's home page in the web UI shows one-paste setup for Claude Code/Cowork, Hermes, and Codex — hub URL and project id already filled in. Teammates paste it into their own agent, which installs the CLI, keeps the beardrive skill (bdrive skill install), signs in, mounts the project, and registers the sync hooks.

Authentication reference

Hubs always require sign-in — every change is attributed to a real account. The whole API — web UI, uploads, project creation, device sync — needs a session; only /api/config and the auth pages stay open (the plain-folder viewer, bdrive web ./folder, remains auth-free). Accounts are email + password + name, kept in a file-backed registry (auth.json: bcrypt password hashes and SHA-256 token digests, atomically rewritten — no plaintext credentials ever touch disk).

Signup is invite-only by default — the safe posture for a hub on a public URL. New people get in only through an expiring invite link an owner mints; the link lets them create an account (bypassing the gates below) and join, in one step. To allow self-service signup instead, set "allow_signup": true with a gate — the server refuses to start an open hub that has none, so a fake email can never just walk in. Three postures:

  • Invite-only (default): allow_signup unset/false. Only invite links create accounts.
  • Approval-gated: allow_signup: true + require_approval: true — anyone can sign up, but a hub admin approves each new account before it works (no SMTP needed).
  • Domain-restricted + verified: allow_signup: true + allowed_domains: ["you.com"] + require_verification: true (needs smtp) — only your company's addresses may sign up, each confirming an emailed link. Verification without SMTP is refused (the link would otherwise only reach the server log).

Admins tune verification/approval live from the web UI (Admin → Signup & access); allowed_domains, the admin list, and allow_signup are server-config-owned so a browser session can never widen who gets in.

bdrive login <url> on a client device opens the server's sign-in page in a browser (sign up right there if needed); when the user signs in, the page bounces a one-time code to the CLI's loopback listener and the terminal finishes on its own, storing a long-lived per-device token (revocable server-side). On headless/SSH machines, bdrive login --device prints a short code to approve from any signed-in browser instead. Every sync and every bdrive init then authenticates with that token.

"Forgot password" emails a one-hour reset link via the auth.smtp block — plain SMTP, so any provider works. With no SMTP configured, the link is printed to the server log so an admin can hand it over; reset is never fully broken.

Two notes: put a hub behind TLS (reverse proxy or tailscale) — bdrive login warns when signing in over plain http to a non-localhost address. Internally all of this sits behind an AuthProvider interface; the open-source server ships the built-in email/password provider, and alternative identity backends can be swapped in without touching the CLI or the API.

Choosing a database

A hub keeps a little metadata — accounts, projects, orgs, invites, shares, devices — separate from your files. (File content and the sync journals always live in the object store; the database never holds them.) You choose where that metadata lives with the database block:

"database": { "driver": "file" }                       // default — JSON under BDRIVE_HOME
"database": { "driver": "sqlite",   "dsn": "/var/lib/bdrive/hub.db" }
"database": { "driver": "postgres", "dsn": "postgres://…@…pooler.supabase.com:6543/postgres" }
  • file (default): zero dependencies, human-readable JSON, perfect for a laptop or a small self-hosted hub.
  • sqlite: one embedded database file — a real DB locally with no server to run.
  • postgres: a managed Postgres such as Supabase for production — just point dsn at its connection string (use the transaction pooler for many connections). Since Supabase is Postgres, this stays fully open-source with no managed-only lock-in.

file and sqlite are single-writer (run one hub instance); Postgres is transactional and can back more than one instance. Switching backends doesn't migrate existing data — pick one when you set the hub up. Both SQL drivers are pure Go, so the binary stays a CGO-free static build.

Upgrading

brew upgrade beardrive (clients and hub are the same binary — keep them roughly in step; the sync protocol is append-only journals + blobs, which old clients read forward). After upgrading a client, re-run bdrive hooks install once per project to pick up any hook improvements, and bdrive skill install once per machine to refresh the agent skill.

Backup

Everything irreplaceable is in two places: the storage root (blobs + journals — files and their entire history) and the metadata database (accounts/projects/orgs/shares). Snapshot both; restore is copy-back.