Ultimate Guide to Boosting Online Privacy: Setting Up a Secure XMPP/Jabber Server with ejabberd on Linux ,Ubuntu ,Debian

XMPP/Jabber server configuration under Linux (ejabberd)


  1. Advantages of having your own Jabber server
  2. Installation and configuration of the ejabberd server
    1. Subdomena
    2. SRV record
    3. Let's Encrypt certificate
    4. Firewall and iptables rules
      1. IP address blacklist
      2. Call limiting
    5. Plik ejabberd.yml
  3. Jabber server configuration test
  4. Creating user accounts and connecting to the server
  5. Changing the address and securing the admin panel
  6. MySQL/MariaDB database
  7. Further configuration of the Jabber server

Internet users have a lot of different ways to communicate with each other. Once upon a time, everyone used Gadu-Gadu instant messengers. I was the only person who preferred alternative solutions from the very beginning and I used the Tlen communicator (the one from O2), and soon I switched to Jabber and I still use it today. In fact, GG and Tlen are probably extinct now, because most people (if not all) have switched to Facebook or Twitter. However, writing about private matters on these websites is not the best solution. If we want to ensure the confidentiality of messages sent via the Internet, we must do it in other ways. One of them is the use of the XMPP/Jabber protocol . What distinguishes Jabber from other technologies on the market is the fact that the network is decentralized, i.e. we have a whole lot of Jabber servers on which we can create an account. Taking down one server does not affect the operation of the others. Google also uses the XMPP/Jabber protocol and if we have a gmail account, we also have the appropriate JID in the form of an email address, which we can enter into one of Jabber's clients, e.g. PSI or Gajim, and we are now able to talk to people , who have accounts on other servers. That's right, other servers, or maybe you could set up your own Jabber server? It so happens that the Debian repository contains the ejabberd software that allows us to implement this project.

Advantages of having your own Jabber server

The XMPP/Jabber protocol is an open and free protocol, i.e. anyone can use it without the need to buy any licenses or pay fees. Communication in this protocol can be encrypted on the client-server and/or server-server lines. Whether this is true depends on several factors, including: depends on the configuration of the server on which we have an account, and having our own server, we also have full control over its configuration.

Communication between clients and the server can basically take place on two ports. By default this is the port 5222. Earlier versions of Jabber software used the port, 5223but it is now considered obsolete and is no longer used, at least not recommended. The difference between these two ports is mainly in establishing an encrypted connection between the client and the server. In the case of a port, 5222the traffic may not be encrypted at all or the STARTTLS method is used (this option is usually found). However, when it comes to the port 5223, classic SSL/TLS is used here, which we use when browsing, e.g. websites via HTTPS.

Not all Jabber servers meet the highest security standards. Some servers can only support weak ciphers, e.g. SSLv2 or SSLv3, the use of which threatens the security of the server and the privacy of its users. Even if the server forces its clients to negotiate TLSv1.2 ciphers, it does not provide 100% immunity to communication interception attempts.

When clients have an account on the same server, the traffic between them will always be encrypted and here only the configuration of this particular server is decisive. If accounts are on different servers, messages between servers may travel unencrypted. This is because the servers must negotiate connection parameters between themselves. If one of them does not support encryption or only offers weak ciphers, we have the choice of either agreeing to such conditions and using these weak ciphers (or not using them at all), or these servers will not establish a connection and communication will not take place at all. possible.

An example of such a server that does not want to cooperate with forced encryption is the one from Google (GMAIL addresses). In the case of this type of servers, we can naturally use OTR (Off-The-Record messaging) or PGP/GPG encryption keys to secure communication ourselves. The problem is that it is not very convenient. OTR may make the whole process much easier, but it still requires the user to perform several additional steps. And if you have your own Jabber server (with forced TLSv1.2), you basically don't need to do anything else to encrypt the traffic, at least in the case of users who have an account on our server. Of course, we can still use OTR or PGP/GPG keys as an additional layer of security.

Installation and configuration of the ejabberd server

There is a package available in the Debian distribution ejabberdand also several packages with different modules ejabberd-mod-*. In the stable release, these packages are in a quite old version (14.07). Therefore, it is better to add the Debian backports repository and install the appropriate packages from there, because here we have version 16.09.

After installing the package ejabberd, /etc/ejabberd/a file will be created in the directory ejabberd.yml. This file contains the configuration of our Jabber server. However, before we can edit this file, we need to do a few other things.


