7 Days to Die runs fine as a headless Linux server, but it eats RAM and the config lives in one giant XML file. Plan for 6-8 GB free or it stutters under a populated map.

TL;DR:

# as root: deps + steam user
apt update && apt install -y steamcmd lib32gcc-s1 libsdl2-2.0-0 screen
adduser --disabled-password --gecos "" steam

# as steam user: install app id 294420 (anonymous)
sudo -iu steam
steamcmd +force_install_dir /home/steam/7dtd \
  +login anonymous +app_update 294420 validate +quit

cd /home/steam/7dtd
cp serverconfig.xml myserver.xml      # edit this copy
./startserver.sh -configfile=myserver.xml

Details below.

Install SteamCMD and deps

Run as root. The Debian/Ubuntu steamcmd package pulls most of what you need, but the game still wants a couple of shared libs at runtime:

apt update
apt install -y steamcmd lib32gcc-s1 libsdl2-2.0-0 libc6 screen

Historically 7DTD needed a pile of 32-bit libs. The current Linux build is 64-bit and SteamCMD itself is the only thing that really needs lib32gcc-s1. Install libsdl2-2.0-0 anyway — the server binary links against it even headless, and a missing SDL2 is the classic "exits silently on first launch" cause.

If apt can't find steamcmd, enable multiverse and accept the Steam license non-interactively:

add-apt-repository multiverse
dpkg --add-architecture i386 && apt update
echo steam steam/question select "I AGREE" | debconf-set-selections
echo steam steam/license note '' | debconf-set-selections
apt install -y steamcmd

Run as a non-root steam user

Never run the server as root. Make a dedicated account:

adduser --disabled-password --gecos "" steam
sudo -iu steam

Install the game into that user's home so EAC and the save dirs land under an unprivileged user:

steamcmd +force_install_dir /home/steam/7dtd \
  +login anonymous +app_update 294420 validate +quit

App id 294420, anonymous login — no Steam account needed for the dedicated server. The download is ~14 GB. validate is worth keeping in your update command; the asset bundles corrupt easily on a half-finished pull.

Config: serverconfig.xml

Don't edit the shipped serverconfig.xml in place — app_update can clobber it. Copy it and point the launcher at your copy:

cd /home/steam/7dtd
cp serverconfig.xml myserver.xml

It's one flat XML file of <property name="..." value="..."/> lines. The ones that actually matter:

<property name="ServerName"            value="Diengdoh 7DTD"/>
<property name="ServerPassword"        value="changeme"/>
<property name="ServerMaxPlayerCount"  value="8"/>
<property name="Region"                value="Europe"/>
<property name="Language"              value="English"/>

<property name="GameWorld"             value="Navezgane"/>
<!-- For a random map instead: -->
<!-- <property name="GameWorld"     value="RWG"/> -->
<!-- <property name="WorldGenSeed"  value="myseed123"/> -->
<!-- <property name="WorldGenSize"  value="6144"/> -->

<property name="EACEnabled"            value="true"/>

<property name="ServerVisibility"      value="2"/>   <!-- 2 public, 1 friends, 0 hidden -->
<property name="ServerPort"            value="26900"/>

Notes from doing this for real:

  • GameWorld: Navezgane is the handcrafted map and boots in seconds. RWG (random gen) plus a WorldGenSeed and WorldGenSize builds a fresh world on first start — that can take several minutes and a chunk of RAM. Don't panic when the first launch sits there "doing nothing".
  • ServerMaxPlayerCount: each player slot costs memory. 8 players on a 6144 map is comfortable on 8 GB. Push to 16 and you want 12 GB+.
  • Region: set it so Steam matchmaking shows you to the right players; mismatched region = "server not found" complaints.

Ports and ufw

7DTD needs a small range. Game traffic is on 26900 TCP+UDP, plus 26901-26902 UDP for the Steam query/raw sockets. The optional web dashboard and telnet are 8080/8081.

# game
ufw allow 26900/tcp
ufw allow 26900/udp
ufw allow 26901:26902/udp

# optional: web control panel + telnet (lock these down!)
ufw allow 8080/tcp
ufw allow from 203.0.113.0/24 to any port 8081 proto tcp

Telnet on 8081 is an unauthenticated-ish admin channel — set TelnetPassword in the config and never expose 8081 to the open internet. Restrict it by source IP or tunnel over SSH. Full primer on the firewall side in /ufw-firewall-rules-ubuntu/.

Enable the web dashboard and telnet in config if you want them:

<property name="WebDashboardEnabled" value="true"/>
<property name="WebDashboardPort"    value="8080"/>
<property name="TelnetEnabled"       value="true"/>
<property name="TelnetPort"          value="8081"/>
<property name="TelnetPassword"      value="setareallone"/>

Start it

For a quick test, run it in the foreground and watch the log scroll. For a session that survives your SSH disconnect, wrap it in screen or tmux:

cd /home/steam/7dtd
screen -dmS 7dtd ./startserver.sh -configfile=myserver.xml
screen -r 7dtd        # attach;  Ctrl-A D to detach

screen is fine for a test box. For anything you actually care about, use systemd — it restarts on crash and starts on boot.

systemd unit

Run it under the steam user with the right working dir. The launcher must run from the install root or it won't find its data.

# /etc/systemd/system/7dtd.service
[Unit]
Description=7 Days to Die Dedicated Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=steam
WorkingDirectory=/home/steam/7dtd
ExecStart=/home/steam/7dtd/startserver.sh -configfile=/home/steam/7dtd/myserver.xml
Restart=on-failure
RestartSec=10
KillSignal=SIGINT
TimeoutStopSec=90

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now 7dtd
journalctl -u 7dtd -f

KillSignal=SIGINT lets the server flush the world save on stop instead of getting hard-killed and corrupting it. More on units in /systemd-service-unit-file/.

Gotchas

  • EAC on Linux. Easy Anti-Cheat works on the Linux server, but it can fail to initialise on minimal/container hosts missing certain libs, and Linux clients with EAC enabled have a long history of being kicked. If your players can't connect and the log mentions EAC, set EACEnabled to false to confirm that's the cause. Disabling it is a real-world workaround for private servers, but obviously kills anti-cheat — don't do it on a public box you care about.
  • RAM. This is the big one. A populated random-gen map will sit at 6-8 GB resident and spike higher on horde night. On a 4 GB VPS the OOM killer eats the process and systemd just keeps restarting it. Give it real memory.
  • First RWG launch looks hung. Random world generation pre-bakes the map. Several minutes of apparent silence is normal — check journalctl for "Generating" lines before assuming it crashed.
  • Allocs server fixes. The community allocs mod (server fixes + web map) is the usual add-on for a proper web map and extra console commands. Optional, drop it in the Mods folder. Not needed to run, but most admins end up wanting it.
  • Config got reset. If your settings vanished after an update, you edited the stock serverconfig.xml instead of your copy. Always -configfile= your own file.

Verify

Three checks. Is it listening, is the log clean, can a client connect:

# ports bound?
ss -tulpn | grep -E '26900|26901|8080'

# server reported ready?
journalctl -u 7dtd --no-pager | grep -i "GameServer.Init"

# watch a client join
journalctl -u 7dtd -f | grep -i "Player connected"

In game: Join a Game → Connect to IP → <your-ip>:26900, enter the password. If it shows in the server browser at all, your region and ports are right.

Same pattern, different engines if you're building out a stable: Project Zomboid is lighter on RAM, and Enshrouded is the other memory-hungry one worth setting up the same way.


Related posts