ejabberd XMPP Server on Ubuntu 24.04 on Azure User Guide
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
ejabberdsystem 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/wsand/boshendpoints - Port 80 serving an unauthenticated
/healthzendpoint 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.serviceas 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.

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.

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.

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).

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.

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.

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'

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.

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 thehosts:list in/opt/ejabberd/conf/ejabberd.yml, register anadmin@<yourdomain>account, add it to theadminACL, and restartejabberd.service. Configure DNS SRV records (_xmpp-client._tcpand_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:inejabberd.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 restartejabberd.service. Your data under/var/lib/ejabberdis preserved. - Storage: all ejabberd state lives under
/var/lib/ejabberdon 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.