prosody (on Uberspace)

Host your own instance of XMPP / Jabber. Fast, easy and decently secure.

/This guide is security critical. See [20]/

I assume the installation to be on a shared host, so the guide uses paths inside $HOME. Keep that in mind for global installations.



Update version of Prosody (0.9.12) and OpenSSL (1.0.2k).

Former changes to this guide on the bottom of the page.

The goal of this guide is to get an own instance with the best available encryption. IM Observatory [0] will rate it with an 'A'.

Parts of this guide are inspired by [1].


newer OpenSSL

For newer methods of encryption we need a recent version of OpenSSL. We'll use toast [2] for that. Check for your currently active version. We want 1.0.2 (as 1.1.x is not supported by luasec 0.5.1 [28]).

openssl version

If you get something different, go ahead:

toast arm && . "${HOME}"/.bash_profile && openssl version

Now you should get 'OpenSSL 1.0.2k 26 Jan 2017'.

prepare Lua

Check for Lua 5.1.x:

lua -v

Prosody doesn't support 5.2.

Now let's get newer modules via luarocks to support PFS [3]. To make everything work nicely, we need to prepare our env. Put this to your profile:

# added for Prosody and Luarocks
export LUA_PATH='/home/UUSER/.luarocks/share/lua/5.1/?.lua;/home/UUSER/.luarocks/share/lua/5.1/?/init.lua;./?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;/home/UUSER/.luarocks/share/lua/5.1/?.lua;/home/UUSER/.luarocks/share/lua/5.1/?/init.lua;./?.lua;/usr/lib64/lua/5.1/?.lua;/usr/lib64/lua/5.1/?/init.lua;/home/UUSER/.luarocks/share/lua/5.1/?.lua;/home/UUSER/.luarocks/share/lua/5.1/?/init.lua;./?.lua'
export LUA_CPATH='/home/UUSER/.luarocks/lib/lua/5.1/?.so;/usr/lib/lua/5.1/?.so;/home/UUSER/.luarocks/lib/lua/5.1/?.so;./?.so;/usr/lib64/lua/5.1/?.so;/usr/lib64/lua/5.1/;/home/UUSER/.luarocks/lib/lua/5.1/?.so'

Replace 'UUSER', of course, and update env:

sed "s/UUSER/${USER}/g" -i "${HOME}"/.bash_profile
. "${HOME}"/.bash_profile

Now we can install the needed modules [5]. If OpenSSL was updated using toast we need to set 'OPENSSL_DIR' for luasec accordingly:

luarocks install luasocket --local
luarocks install luaexpat --local
luarocks install luafilesystem --local
luarocks install luasec 0.5.1 --local OPENSSL_DIR="${HOME}/.toast/armed/usr/local/"

The modules should look like this now:

luarocks list

Installed rocks:

   1.3.0-1 (installed) - /home/UUSER/.luarocks/lib/luarocks/rocks

   1.6.3-2 (installed) - /home/UUSER/.luarocks/lib/luarocks/rocks

   0.5.1-1 (installed) - /home/UUSER/.luarocks/lib/luarocks/rocks

   3.0rc1-2 (installed) - /home/UUSER/.luarocks/lib/luarocks/rocks


Now we can finally install Prosody. Sources are here [6].

toast arm

mkdir -p "${HOME}"/var/prosody/data
mkdir -p "${HOME}"/var/prosody/ssl

Now generate Diffie-Hellman parameters for PFS (which will take a lot of time):

cd "${HOME}"/var/prosody/ssl/
openssl dhparam -out dh-4096.pem 4096

Next we'll need certificates. Skip if you already have some.

I recommend using Let's Encrypt. For instructions on Uberspace look here [21]. Make symlinks to the current certificate and key:

cd "${HOME}"/var/prosody/ssl/
ln -s /home/UUSER/.config/letsencrypt/live/DOMAIN/fullchain.pem .
ln -s /home/UUSER/.config/letsencrypt/live/DOMAIN/privkey.pem .

More information on using certificates in prosody here [14].

PID file:

touch "${HOME}"/var/prosody/

Now on to configure prosody. You can find a commented config at "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua . We copy the original for later reference and also to the right place for use and editing:

mkdir -p "${HOME}"/etc/prosody
cp "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua "${HOME}"/etc/prosody/prosody.cfg.lua.stock
cp "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua "${HOME}"/etc/prosody/prosody.cfg.lua

We put the config to "${HOME}"/etc/prosody/prosody.cfg.lua to avoid later overrides by updates. The following provided config will be almost ready for use. Make sure to edit your users path, your domain, the interfaces IPs and the ports. Get two open TCP ports first [33].

