Skip to content

Guide to Prosŏdy as Family Chat Server

Introduction

People in the Prosody support channel often wish for an install guide for Prosody. There is no official one. Generally it is adviced to look at the documentation and then set it up how you like. One reason for this is, that prosody can be used for many many differnt things in many ways. Here, I'll show you how to set up a personal server for friends and family, with all the modern features enabled that are particularly useful for modern and mobile XMPP as a chat solution.

About myself

I don't come from the tech field but love selfhosting stuff as a hobby and dislike BigTech a lot. I try to have control over my own data and communication and that led me to prosody when the first Android Smartphones emerged. Prosody required me to read a lot of docs and the endless options fascinated me. Since then I hang out a lot in the prosody Chatroom and since many people come with similar questions, I could answer some of them myself after some time. I've seen a lot of misinformation about setting up prosody and hope to make it better and help with this guide to get people on board.

This is a guide made from my experience with prosody and common questions that often arise in the prosody channel for this usecase. It is personally colored, at one point I want to write a more generic one and then have an advanced section for more.

For now, this is what we Setup here:

  • Modern and fast connection establishment.
  • Account creation via invitations
  • Exchange of all types of media
  • Video calls
  • Group chats
  • Message synchronisation across all devices

I will mention and discuss the setup options and always include links to the relevant sections of the documentation; I recommend clicking on these links and reading them if you want to know more about your options or require further information.

Prosody is highly customisable; I will now present the server, pretty much as I have set it up for myself. Feel free to make your own informed decisions that differ from this. If you already run servers and know your way around, you can skip some sections of this guide. This guide uses Debian as an example and the Nano editor in the example snippets. Of course you can use whatever software and OS you like. Most of the guide will work the same way for other Linux and even BSD distributions.

If you want something that requires less tinkering and just want a mondern chat server for friends and family, then maybe look at https://snikket.org too. That is a chat solution based on prosody running with docker-compose that already covers that usecase and is up and running in mere minutes. The main advantage of using plain prosody is that personal modifications are easier this way.

DNS Records

To ensure the server is accessible worldwide, DNS records must be created (essentially the phone book entry that links the IP address to a name) See also https://prosody.im/doc/dns

  1. Purchase a domain name; an internet search will reveal plenty of providers. I'm currently with https://inwx.de, but there's an endless choice. However, a note: some domain extensions (such as .im) do not support DNSSEC and therefore do not support DANE. Whilst this isn't a must, do think about it beforehand, because once the server has users, you cannot change the address so easily.
  2. Add DNS records for your domain. You'll need at least A records, but if you also have an IPv6 address, create AAAA records as well. Assuming your domain is example.com, create A and AAAA records for it using your server's respective IP address.
  3. As you also want to use group chat and share images and videos, create additional records for these services. You can choose any name; common names are groups.example.com and share.example.com, but in principle anything is possible. Note: With most providers, you must omit the base domain name in the web interface. For “share.example.com”, enter “share” in the input fields; for example.com, leave the field blank or enter an “@” It really depends on your provider unfortunately.

Setup including SRV records:

If you have a bit time to spare, you can improve the setup by using SRV records, which will give you greater flexibility and allow you to use your service on any port. You can also use XMPP directly over TLS. Without SRV records, STARTTLS is used for encryption. If you use the direct TLS records (_xmpps.), then also specify them further down in the prosody.cfg.lua file.

Domain TTL Type Target
example.com. 300 A 203.0.113.123
share.example.com. 300 A 203.0.113.123
example.com. 300 AAAA 2001:db8:19ba::1
share.example.com. 300 AAAA 2001:db8:19ba::1
Domain TTL Type Priority Weight Port Target
_xmpp-client._tcp.example.com. 300 SRV 1 0 5222 example.com
_xmpps-client._tcp.example.com. 300 SRV 1 0 5223 example.com
_xmpp-server._tcp.example.com. 300 SRV 1 0 5269 example.com
_xmpps-server._tcp.example.com. 300 SRV 1 0 5270 example.com
_xmpp-server._tcp.groups.example.com. 300 SRV 1 0 5269 example.com
_xmpps-server._tcp.groups.example.com. 300 SRV 1 0 5270 example.com