Morfitronik is hosted on OVH and its domain is morfitronik.pl. The Jabber server will be connected to the subdomain jabber.morfitronik.pl. This subdomain must first be created, i.e. add the appropriate A/AAAA record in the DNS configuration. You may be told that instead of creating a separate A/AAAA record for the subdomain, it is better to create a CNAME record and specify the target address there. From what I found on the Internet , later indication of the target address with CNAME in the SRV record will cause problems, and this is the case with OVH:


That's why I created a separate A/AAAA record instead of CNAME.

DNS record management may be different for different DNS providers. However, as an example, I will describe what it looks like in the case of the OVH web panel. So let's go to the administration panel and go to the tab WWW.


After selecting the domain, general configuration information will appear. We also have min. bookmark Strefa DNS. After switching to it, we will have the following buttons on the right:


Naturally, we click on Dodaj wpis, then select the type of DNS field and select Afor IPv4 and/or AAAAIPv6:


We define the subdomain jabberand indicate the target address:


We accept and should see the following summary:


Below is a text version of the entry, if someone would like to manually add it in the DNS configuration:

jabber.morfitronik.pl IN A 

SRV record

So we have a subdomain configured. Now we need to add SRV records. The SRV record allows you to transparently redirect requests to a different domain or port, where the service is located. In our case it will be a subdomain jabber.morfitronik.pl.

There are several types of SRV records for the XMPP/Jabber protocol . We are interested in client-to-server (c2s) and server-to-server (s2s). This way, clients use the c2s record, while other servers use the s2s record and know which ports to send requests to. Standard ports for the XMPP/Jabber protocol are: 5222 (XMPP client connection (RFC 6120)) and 5269 (XMPP server connection (RFC 6120)). These are the two ports that we must provide in the DNS configuration while also indicating the subdomain jabber.morfitronik.pl.

We visit the OVH panel again and add another entry. This time we select one of the extended fields, i.e SRV.:


And we complete it as shown in the image below:



We do the same for the second record:



Below is an additional text version of these two records in case someone wants to manually edit the DNS configuration:

_xmpp-client._tcp.morfitronik.pl. 18000 IN SRV    0 5 5222 jabber.morfitronik.pl.
_xmpp-server._tcp.morfitronik.pl. 18000 IN SRV    0 5 5269 jabber.morfitronik.pl. 

Older Jabber servers may use the record _jabber._tcpinstead _xmpp-server._tcpand you can also add this SRV record:

_jabber._tcp.morfitronik.pl. 18000 IN SRV    0 5 5269 jabber.morfitronik.pl. 

Let's Encrypt certificate

Having configured the domain and knowing that traffic in the XMPP/Jabber protocol should be encrypted, we need to obtain appropriate certificates for our server. These, in turn, can be generated manually, e.g. using the easy-rsa package , but you can also use the ready-made solution offered by Let's Encrypt and that is what we will use.

There are already several services on Morfitronik that provide an encrypted connection. Installed here is at least web server. It so happens that Let's Encrypt already provides a certificate for this blog , specifically for the morfitronik.pl. It is not possible to generate a certificate separately for the second domain and this process must be performed for both domains at the same time. We do it in the following way:

# certbot certonly \
    -d morfitronik.pl,www.morfitronik.pl,jabber.morfitronik.pl \



When generating the certificate, you must temporarily disable the web server, if you have one. It is also worth mentioning that this subdomain will by default point to the main website directory. Finally, the DNS server returns queries to the same IP address after calling both the domain and subdomain. Therefore, you will need to create a new virtual host in the Apache2 configuration (or another web server) and separate the queries in this way.

Let's Encrypt stores certificates and keys in separate files. For this purpose, ejabberdyou need to combine two of these files into one:

# cd /etc/letsencrypt/live/morfitronik.pl/
# cat privkey.pem fullchain.pem > /etc/ejabberd/ejabberd.pem 

We also generate a file dh4096.pem:

# openssl dhparam 4096 > /etc/ejabberd/dh4096.pem 

Let's make sure that the above files have the appropriate permissions:

# chown root:ejabberd /etc/ejabberd/dh4096.pem
# chown root:ejabberd /etc/ejabberd/ejabberd.pem
# chmod 440 /etc/ejabberd/dh4096.pem
# chmod 640 /etc/ejabberd/ejabberd.pem 

Let's Encrypt certificates are renewed every three months. privkey.pemTherefore, it would be useful to merge the files and fullchain.pemreset the Jabber server every month . If we do not do this, our server will eventually operate without a valid certificate. This task can be automated by creating a simple script and running it periodically using cron. Below is such a script:



systemctl stop ejabberd.service
#systemctl stop epmd.socket
systemctl stop epmd.service

cat $cert_dir/privkey.pem $cert_dir/fullchain.pem > /etc/ejabberd/ejabberd.pem

