Previous Page

nihilist@mainpc - 2024-08-05

XMPP Chat Server Setup (Clearnet + Onion + OMEMO E2EE)

In this tutorial, we're going to check out how to setup a XMPP chat server, that is accessible over Tor, as a hidden service, using Prosody. We'll also cover how to have a Clearnet XMPP server, and how to have OMEMO End to End encryption using the Gajim XMPP client.

XMPP Onion Server Setup

Before starting, check out this tutorial on how to create your first hidden service.


root@ANON-home:~# apt install prosody prosody-modules lua-unbound -y
	
root@ANON-home:~# prosodyctl about 
  /var/lib/prosody/custom_plugins - not a directory!
  /usr/local/lib/prosody/modules - not a directory!
  /var/lib/prosody/custom_plugins/share/lua/5.4/?.lua
  /var/lib/prosody/custom_plugins/share/lua/5.4/?/init.lua


root@ANON-home:~# mkdir /var/lib/prosody/custom_plugins
root@ANON-home:~# mkdir /usr/local/lib/prosody/modules -p

Then, we make sure that the tor hidden service includes the XMPP ports:


root@ANON-home:# vim /etc/tor/torrc
root@ANON-home:# cat /etc/tor/torrc
HiddenServiceDir /var/lib/tor/onions/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion/

[...]

HiddenServicePort 5222 127.0.0.1:5222
HiddenServicePort 5269 127.0.0.1:5269
HiddenServicePort 5280 127.0.0.1:5280
HiddenServicePort 5281 127.0.0.1:5281
	
root@ANON-home:# systemctl restart tor@default

Here, my hidden service is aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion, let's check that the mod_onions module is installed and configure the prosody.cfg.lua file:


root@ANON-home:~# ls /usr/lib/prosody/modules/mod_onions
mod_onions.lua
	
root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

[...]

VirtualHost "localhost"
-- Prosody requires at least one enabled VirtualHost to function. You can
-- safely remove or disable 'localhost' once you have added another.

VirtualHost "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion"
        modules_enabled = {"onions"};
        onions_only = true;
        disco_items = {
                {"conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion","Public Chatroom"},
                {"upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion","Public Chatroom"}
        }

Component "conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "muc"
        modules_enabled = { "onions" };
        onions_only = true;

Component "upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "http_file_share"
        modules_enabled = { "onions" };
        onions_only = true;

[...]


root@ANON-home:~# prosodyctl cert generate aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
Choose key size (2048):
Key written to /var/lib/prosody/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion.key
Please provide details to include in the certificate config file.
Leave the field empty to use the default value or '.' to exclude the field.
countryName (GB):
localityName (The Internet):
organizationName (Your Organisation):
organizationalUnitName (XMPP Department):
commonName (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion):
emailAddress (xmpp@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion):

Config written to /var/lib/prosody/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion.cnf
Certificate written to /var/lib/prosody/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion.crt

root@ANON-home:~# prosodyctl check

[...]

Checking certificates...
Checking certificate for conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
certmanager         info        No certificate present in SSL/TLS configuration for conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion. SNI will be required.
  No 'certificate' found for conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
Checking certificate for localhost
certmanager         info        No certificate present in SSL/TLS configuration for localhost. SNI will be required.
  No 'certificate' found for localhost
Checking certificate for upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
certmanager         info        No certificate present in SSL/TLS configuration for upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion. SNI will be required.
  No 'certificate' found for upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
Checking certificate for aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
certmanager         info        No certificate present in SSL/TLS configuration for aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion. SNI will be required.
  No 'certificate' found for aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion

For more information about certificates please see https://prosody.im/doc/certificates

Problems found, see above.

	
root@ANON-home:# mv /var/lib/prosody/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion.* /etc/prosody/certs/


root@ANON-home:/etc/prosody/certs# prosodyctl adduser nihilist@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion
Enter new password:
Retype new password:

#if you want to create users in batch:
root@ANON-home:/etc/prosody/certs# prosodyctl adduser testuser aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion p4ssw0rd

root@ANON-home:/etc/prosody/certs# systemctl restart prosody
root@ANON-home:/etc/prosody/certs# systemctl status prosody
● prosody.service - Prosody XMPP Server
     Loaded: loaded (/lib/systemd/system/prosody.service; enabled; preset: enabled)
     Active: active (running) since Mon 2024-08-05 22:02:47 CEST; 4s ago
       Docs: https://prosody.im/doc
   Main PID: 3419 (lua5.4)
      Tasks: 1 (limit: 4653)
     Memory: 7.8M
        CPU: 139ms
     CGroup: /system.slice/prosody.service
             └─3419 lua5.4 /usr/bin/prosody -F

Aug 05 22:02:47 ANON-home systemd[1]: Started prosody.service - Prosody XMPP Server.

	

all good now, now let's connect to it using pidgin:


[ mainpc ] [ /dev/pts/9 ] [~/Nextcloud/blog]
→ apt install pidgin -y

[ mainpc ] [ /dev/pts/9 ] [~/Nextcloud/blog]
→ pidgin
	

Then, create your account on the XMPP server:

Next, we can start chatting with Alice, who is another user on that XMPP server like so:

Then from Alice's XMPP client, we accept nihilist's buddy request:

Optional XMPP server options:



if you want to enable message archiving, enable the "mam" module by uncommenting it:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

[...]

modules_enabled = {
                "mam"; -- Store recent messages to allow multi-device synchronization
}

[...]

and then you can mention the expiration time of messages like so:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

archive_expires_after = "1w" -- remove archived messages after 1 week

you can choose to limit the bandwidth usage of your server too, using the mod_limits module:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

limits = {
	c2s = {
		rate = "10kb/s";
	}
	s2sin = {
		rate = "30kb/s";
	}

}

You can also enable archiving on the multi-user chats like so :


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

Component "conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "muc"
        modules_enabled = { "onions", "muc_mam" };
        onions_only = true;

And just like in mod_mam, you can set the expiration time of the messages in MUCs:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

Component "conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "muc"
        modules_enabled = { "onions", "muc_mam" };
        onions_only = true;
		muc_log_expires_after = "1w"
	

Then, you can also enable file archiving using mod_http_file_share:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

Component "upload.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "http_file_share"
        modules_enabled = { "onions" };
        onions_only = true;
		http_file_share_daily_quota = 100*1024*1024;	-- 100 MiB
		http_file_share_after = 7*86400;				-- One week in seconds
		http_file_share_size_limit = 10*1024*1024		-- 10 Mib
	

Then, as you're going to have a multi user chat, you'll most likely need the mod_muc_moderation module:


root@ANON-home:~# vim /etc/prosody/prosody.cfg.lua
root@ANON-home:~# cat /etc/prosody/prosody.cfg.lua

Component "conference.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.onion" "muc"
        modules_enabled = { "onions", "muc_mam", "muc_moderation" };
        onions_only = true;
        muc_log_expires_after = "1w"
	

XMPP Clearnet Server Setup



First edit prosody.cfg.lua like so :


[ Datura ] [ /dev/pts/3 ] [~]
→ vim /etc/prosody/prosody.cfg.lua

[...]

VirtualHost "nowhere.moe"
ssl = {
     certificate = "/etc/ssl/nowhere.moe/fullchain.cer";
         key = "/etc/ssl/nowhere.moe/nowhere.moe.key";
}

VirtualHost "nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion"

[...]

Then copy the existing acme.sh certificates for nowhere.moe into another non-root directory, otherwise prosody wont be able to read them:


[ Datura ] [ /dev/pts/4 ] [/etc/ssl/nowhere.moe]
→ mkdir -p /etc/ssl/nowhere.moe/

[ Datura ] [ /dev/pts/4 ] [/etc/ssl/nowhere.moe]
→ cp -r /root/.acme.sh/nowhere.moe/* /etc/ssl/nowhere.moe

[ Datura ] [ /dev/pts/4 ] [/etc/ssl/nowhere.moe]
→ sudo setfacl -R -m u:prosody:rx  /etc/ssl/nowhere.moe/

[ Datura ] [ /dev/pts/4 ] [/etc/ssl/nowhere.moe]
→ sudo -u prosody cat /etc/ssl/nowhere.moe/nowhere.moe.cer
-----BEGIN CERTIFICATE-----
MIIF5zCCBM+gAwIBAgISBCVaPZeC38+C4bWEm3yPX1LMMA0GCSqGSIb3DQEBCwUA
MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD
EwNSMTAwHhcNMjQwODExMjAyMjI5WhcNMjQxMTA5MjAyMjI4WjAWMRQwEgYDVQQD
Ewtub3doZXJlLm1vZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJPO
[...]
-----END CERTIFICATE-----


to copy it once a day to the correct folder, you can do it via cronjob:


[ Datura ] [ /dev/pts/7 ] [~]
→ crontab -e

0 0 * * * cp -r /root/.acme.sh/nowhere.moe/* /etc/ssl/nowhere.moe ; setfacl -R -m u:prosody:rx  /root/.acme.sh/nowhere.moe ; systemctl restart prosody

Then, don't forget to create the clearnet user:


[ Datura ] [ /dev/pts/7 ] [~]
→ prosodyctl adduser usertest usertestpwd

[ Datura ] [ /dev/pts/7 ] [~]
→ prosodyctl passwd  usertest@nowhere.moe

Then you can just connect to the XMPP server over clearnet aswell, but one thing to note is that pidgin is limited when it comes to encrypting chats, so let's use Gajim instead as it comes with OMEMO encryption out of the box:


user@laptop: apt install gajim -y

XMPP OMEMO End to End Encryption (E2EE)



Now here, you need to tell the other peer (if they don't have OMEMO enabled) to install a XMPP client like gajim, just like you, to use OMEMO encryption just like you, to have end to end encryption.

And that's it! you now have a XMPP server working over both Clearnet, and Tor, with end to end encryption.

Nihilism

Until there is Nothing left.

About nihilist

Donate XMR: 8AUYjhQeG3D5aodJDtqG499N5jXXM71gYKD8LgSsFB9BUV1o7muLv3DXHoydRTK4SZaaUBq4EAUqpZHLrX2VZLH71Jrd9k8


Contact: nihilist@contact.nowhere.moe (PGP)