Setup without SRV records:

The following should be set up as a minimum. This works without SRV records. You won't be able to use direct TLS. Here We will make due with only A and AAAA records. If you want to get into SRV records at a later time, you'll be able to get your Server working with this alone:

Domain TTL Type Target
example.com. 300 A 203.0.113.123
groups.example.com. 300 A 203.0.113.123
share.example.com. 300 A 203.0.113.123
example.com. 300 AAAA 2001:db8:19ba::1
groups.example.com. 300 AAAA 2001:db8:19ba::1
share.example.com. 300 AAAA 2001:db8:19ba::1

About SRV

As you may have noticed, SRV records allow you to do without A/AAAA records. I did not need to include the domain for the group chat as an A/AAAA record here. Please note that this is only possible for XMPP connections. As we want to use the “share.” subdomain for http file sharing and the example.com base domain for invites, these must have an A/AAAA record. If you are short of space for domains or subdomains here, theoretically everything could also be placed on a single A/AAAA record. You can find information on this here or in the chat. The minimum number of domains required for a server with group chat functionality is 2

This is an example screenshot from inwx.de to illustrate. As I said above, it might look a bit differen for you on your DNS hosters website: SRV-Record-example It shows the same record as the second SRV record in the table above, with the difference, that the target is xmpp.example.com instead example.com this allows me to host my Virtualhost "example.com" on am A record of "xmpp.example.com"

Once everything is working, you can later significantly increase the TTL of the records to one hour (3600) or even 10 hours (36000)

Server Setup

I myself hosted on a Raspberry Pi 1B at home and eventually switched to a VPS with Hetzner. https://www.hetzner.com/de/cloud/ For a small Family-Server for maybe up to 30 Persons you can to with the smallest VPS. One core, 1GB RAM and 20GB HDD is plenty. The server can be selected there and set up with the latest Debian. Ensure you install regular updates and set up a firewall. (With Hetzner, this can also be done via the web interface.) See below for the ports that need to be allowed. For information on how Debian generally works and how to operate and secure it, please refer to other websites or guides.

Info: About setup at home

If you are setting up your server at home, the setup is a bit more difficult; you will probably need DYN-DNS (a regular automatic update of your IP address in the DNS record) and will need to forward ports in the router. This guide does not cover this scenario.

Download & Installation

As mentioned in the official documentation, you can install a third-party repository for Prosody on Debian, which offers faster updates than the official Debian repository.

However, this is not essential. You can usually find the latest version quite quickly in the Debian Backports. Personally, though, I prefer to use the Prosody repository. We also need a dependency for the Invites website: libjs-jquery.

For the Debian Stable version, without adding the repository, the following is sufficient:

sudo apt update
sudo apt install prosody libjs-jquery

But if possible, use the version from the backports, at the very least:

sudo apt update
sudo apt install prosody/trixie-backports libjs-jquery

For the latest version, add the repository from the Prosody developers:

sudo wget https://prosody.im/files/prosody.sources -O/etc/apt/sources.list.d/prosody.sources
sudo apt update
sudo apt install prosody libjs-jquery

See also https://prosody.im/download/package_repository

For other installation methods or other operating systems, see: https://prosody.im/download/start

Configuration

First things first:

Only change the default settings if you understand why it is necessary. Generally, everything is set up in a way that already makes sense. This is the biggest problem with almost all guides and why I am writing this in the first place! Please simply use the default configuration that you find during installation. See also https://prosody.im/doc/example_config You want to "harden" the server? It is already. By default it uses the intermediate SSL Configuration from mozilla with only forward secret ciphers and it supports Channel Binding. It is still compatible with older servers you might want to federate with in the Network. In this guide I'll show how to set it to "modern" configuration (TLS1.3 only) with one line. You'll not have to use any low level hacks with 'ssl = {...}'

Info about DANE

If you like tinkering and want even more, then Prosody has very good support for DANE. If you want you can enable that. This is stuff for another guide, not covered by this one.

A few lines should be adjusted. I have listed ONLY these here and added some of my own comments. I do not recommend COPY-PASTE here, but simply adjusting the few lines that you need additionally. The other options not listed here must not be deleted.

The config file