chown root:ejabberd /etc/ejabberd/ejabberd.pem
chmod 640 /etc/ejabberd/ejabberd.pem

systemctl start ejabberd.service 

This is what the cron job looks like:

27  02  1   *   *   /skrypty/ejabberd-cert.sh 

Firewall and iptables rules

We know that jabber will listen for two types of connections on ports 5222 and 5269. These are standard ports and it is almost certain that some bots will attach to our server. Therefore, we must try to secure this service using a packet filter iptables. Basically we need to do three things. The first one is to accept connections in the NEW state to the above-mentioned ones. ports. The second is to limit the number of simultaneous connections for a specific IP address. And the third thing is to implement an address blacklist that will prevent certain people/bots from connecting to the server.

IP address blacklist

Maybe let's start with the last issue, i.e. the blacklist of addresses. We don't have to build it from scratch, because the relevant lists are already maintained and regularly updated. We just need to somehow put these lists on our server's firewall. The easiest way to do this is to use ipset . In the Debian distribution, this tool is available in a package ipsetand you just need to install it.

You can search for a list of addresses on Google, but someone has already done this work for us and created a simple script that can very easily add entire ranges of IP addresses and filter the network traffic reaching our server based on them. The project in question can be found here . In this link we have detailed instructions for using this tool and there should be no problems with implementing it in the system. Of course, you can adjust some things, e.g. the position of the rule in the filter by moving it from the INPUT chain in the FILTER table to the PREROUTING chain in the RAW table, which means that connection requests will not pass through a large part of the filter itself.

Call limiting

The blacklist of addresses may have been uploaded, iptablesbut we won't be able to ban all bad Internet users with it. There will always be someone who will try to attack our server and gain unauthorized access to it or use its resources inappropriately. Therefore, the second security measure we will implement will be to limit the number of connections a single client will be able to establish. We will use two modules for this purpose: connlimit and hashlimit .

So let's redirect all new connections in the TCP protocol to the chain tcp:

iptables -N tcp

iptables -A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -m comment --comment "Connections not started by SYN" -j DROP
iptables -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j tcp 

Now tcpwe create the following two rules in the chain:

iptables -A tcp -p tcp -m tcp --dport 5222 \
    -m connlimit --connlimit-upto 20 --connlimit-mask 0 --connlimit-saddr \
    -m hashlimit --hashlimit-upto 5/min --hashlimit-burst 5 --hashlimit-mode srcip --hashlimit-name xmpp \
    -m comment --comment xmpp-client \
    -j ACCEPT

iptables -A tcp -p tcp -m tcp --dport 5269 \
    -m connlimit --connlimit-upto 20 --connlimit-mask 0 --connlimit-saddr \
    -m hashlimit --hashlimit-upto 10/min --hashlimit-burst 10 --hashlimit-mode srcip --hashlimit-name xmpp \
    -m comment --comment xmpp-server \
    -j ACCEPT 

The first of these rules limits connections for our server's clients, i.e. those who will have an account with us. Roughly, the maximum number of connections that a specific IP address can maintain with our server at a given time is 20. The number of new connections that can be initiated from a given IP in one minute is 5. The situation is similar in the case of the second rule relating to servers , but here we have a limit of 10 new connections per minute. After exceeding these limits, the security mechanism will activate and subsequent connections will be dropped, unless the client or server closes previous connections.

Plik ejabberd.yml

It's time to put together all the things described above and create a configuration for the Jabber server. We are interested in a file /etc/ejabberd/ejabberd.ymlin which something needs to be added and changed. First of all, we need to define the ports on which ejabberdit will listen. Each of these ports must be configured. In this case, we configure three ports: for client connections, server connections and for the web server.

Port 5222 (for client connections):

    port: 5222
    module: ejabberd_c2s
    certfile: "/etc/ejabberd/ejabberd.pem"
      - "no_sslv3"
      - "no_tlsv1"
    ciphers: 'TLS_CIPHERS'
    max_stanza_size: 65536
    shaper: c2s_shaper
    access: c2s
    zlib: false
    resend_on_timeout: if_offline
    tls_compression: false
    dhfile: "/etc/ejabberd/dh4096.pem" 

Port 5269 (for server connections):

    port: 5269
    module: ejabberd_s2s_in
    max_stanza_size: 524288


s2s_use_starttls: optional
s2s_certfile: "/etc/ejabberd/ejabberd.pem"
s2s_dhfile: "/etc/ejabberd/dh4096.pem"

  - "no_sslv3"
  ##- "no_tlsv1"
