Ex
Application Infrastructure Azure

ejabberd XMPP Server on Ubuntu 24.04 on Azure User Guide

| Product: ejabberd XMPP Server on Ubuntu 24.04 LTS on Azure

Overview

ejabberd is a robust, scalable, open source XMPP and Jabber server for real time messaging: one to one chat, presence, group chat rooms (MUC), publish and subscribe, and server to server federation. Install the cloudimg image and you have your own private chat server that any standard XMPP client can connect to, with a built in web admin console for managing virtual hosts, users and rooms. The image installs ejabberd 26.04 from the official ProcessOne package (which bundles its own Erlang runtime) and runs it as the dedicated ejabberd system service. Client connections use port 5222 (c2s) and federation uses port 5269 (s2s). The web admin console is bound to the loopback connector 127.0.0.1:5280, and nginx on port 80 reverse proxies to it with the WebSocket upgrade that ejabberd's XMPP over WebSocket and BOSH endpoints require, plus an unauthenticated health endpoint. The Mnesia database that holds your users, rooms and rosters lives on a dedicated Azure data disk. A unique admin password is generated on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • ejabberd 26.04 installed from the official ProcessOne package and run as the ejabberd system service
  • The built in Mnesia database (no external database required) on a dedicated Azure data disk at /var/lib/ejabberd
  • The web admin console bound to 127.0.0.1:5280, fronted by nginx on port 80 with the WebSocket upgrade for the /ws and /bosh endpoints
  • Port 80 serving an unauthenticated /healthz endpoint for load balancer probes
  • XMPP client to server on port 5222 (STARTTLS) and server to server federation on port 5269
  • A unique admin account generated on first boot, the full JID admin@localhost, recorded in a root only file
  • ejabberd.service + nginx.service as systemd units, enabled and active
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a reasonable starting point; size up for more concurrent users and rooms. NSG inbound: allow 22/tcp from your management network, 80/tcp (and 443/tcp if you add TLS) for the web admin, 5222/tcp for XMPP clients, and 5269/tcp for server to server federation. The web admin is served over plain HTTP by default, so for production put your own domain and a trusted certificate in front of it (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for ejabberd by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). After creation, add inbound rules for 5222 (XMPP clients) and 5269 (federation). Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name ejabberd \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name ejabberd --port 80   --priority 1010
az vm open-port --resource-group <your-rg> --name ejabberd --port 5222 --priority 1020
az vm open-port --resource-group <your-rg> --name ejabberd --port 5269 --priority 1030

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active ejabberd.service nginx.service
sudo -u ejabberd -H /usr/sbin/ejabberdctl status
ss -tlnp | grep -E '5222|5269|5280'

Both services report active and ejabberdctl status reports the node is started. ejabberd listens on port 5222 for XMPP clients and 5269 for federation, while the web admin listens only on the loopback address 127.0.0.1:5280 and is fronted by nginx on port 80.

ejabberd.service and nginx.service active, the ejabberd node started, and the 5222 client, 5269 federation and loopback 5280 web admin listeners

Step 5 - Retrieve your admin password

The ejabberd admin password is generated uniquely on the first boot of your VM and written to a root only file:

sudo cat /root/ejabberd-credentials.txt

This file contains EJABBERD_ADMIN_JID (the full JID admin@localhost), EJABBERD_PASSWORD and the web admin URL. Store the password somewhere safe. The file is mode 0600 and owned by root, so only an administrator can read it. The Mnesia database that holds your users and rooms lives on the dedicated Azure data disk mounted at /var/lib/ejabberd.

The ejabberd node started, the Mnesia spool on the dedicated data disk at /var/lib/ejabberd, and the root only 0600 credentials file with the per-VM admin JID and password

Step 6 - Confirm the health endpoints

nginx serves an unauthenticated health endpoint for load balancers and probes, and challenges the web admin for authentication:

curl -s http://localhost/healthz
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/healthz
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/admin/

/healthz returns ok with HTTP 200 and never requires authentication, so it is safe for an Azure Load Balancer health probe. The web admin at /admin/ returns HTTP 401 until you supply credentials.

The nginx health endpoint returning ok with HTTP 200 on port 80, and the web admin at /admin/ returning HTTP 401 until credentials are supplied

Step 7 - Verify authentication from the command line

The web admin uses HTTP Basic Auth with the full JID admin@localhost as the username. The check below authenticates with the correct per-VM password and reaches the console (HTTP 200), while a wrong password is rejected (HTTP 401). Because the command embeds your unique password, run it interactively rather than from a script; substitute the value of EJABBERD_PASSWORD from Step 5 for <EJABBERD_PASSWORD>:

curl -s -o /dev/null -w 'correct password -> HTTP %{http_code}\n' \
  -u 'admin@localhost:<EJABBERD_PASSWORD>' http://localhost/admin/
curl -s -o /dev/null -w 'wrong password   -> HTTP %{http_code}\n' \
  -u 'admin@localhost:wrong' http://localhost/admin/

The correct per-VM password prints HTTP 200 (reached the admin console); a wrong password prints HTTP 401 (rejected).

The admin authentication round trip: the correct per-VM password reaches the web admin with HTTP 200 and a wrong password is rejected with HTTP 401

Step 8 - Sign in to the web admin

Browse to http://<vm-public-ip>/admin/. The browser shows an HTTP authentication prompt: enter the full JID admin@localhost as the username and the password from Step 5. You land on the ejabberd Web Admin, which lists your virtual hosts and cluster nodes. From here you manage everything: users, rooms, access rules and server internals.

The ejabberd Web Admin main page after signing in, showing the virtual hosts and cluster nodes

Step 9 - Open your virtual host

Click the localhost virtual host to see its overview: the number of registered users, online users, shared rosters and the modules serving this host. The default served domain is localhost; to serve a real public domain, see Maintenance. Everything a user's JID belongs to (for example alice@localhost) is managed under this virtual host.

The localhost virtual host overview in the ejabberd Web Admin, showing registered users, online users and the host modules

Step 10 - Register users

Open Users under the virtual host to list existing accounts and register new ones. Enter a username and password to create a JID such as alice@localhost; that user can then sign in from any XMPP client. You can also register users from the command line:

sudo -u ejabberd -H /usr/sbin/ejabberdctl register alice localhost 'a-strong-password'

The Users management page in the ejabberd Web Admin, where you list and register accounts for the virtual host

Step 11 - Inspect the node

Open the node (for example ejabberd@localhost) to see server internals: the database tables, backend statistics, the running modules and the Erlang virtual machine. This is where you confirm the Mnesia backend and monitor the health of the node.

The ejabberd node page in the Web Admin, showing the database tables and backend statistics for ejabberd@localhost

Step 12 - Connect an XMPP client

Point any XMPP client (for example Gajim, Conversations, Dino or Pidgin) at your server. Sign in with a JID you registered, such as alice@localhost, and the password you set. Set the connection server or host to the VM's public IP address and use port 5222; the appliance requires STARTTLS on client connections. To chat between servers, ejabberd federates over port 5269 (server to server). Create group chat rooms from a client that supports Multi User Chat, or manage them from the web admin.

Step 13 - Confirm data lives on the dedicated disk

ejabberd's data, the Mnesia database that holds your registered users, rooms, rosters and offline messages, is stored under /var/lib/ejabberd on the dedicated Azure data disk, so it survives OS changes and can be resized independently:

findmnt /var/lib/ejabberd

The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM.

Maintenance

  • Password: the admin password is set on first boot. To change it, sign in to the web admin, or run sudo -u ejabberd -H /usr/sbin/ejabberdctl change_password admin localhost '<new-password>'.
  • Serve a real domain: the default served XMPP domain is localhost. For production, set your public domain in the hosts: list in /opt/ejabberd/conf/ejabberd.yml, register an admin@<yourdomain> account, add it to the admin ACL, and restart ejabberd.service. Configure DNS SRV records (_xmpp-client._tcp and _xmpp-server._tcp) for federation.
  • TLS and certificates: the appliance serves the web admin over plain HTTP on port 80 and ejabberd generates a self signed certificate for client STARTTLS. For production, point a DNS name at the VM, obtain a trusted certificate (for example with certbot / Let's Encrypt), list it under certfiles: in ejabberd.yml, and front the web admin with nginx TLS on port 443.
  • Chat rooms (MUC): Multi User Chat is enabled; create and administer rooms from an XMPP client or the web admin. Rooms and their archives are stored in the Mnesia database on the data disk.
  • Federation: server to server is enabled on port 5269 with STARTTLS optional; open the port in your NSG to chat with users on other XMPP servers.
  • Upgrades: ejabberd is installed under /opt/ejabberd; upgrade with the ProcessOne package and restart ejabberd.service. Your data under /var/lib/ejabberd is preserved.
  • Storage: all ejabberd state lives under /var/lib/ejabberd on the data disk; back up that volume to protect your users, rooms and history.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.