I think it would be best to use the original configuration file and simply make a few changes. However, for those who are very impatient, I have a complete configuration here.

The following link to the documentation explains how the configuration file is structured. For example, that there are global sections and sections for Virtualhosts and Components: https://prosody.im/doc/configure#overview. It's worth reading that whole page.

Then open the file sudo nano /etc/prosody/prosody.cfg.lua and enter the address of your admin account. You can choose the part before the '@' freely, and the part after it is the name of the domain you control. This works in the same way as for an email address or in the Fediverse.

prosody.cfg.lua
admins = { "ich@example.org" }  --enter your admin account

In the modules_enabled section, we want to enable some modules that are currently ‘commented out'. Inactive lines, i.e. commented lines, begin with: -- I have added comments ( (1) ) to the options I am configuring here. Remove the comment before the following modules so that they look like this:

  1. Like this one!
"mam"; --(1)!
"turn_external"; --(2)!
"s2s_bidi"; --(3)!
"proxy65"; --(4)!
  1. Find this line and remove the comment "--". mam is important for message synchronisation on the server and for offline messages

  2. We need this to make a Turn server known to clients, so that video calls always work relaiably.

  3. Optional, but we'd like to have it; saves one connection per server-to-server connection

  4. File Transfer Proxy, used when attachments exceed the maximum http_file_share limit

In addition, we want to add the following modules to the list; these come from the Prosody Community Modules, which we first need to obtain separately; we'll do this later on. Related blog post: https://blog.prosody.im/fast-auth/ Simply add these lines at the end of the list:

modules_enabled = {
  --all other modules that are listed...
  "mod_sasl2";
  "mod_sasl2_bind2";
  "mod_sasl2_fast";
  "mod_sasl_ssdp";
  "invites_register_web";
  "invites_page";
  "http_libjs";
  "register_apps";
}

See also https://prosody.im/doc/configure#port_and_network_settings for the following options:

OPTIONAL: Force TLS 1.3

If you are certain that all computers and clients are modern, you can allow only the most modern encryption. Under the modules_enabled section, you can insert a new line after the closing bracket:

tls_profile = "modern" -- Enforce TLS 1.3 for all connections.

Setup your webserver port:

If you are not running a web server on your server, you can run the Prosody web server on the standard https port 443. This would be the ideal setup. To do this, add the following option below the closing bracket after the modules_enabled section.

https_ports = { 443 }

To use Prosody's https port on its default port is the easiest setup. It can co-exist with other web servers. In that case, you don't need to add anything to the config and you won't need a reverse proxy. Just allow the port 5281/tcp in your firewall.

If you want to use an existing webserver to terminate tls for your file_uploads and invites page, then you can then disable Prosody's https_port entirely.

https_ports = { }
For a reverse proxy setup, please read the full page here: https://prosody.im/doc/http


If you want to connect modern with direct TLS, with less roundtrips then STARTTLS, then you should set up the corresponding SRV records. (It was shown in the DNS Records section of the guide). Then add these options to the config file:

c2s_direct_tls_ports = { 5223 }
s2s_direct_tls_ports = { 5270 }

I'd like to store my messages on the server for a bit longer than the default setting of one week. What's a good value here depends on how rarely some users are online with certain clients. Perhaps one week is absolutely sufficient for you. Everything has its pros and cons. Find and change the archive_expires_after option in the config file. We can also specify here how long messages from chat rooms are retained.

archive_expires_after = "3 weeks" --(1)!
muc_log_expires_after = "3 weeks" --(2)! 
  1. Three weeks for messages on your server.
  2. Three weeks too, for groupchat messages on your server.

Now we'll set up the prosody parts of our turn-server for relaiable video-calls (The actual install of that server is covered in the next section of the guide). We need to setup it's domain and password. A secure password can be generated liks this in the command line: openssl rand -base64 33

turn_external_host = "example.com"
turn_external_secret = "your-created-password"
OPTIONAL: Logging to syslog

Logging is a matter of preference; personally, I have everything logged to systemd. If you'd like to do the same, make the following changes. In principle, however, nothing needs to be changed here:

log = {
  info = "*syslog;"
}

