XMPP Academy

Docker: Keep ejabberd automagically updated with Watchtower

Learn how to set up ejabberd with Docker, automate updates with Watchtower, and maintain control of updates for a secure and stable server setup.

Adrien
· 4 min read
Send by email

This blog post will guide you through the process of setting up an ejabberd Community Server using Docker and Docker Compose, and will also introduce Watchtower for automatic updates. This approach ensures that your configuration remains secure and up to date.

Furthermore, we will examine the potential risks associated with automatic updates and suggest Diun as an alternative tool for notification-based updates.

1. Prerequisites

Please ensure that Docker and Docker Compose are installed on your system.
It would be beneficial to have a basic understanding of Docker concepts, including containers, volumes, and bind-mounts.

2. Set up ejabberd in a docker container

Let’s first create a minimal Docker Compose configuration to start an ejabberd instance.

2.1: Prepare the directories

For this setup, we will create a directory structure to store the configuration, database, and logs. This will assist in maintaining an organised setup, facilitating data management and backup.

mkdir ejabberd-setup && cd ejabberd-setup
touch docker-compose.yml
mkdir conf
touch conf/ejabberd.yml
mkdir database
mkdir logs

This should give you the following structure:

ejabberd-setup/
├── conf
│   └── ejabberd.yml
├── database
├── docker-compose.yml
└── logs

To verify the structure, use the tree command. It is a very useful tool which we use on a daily basis.

Set permissions

Since we'll be using bind mounts in this example, it’s important to ensure that specific directories (like database and logs) have the correct permissions for the ejabberd user inside the container (UID 9000, GID 9000).

Customize or skip depending on your needs:

sudo chown -R 9000:9000 database
sudo chown -R 9000:9000 logs

Based on this Issue.

2.2: The docker-compose.yml file

Now, create a docker-compose.yml file inside, containing:

services:
  ejabberd:
    image: ejabberd/ecs:latest
    container_name: ejabberd
    ports:
      - "5222:5222"  # XMPP Client
      - "5280:5280"  # Web Admin Interface, optional
    volumes:
      - ./database:/home/ejabberd/database
      - ./ejabberd.yml:/home/ejabberd/conf/ejabberd.yml
      - ./logs:/home/ejabberd/logs
    restart: unless-stopped

2.3: The ejabberd.yml file

A basic configuration file for ejabberd will be required. we will name it conf/ejabberd.yml.

loglevel: 4
hosts:
- "localhost"

acl:
  admin:
    user:
      - "admin@localhost"

access_rules:
  local:
    allow: all

listen
  -
    port: 5222
    module: ejabberd_c2s

  -
    port: 5280                       # optional
    module: ejabberd_http            # optional
    request_handlers:                # optional
      "/admin": ejabberd_web_admin   # optional

Did you know? Since 23.10, ejabberd now offers users the option to create or update the relevant MySQL, PostgreSQL or SQLite tables automatically with each update. You can read more about it here.

3: Starting ejabberd

Finally, we're set: you can run the following command to start your stack: docker-compose up -d

Your ejabberd instance should now running in a Docker container! Good job! 🎉

From there, customize ejabberd to your liking! Naturally, in this example we're going to keep ejabberd in its barebones configuration, but we recommend that you configure it as you wish at this stage, to suit your needs (Domains, SSL, favorite modules, chosen database, admin accounts, etc.)

Example: You could register your admin account at this stage

To use the admin interface, you need to create an admin account. You can do so by running the following command:

$ docker exec -it ejabberd bin/ejabberdctl register admin localhost very_secret_password
> User admin@localhost successfully registered

Once this step is complete, you will then be able to access the web admin interface at http://localhost:5280/admin.

4. Set up automatic updates

Finally, we come to the most interesting part: how do I keep my containers up to date?

To keep your ejabberd instance up-to-date, you can use Watchtower, a Docker container that automatically updates other containers when new versions are available.

Warning: Auto-updates are undoubtedly convenient, but they can occasionally cause issues if an update includes breaking changes. Always test updates in a staging environment and back up your data before enabling auto-updates. Further information can be found at the end of this post.

If greater control over updates is required (for example, for mission-critical production servers or clusters), we recommend using Diun, which can notify you of available updates and allow you to decide when to apply them.

4.1: Add Watchtower to your docker-compose.yml

To include Watchtower, add it as a service in docker-compose.yml:

services:
  ejabberd:
    image: ejabberd/ecs:latest
    container_name: ejabberd
    ports:
      - "5222:5222"  # XMPP Client
      - "5280:5280"  # Web Admin Interface, optional
    volumes:
      - ./database:/home/ejabberd/database
      - ./ejabberd.yml:/home/ejabberd/conf/ejabberd.yml
      - ./logs:/home/ejabberd/logs
    restart: unless-stopped

  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_POLL_INTERVAL=3600 # Sets how often Watchtower checks for updates (in seconds).
      - WATCHTOWER_CLEANUP=true # Ensures old images are cleaned up after updating.
    restart: unless-stopped

Watchtower offers a wide range of additional features, including the ability to set up notifications, exclude specific containers, and more. For further information, please refer to the Watchtower Docs.

Once the docker-compose.yml has been updated, please bring it up using the following command: docker-compose up -d

And.... here you go, you're all set!

5. Best Practices & closing words

Now Watchtower will now perform periodic checks for updates to your ejabberd container and apply them automatically.

Well to be fair, by default if other containers are running on the same server, Watchtower will also update them. This behaviour can be controlled with the help of environment variables (see Container Selection), which will assist in excluding containers from updates.


One important thing to understand is that Watchtower will only update containers tagged with the :latest tag.

In an environment with numerous Docker containers, using the latest tag streamlines the process of automatic updates. However, it may introduce unanticipated changes with each new, disruptive update. Ideally, we recommend always setting a speficic version like ejabberd/ecs:24.10 and deciding how/when to update it manually (especially if you're into infra-as-code).

However, we recognise that some users may prefer the convenience of automatic updates, personnally that's what I do my homelab but I'm not scared to dig in if stuff breaks.


tl;dr: For a small community server/homelab/personnal instance, Watchtower will help keep things up to date with minimal effort. However, for bigger production environments, it is advisable to tag specific versions to ensure greater control and resilience and update them manually.

With this setup, you now have a fully functioning XMPP server using ejabberd, with automatic updates. You can now start building your chat applications or integrate it with your existing services! 🚀