← back to overview

Get your group set up.

Three steps: run a hub, become the keymaster, install the client on every phone and laptop that needs it. Plan on about an hour if you’re comfortable at a terminal, longer if it’s your first server.

1Run a hub.

Cove is self-hosted. Every group runs its own hub — a small Python server that holds the tamper-evident log for that group and nobody else’s. Nothing about your group’s messages ever touches infrastructure the Cove project controls.

The easiest way to run one is Docker on a small Linux VM (a $5/month box is more than enough for a board of 20). If you already run other services on a Cloudflare Tunnel, Cove drops in the same way.

What you need on the host: just docker and docker compose. You do not need Python, a virtualenv, or pip install. The bootstrap ceremony runs inside the freshly-built container, which brings its own Python and deps.

Since v0.4.76 there’s a single script that handles the whole ceremony — container tear-down, state wipe, image rebuild, bootstrap, key-custody halt, and container start — with a SHA-verified handoff prompt so the root key can’t leave the ceremony half-done. Use it:

git clone https://github.com/cloudseeder/cove.git
cd cove

# One command per hub. The name you pass becomes the Compose
# project name, and drives the defaults for state dir, container
# name, and public hostname.
./scripts/genesis.sh myorg

The name you pass (myorg, lwccoa, whatever) becomes the identifier the script uses everywhere — state directory ./myorg-state, container name myorg-hub, default public hostname myorg-hub.oap.dev. Override any of these with flags if the defaults don’t fit your setup:

./scripts/genesis.sh flhoa \
    --port 8002 \
    --hostname flhoa-hub.oap.dev \
    --org-name "FL HOA" \
    --keymaster "Jane Smith"

Run ./scripts/genesis.sh --help for the full flag list. Notably, --reuse-pubkey <hex> attests an existing pubkey against the fresh hub root instead of generating a new keypair — that’s the “same identity, N hubs” federation entry point.

The script pauses after generating keys and prints SHA-256 fingerprints for root.priv, root.pub, and the initial member’s .priv/.pub. You paste each into offline storage (password manager, encrypted USB, paper), sha256sum each on the receiving machine, and confirm to the script — only then does it shred the priv files from the host and start the container. The hub refuses to start if root.priv is still on disk.

Multiple hubs on one host is a supported layout. Each hub gets its own state directory, port, container name, and Compose project name — all derived from the name you pass. Just make sure each hub has a distinct --port so they don’t collide.
# Verify:
curl http://127.0.0.1:8000/healthz
# {"status":"ok","version":"..."}

Point a domain at the container (Cloudflare Tunnel or Caddy both work — walked through in the docker README) and you have a running hub.

If you’re already running a Cloudflare Tunnel, scripts/tunnel_add.sh automates the ingress-rule + DNS-CNAME + reload step for a new hub:

sudo ./scripts/tunnel_add.sh <hostname> <port>

# e.g.
sudo ./scripts/tunnel_add.sh flhoa-hub.oap.dev 8002

Reads your tunnel name from /etc/cloudflared/config.yml, creates the CNAME via cloudflared tunnel route dns, inserts the ingress block above your http_status:404 catch-all, reloads cloudflared, and verifies with a /healthz check on the public URL. Idempotent — running twice is a no-op after the first success.

2Onboard the keymaster.

The bootstrap ceremony created one member for you: the keymaster. That’s the person who mints invite codes for everyone else, approves new members, and holds the group’s custodial responsibility. It’s almost always you if you set up the hub.

Open the PWA at app.cove.oap.dev (or install it to the dock — instructions in Step 3). At the landing screen, expand “Signing in from a new device? Use your Cove vault” and paste the keymaster’s .pub key you saved offline during Step 1. You won’t have a vault yet on a fresh install — the sign-in will fail. Fall back to “Get started” and choose the paste-an-existing-key option; paste both the .priv and .pub to sign in for the first time.

Once you’re authenticated, open Admin → Identity vault → Create vault with passphrase. Pick a strong passphrase, label it “Backup passphrase”, and click Create. The hub now holds an encrypted copy of your key that only your passphrase can unlock. On every future device you use, you’ll sign in with just your public key + passphrase — no more file-passing.

From there, the rest of the group onboards through invite codes you mint from the Admin panel. No more terminal work.

Why the two-step dance? The first-time paste is the one time you touch the priv key file directly — after that the vault takes over. On new devices you sign in with pubkey + passphrase (or Passkey, see Step 3), the vault decrypts locally, and your identity travels with you. You never paste the file again.

3Install the client.

Cove has three client surfaces at different levels of polish. Pilot-era honesty: the desktop app is the best-supported, the PWA is the everyday-mobile answer, native mobile is not yet built.

