The problem I wanted to solve
Every forum has a kill switch. The admin can delete your posts.
The hosting company can pull the plug. The government can send
a takedown notice.
I wanted to build something where none of that is possible.
The result
Two fully decentralized forums:
- 🌐 blabla.privacy (English — pixel art retro UI)
- 🌐 zonefree.x (French)
Both accessible via Unstoppable Domains (needs Brave browser
or an IPFS resolver).
The stack
Frontend
React app hosted on IPFS via 4EVERLAND. No Vercel, no AWS,
no central server. The frontend is a static hash —
nobody can take it down.
Real-time P2P sync
Gun.js for real-time data sync between browsers.
Every user connected becomes a relay node.
The tricky part: Gun uses CRDT which means deleted data
gets republished by other peers.
Fix: client-side suppression list in localStorage.
When a salon is deleted, its ID is added to a blacklist.
Even if Gun republishes it, the client ignores it.
Identity
Your Ethereum wallet IS your identity. No email, no password,
no account creation. Works with MetaMask, WalletConnect,
TrustWallet.
E2E Encryption
Private messages are encrypted with NaCl box (Curve25519).
Keys are derived deterministically from your wallet signature:
- Wallet signs the message
"ZoneFree E2E Key v1" - Signature is hashed → truncated to 32 bytes
- Used as seed for a Curve25519 keypair
Same wallet = same keys forever. No key server needed.
Smart contract
Solidity on Ethereum Mainnet. Uses Chainlink ETH/USD price
oracle for dynamic pricing. 300 free slots, then paid
subscription forwarded to admin wallet.
Infrastructure
Gun.js relays running on Flux decentralized cloud
(two independent nodes). Frontend on IPFS via 4EVERLAND.
Domains on Unstoppable Domains (on-chain, uncensorable).
The hardest bugs
1. Gun.js CRDT republishing deleted content
Solved with a localStorage suppression list. Deleted IDs
are never re-rendered even if Gun pushes them again.
2. NaCl keys lost on page refresh
Solved by persisting keys in localStorage, cleared
on wallet disconnect.
3. MetaMask SES conflicts
MetaMask injects a Secure EcmaScript sandbox that breaks
many libraries. Replaced XMTP with TweetNaCl which has
no such conflicts.
4. Webpack scope hoisting crashes
Arrow functions assigned to var caused TDZ crashes
in production. Fix: convert all helpers to
function declarations.
Code rules (non-negotiable)
To avoid all webpack/SES conflicts:
- Always
var— neverconst/let - Always
function()— never arrow functions=> - Never spread operators — use
Object.assignand.concat -
CI=true npm run buildmust pass before every commit
Try it
- 🌐 blabla.privacy (Brave browser needed)
- 🌐 zonefree.x (French version)
- ⭐ github.com/AB-lab113/blabla-privacy (open source, GPL-3.0)
Built solo. Zero budget. Zero VC. 100% decentralized. 🦈
Top comments (0)