A Terraria server that stays alive inside tmux can survive an SSH disconnect, but that session disappears when Linux reboots. To bring the same server back automatically, give it a systemd service, an explicit existing world, and a shutdown path that sends the game's exit command and waits.
This example is for a vanilla PC dedicated server on an x86-64 Debian/Ubuntu VPS. It assumes the complete official Linux server tree already works manually. TShock, tModLoader, containers and panel-managed instances have their own launchers: do not add a competing service around one of those.
Fix the identity and paths first#
Use the following layout, adapting every occurrence if yours differs:
| Item | Example |
|---|---|
| Service account and home | terraria, /srv/terraria |
| Complete extracted Linux release | /opt/terraria/server |
| Configuration | /etc/terraria/serverconfig.txt |
| Existing world | /srv/terraria/worlds/main.wld |
| Service | terraria.service |
Before changing supervision, send exit in the existing console, wait for the process to end, and make an independent copy of the stopped world directory. Disable its old cron job, screen startup or panel restart policy. Two processes must never write the same world.
The example expects a dedicated terraria user with /srv/terraria as its home. Create that account using your distribution's account tools if absent. Give it read/execute access to the complete server tree, read access to the configuration, and write access to the world directory and existing world files. Updating or replacing world backups can require directory write access even when the .wld itself is writable.
Keep executables owned by the administrator, with execute permission on TerrariaServer.bin.x86_64; keep the configuration readable only by its owner and the service group because it contains the joining password. Run a foreground check under the intended account before enabling boot startup:
sudo -u terraria -H /bin/bash -c 'cd /opt/terraria/server && TERM=xterm ./TerrariaServer.bin.x86_64 -config /etc/terraria/serverconfig.txt'
The config should select the already verified world without asking questions:
world=/srv/terraria/worlds/main.wld
worldpath=/srv/terraria/worlds
banlist=/srv/terraria/banlist.txt
port=7777
maxplayers=8
password=CHANGE_THIS_PASSWORD
upnp=0
Replace the password before starting. Deliberately omit autocreate: a misspelled path should be investigated, not produce an empty replacement world. Check the startup output, join the expected world, and type exit in the console before continuing.
Give systemd a foreground process and a console channel#
Save this complete example as /etc/systemd/system/terraria.service:
[Unit]
Description=Terraria vanilla dedicated server
After=network.target
RequiresMountsFor=/opt/terraria/server /srv/terraria/worlds
[Service]
Type=simple
User=terraria
Group=terraria
WorkingDirectory=/opt/terraria/server
Environment=HOME=/srv/terraria
Environment=TERM=xterm
UMask=0077
RuntimeDirectory=terraria
RuntimeDirectoryMode=0700
ExecStartPre=/usr/bin/test -r /etc/terraria/serverconfig.txt
ExecStartPre=/usr/bin/test -r /srv/terraria/worlds/main.wld
ExecStartPre=/usr/bin/rm -f /run/terraria/console
ExecStartPre=/usr/bin/mkfifo -m 0600 /run/terraria/console
ExecStart=/bin/bash -c 'exec 3<>/run/terraria/console; exec /opt/terraria/server/TerrariaServer.bin.x86_64 -config /etc/terraria/serverconfig.txt <&3'
ExecStop=/bin/bash -c 'kill -0 "$$MAINPID" 2>/dev/null || exit 0; exec 3<>/run/terraria/console; echo exit >&3; while kill -0 "$$MAINPID" 2>/dev/null; do sleep 1; done'
Restart=on-failure
RestartSec=10
TimeoutStopSec=120
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
The private FIFO under /run/terraria carries console input. Linux allows Bash to open it for reading and writing without waiting for another process. That retained descriptor also prevents idle input from becoming end-of-file. exec replaces Bash with Terraria, so systemd tracks the foreground game process rather than an abandoned background launcher.
On a planned stop, ExecStop writes exit and waits for that process to disappear. The doubled dollar sign passes $MAINPID through systemd's command parser to Bash. The initial check also handles a process that already died. An explicit systemctl stop does not trigger Restart=on-failure.
A 120-second timeout is a chosen starting allowance, not a saving guarantee. If the process hangs beyond it, systemd can terminate it forcibly. Increase the allowance when observed save times require it, and investigate every timeout. Power loss and kernel kills cannot run this shutdown sequence.
Validate a stop and start before testing a reboot#
Check the unit and enable it:
sudo systemd-analyze verify /etc/systemd/system/terraria.service
sudo systemctl daemon-reload
sudo systemctl enable --now terraria.service
sudo systemctl status terraria.service --no-pager
sudo journalctl -u terraria.service -b --no-pager -n 100
sudo ss -ltnp 'sport = :7777'
Resolve reported syntax or executable-path errors first. A readable world precheck prevents an absent file from reaching the selection menu, but it cannot prove the file is healthy or writable. The journal must show the intended world reaching the listening stage. A listening socket proves neither external firewall access nor a successful game join.
Join with the matching vanilla client, make a small recognizable world change, and run sudo systemctl stop terraria.service. Inspect the journal for completion rather than a stop timeout or forced kill. Start it again and verify the change survived. Only then schedule a VPS reboot with players warned and an independent backup available.
After reconnecting, use systemctl is-enabled terraria.service, current-boot status and the same journal/listener checks. Previous shutdown logs are available with journalctl -u terraria.service -b -1 if the journal retained that boot. Verify the world in-game again.
If it works manually but fails at boot, compare the account, absolute paths, filesystem mounts and directory permissions. A service user does not inherit your SSH shell or home. For maintenance across your own VPS fleet, Nexardo can provide a shared infrastructure workspace; the world path and safe stopping policy still need to be explicit in each server's setup.




