Chat like it's Telegram.
Host it like it's yours.

Real-time messaging for your team, your friends, or your homelab — DMs, groups, voice messages, reactions, and end-to-end encrypted secret chats. One container, one SQLite file, zero build step.

No email. No phone number. Pick a username, set a password, start typing.

Everything you expect from a modern messenger

💬

DMs & groups

Real-time delivery over WebSockets, typing indicators, read receipts, presence, and unread management that respects where you actually are.

🔒

Secret chats

End-to-end encrypted DMs with WebCrypto — ECDH key agreement, AES-GCM messages. The server only ever stores ciphertext.

🎤

Voice messages

Hold-free recording with a Telegram-style inline player — progress bar, durations, one tap to play.

📎

Photos & files

Paperclip, paste, or drag-and-drop. Photos open in a fullscreen lightbox; files arrive as tidy download cards.

❤️

Reactions & replies

Six-emoji reactions, threaded replies with jump-to-quote, message editing, deletes, and forwarding with provenance.

🔍

Search & pins

Full-message search across your chats that jumps straight to the result, plus one pinned message per chat.

🌙

Dark mode

The full Telegram night palette, one click away, remembered per device. Drafts, mutes, and formatting included.

📦

Yours, entirely

One Node process, one SQLite file, no build step, no external services. Your data never leaves your machine.

Security that tells you the truth

Hardened by default

  • Passwords hashed with scrypt + per-user salts
  • Sessions expire after 30 days, pruned automatically
  • Rate limiting on logins, uploads, and socket traffic
  • Server-side permission checks on every operation

Honest about secret chats

Secret chats are real, working end-to-end encryption — and we document exactly where the demo-grade line is: no key-fingerprint verification UI, no forward-secrecy ratchet, keys live in your browser. Great against a nosy server admin; not marketed as protection against a motivated nation-state. The README spells it out.

Self-host in one command

# clone, then:
docker compose up -d
# → http://localhost:3000, data in a named volume

Built to be run, not babysat

  • SQLite inside — one file to back up
  • No build step — vanilla ES modules, readable source
  • Env-var config — PORT, DB_FILE, UPLOADS_DIR, TRUST_PROXY
  • Tested — a 100+ assertion end-to-end suite runs the real server
Try it now