XMPP Over Tor On FreeBSD – Talk Privately Without Big Tech Pipelines

Do you feel that Linux is sometimes too loud?
Systemd. Timers. Kernel updates.
Centralized systems are risky. Cloud are computers you don’t own.

Do you want to avoid the Big Tech pipelines?
Set up your own private XMPP chat system over Tor on FreeBSD.

Mission Plan

  1. Prosody XMPP server
  2. SQLite backend
  3. Tor-only access
  4. Group chats (MUC)
  5. Web-based invite system (admin-only)
  6. Web-based GUI (ConverseJS)

Prerequisites

Update your FreeBSD and its packages.

freebsd-update fetch install
pkg update
pkg upgrade

Install the prerequisites.

Tor

Install Tor.

pkg install tor

Enable the service.

sysrc tor_enable="YES"

Edit the torrc configuration file (/usr/local/etc/tor/torrc).

HiddenServiceDir /var/db/tor/my_hidden_service/ # hidden service base dir
HiddenServicePort 5222 127.0.0.1:5222 # XMPP client's access
HiddenServicePort 80 127.0.0.1:5280 # ConverseJS http access

Restart the Tor service.

service tor restart

Check and note your .onion domain name.

cat /var/db/tor/my_hidden_service/hostname

SQLite

Install SQLite.

pkg install sqlite3

LuaDBI

The LuaDBI package doesn’t support SQLite by default.
You can reconfigure and compile it from ports.

cd /usr/ports/databases/luadbi
make config
make package

The package will appear in work-lua54/pkg/lua54-luadbi-${version}.pkg.

Install it with:

pkg install ./lua54-luadbi-${version}.pkg

Lock the package, so pkg will not overwrite it.

pkg lock lua54-luadbi

Prosody

Every dependency is met.
Now you can install and configure the Prosody XMPP server.

pkg install prosody prosody-modules

The main configuration is in /etc/prosody/prosody.cfg.lua.

Set the admin user(s).

admins = { "youruser@yoursite.onion" }

Bind Prosody to local only.

interfaces = { "127.0.0.1" }

Uncomment the following configurations:

  1. storage = "sql"
  2. sql = { driver = "SQLite3", database = "prosody.sqlite" }

Scroll down to the VirtualHost configuration. Add your .onion virtual host.

VirtualHost "yoursite.onion"
ssl = {
key = "/var/lib/prosody/yoursite.onion.key";
certificate = "/var/lib/prosody/yoursite.onion.crt";
}
authentication = "internal_hashed"
c2s_require_encryption = true
consider_websocket_secure = true

You can comment out the localhost VirtualHost in the configuration.
You have to use an Nginx reverse proxy if you require HTTPS for ConverseJS.

Enable and start Prosody with this configuration and generate its certificates.

sysrc prosody_enable="YES"
service prosody start
prosodyctl cert generate yoursite.onion

Multi User Chat (MUC)

The MUC configuration looks like this:

-- MUC
Component "muc.yoursite.onion" "muc"
modules_enabled = { "muc_mam" }
restrict_room_creation = true
muc_room_default_public = false
muc_room_default_members_only = true
muc_room_default_persistent = true

Only admins can create group chats.
The rooms are not public (searchable).
Only registered users can be invited to the MUC rooms.
The rooms remain on the server even if they’re empty.

Invite System

The web-based invite system is safer than open registration.
It’s more comfortable than manual user creation.

Enable and add the necessary modules:

modules_enabled = {
-- all other modules above
"register";
"invites";
"invites_register";
"invites_page";
"invites_register_web";
}

Configure the system to handle invitations:

allow_registration = true
registration_invite_only = true
invite_expiry = 86400 * 7 -- 7 days

Gajim generates invite links in Account / Execute command / Create new account invite.
Only admins can generate invites.

ConverseJS Web Chat

A web GUI can help to onboard new users faster.
ConverseJS is a small XMPP web client.

mod_conversejs is part of the module stack on FreeBSD.
You don’t have to install it separately.

Enable the module in the Prosody configuration.

modules_enabled = {
-- all other modules above
"conversejs";
}

Configure ConverseJS to use OMEMO by default.

conversejs_options = {
    omemo_default = true;
}

conversejs_tags = {
    [[https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js]];
}

Restart Prosody and monitor the logs.

service prosody restart

The web chat is accessible on http://yoursite.onion/conversejs.

Final Thoughts

You did not build a messaging app.
You assembled a small communication environment that does not depend on external platforms.

  • No cloud provider.
  • No algorithm deciding what is visible.

Just a server, a protocol, and a controlled access path through Tor.

But this system is not “invisible”.
It is not magic.
It reduces exposure, it does not erase it.

Tor hides location. XMPP structures communication. FreeBSD isolates execution.
Together they form a narrower attack surface, not a shield.

You still control users. You still manage keys. You still define trust manually.

That is the real shift.

Most systems remove responsibility from the operator. This one returns it.

If you run this setup, you are no longer just a user of communication tools.
You are the boundary.


Discover more from Tom's IT Cafe

Subscribe to get the latest posts sent to your email.

Leave a comment