A dedicated 7 Days to Die server keeps the world running between sessions and stops one player's PC from being the lag source for everyone's blood moon. This guide installs it with SteamCMD on a VPS in about 30 minutes, and adds two things most guides leave out: a shutdown that saves, and a size that fits the game.

Using an AI coding agent? There's a ready-made prompt at the end of this guide.

The honest bit first: this game wants RAM and fast cores

Community guides put the floor at 6 to 8 GB of RAM, and 10 to 16 GB for a full group, mods, or a big map. The game leans on single-thread speed more than core count, so a couple of fast cores beat many slow ones.

We recommend Comet (8 GB) for a small group on a default-size random world, and Pulsar (16 GB) for 8 or more players, mods, or a larger map. Orbit (4 GB) is too small, and we won't pretend otherwise.

Generating a random world is a one-off memory spike that grows steeply with map size. So we use the default size and add swap as a safety net.

What you'll need

  • A PrivateByte VPS: Comet ($15.99/mo: 4 vCPU, 8 GB RAM, 100 GB SSD), or Pulsar ($27.99/mo: 6 vCPU, 16 GB) for bigger groups or mods.
  • 7 Days to Die on Steam for everyone joining. The server needs no game licence.
  • About 30 minutes, mostly downloading and generating the world.

Step 1: Deploy your VPS

In the PrivateByte dashboard, open the store, choose Comet, pick Ubuntu 24.04 and the region closest to your players, and deploy.

PrivateByte dashboard listing three servers, each showing a green Running indicator with its plan and Ubuntu 24.04
Your server appears in the dashboard within a few minutes.

Step 2: Connect, firewall, SteamCMD

ssh root@YOUR_SERVER_IP
Network and Access panel showing the server IP, root username, hidden password with a Reveal button, SSH port 22, and the full ssh command
Everything you need to connect is on the server page, including the exact ssh command.

SSH first, then the game ports, then enable:

apt update && apt upgrade -y
ufw allow OpenSSH
ufw allow 26900/tcp
ufw allow 26900:26903/udp
ufw --force enable

Port 26900 needs TCP and UDP; 26901 to 26903 are UDP. We deliberately do not open telnet (8081) or the web dashboard (8080). Those are admin doors.

Add swap for the world-generation spike:

fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Now SteamCMD, Valve's command-line installer. It's 32-bit, so Ubuntu needs i386 first:

add-apt-repository -y multiverse
dpkg --add-architecture i386
apt update
apt install -y steamcmd

The install shows Steam's licence agreement. Read and accept it yourself. Then create the user the server runs as:

adduser --disabled-password --gecos "" sdtd

Step 3: Install the server

su - sdtd
/usr/games/steamcmd +force_install_dir /home/sdtd/server +login anonymous +app_update 294420 validate +quit

294420 is the dedicated server tool, a different app from the game itself (251570). It's a several-GB download.

Step 4: serverconfig.xml essentials

Never edit the shipped serverconfig.xml. Updates overwrite it. Work on a copy:

cp ~/server/serverconfig.xml ~/myserver.xml
nano ~/myserver.xml

Set these properties (add any that are missing):

<property name="ServerName" value="Our Apocalypse"/>
<property name="ServerPassword" value="CHANGE_ME_join_password"/>
<property name="ServerVisibility" value="0"/>
<property name="ServerMaxPlayerCount" value="8"/>
<property name="GameWorld" value="RWG"/>
<property name="WorldGenSeed" value="ourseed"/>
<property name="WorldGenSize" value="6144"/>
<property name="GameName" value="OurSave"/>
<property name="TelnetEnabled" value="true"/>
<property name="TelnetPort" value="8081"/>
<property name="TelnetPassword" value="CHANGE_ME_telnet_password"/>
<property name="WebDashboardEnabled" value="false"/>
<property name="UserDataFolder" value="/home/sdtd/data"/>

What earns an explanation:

  • ServerVisibility: 2 public, 1 friends only, 0 unlisted. Unlisted plus a password means you join by IP.
  • GameWorld=RWG generates a random world from WorldGenSeed and WorldGenSize on first start. The default Navezgane is the fixed hand-made map. Size must be a multiple of 2048; bigger sizes cost much more memory and time.
  • GameName names the save. Change it later and you start a new world; the old one stays on disk.
  • Telnet is on by default. With an empty password it only listens locally; with a password it listens on every interface. We need the password for the shutdown script, and the firewall keeps 8081 shut. Use a different password from the join one.
  • UserDataFolder pins where saves live, so the backup path below is not a guess.

