XMPP Prosody on Tor: Decentralized Anonymous Messaging Infrastructure
XMPP (Extensible Messaging and Presence Protocol) is a mature, federated instant messaging standard that remains one of the most privacy-capable communication protocols available. Deploying Prosody - a lightweight, extensible XMPP server written in Lua - as a Tor hidden service creates a messaging infrastructure where neither the server location nor client IP addresses are exposed. Unlike Signal or WhatsApp, which require phone number registration and rely on centralized servers, XMPP over Tor allows fully pseudonymous account creation and end-to-end encrypted messaging with OMEMO multi-device encryption. Federation over Tor allows .onion XMPP servers to communicate with each other, enabling distributed networks of anonymous messaging nodes. This architecture is used by privacy communities, activist organizations, and security-conscious teams needing persistent encrypted communication without phone number linkage.
Need this done for your project?
We implement, you ship. Async, documented, done in days.
Install Prosody on Debian/Ubuntu: apt install prosody. The main configuration file is /etc/prosody/prosody.cfg.lua. Set VirtualHost 'youronion.onion' to define the primary domain. Configure admins = { 'admin@youronion.onion' } and set allow_registration = true for self-registration or false for invitation-only. Enable required modules: mod_carbons (message sync across devices), mod_mam (message archive management), mod_csi (client state indication for mobile), mod_blocklist. For TLS, since .onion addresses carry implicit transport security through Tor's encryption, configure a self-signed certificate for the .onion domain - clients connecting through Tor do not need a CA-signed cert because the .onion authentication is cryptographic.
Tor Hidden Service Setup for XMPP Ports
XMPP uses multiple ports: 5222 for client-to-server (c2s) connections and 5269 for server-to-server (s2s) federation. Add to /etc/tor/torrc: HiddenServiceDir /var/lib/tor/prosody/, HiddenServicePort 5222 127.0.0.1:5222, HiddenServicePort 5269 127.0.0.1:5269. For BOSH (HTTP-based XMPP) used by web clients like Converse.js, add HiddenServicePort 5280 127.0.0.1:5280. After obtaining the .onion address, update Prosody's VirtualHost to match. Prosody's component configuration for modules like MUC (multi-user chat rooms) should use Component 'conference.youronion.onion' 'muc'. Restart tor and prosody after configuration changes.
OMEMO End-to-End Encryption Configuration
OMEMO (OMEMO Multi-End Message and Object Encryption) provides end-to-end encryption over XMPP. OMEMO is implemented in clients (Gajim, Conversations, Dino, Monal) rather than the server, so server-side configuration focuses on enabling the necessary modules. Enable mod_pep (Personal Eventing Protocol) - OMEMO keys are distributed via PEP. Enable mod_pubsub for broader publish-subscribe functionality. Enable mod_mam with careful consideration: MAM stores message history on the server, which conflicts with OMEMO's forward secrecy if the server is compromised. For high-security deployments, disable MAM or limit retention to 1 hour. Clients with OMEMO support: Conversations (Android, $0), Gajim (desktop, free), Dino (Linux), Monal (iOS/macOS).
Server-to-Server Federation Over Tor
Federating .onion XMPP servers allows users on different hidden service instances to message each other without clearnet exposure. Enable mod_s2s in Prosody. For federation to work, both servers need their .onion addresses discoverable via DNS SRV records - but DNS does not support .onion. Use Prosody's mod_onions plugin (available from prosody-modules community repository) which implements onion-aware s2s routing without DNS. Configure s2s_allow_encryption_stripping = false and s2s_require_encryption = true. When federating with clearnet XMPP servers, route outbound s2s connections through Tor using the module mod_proxy65 or environment-level torification. This hides the .onion server's clearnet IP from federated servers.
Client Configuration for .onion XMPP Access
Configure XMPP clients to connect to your .onion server through Tor. In Gajim: Edit > Accounts > Connection tab, set hostname to youronion.onion, port 5222, enable custom proxy and configure SOCKS5 proxy at 127.0.0.1:9050 (Tor's default SOCKS port). In Conversations (Android), configure the account with JID user@youronion.onion and under Expert Settings, set Tor proxy. For Tor Browser with web-based XMPP (Converse.js), serve the Converse.js interface through the .onion and configure BOSH/WebSocket to connect to the same .onion. Test connectivity: send a message to echo@anon.im which echoes messages back. Verify OMEMO fingerprint exchange with a trusted contact before sending sensitive information.