This marks the end of the general configuration section; the VirtualHost and Component sections begin here. Remember https://prosody.im/doc/configure#overview Now change the line VirtualHost "localhost" to your own domain:

VirtualHost "example.com"

Create a Component for chatrooms. This must be hosted on its own domain. We also want only users registered with you to be able to create new rooms.

Component "rooms.example.com" "muc"
restrict_room_creation = "local" 

Now create another Component underneath it. It is to allow clients to send files like images, audio, videos. See https://prosody.im/doc/modules/mod_http_file_share

Component "share.example.com" "http_file_share"
modules_disabled = { "s2s" } --(1)!
http_file_share_size_limit = 1024 * 1024 * 100 --(2)!

-- How long to keep the uploaded data:
http_file_share_expires_after = "3 weeks"

http_paths = { --(3)!
file_share = "/"; 
}
  1. This component does not need mod_s2s loaded

  2. Change the last number (in MB) depending on your requirements and server storage: Here, 100MB is the maximum size of uploaded photos/videos etc.

  3. This is Optional: We change the upload path so that the data is located at share.example.com/; if you don't do this, it can be found at: share.example.com/file_share/ by default. It is just a cosmetic change!

Done! This configuration is set! Save it.

However, to ensure the server works properly, we need to take a few more steps before we can get started...

Community Modules

As we want to use “invites” via a website, we need to add some Community modules. We've already mentioned them in the configuration, but they aren't actually on the server yet. We want to receive invitations for new users via a website. If this isn't important to you, you can do without Community Modules entirely. As we're using Community Modules for invites in this guide, I'll also include the new sasl2 modules with fast-auth from there at no extra cost.

As with almost everything you can do with Prosody, there are various approaches here, each with its own pros and cons.

The simplest way to obtain the needed Community Modules.

sudo apt install prosody-modules
For the installation of mod_invites_register_web and its dependencies, this is sufficient. Note, however, that not all Community Modules are included and that this is not as up-to-date as if you were to install them yourself from the repository.

If you'd like to experiment a bit more and delve deeper, this way or the last are recommended.

Clone the repository using Mercurial and then link the modules required for Prosody from there. I personally prefer this method. See: https://prosody.im/doc/installing_modules#prosody-modules

The newer method is via the new Prosody installer: https://prosody.im/doc/plugin_installer


For our guide, I recommend installing only the modules we need for invites and the “sasl2*” modules as described in the configuration above.

  • mod_invites_register_web
  • mod_register_apps
  • mod_invites_page
  • mod_http_libjs
  • mod_sasl2
  • mod_sasl2_bind2
  • mod_sasl2_fast
  • mod_sasl_ssdp

Storage

A word about the database: The default database is perfectly fine for smaller servers and if you do not wish to store messages indefinitely on the server. In that case, simply do nothing to change it. This has the fewest dependencies. Optionally, or if you plan to keep data on the server for a very long time (e.g. archive_expires_after = "1y" or similar) – which I do not recommend – you can remove the comment before storage = "sql" and additionally install sudo apt install lua-sql-sqlite3. It will use sqlite3 in that case. This is by no means generally necessary. I explicitly recommend to not use PostgreSQL or similar. File Storage and sqlite are the two sane choices for a non industrial scale server. You'll statistically more issues and not less, and no advantage in speed if you use something else.

Eturnal Turn Server

For reliable voice and video calls via XMPP, we need a so-called Turn Server. This helps clients find each other and establish a direct connection. If necessary, this can also be mediated by the Turn Server.

Eturnal is easy to configure and fits our project perfectly.

Install:

sudo apt update
sudo apt install eturnal

Setup:

sudo nano /etc/eturnal.yml

Change the line for the “secret”, remove the comment ‘#' and enter the same “secret” that we created above in prosody.cfg.lua as turn_external_secret. The server's IPv4 and v6 addresses should be entered under relay_ipvX_addr. The rest of the configuration can remain as it is.

OPTIONAL: Change the port to reduce the number of access attempts from automated scanners and similar programmes. This does not provide protection; it merely reduces the number of access attempts. The access attempts themselves do not pose a security risk to your server. I'm choosing port 5221 here. You can also OPTIONALLY adjust the relay_min_port and relay_max_port. Bear in mind that you'll need around 4 ports per simultaneous call. (I always forget the exact number that might actually be required.) Don't be too stingy.