pidfile = "/home/UUSER/var/prosody/";
admins = { "admin@domain.tld" }
modules_enabled = {
daemonize = false; -- IMPORTANT for daemontools! DO NOT EDIT!
data_path = "/home/UUSER/var/prosody/data";
log = { info = "*console" } -- IMPORTANT for daemontools! DO NOT EDIT! "*console" sends the output to daemontools.
-- log = { "*console" } -- Use this for more verbose output. IPs will we logged.
allow_registration = false;
s2s_ports = { XXXXX } -- Server to Server
c2s_ports = { XXXXX } -- Client to Server
c2s_require_encryption = true
s2s_require_encryption = true
s2s_secure_auth = true
authentication = "internal_hashed" -- do not save passphrases in cleartext!
interfaces = {"x.x.x.x", "x:x:x:x:x:x:x:x"} -- can otherwise produce high load on hosts with many interfaces [24]

VirtualHost "domain.tld" -- EDIT!
	enabled = true

	ssl = {
		key = "/home/UUSER/var/prosody/ssl/privkey.pem";
		certificate = "/home/UUSER/var/prosody/ssl/fullchain.pem";

		-- Allow perfect forward secrecy.
		dhparam = "/home/UUSER/var/prosody/ssl/dh-4096.pem";

		-- Best ciphers for perfect forward secrecy.

		-- Where Uberspace (or CentOS in general) stores it's trusted CAs.
		cafile = "/etc/pki/tls/certs/ca-bundle.crt";

		-- mittlerweile Standard: options = { "no_sslv2", "no_sslv3", "no_ticket", "no_compression", "cipher_server_preference", "single_dh_use", "single_ecdh_use" }

For replacing 'UUSER' just use this again:

sed "s/UUSER/${USER}/g" -i "${HOME}"/etc/prosody/prosody.cfg.lua


Prosody's team recommends not to change the list of ciphers [25]. The respective line is therefore disabled.

Still I'd like to recommend my customised list which disables following (weak) ciphers

  • AES128
  • DSA
  • DSS

and also only allows ciphers with PFS [26].

muc(multi user chat) functionality is nice to have. You'll need a subdomain for that. Put following to the end of the config:

Component "subdomain.domain.tld" "muc"
	name = "NameOfChatroom"
	restrict_room_creation = false --- users are allowed to create own rooms

More information here [16].

Link the config to where Prosody expects it:

rm "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua
ln -s "${HOME}"/etc/prosody/prosody.cfg.lua "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua

Now create a daemontools service and start it.

For Uberspace:

uberspace-setup-service prosody "${HOME}"/.toast/armed/bin/prosody

Now test whether it's ok:

prosodyctl status

Prosody is running with PID XXXX

Check whether prosody is using the modules we installed via luarocks:

prosodyctl about
Prosody unknown

# Prosody directories
Data directory:   /home/UUSER/.toast/armed/var/lib/prosody
Plugin directory: /home/UUSER/.toast/armed/lib/prosody/modules/
Config directory: /home/UUSER/.toast/armed/etc/prosody
Source directory: /home/UUSER/.toast/armed/lib/prosody

# Lua environment
Lua version:              Lua 5.1

Lua module search paths:

Lua C module search paths:

LuaRocks:         Installed (2.1.2)

# Lua module versions
lfs:      LuaFileSystem 1.6.3
lxp:      LuaExpat 1.3.0
pposix:   0.3.6
socket:   LuaSocket 3.0-rc1
ssl:      0.5.1

Especially check the last entry. If you don't see

ssl:      0.5.1

there's something wrong with the environment and Prosody isn't using luarock's modules.

Don't forget to add DNS entries for you instance [9] [15].

If all is set, test it with IM Observatory. It should look like this [10] [11].

Create account

prosodyctl adduser admin@domain.tld


Filetransfer via mod_proxy65

See [17]. Thanks Tim Krieger.


For handling the connections you can also use libevent as backend [18]. It might come to DNS problems though which need to be addressed in a coming version. [19]

Anyway. Build:

toast arm

and install with luarocks:

luarocks install luaevent --local EVENT_LIBDIR=/home/"${USER}"/.toast/armed/lib

Activate in the config's global section:

use_libevent = true

After restarting Prosody you should get this line in the log:

general    info    Prosody is using the epoll backend for connection handling

Watch out for 'epoll backend'.

Thanks to Christian Schneppe.

Keep it up to date

With new versions of all components coming out you'll want to update your existing installation.


  • Homepage [29]
  • Sources [30]
  • Feed [31]


  • Sources [32]

Prosody itself

Check prosody's website or release feed for new versions. You can install it via toast like in the initial installation.

  • build new version
  • stop the service
  • arm new version
  • update luarocks modules
  • Now our config is not linked to the right place anymore. Change it back and while you are at it save the new stock config fore reference
  • restart the service

toast build "${NEW_URL}" \
&& svc -d "${HOME}"/service/prosody \
&& toast arm "${NEW_URL}" \
&& luarocks install luasocket --local \
&& luarocks install luaexpat --local \
&& luarocks install luafilesystem --local \
&& chmod u+w "${HOME}"/etc/prosody/prosody.cfg.lua.stock
cp "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua "${HOME}"/etc/prosody/prosody.cfg.lua.stock \
&& rm "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua \
&& ln -s "${HOME}"/etc/prosody/prosody.cfg.lua "${HOME}"/.toast/armed/etc/prosody/prosody.cfg.lua \
&& svc -u "${HOME}"/service/prosody

Remove the old version:

toast remove "${OLD_URL}"



  • build new version
  • stop prosody
  • disarm current version
  • arm new version
  • reinstall luasec
  • restart prosody

toast build "${NEW_URL}" \
&& svc -d "${HOME}"/service/prosody \
&& toast disarm "${OLD_URL}" \
&& toast arm "${NEW_URL}" \
&& luarocks install luasec 0.5.1 --local OPENSSL_DIR="${HOME}/.toast/armed/usr/local/" \
&& svc -u "${HOME}"/service/prosody

Remove old version:

toast remove "${OLD_URL}"

Former changes to this document


Update version of Prosody (0.9.11) and OpenSSL (1.0.2j). Translation to english.
Shortened here and there.

2016.03.27 [master d9bd2a1]

Update zu der Liste verwendeter Ciphers. DSA und ECDSA werden nicht mehr genutzt.

Alle vorigen Änderungen am Ende der Seite.

2016.03.26 [master d2f0818]

Problem mit hohem load bei s2sout gelöst. Dank an Adoa Coturnix und Frank! [24] [27]


Neue luasec-Version erschienen. Diese funktioniert aber nur mit lua 5.2+ und somit nicht mit prosody 0.9 [23]


Ich schleiche mich an die Gründe heran, wieso Clients manchmal nicht den c2s-Port finden.

2016.01.29 #2

Änderung der Config, sodass S2S-Authentifizierung nur noch auf Zertifikaten und nicht mehr auf DNS beruht.


Aktualisierung der Versionen von OpenSSL, prosody und den lua-Modulen. Außerdem neu ist ein Abschnitt über die Verwendung von Let’s Encrypt. Dank an mcnesium! [22]


Ungenauigkeiten bzgl. Ort der Config erneut korrigiert. Noch mal Dank an Thomas Kammerer!


libevent als backend für connection handling hinzugefügt. Dank an Christian Schneppe!


Ungenauigkeiten bzgl. Ort der Config korrigiert. Dank an Thomas Kammerer.


  • Allgemeine Überarbeitung. Neu: Prosody updaten.
  • Anleitungen für muc und filetransfer von Tim Krieger. Danke!


Diesmal habe ich auf Anfrage von @el_golfo angehängt, wie ihr euer OpenSSL updatet und die Beispiel-Config angepasst, sodass der Server keine Debug-Infos mehr loggt und damit auch keine IPs mehr. Ich persönlich behalte die Option bei, da die Infos mir - nun ja - beim Debuggen helfen. Wie im Geiste des letzten Updates sei ohnehin gesagt: Wer die genutzte IP nirgendwo aufgezeichnet wissen möchte, sollte sie sowieso korrekt verschleiern, etwa mit TOR. Lernt und lehrt eure Nutzer, wie. Alles andere ist falsche Sicherheit.

Außerdem habe ich noch eine kurze Beschreibung verlinkt, wie ihr Zertifikatketten korrekt zusammensetzt. Dank für die Anregung geht hier an @roflthecat.


Wie mir freundlicherweise von Moritz ( @el_golfo ) mitgeteilt wurde, fehlten in der SSL-Konfiguration die Optionen

[...] "single_dh_use", "single_ecdh_use" [...]

wie sie hier beschrieben werden [12]. Die habe ich nun hinzugefügt, ist empfehlenswert.
Diese erschweren kurz gesagt eine potentielle Attacke auf die Server-Client-Verbindung, wenn OpenSSL "schwache" Primzahlen für DH-Parameter nutzt. OpenSSL tut das aber nur, wenn explizit gesetzt [13].
Ohnehin solltet ihr OTR nutzen, wenn ihr Angriffe auf euren Schriftverkehr fürchtet.