macOS desktop

Signed and notarized. Download the .dmg from GitHub Releases, open, drag to Applications.

Ready

PWA (iOS & Android)

Install app.cove.oap.dev to your home screen. Instructions below.

Ready

Windows / Linux desktop

Unsigned Tauri builds attached to every GitHub release. Works, but expect Gatekeeper/SmartScreen warnings.

Unsigned

Native iOS / Android

Not built yet. The PWA covers this well enough that native isn’t urgent.

Later

Installing the PWA on iPhone (Safari)

  1. Open app.cove.oap.dev in Safari. (Chrome on iOS forwards to Safari for install; other browsers won’t work.)
  2. Tap the Share icon at the bottom of the screen (square with an up-arrow).
  3. Scroll down in the share sheet and tap Add to Home Screen.
  4. Tap Add in the top-right corner.
  5. Open Cove from your home screen. It runs full-screen, has its own icon, and remembers your session between opens (from v0.4.34+).

Installing the PWA on Android (Chrome)

  1. Open app.cove.oap.dev in Chrome.
  2. Tap the menu in the top-right.
  3. Tap Install app (or on some Chrome versions, Add to Home screen).
  4. Confirm on the prompt.
  5. Open Cove from your home screen or app drawer.
Why a PWA and not a native app? Native iOS and Android would need App Store review, provisioning profiles, and platform-specific keychain integrations for every release. That’s a lot of infrastructure for a pilot. The PWA gets you 90% of the native feel — home-screen icon, full-screen, offline caching, push notifications on the roadmap — without any of the store gatekeeping. Native comes later if the pilot outgrows the PWA.
MacOS gotcha: if you install both the desktop app AND the PWA on the same Mac, the dock icon labeled “Cove” will silently launch the desktop app instead of the PWA. Pick one per machine — the PWA is the recommended path since it auto-updates on every push. If you want the PWA, drag /Applications/Cove.app to the trash first, then Safari’s File → Add to Dock… will offer to install the PWA properly.

4Sign in on any device.

Cove’s identity vault (v0.4.76+) turns your keypair into something you can carry to every phone, laptop, and tablet you use — without ever passing the priv file around. Once you’ve created a vault (Step 2), you sign in on a new device in three fields:

  1. Enter your hub URL.
  2. Paste your public key (visible in the sidebar identity chip on any signed-in device).
  3. Unlock: tap “Sign in with Passkey” for a biometric one-tap, or type your passphrase.

That’s it. No fresh invite, no re-attestation. The vault ciphertext is fetched from your hub, unwrapped locally with whichever unlock method you picked, and your session opens with the same identity you had on device #1.

What’s a Passkey?

A Passkey is a biometric-backed credential your device holds — Face ID or Touch ID on Apple, fingerprint or PIN on Android or Windows. It’s the same technology 1Password, Google, and Apple use for password-less sign-in. In Cove, you register a Passkey under Admin → Identity vault → Add Passkey. Every device tied to the same Passkey ecosystem (all your Apple devices sharing one iCloud, or all your Android devices sharing one Google account) gets one-tap sign-in.

Cross-ecosystem: same identity on Apple + Google + Windows.

Passkeys don’t sync between iCloud and Google Password Manager — that’s an industry limitation, not a Cove one. The vault closes the gap: on each ecosystem you add a fresh Passkey (which stays inside that ecosystem’s sync) plus the shared passphrase. iPhone unlocks with iCloud-synced Face ID; Pixel unlocks with Google-synced fingerprint; Windows laptop unlocks with the passphrase. All three end up holding the same Ed25519 identity because the vault has three different wrappers around one canonical CEK.

Devices without biometric hardware (older Mac Minis without a Touch ID keyboard, non-Windows-Hello desktops) can still use the vault — they just default to the passphrase unlock. Add a Touch ID Magic Keyboard or a USB security key any time you want Passkey on those machines.

Backups: don’t lose the last unlock method.

The vault is opaque to the hub — if you lose every unlock method, no one can help you decrypt it. Always keep at least one method the hub’s ecosystem can’t revoke: a passphrase in your password manager, a printed recovery-code slot (roadmap), or a hardware security key you keep in a drawer. The Identity vault section shows a warning banner when only one slot remains.

You’re running.

From here, the day-to-day is: mint invite codes for the rest of the group, hand them out out-of-band (text, in person, on paper), and start posting. Every message is signed, every delivery is receipted, every thread stays whole.

If you hit a wall, the source repo has issue templates. This is a small project by design — the response won’t be instant, but it will be real.