Practices Messaging

walkytalky is self-hosted, and self-hosting means your own Firebase project

An MIT-licensed iOS chat app with real end-to-end encryption and no service behind it. The data plane is Firebase, and the account, the rules and the console are Google's.

walkytalky is a one-to-one chat app for iOS, MIT licensed, with no service behind it. The repository says so plainly: there is no shared instance, every deployer stands up their own Firebase project, and self-hosting means exactly that. The app is the client, and Firebase is the only backend.

What is actually yours

The cryptography holds up. Keys are derived on-device through an offline QR handshake between the two devices, an X25519 ECDH exchange running into HKDF-SHA256 with the conversation id as salt, and the result never touches the server. Messages and media are AES-256-GCM, with the nonce stored separately in Firestore and the payload as ciphertext plus tag. Re-pairing mints a new key version and throws the old one away, so old messages become unreadable on purpose. Images are downscaled and stripped of EXIF and GPS before encryption, and decrypted media renders from an app-private sandbox rather than the Photos library. Firebase Auth is anonymous only, accounts are enforced to one device at a time through a Firestore transaction, and the local passcode is PBKDF2 with a per-device salt in the iOS Keychain.

That is a real design. It is also the honest version of the word: you own the keys, and Google holds the encrypted blobs, the auth and the project.

What you have to do by hand

There is no add-contact flow, and the README calls that a scope boundary rather than a missing feature. An admin works in the Firebase console: read each user’s uid out of the app, create the conversation document with both uids in participants, optionally set display names, then get both devices together, in person or on a video call, to pair by QR. The security rules in firebase/SecurityRules/ are the actual access-control boundary for the data, checked server-side against participant membership rather than trusting the client, and the README’s instruction is to read them before deploying them.

The trade-offs, stated

A conversation is two people because the key comes from a pairwise ECDH exchange, so a third participant added to that array breaks decryption for everyone in it. Notifications are deliberately not real push: that capability is gated behind a paid Apple Developer Program membership, which would contradict the free-Apple-ID promise, so the app does an opportunistic background check that posts a fixed “You have a new message” with no preview and that iOS may run hours later or not at all after a force-quit. No group chat, no video, iOS only for now, and a published wire protocol describing the exact payload layouts for anyone building another client.

My read

This is the useful end of the self-hosting argument, because it does not pretend. The account, the storage, the push path and the console are somebody else’s cloud, and the app’s own documentation says so on the first screen instead of the last. What you bring is the key material and the trust decisions, and your uptime depends on a company you do not pay.

The part I would actually check before trusting it with anything: the security rules. In a design like this the rules are the whole boundary. The encryption protects the message bodies; the rules decide who can write a message, claim a conversation or overwrite a doc. The README says to read them before deploying them, which is the right instruction, and it is the part that takes an afternoon.

Source: pkMinhas/walkytalky-private-messenger, README and self-hosting guide