/etc/eturnal.yml
  ## Shared secret for deriving temporary TURN credentials (default: $RANDOM):
  secret: "your-secret-turn-access-token"

  listen:
    -
      ip: "::"
      port: 5221
      transport: udp
    -
      ip: "::"
      port: 5221
      transport: tcp
    #-
    #  ip: "::"
    #  port: 5349
    #  transport: tls

  ## TLS certificate/key files (must be readable by the 'eturnal' user!):
  #tls_crt_file: /etc/eturnal/tls/crt.pem
  #tls_key_file: /etc/eturnal/tls/key.pem

  ## The server's public IPv4 address (default: autodetected):
  relay_iPv4_addr: "203.0.113.123"
  ## The server's public IPv6 address (optional):
  relay_iPv6_addr: "2001:db8:19ba::1"

Then restart eturnal: sudo systemctl restart eturnal.service

Info: About setup at home

If you want to set up your XMPP server at home, you will first need a “real” IPv4 address; make sure you do not have DS-LITE. Secondly, you may need to update your IPv4 and IPv6 addresses regularly. This script can help you with that: https://github.com/processone/eturnal/blob/master/examples/check-relay-ip

Ports & Firewall

The following ports must be opened to the internet in our example setup. Adjust this depending on the options you have chosen yourself. (e.g. File_Share on the standard port 5281 instead of 443?)

TCP Reason
80/443 http (Certbot) and https (Prosody invites and file-share)
5222 XMPP apps “Client to Server (c2s)”
5223 XMPP apps with “direct TLS”
5000 File transfer proxy (if data exceeds http_file_share_size_limit)
5269 XMPP Server to Server (s2s) port
5270 XMPP s2s with "direct TLS"
TCP and UDP Reason
5221 STUN/TURN
UDP Reason
49152-65535 Turn server data channels

Certificates

To enable your server to communicate with apps and other servers, you need certificates for encryption. These must come from a source that other servers and the apps/clients trust. The most popular provider for this is Let's Encrypt. Here, too, there are countless ways to obtain certificates.

Personally, I use wildcard certificates with the so-called DNS challenge using the ACME client “lego”. If none of this means anything to you, you can either read up on it or choose a simpler method.

The simple way:

Install the recommended client Certbot. sudo apt install certbot

Standalone mode (without a web server)

Standalone mode is the simplest option if no web server is running on port 80. Certbot briefly starts a small server itself for validation.

Important: Port 80 must be accessible (open the firewall!). If you are already running a web server for something else, adjust your setup accordingly. In that case, standalone mode is probably not the right choice for you.

Create your first certificate

Adjust the domains to suit your setup:

sudo certbot certonly --standalone \
-d example.com \
-d groups.example.com \ 
-d share.example.com \
--agree-tos \
-m admin@example.com \ #enter your email address
--deploy-hook "prosodyctl --root cert import /etc/letsencrypt/live"

All certificate renewals will now be carried out automatically once this command has run successfully. If you have already set up Prosody with the same virtual hosts and components and have restarted it as described, everything should now be working.

Conclusion

Restart prosody: to apply everything we set up:

sudo systemctl restart prosody.service

Now create the user you entered at the start of the config file using:

sudo prosodyctl adduser ich@example.org

Run the following command to validate:

sudo prosodyctl check Try to understand and resolve any issues displayed, and please feel free to give me feedback. No errors should occur.

Then run sudo prosodyctl check features

Now log in with your admin account, e.g. using the Cheogram client (Android), or Gajim (desktop), both of which are particularly suitable for administrators. Incidentally, the standard client for Android is Conversations.

You can now create “invites” and invite additional members from Cheogram, Monal (iOS), Conversations and also Gajim (via ad-hoc commands in the menu). Give it a go.

If you encounter connection issues, you can use sudo prosodyctl check connectivity, for example. See also sudo prosodyctl shell help. If problems persist, you can get help in the Prosody support channel. Feedback to the guide welcome: https://codeberg.org/Menelmacar/Prosody-Guide/issues

This guide is licensed under CC0 1.0