Wesnoth Dedicated Multiplayer Server on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of the Wesnoth 1.18 dedicated multiplayer game server on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images.
wesnothd is the dedicated multiplayer server of The Battle for Wesnoth, the open source turn based fantasy strategy game. It is the headless companion to the desktop game: your players keep using their normal Wesnoth client, change the server address from the public one to your VM, and get their own lobby where they can chat, create games, join each other and play a full match relayed through your host. The server relays the game between clients and gives whoever runs it moderator control over that lobby.
This image ships the SERVER, not the game. There is no desktop client and no graphical interface on this VM, and there is no web interface either. Everything in this guide is done over SSH, plus the in game admin commands you type from a connected Wesnoth client. Your players supply their own copy of the game.
No game content is redistributed. wesnothd is a WML relay and needs no campaigns, maps, artwork or music, so none are installed. The only Wesnoth bytes on this VM are the server binary itself and its GNU General Public License version 2 licence text under /usr/share/doc/wesnothd/.
Version compatibility matters, and it is not optional. Wesnoth's network protocol is version gated. This server is built from the 1.18.7 upstream source release and accepts the 1.18.* client series only. A 1.16 client, or a 1.19 development build, is cleanly refused with the accepted version list rather than half connecting. Ubuntu 24.04's own repository only carries the older 1.16 line, which is exactly why this image builds 1.18 from source instead.
Security by design. A public game port is the whole point of a game server, so everything else is locked down:
-
No administrator password exists in the image. The captured image contains no server configuration file at all. The moderator password is generated uniquely on your VM at first boot and written only to
/etc/wesnothd/server.cfgand a root only credentials file. Nothing is shared between customers. -
The server physically cannot start before that happens.
wesnothd.serviceis enabled so it survives reboots, but it carries two start up conditions: the first boot ready marker and the server configuration. Neither exists in the shipped image, so the game port cannot be bound by a server that has no moderator password. -
One port, and nothing else. TCP
15000is the only listener this product opens. The moderator control channel is a FIFO inside a directory readable only by root and the service account, and the configuration file holding the password is not world readable. -
The server runs unprivileged as the dedicated
wesnothdsystem account under a hardened systemd unit.
What is included:
-
wesnothd 1.18.7, built from the official upstream source release with the server target only, verified against a pinned SHA 256 checksum before extraction, running under systemd as
wesnothd.service -
A per VM moderator password generated on first boot and written to a root only credentials file
-
wesnothd-selfcheck, a bundled command that proves the server end to end by driving the real Wesnoth wire protocol as two independent clients, creating a game and relaying a lobby message -
Ubuntu 24.04 LTS, fully patched, with unattended security upgrades enabled
Key facts
| Item | Value |
|---|---|
| Platform | Ubuntu 24.04 LTS on Azure |
| Default administrative user | azureuser |
| Game port | 15000/tcp |
| Accepted client versions | 1.18.* |
| Server binary | /usr/local/bin/wesnothd |
| Server configuration | /etc/wesnothd/server.cfg |
| Per VM credentials | /root/wesnothd-credentials.txt |
Prerequisites
-
Active Azure subscription, an SSH public key, and a VNet and subnet in the target region
-
Subscription to this listing on Azure Marketplace
-
A Network Security Group allowing TCP 22 for administration and TCP 15000 for the game itself. Your players connect to
15000, so it must be reachable from wherever they are. No other port needs to be opened. -
A copy of Wesnoth 1.18.x on each player's machine. The server accepts that series only.
Recommended virtual machine size: Standard_B2s with 2 vCPU and 4 GB RAM comfortably hosts a community lobby with several concurrent games. wesnothd relays turns rather than simulating them, so it is light on CPU. For a large public server or a tournament with many simultaneous matches, choose Standard_D2s_v5 or above.
Deploy the virtual machine
Deploy from the Azure Portal by selecting the image from Azure Marketplace, choosing your VM size, and supplying your SSH public key for the azureuser account. Or deploy from the Azure CLI.
These commands run on your own workstation, not on the VM:
az vm create \
--resource-group my-resource-group \
--name my-wesnoth-vm \
--image <this-marketplace-image> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
az vm open-port --resource-group my-resource-group --name my-wesnoth-vm --port 15000
Connect over SSH once the VM is running:
ssh azureuser@<vm-ip>
Confirm the server is healthy
The server starts automatically once first boot has generated your moderator password. Check it and confirm the version:
systemctl is-active wesnothd
wesnothd --version
Expected output
active
Battle for Wesnoth server 1.18.7
Now confirm the network posture. Exactly one port belongs to this product, and it is the game port:
ss -tln | grep 15000
Expected output
LISTEN 0 4096 0.0.0.0:15000 0.0.0.0:*
LISTEN 0 4096 [::]:15000 [::]:*
That is the shape you want: 15000 reachable by your players, and nothing else added to the machine.

