WebRTC Signaling Server as a Tor Hidden Service: Private P2P Calls
WebRTC enables peer-to-peer audio and video calls directly between browsers. Standard WebRTC deployments use STUN and TURN servers that can reveal participant IP addresses, and the signaling server (which coordinates the connection) is typically a clearnet service that logs connection metadata. Deploying a WebRTC signaling server as a Tor hidden service provides: a signaling endpoint that does not require clearnet exposure, no IP address revelation through STUN (since the connection is already over Tor), and metadata protection for who is calling whom. This enables truly private web-based video calls where neither the signaling server operator nor any network observer knows the participants' IP addresses.
Need this done for your project?
We implement, you ship. Async, documented, done in days.
Standard WebRTC uses ICE (Interactive Connectivity Establishment) which gathers ICE candidates including STUN candidates (public IP addresses of each participant) and TURN relay candidates. In standard WebRTC, the peer's IP address is visible in the ICE candidate exchange - this is how WebRTC-based IP leaks work in browsers. Tor Browser disables WebRTC entirely to prevent this leak. Therefore, WebRTC-based calls cannot be made directly from Tor Browser. The solution: use Tor Browser for the signaling phase (joining the call room, exchanging encrypted session parameters) but use a desktop application or a non-Tor-Browser for the actual WebRTC call. Alternatively, use a WebRTC-over-TCP approach with Tor providing the transport, circumventing the standard ICE process.
Jitsi Meet Deployment as Hidden Service
Jitsi Meet is an open-source video conferencing platform that supports self-hosting. Deploy Jitsi Meet using the official Debian package (apt install jitsi-meet) on Ubuntu/Debian. Jitsi Meet uses Nginx for the web interface, Prosody XMPP for signaling, Jicofo for conference focus management, and JVB (Jitsi Videobridge) for media relay. Configure the Tor hidden service to point to Nginx (port 443): HiddenServicePort 443 127.0.0.1:443. Participants access the meeting via the .onion address in a standard browser (not Tor Browser, since WebRTC requires a browser without WebRTC restrictions). The .onion address provides an anonymous URL for the meeting that is not indexed or discoverable by clearnet users. The actual WebRTC media still reveals participant IPs through the JVB relay - you can mitigate this by running JVB with TURN relay enabled so all media routes through JVB rather than peer-to-peer.
Matrix + Element: Text Chat with Tor-Accessible Voice
Matrix with Element (the web client) provides an alternative for privacy-preserving communication. Deploy a Synapse Matrix homeserver as a .onion service (as described in the Matrix .onion setup guide). Element web client supports WebRTC calls within Matrix rooms. When accessed via a non-Tor browser with the .onion homeserver configured, Element provides voice and video calls where the signaling happens through the .onion Matrix server. This is easier to configure for fully private calls than standalone Jitsi because Matrix's federation model provides additional anonymity - the homeserver administrator handles call routing without knowing the actual call content (E2EE calls) or the participants' external IPs if they access through Tor.
SimpleWebRTC and Custom Signaling Servers
For minimal deployments, run a simple WebRTC signaling server (PeerJS Server, Socket.IO-based custom server) as a .onion service. Install PeerJS Server: npm install peer -g, run: peerjs --port 9000 --host 127.0.0.1. Configure Tor hidden service to port 9000. Participants use the PeerJS client library with the .onion address as the signaling server. This provides: .onion-based signaling (no clearnet server for call coordination), peer-to-peer WebRTC media (still reveals IPs through ICE unless TURN is used), and a simple URL scheme for room joining. For private calls where participants are already known to each other (no discovery), the PeerJS approach is simpler than Jitsi or Matrix.
Privacy Properties of Different Architectures
Compare the privacy properties of different WebRTC-over-Tor architectures: (1) Jitsi via .onion URL, browser with TURN forced: signaling is .onion (private), media routes through JVB (JVB sees participant IPs), call content is encrypted in transit. JVB operator knows participant IP addresses. (2) Matrix/Element via .onion, E2EE calls: homeserver operator handles signaling metadata (knows who called whom, when), call content is end-to-end encrypted (homeserver cannot decrypt), participant IPs visible through WebRTC ICE if no TURN. (3) Tor + regular browser + WebRTC with TURN forced: Tor hides participant IP from signaling server, TURN relay hides IPs from WebRTC peer, strongest IP protection but adds JVB/TURN server as infrastructure dependency.