ejabberd

ejabberd is a distributed, fault-tolerant technology that allows the creation of large-scale instant messaging applications. The server can reliably support thousands of simultaneous users on a single node and has been designed to provide exceptional standards of fault tolerance. As an open source technology, based on industry-standards, ejabberd can be used to build bespoke solutions very cost effectively.


Note

For this guide you should be familiar with the basic concepts of

This guide is based on the initial pull request from fm0de and the work from clerie.

Installation

Download, configure, compile and install ejabberd. Use the following options for ./configure:

  • --prefix=$HOME/: Install to your personal uberspace

  • --enable-user=$USER: Allow execution of ejabberd as $USER

  • --enable-mysql --enable-new-sql-schema: optionally compile with mysql support and use the new schema

Run ./configure --help to see all options.

[isabell@stardust ~]$ wget https://github.com/processone/ejabberd/archive/20.04.tar.gz
[isabell@stardust ~]$ tar xf 20.04.tar.gz
[isabell@stardust ~]$ cd ejabberd-20.04/
[isabell@stardust ejabberd-20.04]$ ./autogen.sh
[isabell@stardust ejabberd-20.04]$ ./configure --enable-user=$USER --prefix=$HOME/opt/ejabberd --enable-mysql --enable-new-sql-schema
[isabell@stardust ejabberd-20.04]$ make install

The files will be installed to the following locations:

  • ~/sbin/: executables (ejabberdctl)

  • ~/etc/ejabberd/: configuration files (mainly ejabberd.yml)

  • ~/var/lib/ejabberd/: runtime files including internal mnesia database

  • ~/var/log/ejabberd/: logfiles

Basic Configuration

A standard config file is provided at ~/etc/ejabberd/ejabberd.yml. Adjust it with correct settings as explained in the next sections.

This section covers only the basic configuration to get ejabberd up and running. See below for additional security and configuration best practices. Any option that is not covered here can be found at the ejabberd documentation.

Domains

Your ejabberd domain isabell.example needs to be setup. We will additionally use the following subomains:

  • conference.isabell.example: Multi-user chat rooms

  • proxy.isabell.example: File transfer proxy

  • pubsub.isabell.example: PubSub

  • xmpp.isabell.example: Web-based features like file uploads and web sockets

Run the following commands to register the domains:

[isabell@stardust ~]$ uberspace web domain add isabell.example
[isabell@stardust ~]$ uberspace web domain add conference.isabell.example
[isabell@stardust ~]$ uberspace web domain add proxy.isabell.example
[isabell@stardust ~]$ uberspace web domain add pubsub.isabell.example
[isabell@stardust ~]$ uberspace web domain add xmpp.isabell.example

Change the host configuration to listen for your domain:

 hosts:
   - "isabell.example"

TLS Certificates

We also need the TLS certificates which are fetched by Uberspace when visiting the domains, either in a browser or by running the following commands:

[isabell@stardust ~]$ curl https://isabell.example
[isabell@stardust ~]$ curl https://conference.isabell.example
[isabell@stardust ~]$ curl https://proxy.isabell.example
[isabell@stardust ~]$ curl https://pubsub.isabell.example
[isabell@stardust ~]$ curl https://xmpp.isabell.example

Provide location of your keys and certificates:

 certfiles:
   - "/home/isabell/etc/certificates/isabell.example.crt"
   - "/home/isabell/etc/certificates/isabell.example.key"
   - "/home/isabell/etc/certificates/conference.isabell.example.crt"
   - "/home/isabell/etc/certificates/conference.isabell.example.key"
   - "/home/isabell/etc/certificates/proxy.isabell.example.crt"
   - "/home/isabell/etc/certificates/proxy.isabell.example.key"
   - "/home/isabell/etc/certificates/pubsub.isabell.example.crt"
   - "/home/isabell/etc/certificates/pubsub.isabell.example.key"
   - "/home/isabell/etc/certificates/xmpp.isabell.example.crt"
   - "/home/isabell/etc/certificates/xmpp.isabell.example.key"

