ejabberd + Biboumi + Docker = 🌞💬

Dominik e08a86e094 fixed typo 2 years ago
.vscode b7a2093bbd initial 2 years ago
EXTRAS 660327c557 references cleaned up 2 years ago
data 4b367b76cf added content types 2 years ago
.env.example e08a86e094 fixed typo 2 years ago
.gitignore 8770b6a44b fixed/reworked setting hostname/ip config 2 years ago
LICENSE 3981f316eb removed (c) 2 years ago
README.md 0049b2c7de fixed macro syntax error 2 years ago
RELEASE.md bddabd12f8 updated TASKS/RELEASE 2 years ago
TASKS.md bddabd12f8 updated TASKS/RELEASE 2 years ago
docker-compose.yml 089bad5c84 added redirect for webchat 2 years ago
entrypoint.sh 91c43f3945 added generator for xep-0156 discovery files 2 years ago

README.md

Dockerized XMPP with IRC gateway

This setup packs all necessary configurations to run an ejabberd XMPP Server with a Biboumi IRC Gateway. Just put your IP and hostname in the .env file, fire up docker-compose and you're good to go! The whole service lives in a single folder to ease backup and migration. All persistent data is stored in ./data/. The configuration was crowd-sourced, for more details, see EXTRAS/reference-configurations.

Used docker images

  • This setup uses ejabberd/ecs from the ProcessOne ejabberd developers. The underlying Dockerfile builds the server from source and installs it into a Alpine image. The server runs as unprivileged user (uid 9000). This image doesn't come with many parameters or helper scripts, so all configurations are made in the ejabberd.yml configuration file. rroemhild/docker-ejabberd wasn't used as it didn't run reliably for me in July 2018. Still it is worth to take a look and learn from the used parameters and helper scripts.
  • Biboumi runs from louiz/biboumi. The image is provided by the Biboumi developer himself and only contains the binary as it is based on FROM scratch. All parameters are set using environment variables defined in docker-compose.yml. The server runs under a unprivileged user (uid 1000).

Prerequisites

It is assumed that on the docker host we're already running

  1. a jwilder/nginx-proxy reverse proxy
  2. together with jrcs/letsencrypt-nginx-proxy-companion to obtain letsencrypt TLS certificates,
  3. as well as watchtower to keep images up-to-date.

Design decisions:

  1. One host per instance / no vhosts
  2. No cluster setup
  3. Turn key, only need to set IP and hostname in .env
  4. Compliance with https://compliance.conversations.im/
  5. External acme client – for more flexibility when serving other containers on the same host. (Port 80 can be bound only once, so there can be only one acme client per host.)
  6. Limited administration to ejabberdctl. Disabled in-band registration, web administration and the web API.

Startup process

  • ejabberd
    • The ejabberd image starts with a modified entrypoint.sh which generates the file ~/ env.yml based on variables set in .env
    • ejabberd starts with ~/conf/ejabberd.yml which includes the configurations from ~/conf/conf.d/ and ~/ env.yml from above
  • Certificates
    • letsencrypt-nginx-proxy-companion obtains the Let's Encrypt Certificates based on the environment variables set in docker-compose.yml. The hostname is set in .env, so no need to modify docker-compose.yml.

Backup

cronjob one-liner, running in the ejabberd container, dumps daily the ejabberd DB into ./data/backup/.

Open Ports

Marked [x] ports will be opened on the Docker host, so they should not be used by another service on the same host.

  • 5222:5222 Client 2 Server — bare minimum to speak with clients
  • 5223:5223 XMPP over TLS is actually deprecated, instead STARTTLS on port 5222 should be used. It is active for backward compatibility or could be moved to port 443 to ease usage behind firewalls.
  • 5269:5269 Server 2 Server — only needed when we want to speak with users from other servers
  • 5280:5280 Web admin (disabled), BOSH and WebSocket
  • 5443:5443 HTTP Upload
  • 113:8113 Identd so IRC servers can differentiate between users
  • 443!8080 Integrated webserver to serve static content, such as a javascript xmpp client. The port is exposed via the reverse proxy.
  • 5347:5347 Only used for internal unencrypted communication with the Biboumi (IRC gateway) component
  • ----:4560 XMLRPC — API, disabled

BOSH (previously known as 'HTTP binding' or "http-bind") is a technology to use XMPP over HTTP. This allows XMPP applications to run in web pages, but also any other HTTP-only environment such as behind restrictive firewalls.

Used volumes

