All Guides·Downloads

Reference · v1.0.0

The Server Handbook

The complete manual for devilutionx-server — every flag, every deployment path, and the reasoning behind the machine. The same text ships inside every server package and lives in the repository as HANDBOOK.md.

Reference Linux · WSL · Docker v1.0.0

What it is

A port of DevilutionX that runs the game engine as a headless dedicated server — no window, no display server, no window manager, no audio device. It hosts a public multiplayer game (TCP/IP or ZeroTier), keeps an idle player seated in the game so the world stays up, and runs forever until stopped — ideal for a systemd service, a container, or any machine without a desktop.

The normal devilutionx client is unaffected and joins the server's game exactly like any other multiplayer game.

Building from source (Linux / WSL)

cd DevilutionX-1.5.5
cmake -B build-server -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF
cmake --build build-server -j$(nproc) --target devilutionx devilutionx-server

This produces:

Quick start

With the game MPQs (hellfire.mpq, hfmonk.mpq, …) in a directory:

cd build-server
./devilutionx-server --data-dir /path/to/mpqs \
    --save-dir ~/.local/share/devilutionx-server \
    --config-dir ~/.config/devilutionx-server

The server prints Hosting game … on TCP/IP, binds TCP port 6112 on all interfaces, and idles until killed. Stop it with Ctrl+C (SIGINT), kill (SIGTERM), or systemctl stop — it shuts down cleanly and saves.

Then, on a client machine, run stock DevilutionX → Multiplayer → TCP/IP → enter the server's IP → join server-XXXX (or your --name).

Options

--server-tcp [ADDRESS]   Host a TCP/IP game (default). Binds to all interfaces
                         by default; give an address to bind to, e.g. a
                         ZeroTier interface address.
--server-zerotier        Host a ZeroTier game on the configured network.
--server-zt-network ID   Join the ZeroTier network with the given 16-hex-digit
                         ID before hosting (default: Diasurgical public Earth).
--join ADDRESS           Do not host: join the game at ADDRESS as an idle
                         player instead (TCP/IP host name or IP, or the
                         advertised game name for ZeroTier).
--name NAME              Game name shown in the game list (default: server-<pid>).
--password PASSWORD      Password of the game (hosted or joined; default: public).
--port PORT              TCP port to listen on (default: 6112).
--hero-class CLASS       Idle player class: warrior rogue sorcerer monk bard
                         barbarian (default: warrior).
--hero-name NAME         Idle player name (default: Server).
--game GAME              hellfire or diablo (default: hellfire).
--difficulty N           0 = normal, 1 = nightmare, 2 = hell (default: 0).
--full-quests            Enable the full quest set for the game.
--data-dir PATH          Asset (MPQ) search directory.
--save-dir PATH          Directory for the server hero save.
--config-dir PATH        Directory for configuration files.
-f                       Display frame count in the log.
--verbose                More verbose logging.
-h, --help               Show this help.

Public games over TCP/IP

Public games over ZeroTier

  1. Create (or pick) a ZeroTier network and have every player plus the server join it.
  2. On the server: join the network with the ZeroTier CLI (zerotier-cli join <network>), authorize the node, then run:
    ./devilutionx-server --server-zerotier \
        --server-zt-network 0123456789abcdef \
        --name "My ZT Server" --data-dir ... --save-dir ... --config-dir ...

    (If the network is joined externally as above, --server-zt-network can be omitted; the server will use the network configured in its ini file — by default the Diasurgical public Earth network.)

  3. Clients join the same ZeroTier network, run stock DevilutionX → Multiplayer → ZeroTier, and pick the game from the list.

You can also bind a TCP game to the ZeroTier interface only: --server-tcp <zt-ip-address>.

The idle player

The server seats a real player (Server by default) so the simulation stays alive. On first start it creates a save for the configured --hero-class; later runs reuse that save (level, equipment, etc. persist). The idle player just stands in town — it takes no actions.

Bot mode (--join) behaves the same, but joins someone else's game instead of hosting — e.g. --join 192.168.1.10 --hero-name Bot.

Running as a service (systemd)

[Unit]
Description=DevilutionX headless dedicated server
After=network-online.target
Wants=network-online.target

[Service]
User=games
ExecStart=/opt/devilutionx/devilutionx-server \
    --data-dir /opt/devilutionx \
    --save-dir /var/lib/devilutionx-server \
    --config-dir /etc/devilutionx-server \
    --name "My Public Server" --server-tcp
Restart=on-failure
# The server needs no display, audio, or input devices.

[Install]
WantedBy=multi-user.target

The binary itself requires no window manager and works in containers (docker run -d -p 6112:6112 …) without extra device passthroughs.

Logging and diagnostics

The server logs to stderr (journald picks it up under systemd):

Use --verbose for packet-level debug logging.

Tests

Bash smoke/soak tests ship in the source tree (test/):

Implementation notes