Modern XMPP Server

This is what I did to configure my XMPP server, using only packages supported in Debian and 100% compliant with the tests for XEP-0459: XMPP Compliance Suites 2022 on conversations’ website.

This guide was originally written for prosody 0.9 under Debian jessie, but is being kept up to date as I upgrade my server to new Debian releases.


I’ve decided to install prosody, mostly because it was recommended by the RTC QuickStart Guide; I’ve heard that similar results can be reached with ejabberd and other servers.

I’m also targetting Debian stable (+ backports); currently that’s bookworm and prosody 0.12.

Installation and prerequisites

You will need to install the packages prosody, prosody-modules, and coturn.

You also need to setup some TLS certificates (I used Let’s Encrypt); and make them readable by the prosody user; you can see Chapter 12 of the RTC QuickStart Guide for more details.

With prosody 0.10+ you will also need to configure the location of the certificate for https with a configuration stanza such as:

https_ssl = {
    certificate = "/etc/ssl/public/";
    key = "/etc/ssl/private/";
legacy_ssl_ssl = {
    certificate = "/etc/ssl/public/";
    key = "/etc/ssl/private/";

or see the prosody documentation on certificates to see where to put certificates so that prosody is able to autodetect them.

On your firewall, you’ll need to open the following TCP ports:

  • 5222 (client2server)

  • 5223 (client2server, https)

  • 5269 (server2server)

  • 5280 (default http port for prosody)

  • 5281 (default https port for prosody)

  • 3478 (coturn)

As well as the following port for UDP

  • 3478 (coturn)

The http ports are needed to enable some services provided via http(s), including rich media transfers.

With just a handful of users, I didn’t bother to configure LDAP or anything else, but just created users manually via:

prosodyctl adduser

prosody configuration

You can then start configuring prosody by editing /etc/prosody/prosody.cfg.lua and changing a few values from the distribution defaults.

First of all, enforce the use of certificate checking for server2server communications with:

s2s_secure_auth = true

and then, if you need to, add to the whitelist any server that you want to talk to and doesn’t support secure s2s communication (but note that is no longer needed nor useful, as it doesn’t support xmpp any longer):

s2s_insecure_domains = { "" }

Also add at least an user (that you have already created with prosodyctl adduser as described above) as an admin:

admins = { "" }

disabling in-band registration

mod_register is now enabled by default to provide password changing services, but unless you have the resources to moderate new users you probably want to disable registration to prevent the server from being used to send spim; to do so add the line:

allow_registration = false


Support for video calls requires an external STUN / TURN server such as coturn, which can be installed on the same machine; its configuration require setting a realm and a secret for auth in /etc/turnserver.conf:
static-auth-secret=<a long random string>

And then you will have to set the same values in /etc/prosody/prosody.cfg.lua:

turncredentials_host = ''
turncredentials_secret = '<the same long string as above>'


For each virtualhost you want to configure, create a file /etc/prosody/conf.avail/ with contents like the following:

VirtualHost ""
        enabled = true
        ssl = {
            key = "/etc/ssl/private/";
            certificate = "/etc/ssl/public/";

For the domains where you also want to enable MUCs, add the follwing lines:

Component "" "muc"
        restrict_room_creation = "local"
        modules_enabled = {

the "local" configures prosody so that only local users are allowed to create new rooms (but then everybody can join them, if the room administrator allows it): this may help reduce unwanted usages of your server by random people.

Enabling the mam_muc module (on prosody 0.10 only) allows people to syncronize message history between multiple clients (XEP-0313)

You can also add the following line to enable rich media transfers via http uploads (XEP-0363):

Component "" "http_upload"

The defaults are pretty sane, but see for details on what knobs you can configure for this module; you may want e.g. to change the maximum file size limit and setup an expiry date:

Component "" "http_upload"
    http_upload_file_size_limit = 1024 * 1024 * 2
    http_upload_expire_after = 60 * 60 * 24 * 7

Don’t forget to enable the virtualhost by linking the file inside /etc/prosody/conf.d/.

additional modules

Most of the other interesting XEPs are enabled by loading additional modules inside /etc/prosody/prosody.cfg.lua (under modules_enabled); to enable mod_something just add a line like:


Most of these come from the prosody-modules package (and thus from ).

mod_mam (XEP-0313)

Archive messages on the server for a limited period of time (default 1 week) and allow clients to retrieve them; this is required to syncronize message history between multiple clients.

With prosody 0.9 only an in-memory storage backend is available, which may make this module problematic on servers with many users. prosody 0.10 will fix this by adding support for an SQL backed storage with archiving capabilities.

mod_throttle_presence + mod_filter_chatstates (XEP-0352)

Filter out presence updates and chat states when the client announces (via Client State Indication) that the user isn’t looking. This is useful to reduce power and bandwidth usage for “useless” traffic.

cloud_notify (XEP-0357)

Allow clients to register an “app server” that is notified about new messages

Proxied file transfers

To enable proxied file transfers for clients behind NAT or firewalls, you need to add "proxy65"; to the list of additional modules, and then enable it in at least one virtual host with the lines:

Component "" "proxy65"
        proxy65_address = ""

See also