ejabber runs under user ejabberd with uid/guid 9000. All data is stored in /home/ejabberd/ within the container.

  • ./data/conf/ejabberd.yml — main configuration file
  • .data/database/ — Erlang DB used to store all application data
  • .data/backup/ — place to to store DB dumps
  • .data/uploads/ — files transferred between users
  • .data/cron/backup.sh — job to daily dump the DB
  • ./opt/docker/proxy/data/certs/im.example.net/ — certificates and key material (to be changed as per the local docker host setup)
  • .data/www/ — static web content
  • ./data/biboumi/database/ — sqlite DB for Biboumi. The Biboumi configuration is defined via environment variables in docker-compose.yml.

Installation & Configuration

  1. Clone the repo and the reverse proxy and Let's Encrypt companion) to /opt/docker.

  2. Copy .env.template to .env and setup your hostname and ip. A fixed ip is necessary to stun/turn to work.

  3. Setup DNS To allow service discovery, following DNS records have to be created.

    im                              3600 IN A               1.2.3.4
    *.im                            3600 IN CNAME           in
    #_service._proto.name TTL class SRV priority weight port target
    _xmpp-client._tcp.im.example.net.  3600 IN SRV    5 0 5222 im.example.net.
    _xmpp-clients._tcp.im.example.net. 3600 IN SRV   10 0 5223 im.example.net.
    _xmpp-server._tcp.im.example.net.  3600 IN SRV    5 0 5269 im.example.net.
    

    To check the records: https://kingant.net/check_xmpp_dns/

    1. Run docker-compose up and watch out for possible errors. If everything goes fine, re-run with -d.

    2. Create users

    ejabberd comes by default with no users. Privileges and ACLs for users are set in conf/conf.d/32-access.yml. In the default configuration file admin is set as privileged user already.

    To create new users, run from the docker host: docker exec -it ejabberd /home/ejabberd/bin/ejabberdctl register <user> <domain> <password>

    We'll need to create at least a user for the IRC gateway.

    user=ircadmin
    pass=`apg -q -n1 -m12`
    docker exec -it ejabberd /home/ejabberd/bin/ejabberdctl register $user $hostname $pass
        
    Further self-registration or LDAP authentication can be enabled in `ejabberd.yml`.
    
    1. (Optional) Run the XMPP compliance tester

      jar_file=ComplianceTester-0.2.3.jar
      dl_url=https://gultsch.de/files/$jar_file
      domain=$hostname
      docker run --rm -it --name=xmpptest openjdk:alpine \
      /bin/sh -c "wget $dl_url ; java -jar $jar_file $user@$domain $pass" \
      | tee $domain.txt
      
    2. (Optional) Setup a static website data/www/ can be used to serve a static site, e.g. for presenting compliance test results, a web xmpp client or client setup instructions

      cd $inst_dir/data/www
      git clone --depth=1 https://github.com/conversejs/converse.js.git
      mv converse.js webchat
      cp webchat/fullscreen.html webchat/index.html
      sed -i \
      -e '/analytics/d' \
      -e '/piwik/d' \
      -e "/bosh_service_url/s/conversejs.org/$hostname:5280/" \
      -e "/bosh_service_url/s/http-bind/bosh/" \
      webchat/index.html
      

Maintenance

Get a shell in the container

docker exec -it ejabberd sh

Control the server

docker exec -it ejabberd /home/ejabberd/bin/ejabberdctl \

  • registered_users <host> List all registered users in HOST
  • unregister <user> <host> List all registered users in HOST
  • modules_available List the contributed modules available to install
  • modules_installed List the contributed modules already installed
  • mnesia Get details about the database
  • reload_config Reload ejabberd configuration file into memory (this will not start new servers)
  • connected_users list connected users with their resources
  • backup /home/ejabberd/backup/ejabberd.backup Backup database
  • install_fallback /home/ejabberd/backup/ejabberd.backup restores the db and makes it active after the next restart
  • help lists available commands
Biboumi

Biboumi documentation

Check if the IRC server certificate is valid

firefox https://www.sslshopper.com/ssl-checker.html#hostname=irc.example.net:6697

Notes and pitfalls

The Node and DB name changes with the hostname

Docker's randomly generated hostnames causes ejabberd to calculate different unique node and DB name. To prevent a new DB beeing created with each container restart, use docker run --hostname <hostname> or hostname: and domainname: in the docker-compose.yml.

/opt/docker/proxy/data/certs/<hostname> should be readable by ejabberd user.

Debugging

Inspect the vanilla container: docker run --rm -it --entrypoint /bin/sh ejabberd/ecs

Dump current configuration as seen by ejabberd: docker exec ejabberd /bin/sh -c "bin/ejabberdctl dump_config ~/backup/config-dump.yml"