Privacy-first chat: single-tenant, invite-only, no face/ID verification, no cross-tracking, minimal data. Protect users through design—not surveillance.
A self-hosted chat server and web client you can run as a viable alternative to Slack/Discord. See our Privacy stance, how truly secure communications work (E2E, attestation, pinning), and the E2E and tamper detection roadmap.
- Go 1.23+ (for the server)
- Node.js (for building/running the web client)
go run ./cmd/serverServer listens on TCP :9000 and HTTP/WebSocket :8080 by default. Data is stored in ./chatdata (WAL + snapshots).
cd web
npm install
npm run devOpen http://localhost:5173 (or http://localhost:5173/default).
For a named instance use the path, e.g. http://localhost:5173/[YOUR_SLUG_HERE]. Set VITE_WS_URL and optionally VITE_INSTANCE_SLUG in web/.env if the server or instance slug differs. When the server uses TLS, set VITE_WS_URL=https://localhost:8080 so the client uses WSS; optional VITE_HTTP_SCHEME, VITE_SERVER_HOST, VITE_SERVER_PORT build the default URL when VITE_WS_URL is unset. Self-hosters can set VITE_APP_BASE_PATH to serve the app at a custom path (defaults to /).
Enter a username and click Join. The app stores your reconnect token per instance and username, so next time you can enter the same username and click Join to auto-reconnect without pasting the token. Use the sidebar to switch channels.
Resetting sessions (testing): Restarting the server clears all in-memory sessions. For a running server, set ENABLE_RESET_SESSIONS=1 and type /reset-sessions in chat to clear all sessions so any name can join again.
Server configuration is via environment variables or .env (see .env.example). Full reference: Configuration. For WebSocket disconnects and keeping sessions open, see Staying Connected.
The server handles SIGINT (Ctrl+C) and SIGTERM: it stops accepting new connections, flushes state (final snapshot, closes WAL), and exits. Use with systemd, Docker, or Kubernetes as needed.
All project documentation is maintained in the wiki.
| Topic | Doc |
|---|---|
| Server configuration (env vars, private rooms, retention) | Configuration |
| Staying connected (WebSocket, timeouts, heartbeat) | Staying Connected |
| I2P (optional transport) | I2P |
| TLS and local development (certs, LAN, troubleshooting) | TLS & Local Dev |
| Docker | Docker |
| Desktop app (Tauri) | Desktop App |
| Roadmap | Roadmap |
| E2E and tamper detection | E2E & Tamper Detection |
| Join modes (session vs account) | Join Modes |
| Local setup (dependencies, tools) | Setup |
| External references | References |
Commercial use requires a license from the copyright holder (see LICENSE). Personal and non-commercial use are permitted under the repository license. License validation is supported by the server and desktop app when you have a license key and validation URL from the copyright holder; the tooling to run a license server is not part of this repository.
See repository license file