Retrieve your per VM credentials
The moderator password is generated on this VM's first boot and exists nowhere else. Read it as root:
sudo cat /root/wesnothd-credentials.txt
Expected output
# Wesnoth 1.18.7 dedicated multiplayer server (wesnothd) — generated on
# first boot. The administrator password below is UNIQUE to this VM. Store it
# somewhere safe; it is shown in plain text only here and in the server config.
# --- The game server your players connect to ---
WESNOTHD_URL=wesnoth://<vm-ip>:15000
wesnothd.host=<vm-ip>
wesnothd.port=15000
wesnothd.versions_accepted=1.18.*
# --- Administrator credential ---
# In a connected Wesnoth 1.18 client, type this in the lobby chat:
# /query admin <WESNOTHD_ADMIN_PASSWORD>
# The server replies "You are now recognized as an administrator." and you can
# then use /query kick, /query ban, /query motd and the rest.
wesnothd.admin_password=<WESNOTHD_ADMIN_PASSWORD>
# Players join with: Multiplayer -> Join Official Server -> change the address to
# <vm-ip>:15000
# Only Wesnoth 1.18.x clients are admitted; anything else is cleanly refused.
#
# Re-verify the whole server at any time (drives a real two-client session):
# sudo wesnothd-selfcheck
wesnothd.admin_password is the moderator password for this server and this server only. Store it somewhere safe. Anyone who has it can moderate your lobby, so treat it like a root password.
The address recorded in WESNOTHD_URL and wesnothd.host is the address of the VM's own network interface as the VM itself sees it. Azure's instance metadata service returns an empty body for Standard SKU public IP addresses, so first boot deliberately falls back to that interface address rather than writing an empty host. Your players connect on the VM's public address, which you can read at any time with az vm show ... --query publicIps, shown further down this guide. The port is 15000 either way.

Prove the server really hosts games
A listening socket is not proof that a game server works. The bundled self check drives the real Wesnoth wire protocol as two independent clients: it logs both into your lobby, confirms a client on an unsupported version is refused, relays a lobby chat message from one to the other, has the first create a multiplayer game, confirms the second sees that game advertised live in the lobby game list, round trips your moderator password against a wrong one and the real one, and checks that the control channel and the configuration file are not readable by other users on the VM.
sudo wesnothd-selfcheck
Expected output
[wesnothd-selfcheck] 1. wesnothd binary version
OK: Battle for Wesnoth server 1.18.7
[wesnothd-selfcheck] 2. game port 15000 reachable on this VM's routable address <vm-ip>
OK: TCP <vm-ip>:15000 accepts connections
[wesnothd-selfcheck] 3. host client logs in and joins the lobby
OK: cimg-host-f80d79 joined the lobby (handshake 42, version 1.18.7 accepted, [join_lobby] received)
[wesnothd-selfcheck] 4. second, independent client logs in and joins the same lobby
OK: cimg-obs-f80d79 joined the lobby alongside cimg-host-f80d79
[wesnothd-selfcheck] 5. client on an unsupported version is refused
OK: server returned [reject] with its accepted_versions list
[wesnothd-selfcheck] 6. lobby chat is relayed live from one client to the other
OK: message relayed cimg-host-f80d79 -> cimg-obs-f80d79 through the server
[wesnothd-selfcheck] 7. host creates a multiplayer game
OK: [create_game] and its [scenario] accepted for 'cloudimg selfcheck f80d79'
[wesnothd-selfcheck] 8. the second client sees the new game advertised in the lobby game list
OK: cimg-obs-f80d79 sees 'cloudimg selfcheck f80d79' advertised by the server (broadcast live)
[wesnothd-selfcheck] 9. per-VM administrator credential is accepted, a wrong one is refused
OK: wrong password refused; the per-VM password granted administrator rights
[wesnothd-selfcheck] 10. control FIFO and server configuration are not world-accessible
OK: /run/wesnothd/socket mode 640 - not world-writable
OK: /etc/wesnothd/server.cfg mode 640 - not world-readable
WESNOTHD_SELFCHECK_OK
Run this any time you want to confirm the server is genuinely serving, for example after changing the configuration or resizing the VM.

