When a Terraria process exits immediately, an open firewall will not fix it. Capture the first startup failure and determine whether Linux failed to execute the program, the runtime failed to load, the world could not be opened, or a running process was terminated.
This guide covers the vanilla PC dedicated server on Linux. Examples use /opt/terraria/server, the terraria account and terraria.service; substitute your actual paths and supervisor. TShock and tModLoader use different runtimes, so their installation recipes are not interchangeable with vanilla.
Preserve the failed attempt#
For a systemd instance, collect the effective unit and current-boot messages before clearing a failed state or installing anything:
sudo systemctl status terraria.service --no-pager
sudo systemctl cat terraria.service
sudo journalctl -u terraria.service -b --no-pager -n 150
sudo systemctl show terraria.service -p Result -p ExecMainCode -p ExecMainStatus -p NRestarts
The journal may include a restart loop; find the first application error in an attempt, not just the final restart-limit message. Save that output privately. Then stop the service to prevent additional automatic attempts while investigating. Do not start a second manual process against a world still owned by the first.
A message such as 203/EXEC means systemd could not execute its configured program. If ExecStart runs Bash or another wrapper, that wrapper may launch successfully and report a different child-process error. Read both the unit and its actual output.
Check the executable and CPU before installing a runtime#
Run these inspection commands against the actual binary, using file and binutils from your distribution if needed:
uname -m
file /opt/terraria/server/TerrariaServer.bin.x86_64
readelf -l /opt/terraria/server/TerrariaServer.bin.x86_64
namei -l /opt/terraria/server/TerrariaServer.bin.x86_64
findmnt -T /opt/terraria/server/TerrariaServer.bin.x86_64
An x86-64 Linux executable is not an ARM64 executable. A Raspberry Pi can run a 64-bit OS while still reporting aarch64; adding an execute bit does not translate its instructions. Use a supported architecture/runtime route for the selected server distribution, or move vanilla to a compatible machine. Do not disguise that migration as a permission fix.
Interpret the actual message:
| Observation | Check and next action |
|---|---|
Permission denied | Inspect the file's execute bit, directory traversal rights, mount noexec and security-policy denials. Correct the specific denied access. |
Exec format error | Compare CPU architecture and file format; confirm you selected the Linux release rather than a Windows executable. |
No such file or directory, but the binary exists | Inspect the ELF interpreter reported by readelf; a missing loader can produce this error too. For a script, inspect its shebang interpreter and line endings. |
.so missing or GLIBC_… not found | Resolve the named library or libc compatibility against the distribution and architecture, rather than copying an arbitrary library. |
Grant execution only where appropriate, for example chmod u+x when the launching account owns the trusted binary. If an administrator owns it and the service user is another account, administrator-controlled mode 0755 may be appropriate. chmod 777 both widens write access and leaves architecture or loader problems untouched.
Keep the server release together#
For a trusted official download, this command displays linked-library resolution:
ldd /opt/terraria/server/TerrariaServer.bin.x86_64
Use it only on a trusted executable. A clean result does not prove that every managed assembly or library loaded later is available. Keep the entire matching Linux release tree, not just its main executable. If an update mixed old and new files, unpack a clean matching release into another directory, retain the old installation and world backup, and point the launcher at the complete replacement.
Do not install a random Mono or .NET version merely because a forum mentions it. Likewise, deleting bundled System* or Mono* files can turn a diagnosed mismatch into a different broken installation. Follow the requirements for the exact server package you run. A crash mentioning console/terminal initialization is a separate branch: compare the service's TERM with the supported launch environment, rather than changing game files.
A world prompt is not a healthy unattended server#
If startup asks you to choose a world or enter a port, inspect -config, its absolute path, and the account's access to it. A missing configuration may return to interactive setup instead of producing the failure you expected. Check the selected world independently:
sudo -u terraria test -r /etc/terraria/serverconfig.txt
sudo -u terraria test -r /srv/terraria/worlds/main.wld
sudo -u terraria test -w /srv/terraria/worlds/main.wld
sudo -u terraria test -w /srv/terraria/worlds
namei -l /srv/terraria/worlds/main.wld
df -h /srv/terraria/worlds
df -i /srv/terraria/worlds
A successful test is silent; a failed one returns a nonzero status. These checks narrow ordinary permissions, space and inode failures, but do not override read-only mounts or mandatory access controls. Confirm the effective world path and service HOME, not the world visible to your SSH account. Preserve a stopped copy before any world-specific recovery; do not enable autocreate to hide an absent file.
If the error says the address is already in use, inspect sudo ss -ltnp 'sport = :7777'. Identify the owning instance and arrange one writer or a separate port/world. A server that loads its world and listens but rejects a client's version belongs to connection/compatibility troubleshooting, not this executable-repair branch.
Prove a memory kill rather than inferring one#
An unexplained Killed, signal 9 or shell exit status 137 identifies termination, not its cause. Read kernel messages for the same boot and incident window:
sudo journalctl -k -b --since '20 minutes ago' --no-pager
sudo systemctl show terraria.service -p Result -p MemoryMax -p EffectiveMemoryMax -p MemoryCurrent -p ControlGroup
Look for a matching process, time and out-of-memory report. On cgroup v2, the unit's ControlGroup identifies its directory under /sys/fs/cgroup; inspect memory.events there while it exists. An increase in oom_kill records OOM-killed processes in that group, but an old counter without a before/after comparison does not date this incident. A stopped unit's group may already be gone.
Host free memory does not establish the service's allowance: a unit, container or parent group can impose a smaller limit. Conversely, absent or unavailable kernel history does not prove that OOM never happened. Preserve the service result, kernel evidence and configured limits before changing capacity. When operating your own VPS fleet, Nexardo can centralize infrastructure work, while diagnosis still depends on the actual process and host evidence.
After one justified change, start one instance and follow its first startup messages. Verify a matching client can join the expected world, then confirm a normal save/restart preserves a recognizable change. Keep the original failure, release identity and sanitized paths when requesting further help; remove passwords from configuration excerpts.




