ejabberd XMPP server configuration guide
I will be keeping this post up to date to keep track on how to configure and
mantain an ejabberd server working efficiently and secure. I strongly advise
any reader to read carefully what is written here and not just copy-and-paste
the configuration file.
My blog also contains a bunch of other posts regarding ejabberd that are worth
giving a look at, use the search form.
Server
CentOS 7.5.1804 x86_64
Erlang/OTP 21.1.1-1 x86_64
ejabberd 18.09
Client
LineageOS 15.1 (Android Nougat)
Conversations 2.3.5+fcr
.:. Installation and initial configuration
Download and install erlang (release numbers here may not be up to date):
[root@CentOS ~]$ cd /tmp/
[root@CentOS tmp]$ wget http://packages.erlang-solutions.com/site/esl/esl-erlang/FLAVOUR_1_general/esl-erlang_17.1-1~centos~6_amd64.rpm
[root@CentOS tmp]$ yum localinstall esl-erlang_17.1-1~centos~6_amd64.rpm
Alternatively add erlang-solutions repo erlang-solutions.com:
[root@CentOS ~]$ cd /tmp/
[root@CentOS tmp]$ wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
[root@CentOS tmp]$ rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
[root@CentOS tmp]$ yum install esl-erlang
As for ejabberd, ProcessOne also provides a few precompiled installers but when installed this way I was not able to make it run as unpriviledged user (no one should feel confortable with having an internet exposed service running as root) so the only viable option here is to compile from source. Get the source from process-one.net, install the required dependencies, compile and install:
[root@CentOS ~]$ tar -xvf ejabberd-xxx.tgz
[root@CentOS ~]$ yum install gcc gcc-c++ expat-devel openssl-devel automake git libyaml libyaml-devel
[root@CentOS ~]$ cd ejabberd-xxx
### where `ejabber` is the unpriviledged user that will run the ejabberd service
[root@CentOS ejabberd-xxx]$ ./configure --enable-user=ejabberd --disable-graphics
[root@CentOS ejabberd-xxx]$ make && make install
Now ejabberd should be installed, if everything went well it is time to create a jabber user and grant him admin priviledges:
[root@CentOS ~]$ ejabberdctl register admin domain.tld password
[root@CentOS ~]$ vi /usr/local/etc/ejabberd/ejabberd.yml
---
acl:
admin:
user:
- "admin": "domain.tld"
.:. TL;DR - configuration file
The complete configuration file I use can be downloaded
uwot.eu/ejabberd.yml.
Replace domain.tld
with a valid domain name and admin
with a valid user
(the one created before).
Also check that .pem files are following the same naming scheme and that all
the paths are correct.
.:. Securing the connection
Create a self signed SSL cerficate:
[root@CentOS /]$ cd /usr/local/etc/ejabberd/ejabberd.yml
[root@CentOS ejabberd]$ openssl req -x509 -sha256 -nodes -days 1826 -newkey rsa:2048 -keyout ejabberd.pem -out ejabberd.pem
[root@CentOS ejabberd]$ openssl dhparam -out dhparams.pem 4096
[root@CentOS ejabberd]$ chmod 600 ejabberd.pem dhparams.pem && chown ejabberd:ejabberd ejabberd.pem dhparams.pem
4096 might be overkill but better be on the safe side, SHA-2 is also used
instead of the not so secure SHA-1.
The certificate will be used to encrypt server-to-server (s2s),
client-to-server (c2s), ejabberd_http and HTTP File Upload connections.
Alternatively a valid certificate issued by letsencrypt can be used, to do so
create a single .pem file containing the private key followed by fullchain:
[root@CentOS /]$ cd /etc/letsencrypt/live/domain.tld
[root@CentOS /]$ cat privkey.pem fullchain.pem /usr/local/etc/ejabberd/ejabberd.pem
Also define some macro in ejabberd.yml
configuration file:
define_macro:
'TLS_CIPHERS': "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
'TLS_OPTIONS':
- "no_sslv2, no_sslv3, no_tlsv1"
- "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
- "no_compression"
'DH_FILE': "/usr/local/etc/ejabberd/dhparams.pem" # generated with: openssl dhparam -out dhparams.pem 4096
c2s_dhfile: 'DH_FILE'
s2s_dhfile: 'DH_FILE'
c2s_ciphers: 'TLS_CIPHERS'
s2s_ciphers: 'TLS_CIPHERS'
c2s_protocol_options: 'TLS_OPTIONS'
s2s_protocol_options: 'TLS_OPTIONS'
.:. c2s aka client-to-server
This section defines how client to server connections are handled, what kind of encryption is used and a bunch of other important stuff.
listen:
-
port: 5222
ip: "0.0.0.0"
module: ejabberd_c2s
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s
zlib: false
starttls: true
starttls_required: true
tls_compression: false
protocol_options: 'TLS_OPTIONS'
dhfile: 'DH_FILE'
ciphers: 'TLS_CIPHERS'
Zlib stream compression is disabled because it poses a security threat when
used alongside STARTTLS.
The ciphers paramater in ejabberd’s config file accept every cipher supported
by OpenSSL, this can be checked with openssl ciphers
command.
To be sure that the selected cipher is actually being used run:
openssl s_client -connect host:port -starttls xmpp
Some old insecure ciphers are also disabled.
.:. s2s aka server-to-server
XMPP protocol, just like email, is based on the concept of federation, everyone can run his own server and still be able to communicate with people using other servers. This section defines how server to server connections are handled, what kind of encryption is used and more.
s2s_use_starttls: required
listen:
-
port: 5269
ip: "0.0.0.0"
module: ejabberd_s2s_in
max_stanza_size: 131072
shaper: s2s_shaper
tls_compression: false
I like to enforce STARTTLS for server-to-server connections too; certfile,
dhparam and protocol options we already specified outside the s2s listener
section by using s2s_dhfile
, s2s_ciphers
and s2s_protocol_options
.
.:. HTTP File Upload
Use HTTP File Upload (XEP-0363), more info in the following link:
HTTP file upload.
A SOCKS5 proxy can also be used to allow file sharing betwen clients, for more
information refer to: SOCKS5 proxy.
.:. Audio and Video calls
Refer to the following post for more informations: link
.:. Legacy service and startup script
This is not needed on CentOS 7 since it uses Systemd (sigh).
To run ejabberd automatically at boot and manage it with
service ejabberd _option_
copy the following script in /etc/init.d/
.
#!/bin/sh
#
# ejabberd Startup script for the ejabberd XMPP Server
#
# chkconfig: - 99 10
# description: ejabberd XMPP server
# Source function library.
. /etc/init.d/functions
set -o errexit
set -o nounset
export HOME=/root
RETVAL=0
start() {
echo ".:. Starting ejabberd..."
ejabberdctl start
sleep 5
return $RETVAL
}
stop() {
echo ".:. Shutting down ejabberd... "
ejabberdctl stop
sleep 5
return $RETVAL
}
status() {
echo ".:. Checking ejabberd status:"
ejabberdctl status
return $RETVAL
}
restart() {
echo ".:. Restarting ejabberd..."
ejabberdctl restart
sleep 5
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
restart
;;
*)
echo "Usage: ejabberd {start|stop|status|restart}"
exit 1
;;
esac
exit $RETVAL
…and:
[root@CentOS ~]$ chkconfig --add ejabberd
### run ejabberd at system startup
[root@CentOS ~]$ chkconfig ejabberd on|off
### manage ejabberd service
[root@CentOS ~]$ service ejabberd {start|stop|status|restart}
.:. Systemd unit script
Ejabberd source code also include a systemd unit script, it is named
ejabberd.service
and can be found in the root of the tar archive.
To install it simply copy it in the right directory:
cp ejabberd.service /etc/systemd/system/multi-user.target.wants/
…and:
### run ejabberd at system startup
[root@CentOS ~]$ systemctl enable|disable ejabberd
### manage ejabberd service
[root@CentOS ~]$ ejabberdctl {start|stop|status|restart}
.:. Logrotate logs
In case it is not installed by default install logrotate.
[root@CentOS ~]$ yum install logrotate
Define how the rotation will happen:
[root@CentOS ~]$ vi /etc/logrotate.d/ejabberd
---
/usr/local/var/log/ejabberd/ejabberd.log {
weekly
missingok
rotate 10
compress
delaycompress
ifempty
nomail
sharedscripts
postrotate /usr/local/sbin/ejabberdctl --node ejabberd reopen-log > /dev/null
endscript
}
.:. Troubleshooting
If for some reason ejabberd fail to start check out this page:
Erlang cookie
Erlang cookie file (placed in /root/ in my case) must be chmodded to 600 and
owned by ejabberd
user and group.
Another useful resource is the official installation and configuration guide:
Ejabberd documentation.
.:. Automating ejabberd upgrading procedure with Ansible
Refer to: Ansible Ejabberd upgrade procudure.
.:. Clients
The one I suggest to use is Conversations on
Android, ChatSecure on iOS and Gajim on non botnet devices.
Everyone of these three clients are free open source libre software and works
really well with ejabberd.