Installation of Prosody XMPP server
Choosing “the” right messenger is not an easy task as you (or at least I do) want to pick one with a good balance of usability on the one side and security/privacy on the other. And of course your friends and family need to agree on it as well - otherwise it’s a pretty lonesome experience… ;-)
Probably messengers you could easily agree on would be Signal or Threema. Both are easy to use and come with strong end-2-end encryption. However both are not federated: there is one central server which you need to rely on. Also both lack real multi-device support and Signal even requires your mobile number. Nevertheless, both are pretty good and I’d recommend them.
However, my personal preference would be either a Matrix or XMPP (formerly “Jabber”) based messenger. Both come with end-2-end encryption (for the latter make sure to enable OMEMO), are federated and no personal information is required to sign on. Also both feature real multi-device support. As I enjoy playing around with stuff like this I decided to install an XMPP server, Prosody in particular. See the official documentation here.
Prerequisites
I’m assuming Ubuntu 20.04 as operating system and that you’ve done a basic setup/hardening of your server. From what I see Prosody does not have very huge hardware requirements but of course this will depend on the amount of users you’re going to expect. For a small instance 1GB RAM and probably 1 or 2 CPU cores will be sufficient.
DNS records
Depending on which services you’d like to offer, you will have to create a couple of DNS records. Let’s go with example.com
. Assuming this will be your XMPP domain, you will create user names like <username>@example.com
. Let example.com
point to your server IP (A-record) and then create some C-names all pointing to example.com
:
conference.example.com
pubsub.example.com
proxy.example.com
uploads.example.com
turn.example.com
Also make sure to create some srv records:
service | protocol | priority | weight | port | target |
---|---|---|---|---|---|
xmpps-client | tcp | 1 | 1 | 443 | example.net |
xmpp-server | tcp | 1 | 1 | 5269 | example.net |
xmpp-client | tcp | 5 | 1 | 5222 | example.net |
If port 443 is not available because there’s a web server already running on that port: don’t worry, see below.
Software
As I’d install the latest version of Prosody let’s add its repository (example for Ubuntu 20.04):
1
2
3
$ echo "deb [signed-by=/usr/share/keyrings/prosody-keyring.gpg] https://packages.prosody.im/debian focal main" > /etc/apt/sources.list.d/prosody.list
$ wget https://prosody.im/files/prosody-debian-packages.key -O /usr/share/keyrings/prosody-keyring.gpg
$ apt get update
…and actually install everything:
1
2
$ apt install prosody lua-dbi-postgresql postgresql snapd fuse coturn nginx
$ systemctl stop nginx
Configuration
Prosody should now be running already, however some configuration changes need to be applied of course.
Postgresql
First I’d set password_encryption = scram-sha-256
in /etc/postgresql/12/main/postgresql.conf
and also set scram-sha-256
in /etc/postgresql/12/main/pg_hba.conf
:
1
2
3
4
# IPv4 local connections:
host all all 127.0.0.1/32 scram-sha-256
# IPv6 local connections:
host all all ::1/128 scram-sha-256
Restart Postgresql and create a user and a database for Prosody:
1
2
3
4
$ systemctl restart postgresql
$ su - postgresql
$ createuser --pwprompt <DB_USER>
$ createdb --owner=<DB_USER> <DB_NAME>
Take a note of the password you choose.
Certificates
Install certbot and get required certificates (open ports 80 and 443):
1
2
3
4
5
6
$ snap install core; snap refresh core
$ snap install --classic certbot
$ ufw allow 80/tcp
$ ufw allow 443/tcp
$ certbot certonly --standalone -d example.com -d conference.example.com -d pubsub.example.com -d proxy.example.com -d uploads.example.com
$ certbot certonly --standalone -d turn.example.com
Coturn
Make sure coturn does not run as root
. I think with Ubuntu 20.04 it’s not default anymore, but check it anyway: proc-user=
and proc-group=
should both be set to turnserver
in /etc/turnserver.conf
. With coturn not running as privileged user it cannot read the certificates generated by certbot. I’d copy the “turn.example.com” certificates to a new location and make them readable for group turnserver. (Don’t forget to copy them each time you’ll update the certificates with certbot!) Add the correct path in /etc/turnserver.conf
to cert=
and pkey=
. Also make sure lt-cred-mech
and use-auth-secret
are not commented, set a secret for static-auth-secret=
. realm=
should point to turn.example.com
. Tweak the rest of the settings to your likings. Then restart coturn:
1
$ systemctl restart coturn
Prosody
Taking care of the certificates is quite easy (s. also here):
1
$ prosodyctl --root cert import /etc/letsencrypt/live
Make sure certificates = "certs"
is not commented in /etc/prosody/prosody.cfg.lua
.
There are a few additional settings to change in /etc/prosody/prosody.cfg.lua
:
- add an admin user (we’ll actually create it later):
admins = { "<USERNAME>@example.com" }
- enable required modules by removing “
--
”, I’d keep/enable all in sections “Generally required”, “Not essential, but recommended” and “Nice to have” with exception maybe of"version";
and"register";
(the latter depending if you would like to let users register) - also probably enable:
"announce";
"groups";
"motd";
"proxy65";
- enable Postgresql as storage:
storage = "sql"
sql = { driver = "PostgreSQL", database = "<DB_NAME>", username = "<DB_USER>", password = "<DB_PASSWORD>", host = "localhost" }
- configure turnsever:
turn_external_host = "turn.example.com"
turn_external_secret = "<YOUR_SECRET>"
- set ports/encryption handling:
c2s_require_encryption = true
c2s_direct_tls_ports = 5223
s2s_require_encryption = true
s2s_direct_tls_ports = 5270
s2s_secure_auth = true
- add a new virtual host:
VirtualHost "example.com"
- below that virtual host enable/configure a few modules:
modules_enabled = {"cloud_notify";}
modules_enabled = {"muc_mam";}
Component "uploads.example.com" "http_file_share"
Component "proxy.example.com" "proxy65"
Component "pubsub.example.com" "pubsub"
- finally remove world readability:
chmod 640 /etc/prosody/prosody.cfg.lua
We already enabled one module which actually is not installed yet: cloud_notify
. To install the additional module follow this documentation: https://prosody.im/doc/installing_modules
As you might have noticed we have created an srv record for encrypted client connections (xmpps-client) pointing to port 443
, however the Prosody configuration above is pointing to port 5223
. This does of course not add up. As Prosody is not running as root (which it shouldn’t!) it cannot open a privileged port anyway. So we will leave that to nginx by redirecting XMMP traffic to port 5223
. If you already have a webserver listening on port 443
this solution comes handy as well. To do that we will need the following:
- make sure that “
include /etc/nginx/conf.d/*.conf;
” in/etc/nginx/nginx.conf
is outside of “http { }
” - reconfigure your webserver to listen to a different port i.e.
9443
(if you don’t have a webserver listening on port443
simply skip corresponding settings) - create a new configuration file in
/etc/nginx/conf.d/
with following content (s. nginx documentation here):1 2 3 4 5 6 7 8 9 10 11 12
stream { map $ssl_preread_alpn_protocols $proxy { ~\bhttp/1.1\b <SERVER_IP>:9443; ~\bxmpp-client\b <SERVER_IP>:5223; } server { listen 443; ssl_preread on; proxy_pass $proxy; } }
HTTP traffic will be redirected to “SERVER_IP:9443” and XMPP traffic will go to “SERVER_IP:5223”.
Now restart Prosody and nginx:
1
2
$ systemctl restart prosody
$ systemctl restart nginx
Let’s finally create the first user:
1
$ prosodyctl adduser <USERNAME>@example.com
You should choose the same USERNAME as the one you configured as “admin” above. Of course you can add additional users the same way. Only users listed as “admins” in the configuration file will actually have administrative privileges.
Firewall ports
At last we need to open some additional ports on our firewall:
1
2
3
4
5
6
7
8
9
10
$ ufw allow 3478 #turnserver
$ ufw allow 5349 #turnserver
$ ufw allow 49152:65535/udp #turnserver
$ ufw allow 5000/tcp #prosody file transfer proxy
$ ufw allow 5222/tcp #prosody client connections
$ ufw allow 5269/tcp #prosody server-to-server connections
$ ufw allow 5281/tcp #prosody HTTPS
$ ufw allow 5270/tcp #prosody server-to-server direct TLS connection
$ ufw allow 5223/tcp #prosody client direct TLS connections
$ ufw allow 9443/tcp #webserver
Compliance test
You might want to register your server with https://compliance.conversations.im/ to check your server’s compliance score (create an unprivileged test user for this matter). If you followed the instructions above you should gain at least 95%. The only test failing is the one for “XEP-0153”. However, according to Prosody’s documentation “XEP-0153” should be enabled anyway. Not sure why that check is failing.
Finally…
…create users for your friends and family or simply enable registration via register
module and install a client. There are several clients out there for nearly every OS. (However, make sure to enable OMEMO for your chats to have them end-2-end encrypted!) Just to list a few:
- Gajim (Linux/Windows)
- Conversations (Android)
- Siskin (iOS)
- Monal (iOS/MacOSX)