Skip to content
back to the quest log
Anonchat visitor identity screen with an optional display name and recovery key link
epic◆ productlive

Anonchat

Anonymous inbox with real E2EE

A self-hosted anonymous messaging inbox where the browser encrypts messages, reactions, notes, and attachments before the server receives them.

role
Creator and full-stack engineer
org
Independent
when
2026

What it is

Anonchat gives any visitor a persistent private conversation with a site owner without asking for an email address, phone number, or social login. A recovery secret deterministically restores the same anonymous identity on another device.

The public chat and the owner dashboard share a React application. A Fastify API, PostgreSQL, native WebSockets, and pluggable local or S3-compatible storage keep the deployment small enough for one VPS.

The server stores and relays ciphertext. Search, previews, attachment rendering, reactions, and shared notes are decrypted in the browser, with the limits of that threat model documented instead of hidden.

where the effort went

  • Security96
  • Realtime86
  • Privacy UX92
  • Operations78

the numbers

Repository
413 files
History
316 commits
Test files
38
Server plaintext
0 messages

built with

  • React
  • TypeScript
  • Fastify
  • PostgreSQL
  • Prisma
  • WebSocket
  • X25519
  • Ed25519
  • XChaCha20-Poly1305
  • S3
  • Docker

delivery record

What I made

I wanted a contact channel that did not turn a first conversation into an identity form or hand readable message history to the hosting layer.

  • 01

    Passwordless anonymous identity derived from a 256-bit recovery secret

  • 02

    End-to-end encrypted chat, attachments, reactions, and shared rich-text notes

  • 03

    Owner dashboard with moderation, TOTP, session controls, and live replies

  • 04

    Native WebSocket delivery with REST cursor recovery after reconnects

  • 05

    Local disk and S3-compatible ciphertext storage behind one adapter

  • 06

    Deployment templates for a VPS, Railway, Render, AWS, GCP, and Azure

Hard problems

The constraints mattered as much as the finished interface.

01field note

Useful messaging without server plaintext

problem
True encryption removes server-side search, content previews, malware inspection, and notification text.
response
I moved search and previews into the authenticated browser, enforced ciphertext ceilings on the server, and kept push notifications deliberately generic.

Result: A database or backup leak exposes metadata, but not conversation content or attachment bytes.

02field note

Anonymous identity that survives a device change

problem
Without accounts, the server cannot use password resets or email recovery to identify a returning visitor.
response
Ed25519 and X25519 keypairs are deterministically derived from a recovery secret, then authenticated through signed server challenges.

Result: The same secret restores the same conversation without the server ever receiving the private key.

03field note

Link previews without opening an SSRF path

problem
Browsers cannot fetch arbitrary Open Graph pages because of CORS, while a naive server proxy can reach private networks.
response
The preview fetcher blocks reserved addresses before and during connection, limits schemes, redirects, time, and streamed response size, and can be disabled.

Screens

after shipping

What stayed with me

  • Privacy features are credible only when their limitations are as visible as their guarantees.

  • For a single-owner inbox, PostgreSQL plus one application process is a clearer reliability choice than adding Redis and a queue by default.