Blood moon and day length are in the same file. These are the shipped defaults:

<property name="DayNightLength" value="60"/>
<property name="DayLightLength" value="18"/>
<property name="BloodMoonFrequency" value="7"/>
<property name="BloodMoonRange" value="0"/>
<property name="BloodMoonWarning" value="8"/>
<property name="BloodMoonEnemyCount" value="8"/>

DayNightLength is real minutes per in-game day, DayLightLength is hours of daylight out of 24, and BloodMoonFrequency is in-game days between blood moons (0 turns them off). BloodMoonRange randomises the day by that many days either side. BloodMoonEnemyCount is zombies allowed at once per player during the horde, so on a small box it is your first performance lever.

Easy Anti-Cheat (EACEnabled) is on by default. Leave it on for vanilla; most mods need it off.

Step 5: Set up a safe shutdown

The server saves on the telnet shutdown command. Killing the process instead is how you lose an evening. Two small scripts, as root:

nano /usr/local/bin/sdtd-cmd
#!/bin/bash
# usage: sdtd-cmd "console command"
exec 3<>/dev/tcp/127.0.0.1/8081
sleep 2
printf '%s\r\n' "$(cat /home/sdtd/telnet.pass)" >&3
sleep 2
printf '%s\r\n' "$1" >&3
sleep 3
exec 3>&-
nano /usr/local/bin/sdtd-stop
#!/bin/bash
/usr/local/bin/sdtd-cmd shutdown
for i in $(seq 1 120); do
  pgrep -u sdtd -f '[7]DaysToDieServer.x86_64' >/dev/null || exit 0
  sleep 1
done
exit 0

Store the telnet password (same value as TelnetPassword) where only sdtd can read it:

chmod 755 /usr/local/bin/sdtd-cmd /usr/local/bin/sdtd-stop
read -rs -p "Telnet password: " P; echo
printf '%s' "$P" > /home/sdtd/telnet.pass; unset P
chown sdtd:sdtd /home/sdtd/telnet.pass && chmod 600 /home/sdtd/telnet.pass

The [7] in the pgrep pattern stops it matching its own command line and waiting forever.

Step 6: Hand it to systemd

nano /etc/systemd/system/sdtd.service
[Unit]
Description=7 Days to Die server
After=network-online.target
Wants=network-online.target

[Service]
User=sdtd
WorkingDirectory=/home/sdtd/server
ExecStart=/home/sdtd/server/7DaysToDieServer.x86_64 -logfile /home/sdtd/server/output_log.txt -quit -batchmode -nographics -dedicated -configfile=/home/sdtd/myserver.xml
ExecStop=/usr/local/bin/sdtd-stop
TimeoutStopSec=180
Restart=on-failure

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now sdtd
tail -f /home/sdtd/server/output_log.txt

The first start generates the world: roughly 5 to 15 minutes on the default size, longer for bigger maps. Watch the log until it settles (look for GameServer.Init successful), then press Ctrl+C. The server keeps running.

On shutdown, systemd runs sdtd-stop, which sends shutdown and waits up to two minutes for exit. Without that, a reboot is a crash.

Step 7: Connect

In 7 Days to Die, choose Join a Game, then Connect to IP. Enter the server IP, port 26900, and the join password. Every player must be on the same game branch as the server (stable by default).

Verify it works

You can join. Connect and place a chest.

It saves on restart, the check that matters. systemctl restart sdtd, wait a couple of minutes, rejoin. The chest must still be there. journalctl -u sdtd confirms sdtd-stop ran.

Saves are where you think. ls /home/sdtd/data/Saves should show your world. The startup log line GamePref.SaveGameFolder shows what the server believes.

The negative control. From your own machine:

nc -zv -w 5 YOUR_SERVER_IP 8081

This should fail: telnet must not be reachable from the internet. The same command against port 22 should succeed, proving the probe works.

It survives a reboot. reboot, wait, rejoin.

Backups

Everything worth keeping is under /home/sdtd/data. PrivateByte's daily server backups include it, but a game-aware copy is better. Save through telnet, then archive:

nano /usr/local/bin/sdtd-backup
#!/bin/bash
/usr/local/bin/sdtd-cmd saveworld
sleep 15
mkdir -p /home/sdtd/backups
tar -czf /home/sdtd/backups/sdtd-$(date +%F-%H%M).tar.gz -C /home/sdtd data
find /home/sdtd/backups -name 'sdtd-*.tar.gz' -mtime +7 -delete
chmod 755 /usr/local/bin/sdtd-backup

Then add the schedule for the sdtd user with crontab -u sdtd -e:

0 4 * * * /usr/local/bin/sdtd-backup

A backup you have never restored is a hope. Once, on a quiet evening: stop the service, move data aside, extract an archive, start, and confirm the world loads.

Updates

Client and server must match. Update when the game does:

systemctl stop sdtd
su - sdtd -c "/usr/games/steamcmd +force_install_dir /home/sdtd/server +login anonymous +app_info_update 1 +app_update 294420 validate +quit"
systemctl start sdtd

+app_info_update 1 matters: without it SteamCMD can report success while keeping the old build.

Stable is the default. For experimental or older builds, add -beta <branch> after +app_update 294420 (for example -beta latest_experimental); older versions exist as named branches on Steam. A client on one branch cannot join a server on another. Experimental builds can change save layout, so copy data first.

Troubleshooting

"Incompatible version". Server and client are on different builds. Update the server, or move the client to the same branch.

Nobody can connect. ufw status must show 26900/tcp and 26900:26903/udp.

Killed or restarting during world generation. Out of memory. Check free -m and dmesg | grep -i kill. Use the default WorldGenSize, keep the swap, or move to Pulsar.

Lag, especially during blood moons. Lower BloodMoonEnemyCount and MaxSpawnedZombies, and check top for one pinned core. More cores will not fix it; fewer zombies will.

The world reset. You changed GameName or UserDataFolder, so the server started a new save. Set them back and restart; the old files never moved.

Telnet script does nothing. Check telnet.pass matches TelnetPassword exactly and TelnetEnabled is true.

Do it with an AI agent

If you'd rather hand this to Claude Code, Cursor, or another coding agent, don't paste the article at it; agents skim warnings and lose ordering. Copy this instead, and run it from your own machine with your agent able to SSH out.

Prompt for an AI agent
Set up a 7 Days to Die dedicated server on a fresh Ubuntu 24.04 VPS with
SteamCMD, running as an unprivileged user under systemd, unlisted and
password-gated, with a telnet-based safe shutdown and a backup job.

FILL IN BEFORE YOU START:
- SERVER_IP   = <VPS IP from the PrivateByte dashboard>
- SERVER_NAME = <display name>
- GAME_NAME   = <save name; treat as permanent, changing it starts a NEW world>
- The join password and the telnet password are MINE. You never see them.

WHAT TO DO:
1. SSH to root@SERVER_IP. Confirm Ubuntu 24.04, run "free -m", tell me the RAM.
   If under 8 GB, warn me (6-8 GB minimum; world generation can be OOM-killed)
   and WAIT for my decision.
2. apt update && apt upgrade -y.
3. Firewall, in THIS EXACT ORDER: ufw allow OpenSSH; ufw allow 26900/tcp;
   ufw allow 26900:26903/udp; ufw --force enable.