s2s_ciphers: 'TLS_CIPHERS'
s2s_tls_compression: false 

Port 5280 (for web server):

    port: 5280
    module: ejabberd_http
      "/websocket": ejabberd_http_ws
    ##  "/pub/archive": mod_http_fileserver
    web_admin: true
    http_bind: true
    ## register: true
    ## captcha: true
    tls: true
    certfile: "/etc/ejabberd/ejabberd.pem" 

In the case of ports 5222 and 5269, we use a macro named TLS_CIPHERSreferring to the supported ciphers. We need to specify this macro in the configuration ejabberd(you can also add !SHA1 and thus disable TLSv1.1 protocols):


A Jabber server configured in this way will only accept connection attempts that offer TLSv1.1 and TLSv1.2 ciphers. Encryption is required for clients. However, due to problems with enforcing encryption in the case of servers, e.g. GMAIL, connection encryption is optional. You can, of course, force encryption on the server=server line by manipulating the parameter, s2s_use_starttlsbut then you must be aware that your server will not be able to establish a connection with many Jabber servers.

To improve the security of encrypted connections, we use our own file with DH (Diffie-Hellman) parameters. If we hadn't generated the file earlier dh4096.pem, it ejabberdwould have used a prime number of 1024 bits.

We also configure the domain and authentication via the SASL (Simple Authentication and Security Layer) mechanism:

disable_sasl_mechanisms: "digest-md5"

  - "morfitronik.pl"

fqdn: "jabber.morfitronik.pl" 

Jabber server configuration test

Once we have everything set up correctly, it would be useful to check the server configuration in terms of the encryption offered when connecting to clients and other servers. We can perform this type of test on xmpp.net . There are two separate tests. My Jabber server received a rating in both cases A.

Link to client test :


Link to the server test :


Creating user accounts and connecting to the server

Our Jabber server should now be running, but there is no user account created on it yet that can be used to log in. We can create an account from the terminal or using the administration panel provided by the web server.

Below is an example console command that creates an account on the Jabber server:

# ejabberdctl register user morfitronik.pl haslo
User [email protected] successfully registered 

It is worth examining the tool ejabberdctl( here is a link to the manual ).

This is what the admin panel looks like:


Changing the address and securing the admin panel

By default, the admin panel is launched at the address (domain ) and port 5280 ejabberdindicated in the configuration. There are two problems with this address. morfitronik.plThe first is to expose this panel to the public, which is not very prudent. The second problem is the non-standard port for websites, which means you have to enter it every time you want to manage the server. Of course, you could ejabberddefine port 80 or 443 for this panel in the configuration, but in this case Apache2 is listening on these ports and serving this blog. Therefore, it is impossible to have two services that will listen on the same port. However, you can add a proxy to the Apache2 server and redirect queries to the indicated address and port. In this way, when we enter the address http://jabber.morfitronik.pl(port 80) or https://jabber.morfitronik.pl (port 443) in the browser, we will be automatically redirected to the address https://jabber.morfitronik.pl:5280/admin/where we will be presented with a login window to the Jabber server, which we will additionally secure with x509 certificates.

We will start by writing the configuration for the virtual host. So let's create a file ejabberd.conf in the directory /etc/apache2/sites-available/and add the following content to it:

<VirtualHost *:80>
    ServerName jabber.morfitronik.pl
    ServerAdmin [email protected]
    DocumentRoot /apache2/jabber
    Redirect permanent / https://jabber.morfitronik.pl/

    LogLevel info
    ErrorLog ${APACHE_LOG_DIR}/error_jabber.morfitronik.log
    CustomLog ${APACHE_LOG_DIR}/access_jabber.morfitronik.log combined

    php_admin_value open_basedir "/apache2/jabber/"

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName jabber.morfitronik.pl
        ServerAdmin [email protected]
        DocumentRoot /apache2/jabber

        LogLevel info ssl:warn
        ErrorLog ${APACHE_LOG_DIR}/error_jabber.morfitronik.log
        CustomLog ${APACHE_LOG_DIR}/access_jabber.morfitronik.log combined

        php_admin_value open_basedir "/apache2/jabber/"

        SSLEngine on
        SSLCertificateFile      /etc/letsencrypt/live/morfitronik.pl/fullchain.pem
        SSLCertificateKeyFile   /etc/letsencrypt/live/morfitronik.pl/privkey.pem

        <FilesMatch "\.(cgi|shtml|phtml|php)$">
                SSLOptions +StdEnvVars
        <Directory /usr/lib/cgi-bin>
                SSLOptions +StdEnvVars

        BrowserMatch "MSIE [2-6]" \
                nokeepalive ssl-unclean-shutdown \
                downgrade-1.0 force-response-1.0
        BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown



We enable the configuration for this virtual host by linking the file created above to the directory /etc/apache2/sites-enabled/.

Now let's enable the proxy_http module in Apache2 , thanks to which our web server will be able to redirect queries:

# a2enmod proxy_http 

We also need to add /etc/apache2/sites-available/ejabberd.confthe proxy configuration to the file, i.e. which queries should be taken into account. Since in the section with port 80 we are redirected to port 443, we only add the following code to this second section:

SSLProxyEngine on
ProxyRequests Off
ProxyVia Off

<Proxy *>
     Require all granted

ProxyPass /admin https://jabber.morfitronik.pl:5280/admin
ProxyPassReverse /admin https://jabber.morfitronik.pl:5280/admin 

In this way, queries jabber.morfitronik.pl/adminwill be automatically redirected internally by Apache2 jabber.morfitronik.pl:5280/adminand we will no longer need to enter this port, which is non-standard from the WWW point of view.

To simplify our lives even more, we can also skip entering the resource /adminand redirect from jabber.morfitronik.plto jabber.morfitronik.pl/adminusing a directive RedirectMatchor module mod_rewrite:

# RedirectMatch ^/$ https://jabber.morfitronik.pl/admin/

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule   ^/$  /admin/  [R]

The last thing is to secure the admin panel with certificates. Here we must have our own CA and appropriate certificates. If we do not have the appropriate files, we need to generate them first. The entire process of generating certificates using easy-rsa has been described separately. We will use ready-made certificates here. Basically, we need to send the CA certificate to the server and add /etc/apache2/sites-available/ejabberd.confthe following line to the file:

SSLCACertificateFile    /etc/CA/keys/ca.crt 

All client certificates issued by our CA will be trusted in this way. In the same file, we also add the following code block:

<Location "/admin">
#   SSLOptions +StdEnvVars
    SSLVerifyClient optional
    SSLVerifyDepth 1
#   SSLRenegBufferSize 524288

    <IfModule mod_rewrite.c>
            RewriteEngine on
            RewriteCond %{SSL:SSL_CLIENT_VERIFY} !^SUCCESS$
    #       RewriteCond %{REMOTE_ADDR} !^$
            RewriteRule ^(.*) https://morfitronik.pl [R=301,L]


Its purpose is to secure the resource located at the address jabber.morfitronik.pl/admin/. Anyone attempting to visit this URL will be required to provide a valid certificate. Otherwise, access will be denied and the visitor will be redirected to https://morfitronik.pl.

We save the configuration and restart the Apache2 server:

# systemctl restart apache2 

We need to import the client certificate in the browser. In this case, we will do it using Firefox as an example. So go to Preferences > Advanced. Then, on the Certificates tab, click View Certificates. In the window that appears, go to the Your Certificates tab and click the Import button, where we provide the path to the file client.p12:


We are now visiting the address jabber.morfitronik.pl. It doesn't matter whether we add z at the beginning of http/ httpsand whether we specify the resource /admin/, because we will end up in the same place anyway. Once we have the appropriate certificate, we should see the login window to the admin panel.

MySQL/MariaDB database

ejabberdby default it uses a built-in database called Mnesia. If we already have a database server installed on our VPS, e.g. MySQL or MariaDB, we can naturally connect this server to the Jabber server. We just need to obtain a schema based on which we will create a database for ejabberd. Here are templates of database diagrams that we can use. We just need to realize that if our database server is MySQL, it must be at least version 5.6. Otherwise, when importing the database schema, we will encounter an error while creating the FULLTEXT index. We download the file mysql.sqland import it on the database server. First we create a new database:

# mysql -u root -p

mysql> CREATE DATABASE ejabberd; 

And then we load the database schema:

# mysql -u root -p ejabberd < ./mysql.sql 

/etc/ejabberd/ejabberd.ymlWe also need to include the appropriate configuration in the file . We change the authentication method from internalto sql:

## auth_method: internal
auth_method: sql 

Then we define the configuration for the database:

sql_type: mysql
sql_server: "localhost"
sql_database: "ejabberd"
sql_username: "ejabberd"
sql_password: "pass-pass"
## sql_port: 3306 

We can also set the default base for modules:

default_db: sql 

We save the configuration and restart the Jabber server.

Further configuration of the Jabber server

Above, we only managed to set up a very basic Jabber server and secure it quite well, but this is only the beginning. ejabberdit has a whole lot of modules that you need to configure yourself using the official manual .

Share post
You must be logged in to post a comment