Disable ACME to avoid ejabberd logging a warning:

acme:
  auto: false

Firewall Ports

In the basic configuration ejabberd needs five open ports: two for client-to-server (c2s), two for server-to-server (s2s), and one for the file transfer proxy. HTTP connections are handled by a web backend.

To make the application accessible from the outside, open a port in the firewall:

[isabell@stardust ~] uberspace port add
Port 40132 will be open for TCP and UDP traffic in a few minutes.
[isabell@stardust ~]$

Change the port numbers to the opened ports:

 listen:
   - # c2s
     port: <port-1>
     ip: "::"
     module: ejabberd_c2s
     
   - # 'secure' c2s
     port: <port-2>
     ip: "::"
     module: ejabberd_c2s
     tls: true
     
   - # s2s
     port: <port-3>
     ip: "::"
     module: ejabberd_s2s_in
     
   - # 'secure' s2s
     port: <port-4>
     ip: "::"
     module: ejabberd_s2s_in
     tls: true
     

DNS Records

Since standard ports cannot be used on Uberspace DNS records must be set for c2s and s2s connections. Refer to the XMPP wiki for setup and point them to the corresponding ports.

_xmpp-client._tcp.isabell.example. 86400 IN SRV 5 0 <port-1> isabell.example.
_xmpps-client._tcp.isabell.example. 86400 IN SRV 4 0 <port-2> isabell.example.
_xmpp-server._tcp.isabell.example. 86400 IN SRV 5 0 <port-3> isabell.example.
_xmpps-server._tcp.isabell.example. 86400 IN SRV 4 0 <port-4> isabell.example.

File Transfer Proxy

Configure mod_proxy65 by setting the host and port values:

modules:
  
  mod_proxy65:
    access: local
    max_connections: 5
    host: "proxy.isabell.example"
    name: "File Transfer Proxy"
    ip: "::"
    port: <port-5>
  

Web-based Features

For web-based features like file uploads and web sockets adjust the configuration to listen on port 5443 without TLS:

listen:
  
  -
    port: 5443
    ip: "::"
    module: ejabberd_http
    #tls: true
    request_handlers:
      "/admin": ejabberd_web_admin
      "/api": mod_http_api
      "/bosh": mod_bosh
      "/captcha": ejabberd_captcha
      "/upload": mod_http_upload
      "/ws": ejabberd_http_ws
  

Additionally create a web-backend for xmpp.isabell.example/ on port 5443.

To make the application accessible from the outside, configure a web backend:

