Skip to main content
Chat encrypts messages and attachments in the browser. Xitter keeps only ciphertext, public keys, membership and event history.
  • Images, videos and files are stored as multipart ciphertext under MEDIA_DIR/chat. Downloads require membership.
  • Requests from accounts you don’t follow stay separate until accepted.
  • Group creation, membership changes, edits, reactions, read receipts and typing use the pinned client’s XChat events.

Passcode recovery

Passcode recovery requires a Juicebox software realm. deploy/juicebox builds upstream commit 2e485aac584a6c9ada1fb9f156dc4d7cad3ab338 with a PostgreSQL provider patch. It is also AGPL. The realm stack has its own persistent PostgreSQL volume and binds the realm to 127.0.0.1:8580, with no public database port.
1

Generate chat secrets

Start Xitter once. It writes data/chat-secrets.json.
2

Prepare the realm configuration

From the project root:
This writes realm.env, which is ignored by Git. The script refuses to overwrite an existing configuration.
3

Start the realm

With Docker Compose, you can instead add --profile keybackup to docker compose up. If Xitter runs inside Docker, connect it to the realm’s network and set JUICEBOX_URL=http://realm:8580. Browsers keep using Xitter’s authenticated same-origin proxy at /juicebox/.
Keep the realm ID, signing secret and database password stable, and back up the realm’s PostgreSQL volume together with its configuration. Changing the realm ID or losing its database prevents recovery of existing chat keys.
The local development realm and a server realm have separate record stores. Starting a server realm does not transfer local backups.

Moving accounts

Encrypted chats stay behind when an account moves, since their keys never leave the browser.