Point your players at the server
Each player needs Wesnoth 1.18.x installed. In the game:
- Choose Multiplayer from the title screen.
- Choose Join Official Server, then edit the server address, or use Connect to Server if your client offers it.
- Enter your VM's public address and port, for example
20.0.0.1:15000. - Pick any username and connect. There is no registration on this server, so any name that is not already in use is accepted.
Players land in your lobby, where they can create a game, join one another and start playing. The WESNOTHD_URL line in the credentials file is the same address in the wesnoth:// form that recent clients accept directly.
Find the public address of the VM at any time from your own workstation:
az vm show --resource-group my-resource-group --name my-wesnoth-vm \
--show-details --query publicIps --output tsv
Moderate the lobby from inside the game
Connect with any Wesnoth 1.18 client, then type this in the lobby chat, substituting the password from your credentials file:
/query admin <WESNOTHD_ADMIN_PASSWORD>
The server replies You are now recognized as an administrator. and your client gains moderator rights. A wrong password is refused with Error: wrong password, and the attempt is logged on the server.
Once recognised you can use the moderation commands from the lobby chat:
| Command | What it does |
|---|---|
/query status |
Lists connected players and their addresses |
/query games |
Lists the games currently running on the server |
/query kick <nick> |
Disconnects a player |
/query kban <nick> <time> <reason> |
Kicks and bans a player for a period |
/query bans |
Shows the current ban list |
/query unban <mask> |
Lifts a ban |
/query motd <text> |
Sets the message of the day players see on joining |
/query metrics |
Shows server traffic and performance counters |
/query help |
Lists every command the server accepts |