4. Add 4 GB swap (/swapfile, chmod 600, fstab entry) if none exists.
5. add-apt-repository -y multiverse; dpkg --add-architecture i386; apt update.
   Then STOP and tell me to run "apt install -y steamcmd" myself (it shows
   Steam's licence agreement; accepting it is mine). WAIT.
6. adduser --disabled-password --gecos "" sdtd (no sudo).
7. As sdtd: /usr/games/steamcmd +force_install_dir /home/sdtd/server
   +login anonymous +app_update 294420 validate +quit
8. As sdtd: cp ~/server/serverconfig.xml ~/myserver.xml (never edit the
   shipped file). In myserver.xml set ServerName, ServerVisibility=0,
   ServerMaxPlayerCount=8, GameWorld=RWG, WorldGenSize=6144, GameName,
   TelnetEnabled=true, TelnetPort=8081, WebDashboardEnabled=false,
   UserDataFolder=/home/sdtd/data. Leave ServerPassword and TelnetPassword for
   me: STOP and tell me to type both into the file myself (different values),
   and to write the telnet password into /home/sdtd/telnet.pass (owner sdtd,
   chmod 600). WAIT for my confirmation.
9. Create /usr/local/bin/sdtd-cmd (bash, opens /dev/tcp/127.0.0.1/8081, sends
   the password read from /home/sdtd/telnet.pass, then the command) and
   /usr/local/bin/sdtd-stop (runs sdtd-cmd shutdown, then waits up to 120 s
   with pgrep -u sdtd -f '[7]DaysToDieServer.x86_64'). chmod 755.
10. /etc/systemd/system/sdtd.service: User=sdtd,
    WorkingDirectory=/home/sdtd/server, ExecStart=/home/sdtd/server/7DaysToDieServer.x86_64
    -logfile /home/sdtd/server/output_log.txt -quit -batchmode -nographics
    -dedicated -configfile=/home/sdtd/myserver.xml,
    ExecStop=/usr/local/bin/sdtd-stop, TimeoutStopSec=180,
    Restart=on-failure. daemon-reload, enable --now.
11. Create /usr/local/bin/sdtd-backup (sdtd-cmd saveworld, sleep 15, tar
    /home/sdtd/data to /home/sdtd/backups, delete archives older than 7 days)
    and a 04:00 cron entry for the sdtd user.

RULES:
- Never read, print or log either password, myserver.xml's password lines, or
  telnet.pass. To check they are set, check they are non-empty.
- Never open 8080 or 8081. Never run the server as root.
- Do not shorten the sdtd-stop wait; it is what lets the world save.
- If /home/sdtd/data already exists, STOP and ask; that directory is the save.

VERIFY, AND SHOW ME THE OUTPUT OF EACH:
- "systemctl status sdtd" -> active, after the first world generation finishes
  (tail /home/sdtd/server/output_log.txt; wait for it)
- "ls /home/sdtd/data/Saves" -> the world exists
- "ufw status" -> OpenSSH, 26900/tcp, 26900:26903/udp only
- THE NEGATIVE CONTROL, from MY machine: "nc -zv -w 5 SERVER_IP 8081" MUST
  fail and "nc -zv -w 5 SERVER_IP 22" MUST succeed.
- I join at SERVER_IP:26900 and place a chest; "systemctl restart sdtd"; I
  rejoin and confirm the chest survived.
- "/usr/local/bin/sdtd-backup" run once by hand as sdtd -> a .tar.gz appears
  in /home/sdtd/backups
- reboot, wait 3 minutes, "systemctl status sdtd" -> active

Do not tell me a step succeeded without showing the output that proves it. If a
verification fails, stop and report the actual error. Do not retry silently or
improvise a workaround, especially around the firewall or /home/sdtd/data.

Worth stealing: the passwords and licence agreement are handed back to you, and the checks prove the outcome (the save survived a restart, telnet is closed from outside), not that a service says active.

Hosting more than one game? The same console-under-systemd pattern runs our Terraria guide. Project Zomboid is the other zombie survival server, Palworld is the memory-hungry one, Valheim is the Docker version, and the Minecraft guide covers the evergreen.

Deploy your VPS

The Comet plan is the honest starting size for a small group; Pulsar when the group or mod list grows.

Comet plan
$15.99/mo
4 vCPU · 8 GB RAM · 100 GB SSD
Deploy a Comet VPS
  • Unmetered bandwidth, no overage
  • Free DDoS protection
  • Daily automated backups
  • Browser console access
Ready in a few minutes. No contract, cancel any time.

Common questions

How much RAM does a 7 Days to Die server need? 6 to 8 GB minimum, 10 to 16 GB for a full group or mods. 8 GB (Comet) suits a small group; 16 GB (Pulsar) is the comfortable step up. 4 GB is too small.

Which ports does it use? 26900 TCP and UDP, plus UDP 26901 to 26903. Keep telnet (8081) and the web dashboard (8080) closed to the internet.

How do I make the blood moon less brutal, or turn it off? Lower BloodMoonEnemyCount for smaller hordes, change BloodMoonFrequency (default 7 days), or set it to 0 to disable. Restart after editing.

Can I use mods? Yes, but most need EACEnabled set to false, every player needs the same mods, and memory use rises. Take a backup first.

Where do I add admins? Add your 64-bit Steam ID to serveradmin.xml in the server's user data folder, or use the telnet console. Restart to pick up file edits.