Decentralized browser chat over libp2p. Everyone who opens the app joins the same room. Identity is a 12-word BIP39 seed phrase; every message is cryptographically signed with the Ed25519 key derived from that phrase.
Live site: https://nunchi-trade.github.io/chat/
- Identity — A BIP39 mnemonic derives an Ed25519 libp2p keypair and peer ID.
- Network — Browsers dial a Kubo (IPFS) node over WebSocket as a circuit relay, discover peers via gossipsub, then connect over WebRTC.
- Room — All clients use gossipsub topic
nunchi-trade.chat.v1. - Messages — Signed locally; other clients verify before showing as trusted.
# Install (Arch)
sudo pacman -S kubo
# Server profile (no mDNS) + WebSocket relay — required on Hetzner/public VPS
./scripts/setup-kubo-relay.sh
# Auto-start on boot (systemd)
sudo ./scripts/install-ipfs-service.shCheck status: systemctl status ipfs · logs: journalctl -u ipfs -f
Kubo relays connections but does not forward gossipsub chat topics. A small local bridge keeps the chat mesh alive:
sudo ./scripts/install-chat-bridge.shSet GitHub variable VITE_BRIDGE_PEER_ID (printed by the install script), then redeploy Pages.
Copy the /tcp/4001/ws/p2p/... address from ipfs id into .env:
cp .env.example .env
# edit VITE_RELAY_MULTIADDR if your peer id or IP differs
npm install
npm run devOpen two tabs → Generate new phrase → Join chat.
GitHub Pages is HTTPS, so the relay must use Secure WebSocket (Kubo AutoTLS → *.libp2p.direct).
./scripts/setup-kubo-relay.sh
sudo ./scripts/install-ipfs-service.sh # includes AutoTLS logging
systemctl restart ipfs
./scripts/print-relay-multiaddr.sh # copy /tls/ws multiaddrSet GitHub variable VITE_RELAY_MULTIADDR to that value, then redeploy Pages.
The small relay/ server still works if you prefer not to run Kubo:
cd relay && npm install && PORT=8787 node relay.mjs- Seed phrase = full control of your identity. Never share it.
- The IPFS node is a connectivity relay, not a message store.
- Demo software — not audited for production.
MIT