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
- Prosody XMPP server
- SQLite backend
- Tor-only access
- Group chats (MUC)
- Web-based invite system (admin-only)
- Web-based GUI (ConverseJS)
Prerequisites
Update your FreeBSD and its packages.
freebsd-update fetch installpkg updatepkg 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 dirHiddenServicePort 5222 127.0.0.1:5222 # XMPP client's accessHiddenServicePort 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/luadbimake configmake 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:
storage = "sql"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 = trueconsider_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 startprosodyctl cert generate yoursite.onion
Multi User Chat (MUC)
The MUC configuration looks like this:
-- MUCComponent "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 = trueregistration_invite_only = trueinvite_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.