2021-08-04 | 11 minutes reading

Howto setup your personal XMPP server

There are several good reasons to have your own chat server instance. Some are philosophical like federalization of internet, some practical like keeping your data safe and only for yourself, some ethical like creating secure communication node for those who for any reason can not host their own. Or maybe you would like to know how the basic architectural patterns of client-server and server-server communication works. So let's dive in.

Articles of this series

2021-08-04 Howto setup your personal XMPP server
2021-07-01 Howto setup your personal CalDAV/CardDAV server
2021-02-12 Howto proxy your self-hosted services using web server
2021-01-08 Howto setup and secure web server
2020-12-30 Services you can selfhost on you personal Linux VPS
2020-09-22 Howto secure your personal Linux VPS
2020-08-21 Howto setup your personal Linux VPS
2020-07-20 Why setup your personal Linux VPS

Choosing the protocol

Nowadays, you have three main open protocols with several implementations on both client and server side. IRC, Matrix and XMPP. I am going to oversimplify here, so those of you, who have some knowledge regarding these protocols, feel free to skip this section.

For those who don't know IRC, it's like that 90s old school internet chat, where you would log in and hang out in some chat room. It supports one on one chats and there are even clients for mobile phones, but you are not able to share files, there is no delayed message delivery after you come back online, it does not support automated federation and so on.

On the other hand, Matrix, or rather its main implementation Element (formerly Riot.IM) is much more robust and modern. It supports end-to-end encryption, file exchange, audio and video calls, it is HTTP based, and messages are instantly saved and redistributed inside federated servers. An open source Slack or Skype on steroids. But it requires PostgresSQL server, some web server as a reverse proxy, and it is very heavy on using space/database resources. Specially when you use it to federate with other servers.

And this is why I like and choose XMPP. I don't need all the bells and whistles, and I really want it to be light on system resources. I need to chat and share files, I want it simple and working. I have my own instance for my family, I federate with the people from work, some other developers and friends, that do have accounts somewhere, or they host their own instances like I do.

Choosing the implementation

There are many options! Openfire, ejabberd, Prosody, MongooseIM, Metronome IM... Check them out, choose what you like. I am using Prosody for several years. It is Lua based, super lightweight (memory consumption under 50MB most of the time), simple to configure and it is supported on OpenBSD.


Installation instructions are straightforward, just use default package manager of your operating system, so for example:

apt install prosody
yum install prosody
pkg_add prosody


Official documentation is great. When you kick off from default config, you only need to change the VirtuaHost line to your custom domain and create users using prosodyctl command line tool like so:

prosodyctl adduser mranderson@cooldomain.xyz

and server is now up and running. It is not a very usable setup though. So here are the steps for a good one:

  1. If you have a firewall, you need to enable couple of ports

  2. To support SSL, you need to get certificates for example from Let's Encrypt and then add their paths to the main config. Don't forget to add a certbot post_hook that will always copy the certs after the renewal procedure from /etc/letsencrypt/live to your specific location:

certificates = "certs"
https_certificate = "/etc/prosody/certs/cooldomain.xyz.crt"
https_key = "/etc/prosody/certs/cooldomain.xyz.key"
  1. To support federation and to be sure most of the clients will be happy to connect to your server, you need to set up some DNS. First two enable clients and servers to discover port where you listen to. Another two are for additional XMPP components (modules) we will enable and provide. One for file upload/sharing and last one is proxy that will enable file transfers from behind the firewalls:
_xmpp-client._tcp   600  IN  SRV   5   0    5222    cooldomain.xyz.
_xmpp-server._tcp   600  IN  SRV   5   0    5269    cooldomain.xyz.
upload              600  IN  A
proxy               600  IN  A
  1. Add/Enable default sane list of modules that need to be turned on to make it work nicely.
modules_enabled = {
    "roster";    -- Allow users to have a roster
    "saslauth";  -- Authentication for clients and servers
    "tls";       -- Add support for secure TLS on c2s/s2s connections
    "dialback";  -- s2s dialback support
    "disco";     -- Automatic service discovery by clients
    "carbons";   -- Deliver to all clients with the same account logged in
    "pep";       -- Enables users to publish their avatar, mood, activity...
    "private";   -- Private XML storage (for room bookmarks, etc.)
    "blocklist"; -- Allow users to block communications with other users
    "vcard4";    -- User profiles (stored in PEP)
    "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
    "version";   -- Replies to server version requests
    "uptime";    -- Report how long server has been running
    "time";      -- Let others know the time here on this server
    "ping";      -- Replies to XMPP pings with pongs
    "mam";       -- Archive messages on server for delayed delivery
    "csi_simple"; -- Simple Mobile optimizations
    "bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
    "websocket"; -- XMPP over WebSockets
    "http_files"; -- Serve static files from a directory over HTTP
    "http_upload"; -- enable files sharing between users
    "groups"; -- Shared roster support
    "smacks"; -- Keep chat alive when the network drops for a few seconds
    "server_contact_info"; -- Publish contact information for this service
    "proxy65"; -- Enables file transfer service for clients behind NAT

In my case (OpenBSD), modules "http_upload" and "smacks" were not in the default installation and I had to download them and link them manually. If it is your case too, you can find all prosody modules here. My path to modules dir is /usr/local/lib/prosody/modules/. If you don't know yours, just search filesystem for some core module like "mod_motd.lua" using "mlocate" package for example. Best practice for adding custom modules is not to put them to system modules directory, but into separate folder and specify the folder in the config like so:

plugin_paths = { "/usr/local/lib/prosody-custom-modules" }
  1. The last thing is to enable two Components we mentioned during DNS setup:
Component "upload.cooldomain.xyz" "http_upload"
http_upload_file_size_limit = 20971520
http_max_content_size = 31457280
Component "proxy.cooldomain.xyz" "proxy65"
proxy65_ports = { 5000 }


And here you go! Enjoy the self-hosted communication ride :) Full config resulting from this howto can be [downloaded here](https://mizik.eu/download/prosody.cfg.lua)

tags: VPS, Linux, Self-host