The following ports have to be opened in your firewall:

5222/tcp  # XMPP Client-to-Server
5269/tcp  # XMPP Server-to-Server
5281/tcp  # XMPP HTTPS (for XEP-0363)

Prosody (formerly lxmppd) is a cross-platform XMPP server written in Lua. Its development goals include low resource usage, ease of use, and extensibility.


sudo apt install lua-unbound prosody prosody-modules


modules_enabled = {
	-- Generally required
		"disco"; -- Service discovery
		"roster"; -- Allow users to have a roster. Recommended ;)
		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
		"tls"; -- Add support for secure TLS on c2s/s2s connections
	-- Not essential, but recommended
		"blocklist"; -- Allow users to block communications with other users
		"bookmarks"; -- Synchronise the list of open rooms between clients
		"carbons"; -- Keep multiple online clients in sync
		"dialback"; -- Support for verifying remote servers using DNS
		"limits"; -- Enable bandwidth limiting for XMPP connections
		"pep"; -- Allow users to store public and private data in their account
		"private"; -- Legacy account storage mechanism (XEP-0049)
		"smacks"; -- Stream management and resumption (XEP-0198)
		"vcard4"; -- User profiles (stored in PEP)
		"vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
	-- Nice to have
		"csi_simple"; -- Simple but effective traffic optimizations for mobile devices
		--"invites"; -- Create and manage invites
		--"invites_adhoc"; -- Allow admins/users to create invitations via their client
		--"invites_register"; -- Allows invited users to create accounts
		"ping"; -- Replies to XMPP pings with pongs
		--"register"; -- Allow users to register on this server using a client and change passwords
		"time"; -- Let others know the time here on this server
		"uptime"; -- Report how long server has been running
		"version"; -- Replies to server version requests
		--"mam"; -- Store recent messages to allow multi-device synchronization
		--"turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls
	-- Admin interfaces
		--"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
		"admin_shell"; -- Allow secure administration via 'prosodyctl shell'
	-- HTTP modules
		--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
		--"http_openmetrics"; -- for exposing metrics to stats collectors
		--"websocket"; -- XMPP over WebSockets
	-- Other specific functionality
		"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
		--"announce"; -- Send announcement to all online users
		--"groups"; -- Shared roster support
		--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
		--"mimicking"; -- Prevent address spoofing
		--"motd"; -- Send a message to users when they log in
		--"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
		--"s2s_bidi"; -- Bi-directional server-to-server (XEP-0288)
		--"server_contact_info"; -- Publish contact information for this service
		--"tombstones"; -- Prevent registration of deleted accounts
		--"watchregistrations"; -- Alert admins of registrations
		--"welcome"; -- Welcome users who register accounts
-- Disable account creation by default, for security
-- For more information see
allow_registration = false
-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption. 
c2s_require_encryption = true
-- Force servers to use encrypted connections? This option will
-- prevent servers from authenticating unless they are using encryption.
s2s_require_encryption = true
-- Server-to-server authentication
-- Require valid certificates for server-to-server connections?
-- If false, other methods such as dialback (DNS) may be used instead.
s2s_secure_auth = true

Virtual hosts

Create a virtual host configuration:

VirtualHost ""
modules_enabled = {
ssl = {
                key = "/etc/prosody/certs/";
                certificate = "/etc/prosody/certs/";
                protocol = "tlsv1_2+";
                ciphers = "EECDH+AESGCM:EDH+AESGCM";
                dhparam = "/etc/ssl/dhparams.pem";
Component "" "muc"
Component "" "http_file_share"

Enable the configuration:

sudo ln -s /etc/prosody/conf.avail/ /etc/prosody/conf.d/

SSL certificates

Copy your SSL certificates to a directory Prosody can read:

sudo mkdir -p /etc/prosody/certs/
sudo cp /etc/letsencrypt/live/ /etc/prosody/certs/
sudo cp /etc/letsencrypt/live/ /etc/prosody/certs/

Set strict permissions:

sudo chown -R root:prosody /etc/prosody/certs/
sudo chmod 750 /etc/prosody/certs/

Add users

sudo prosodyctl adduser
sudo prosodyctl adduser

sudo systemctl restart prosody.service

Unlike Apache, nginx, Dovecot and Postfix, Prosody does not shortly run as root when started in order to read from /etc/ssl/ or /etc/letsencrypt/. So certificates have to be copied to the /etc/prosody/ directory. If you use Let's Encrypt, this means that you have to renew those copies every three months.

This can be automated with a script you put in /etc/letsencrypt/renewal-hooks/post/:

cp /etc/letsencrypt/live/ /etc/prosody/certs/
cp /etc/letsencrypt/live/ /etc/prosody/certs/
chown -R root:prosody /etc/prosody/certs/
chmod 750 /etc/prosody/certs/
chmod 640 /etc/prosody/certs/*
systemctl reload prosody.service