[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$

HTTP File Upload

Configure the put_url and the doc_root settings for mod_http_upload to match the domain and your user folder:

modules:
  
  mod_http_upload:
    put_url: "https://xmpp.@HOST@/upload"
    file_mode: "0640"
    dir_mode: "2750"
    max_size: 104857600 # 100 MB
    access: local
    thumbnail: false
    docroot: "/home/isabell/ejabberd/uploads"
    secret_length: 40
 

Password Hashing

ejabberd defaults to plain text passwords so the following two lines need to be added to enable scram:

auth_method: internal
auth_password_format: scram

Reduce Loglevel

By default ejabberd does verbose logging. This can be useful for testing different configuration options. When taking your ejabberd instance to production you can reduce the logging by setting the loglevel to warning:

loglevel: warning

Admin User

Configure your admin user (which will be created later):

acl:
  admin:
    user:
      - "admin@isabell.example"
  local:
    user_regexp: ""
  loopback:
    ip:
      - "127.0.0.0/8"
      - "::1/128"

MQTT

Disable MQTT by commenting out the listener for module mod_mqtt:

listen:
  
  #-
  #  port: 1883
  #  ip: "::"
  #  module: mod_mqtt
  #  backlog: 1000
  

Additionally comment out the module itself:

modules:
  
  #mod_mqtt: {}
  

MySQL

For a production server it is recommended to store users, messages and data of other modules in a MySQL database instead of the mnesia database. To use MySQL make sure to include the corresponding options during compilation.

You’ll need your MySQL credentials. Get them with my_print_defaults:

[isabell@stardust ~]$ my_print_defaults client
--default-character-set=utf8mb4
--user=isabell
--password=MySuperSecretPassword
[isabell@stardust ~]$

Create an additional database with the name isabell_ejabberd and import the new database schema:

[isabell@local ~]$ mysql isabell_ejabberd < ~/ejabberd-20.04/sql/mysql.new.sql

Configure ejabberd to use the MySQL database:

sql_type: mysql
sql_server: "localhost"
sql_database: "isabell_ejabberd"
sql_username: "isabell"
sql_password: "MySuperSecretPassword"
sql_pool_size: 5
default_db: sql

Additionally adjust the configuration of the proxy65 module:

module:
  
  mod_proxy65:
    
    name: "File Transfer Proxy"
    
    ram_db_type: sql
    
  

Compliance Configuration

The following configuration settings are not needed for basic operation but are reuqired to pass the Compliance Test. It is based on ProcessOne’s blog post How to configure ejabberd to get 100% in XMPP compliance test.

HTTP File Upload: CORS

As specified in XEP-0363 the Cross-Origin Request Sharing (CORS) header needs to be set for HTTP file upload. This can be done by adding the following web headers:

Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET,HEAD,PUT,OPTIONS
Access-Control-Allow-Origin: https://xmpp.isabell.example

Contact Addresses

As specified in XEP-0157 configure a contact addresses for abuse of the service:

modules:
  
  mod_disco:
    server_info:
      -
        modules: all
        name: "abuse-addresses"
        urls:
          - "mailto:abuse@isabell.example"
  

If you like, do the same for the names “support-addresses” and “admin-addresses”.

Alternative Connection Methods

XEP-0156 defines the discovering of alternative XMPP connection methods which refer to the HTTP-based features BOSH and web sockets. To pass this compliance test two steps are required.

First, create the following DNS record:

_xmppconnect TXT [ _xmpp-client-websocket=wss://xmpp.isabell.example:443/ws ] 3600

Second, create the file ~/html/.well-known/host-meta with the following content:

<?xml version='1.0' encoding='utf-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
    <Link rel="urn:xmpp:alt-connections:xbosh" href="https://xmpp.isabell.example/bosh" />
    <Link rel="urn:xmpp:alt-connections:websocket" href="wss://xmpp.isabell.example/ws" />
</XRD>

And create the file ~/html/.well-known/host-meta.json with the following content:

{
  "links": [
    {
      "rel": "urn:xmpp:alt-connections:xbosh",
      "href": "https://xmpp.isabell.example/bosh"
    },
    {
      "rel": "urn:xmpp:alt-connections:websocket",
      "href": "wss://xmpp.isabell.example/ws"
    }
  ]
}

STUN Server

ejabberd has built-in support for STUN and TURN. First, open two new firewall ports.

To make the application accessible from the outside, open a port in the firewall:

[isabell@stardust ~] uberspace port add
Port 40132 will be open for TCP and UDP traffic in a few minutes.
[isabell@stardust ~]$

Next, add the following DNS records:

_stun._udp SRV 0 <port-6> isabell.example 3600
_stun._tcp SRV 0 <port-6> isabell.example 3600
_stuns._tcp SRV 0 <port-7> isabell.example 3600

Finally configure the mod_stun_disco module:

modules:
  
  mod_stun_disco:
    credentials_lifetime: 12h
    services:
      -
        host: "@HOST@"
        port: <port-6>
        transport: udp
        type: stun
        restricted: true
      -
        host: "@HOST@"
        port: <port-6>
        transport: tcp
        type: stun
        restricted: true
      -
        host: "@HOST@"
        port: <port-7>
        transport: tcp
        type: stuns
        restricted: true

Security Configuration

The following configuration settings are not needed for basic operation but improve the security of your server.

Sensitive Data

To hide sensitive data like IP addresses from logfiles add the following line to the configuration file:

hide_sensitive_log_data: true

Admin Interface

By default the the web-based admin interface is publicly available together with the other web-based features on port 5443. For better security it is recommended to run it on a separate port that is not exposed to the public.

To do this, comment out the /admin route on the HTTP listener:

listen:
  
  -
    port: 5443
    ip: "::"
    module: ejabberd_http
    tls: false
    request_handlers:
      #/admin: ejabberd_web_admin
      /api: mod_http_api
      /bosh: mod_bosh
      /captcha: ejabberd_captcha
      /upload: mod_http_upload
      /ws: ejabberd_http_ws
  

Add a separate listener on a differet port (e. g. 5280):

listen:
  
  -
    port: 5280
    ip: "::"
    module: ejabberd_http
    request_handlers:
      /admin: ejabberd_web_admin
  

The admin interface can then be accessed from your local machine via SSH port forward:

[isabell@local ~]$ ssh -L 5280:localhost:5280 isabell@stardust.uber.space -N

File Upload Quota

To limit the size of uploaded files add the module mod_http_upload_quote to the modules configuration and set the max_days parameter to an appropriate value:

modules:
  
  mod_http_upload_quota:
    max_days: 14
  

Strong TLS Options

To disable old TLS versions and to use only strong ciphers add the following top-level configuration options:

c2s_protocol_options:
  - "no_sslv3"
  - "no_tlsv1"
  - "no_tlsv1_1"
  - "cipher_server_preference"
  - "no_compression"
c2s_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"
s2s_use_starttls: required
s2s_protocol_options:
  - "no_sslv3"
  - "no_tlsv1"
  - "no_tlsv1_1"
  - "cipher_server_preference"
  - "no_compression"
s2s_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"

Additionally enforce StartTLS for he c2s listener:

 listen:
   
   - # c2s
     port: <port-1>
     ip: "::"
     module: ejabberd_c2s
     starttls: true
     starttls_required: true
   

OS Version

To stop ejabberd from exposing details about the Operating System adjust the configuration of the mod_version module:

 modules:
   
   mod_version:
     show_os: false
   

Startup

The next step is to bring your ejabberd online and start using it.

Setup Daemon

Create a supervisord service by adding the following content to the new file ~/etc/services.d/ejabberd.ini:

[program:ejabberd]
command=%(ENV_HOME)s/sbin/ejabberdctl --config-dir %(ENV_HOME)s/etc/ejabberd foreground
autostart=yes
autorestart=yes
stopasgroup=true
killasgroup=true
stopsignal=INT

After creating the configuration, tell supervisord to refresh its configuration and start the service:

[isabell@stardust ~]$ supervisorctl reread
SERVICE: available
[isabell@stardust ~]$ supervisorctl update
SERVICE: added process group
[isabell@stardust ~]$ supervisorctl status
SERVICE                            RUNNING   pid 26020, uptime 0:03:14
[isabell@stardust ~]$

Administrator User

Register your administrator user:

[isabell@stardust ~]$ ~/sbin/ejabberdctl register admin isabell.example <password>

Maintenance

Note

Check the update feed regularly to stay informed about the newest version.

Backups

Backup the following directories:

  • ~/etc/ejabberd/

  • ~/var/lib/ejabberd/

  • ~/var/log/ejabberd/

If you use MySQL, additionally backup the MySQL database:

[isabell@stardust ~]$ mysqldump isabell_ejabberd | xz - > ~/isabell_ejabberd.sql.xz

Updates

Check ejabberd’s releases for the latest version. If a newer version is available, repeat the “Installation” step, stop the daemon, merge changes on the configuration file and start the daemon again:

[isabell@stardust ~]$ supervisorctl stop ejabberd
[isabell@stardust ~]$ nvim -d ~/etc/ejabberd/ejabberd.yml-new ~/etc/ejabberd/ejabberd.yml
[isabell@stardust ~]$ supervisorctl start ejabberd

Additionally check the release notes for the new version which you will find at the upgrade documentation. Changes to the database schema are included there as well.

Logfiles

Regularely check the logfiles at ~/var/log/ejabberd/, especially error.log.


Tested with ejabberd 20.04 and Uberspace 7.7.0.

Written by: fm0de, jo-mei, coderkun