Moderate from the server shell
The same commands are available without a game client through the server's control FIFO. This is useful for scripting or for an emergency when you cannot get a client connected. Run as root:
sudo timeout 5 sh -c 'echo "status" > /run/wesnothd/socket'
sudo journalctl -u wesnothd --since "1 minute ago" --no-pager | tail -20
The server executes the command and writes the answer to its journal. The FIFO lives in a directory owned by root and the wesnothd service account with mode 0750, so ordinary users on the VM cannot drive it.
Change the server settings
The configuration lives at /etc/wesnothd/server.cfg and is read at start up. It is owned root:wesnothd with mode 0640, because it holds your moderator password.
sudo cat /etc/wesnothd/server.cfg
Useful keys:
| Key | Meaning |
|---|---|
versions_accepted |
Which client series may connect. 1.18.* by default. Widening this to a series the binary does not speak will break games, not enable them |
passwd |
The moderator password checked by /query admin |
motd |
The message of the day shown when a player joins |
max_messages and messages_time_period |
Chat flood control: how many messages a player may send in that many seconds |
save_replays |
Whether finished games are written to disk. Off by default so the appliance does not grow its disk unattended |
fifo_path |
The shell control channel described above |
After editing, restart the server. Connected players are disconnected, so pick a quiet moment:
sudo systemctl restart wesnothd
systemctl is-active wesnothd
Turn on replay saving
If you want finished games kept for later viewing, give the server a directory it can write to and enable the option:
sudo install -d -o wesnothd -g wesnothd -m 0750 /var/lib/wesnothd/replays
sudo sed -i 's|^save_replays=.*|save_replays="yes"|' /etc/wesnothd/server.cfg
sudo sh -c 'grep -q ^replay_save_path /etc/wesnothd/server.cfg || echo "replay_save_path=\"/var/lib/wesnothd/replays/\"" >> /etc/wesnothd/server.cfg'
sudo systemctl restart wesnothd
Replays accumulate indefinitely, so keep an eye on du -sh /var/lib/wesnothd/replays or prune them on a schedule.
Change the moderator password
Rotate the password whenever someone leaves your moderator group:
NEW_PASSWORD=$(openssl rand -hex 24)
sudo sed -i "s|^passwd=.*|passwd=\"${NEW_PASSWORD}\"|" /etc/wesnothd/server.cfg
sudo sed -i "s|^wesnothd.admin_password=.*|wesnothd.admin_password=${NEW_PASSWORD}|" /root/wesnothd-credentials.txt
sudo systemctl restart wesnothd
sudo wesnothd-selfcheck
The self check at the end re-proves the new password authenticates, so you never rotate into a server you cannot moderate.
Server components
| Component | Version | Purpose |
|---|---|---|
| wesnothd | 1.18.7 | The dedicated multiplayer game server, built from the official upstream source release, server target only |
| Ubuntu Server | 24.04 LTS | Base operating system, fully patched with unattended security upgrades enabled |
| systemd unit | wesnothd.service |
Runs the server unprivileged, gated so it cannot start before first boot has minted your password |
| systemd unit | wesnothd-firstboot.service |
Runs once on your first boot to generate the per VM moderator password and configuration |
Filesystem layout
| Path | Purpose |
|---|---|
/usr/local/bin/wesnothd |
The server binary |
/etc/wesnothd/server.cfg |
Server configuration, including the moderator password. 0640 root:wesnothd |
/run/wesnothd/socket |
Moderator control FIFO, inside a 0750 directory |
/root/wesnothd-credentials.txt |
Per VM credentials. 0600 root:root |
/usr/share/doc/wesnothd/COPYING |
The upstream GNU General Public License version 2 text |
/usr/local/sbin/wesnothd-selfcheck |
End to end server self check |
/var/lib/cloudimg/ |
First boot markers and sentinel |
/etc/cloudimg-build-versions |
What was built into this image, and from which pinned source |
Network ports
| Port | Bound to | Purpose |
|---|---|---|
15000/tcp |
All interfaces | The Wesnoth game port. Your players connect here |
22/tcp |
All interfaces | SSH administration |
Managing the service
sudo systemctl status wesnothd --no-pager
sudo systemctl restart wesnothd
sudo systemctl stop wesnothd
sudo journalctl -u wesnothd --no-pager -n 50
Scripts and log files
| Path | Purpose |
|---|---|
/usr/local/sbin/wesnothd-firstboot.sh |
Generates the per VM moderator password and configuration on first boot |
/usr/local/sbin/wesnothd-selfcheck |
Drives a real two client protocol session against this server |
/var/log/cloudimg-firstboot.log |
What first boot did on this VM |
/stage/scripts/initial_boot_update.sh |
Applies operating system updates on first boot |
/stage/scripts/initial_boot_update.log |
Output of that update run |
On startup
On the very first boot, wesnothd-firstboot.service generates a moderator password unique to this VM, writes /etc/wesnothd/server.cfg, releases the two start up conditions on wesnothd.service, starts the server, waits for the game port to bind, and writes your credentials file. It then disables itself, so it never runs again. Its log is /var/log/cloudimg-firstboot.log.
/stage/scripts/initial_boot_update.sh applies operating system updates on first boot from a root crontab entry. List it with:
sudo crontab -l
To disable it, edit the root crontab with sudo crontab -e and remove the initial_boot_update.sh line.
Troubleshooting
Players get "The server responded with an unknown version" or are refused on connect
The client series does not match. This server accepts 1.18.* only. Check what the server thinks:
sudo grep versions_accepted /etc/wesnothd/server.cfg
wesnothd --version
Ask the player to install Wesnoth 1.18.x. Do not widen versions_accepted to a series this binary does not speak: the handshake would succeed and the game would then desynchronise.
Nothing answers on port 15000
First check the service and the two start up conditions:
systemctl is-active wesnothd
systemctl status wesnothd --no-pager | head -20
sudo ls -l /var/lib/cloudimg/wesnothd-ready /etc/wesnothd/server.cfg
If systemctl status reports the unit was skipped because a condition failed, first boot did not complete. Look at what it did:
sudo cat /var/log/cloudimg-firstboot.log
If the service is active locally but players still cannot reach it, the port is not open in Azure. From your workstation:
az vm open-port --resource-group my-resource-group --name my-wesnoth-vm --port 15000
/query admin says "Error: wrong password"
You are using a password from somewhere other than this VM. Every VM gets its own:
sudo grep '^wesnothd.admin_password' /root/wesnothd-credentials.txt
If the credentials file and /etc/wesnothd/server.cfg have drifted apart, server.cfg is what the server checks against.
/query admin says "No password set"
server.cfg has no passwd key, usually because it was edited by hand. Restore it and restart:
sudo grep '^passwd' /etc/wesnothd/server.cfg || echo "no passwd key present"
sudo systemctl restart wesnothd
The self check reports an error
Read the step it stopped on, then look at the server's own view:
sudo journalctl -u wesnothd --no-pager -n 60
A failure at the login step usually means the service is not running. A failure at the game creation step means the server is up but rejecting the session, which the journal will explain.
Security recommendations
-
Restrict SSH. Limit TCP 22 in your Network Security Group to your own address range, and use SSH keys rather than passwords.
-
Leave the game port open only as wide as you need. TCP 15000 has to be reachable by your players, but if your community is on a known network you can scope the rule to it rather than to the whole internet.
-
Guard the moderator password. It is the only privileged boundary on this server. Keep
/root/wesnothd-credentials.txtroot only, rotate the password when someone leaves your moderator group, and never paste it into a public lobby. -
Set a message of the day with
/query motdso players can see they are on your server and know your rules. -
Use the ban list.
/query kbanand/query bansare the tools for dealing with disruptive players; the server keeps bans across reconnects. -
Keep the operating system patched. Unattended security upgrades are enabled. Check them with
systemctl status unattended-upgrades --no-pager. -
Watch disk if you enable replay saving. Replays are off by default for exactly this reason.
Support
cloudimg provides 24/7 support for this image. Contact support@cloudimg.co.uk with your VM's region, size and the output of sudo wesnothd-selfcheck.
Upstream project documentation for the multiplayer server is at wiki.wesnoth.org/MultiplayerServers. BATTLE FOR WESNOTH and WESNOTH are names and marks of The Battle for Wesnoth project and its contributors. cloudimg is not affiliated with, endorsed by, or sponsored by that project; this image packages the project's GNU General Public License version 2 licensed dedicated server unmodified.