initial commit
This commit is contained in:
commit
910b438686
19 files changed
+1790
No files matched your search
+698
@@ -0,0 +1,698 @@
|
||||
# terraria-server-manager
|
||||
|
||||
Run any number of vanilla Terraria and tModLoader dedicated servers on one Linux host, each managed as its own systemd service, with the `terractl` command.
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
2. [Components](#components)
|
||||
3. [Directory layout](#directory-layout)
|
||||
4. [Installation](#installation)
|
||||
5. [Migrating from the manual install](#migrating-from-the-manual-install)
|
||||
6. [Server zips](#server-zips)
|
||||
7. [Creating an instance](#creating-an-instance)
|
||||
8. [Starting, stopping and boot](#starting-stopping-and-boot)
|
||||
9. [The server console](#the-server-console)
|
||||
10. [Configuration](#configuration)
|
||||
11. [Mods (tModLoader)](#mods-tmodloader)
|
||||
12. [Versions and upgrades](#versions-and-upgrades)
|
||||
13. [Deleting and restoring](#deleting-and-restoring)
|
||||
14. [Backups](#backups)
|
||||
15. [Permissions](#permissions)
|
||||
16. [Running by hand for debugging](#running-by-hand-for-debugging)
|
||||
17. [Troubleshooting](#troubleshooting)
|
||||
18. [Command reference](#command-reference)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Each server is an **instance** with a short name such as `survival` or `calamity`. An instance is:
|
||||
|
||||
- a directory, `/var/lib/terraria/instances/<name>/`, holding everything about that server;
|
||||
- a systemd service, `terraria@<name>.service`, that runs it as the unprivileged `terraria` user.
|
||||
|
||||
Server software is never installed by hand. You drop the official zips into `/var/lib/terraria/dist`, and the first time an instance starts, the right zip is unpacked into that instance's `server/` folder. Worlds, mods and settings live separately in `data/`, so server software can be replaced or upgraded without touching them.
|
||||
|
||||
Each instance chooses between **vanilla** and **tModLoader** independently, so both kinds can run side by side on different ports.
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
Everything is installed by the `terraria-server-manager` package:
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `/usr/lib/systemd/system/terraria@.service` | Template service. One copy runs per instance. |
|
||||
| `/usr/lib/systemd/system/terraria@.socket` | Creates the console pipe the server reads commands from. |
|
||||
| `/usr/bin/terractl` | Helper script. The service calls it to set up, run and stop servers; you use it for everyday management. |
|
||||
| `/etc/default/terractl` | Optional overrides (locations, stop timeout). |
|
||||
| `/usr/lib/sysusers.d/terractl.conf` | Defines the `terraria` system user. |
|
||||
| `/usr/lib/tmpfiles.d/terractl.conf` | Creates `/var/lib/terraria` and its subdirectories. |
|
||||
| `/usr/share/terraria-server-manager/export-tmod-mods.ps1` | Optional. Copy to your Windows PC to collect your enabled tModLoader mods. |
|
||||
|
||||
What happens when an instance starts:
|
||||
|
||||
1. systemd creates the console pipe `/run/terraria/<name>.stdin` (from the socket unit).
|
||||
2. `terractl prepare <name>` creates the instance directory and default configs if they're missing, and unpacks the server zip if it hasn't been unpacked yet.
|
||||
3. `terractl run <name>` starts the vanilla or tModLoader server, reading commands from the pipe and logging to the journal.
|
||||
|
||||
On stop, `terractl stop` sends `exit` through the pipe so the world is saved before the server shuts down.
|
||||
|
||||
---
|
||||
|
||||
## Directory layout
|
||||
|
||||
```
|
||||
/var/lib/terraria/ Home of the 'terraria' user
|
||||
├── dist/ Server zips (you add these; never modified)
|
||||
│ ├── terraria-server-1458.zip
|
||||
│ └── tModLoader-v2026.07.3.0.zip
|
||||
└── instances/
|
||||
├── <name>/ One directory per instance
|
||||
│ ├── instance.conf Which server type and zip to use
|
||||
│ ├── serverconfig.txt Terraria's own settings (port, world, password...)
|
||||
│ ├── server/ Unpacked server software (replaceable)
|
||||
│ │ └── .installed Records what was unpacked
|
||||
│ └── data/ Your data (never touched by upgrades)
|
||||
│ ├── Worlds/ World files
|
||||
│ ├── Mods/ tModLoader mods + enabled.json
|
||||
│ ├── ModConfigs/ tModLoader mod settings
|
||||
│ └── banlist.txt
|
||||
└── .deleted/ Backups made by 'terractl delete'
|
||||
|
||||
/run/terraria/<name>.stdin Console pipe (exists only while running)
|
||||
```
|
||||
|
||||
The server can write only inside `instances/`. It reads `dist/` but can never change it.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
The package works on Debian 12 or newer and Ubuntu 22.04 or newer.
|
||||
|
||||
```bash
|
||||
sudo apt install ./terraria-server-manager_2.0.0_all.deb
|
||||
```
|
||||
|
||||
Using `apt install ./file.deb` (rather than `dpkg -i`) installs the dependencies automatically. `unzip` is required. `curl` and the ICU library are "recommended", which apt installs by default; they're only needed for tModLoader instances, which crash with `Aborted` without ICU.
|
||||
|
||||
Installing the package:
|
||||
|
||||
- creates the `terraria` system user and group;
|
||||
- creates `/var/lib/terraria/`, `/var/lib/terraria/instances/` and `/var/lib/terraria/dist/`;
|
||||
- installs the units and helper script.
|
||||
|
||||
It doesn't start or enable anything.
|
||||
|
||||
If you use a firewall, open each instance's port for **TCP**. Terraria uses TCP only.
|
||||
|
||||
```bash
|
||||
sudo ufw allow 7777/tcp # example with ufw
|
||||
```
|
||||
|
||||
### Upgrading the package
|
||||
|
||||
```bash
|
||||
sudo apt install ./terraria-server-manager_<new-version>_all.deb
|
||||
```
|
||||
|
||||
Running servers are not restarted. Each one picks up the new version the next time it starts. Your changes to `/etc/default/terractl` are kept; if the new package also changes that file, dpkg asks which version to keep.
|
||||
|
||||
### Removing the package
|
||||
|
||||
```bash
|
||||
sudo apt remove terraria-server-manager # stops all instances (worlds are saved first)
|
||||
sudo apt purge terraria-server-manager # also removes config and boot-time enablement
|
||||
```
|
||||
|
||||
Neither command deletes `/var/lib/terraria` or the `terraria` user, so your worlds survive even a purge. To delete everything:
|
||||
|
||||
```bash
|
||||
sudo rm -rf /var/lib/terraria && sudo userdel terraria
|
||||
```
|
||||
|
||||
### Upgrading from the `terraria-instance` package
|
||||
|
||||
Versions before 2.0.0 were packaged as `terraria-instance`, and the command had the same name. The new package declares that it replaces the old one, so installing it removes `terraria-instance` automatically:
|
||||
|
||||
```bash
|
||||
sudo apt install ./terraria-server-manager_2.0.0_all.deb
|
||||
```
|
||||
|
||||
Things to know:
|
||||
|
||||
- **Instances are stopped (and saved) during the switch**, because removing the old package stops them. Start them again afterwards with `sudo systemctl start terraria@<name>`. Instances, worlds, mods and the `terraria` user all carry over unchanged.
|
||||
- **The command is now `terractl`.** Update any scripts or cron jobs that call `terraria-instance`.
|
||||
|
||||
**Clean up the old package straight after upgrading.** The old package is removed, but dpkg still keeps a record of it because its settings file is left behind. Purging that record, including with a general cleanup like `apt purge ~c` or `apt autoremove --purge`, runs the old package's purge step. Because the instances have the same unit names, that step deletes their start-at-boot links. So purge it deliberately, then re-enable the instances:
|
||||
|
||||
```bash
|
||||
# 1. If you customised it, copy the old settings file across (purging deletes it)
|
||||
sudo cp /etc/default/terraria-instance /etc/default/terractl
|
||||
|
||||
# 2. Note which instances start at boot, purge the old package, re-enable them
|
||||
enabled=$(ls /etc/systemd/system/multi-user.target.wants/ | grep '^terraria@')
|
||||
sudo apt purge terraria-instance
|
||||
for unit in $enabled; do sudo systemctl enable "$unit"; done
|
||||
```
|
||||
|
||||
### Building from source
|
||||
|
||||
From the git repository:
|
||||
|
||||
```bash
|
||||
make check # syntax-check the scripts (and shellcheck, if installed)
|
||||
make deb # builds build/terraria-server-manager_<version>_all.deb
|
||||
sudo make install # or install directly without a package (PREFIX=/usr/local)
|
||||
sudo make uninstall # removes a 'make install' (keeps settings and data)
|
||||
```
|
||||
|
||||
The version comes from the `VERSION` file. Set `Maintainer:` in `packaging/deb/control` to yourself before publishing packages.
|
||||
|
||||
### Changing locations
|
||||
|
||||
`/etc/default/terractl` can move the instances or zips directory. If you move the instances directory, the service also needs permission to write to the new location:
|
||||
|
||||
```bash
|
||||
sudo systemctl edit terraria@.service
|
||||
```
|
||||
```ini
|
||||
[Service]
|
||||
ReadWritePaths=/your/new/path
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migrating from the manual install
|
||||
|
||||
The earlier manual setup used `/opt/terraria`, `/terraria`, and a script called `terraria-instance` in `/usr/local/bin`. To move to the package:
|
||||
|
||||
```bash
|
||||
# 1. Note which instances start at boot, then stop everything
|
||||
ls /etc/systemd/system/multi-user.target.wants/ | grep terraria@
|
||||
sudo systemctl stop 'terraria@*'
|
||||
|
||||
# 2. Remove the old files. These would override the package's versions:
|
||||
# /etc/systemd/system takes precedence over /usr/lib/systemd/system, and
|
||||
# /usr/local/bin comes before /usr/bin in PATH.
|
||||
sudo rm /etc/systemd/system/terraria@.service /etc/systemd/system/terraria@.socket
|
||||
sudo rm /usr/local/bin/terraria-instance
|
||||
|
||||
# 3. Install the package (keeps the existing 'terraria' user)
|
||||
sudo apt install ./terraria-server-manager_2.0.0_all.deb
|
||||
|
||||
# 4. Move instances and zips
|
||||
for d in /opt/terraria/*/; do
|
||||
[ -f "$d/instance.conf" ] && sudo mv "$d" /var/lib/terraria/instances/
|
||||
done
|
||||
[ -d /opt/terraria/.deleted ] && sudo mv /opt/terraria/.deleted /var/lib/terraria/instances/
|
||||
sudo mv /terraria/*.zip /var/lib/terraria/dist/
|
||||
|
||||
# 5. serverconfig.txt contains absolute paths; update them
|
||||
sudo sed -i 's#/opt/terraria/#/var/lib/terraria/instances/#g' \
|
||||
/var/lib/terraria/instances/*/serverconfig.txt
|
||||
sudo chown -R terraria:terraria /var/lib/terraria/instances
|
||||
|
||||
# 6. Re-enable instances (the old boot links point at the deleted unit file)
|
||||
sudo systemctl reenable terraria@calamity # repeat for each instance from step 1
|
||||
sudo systemctl start terraria@calamity
|
||||
```
|
||||
|
||||
Once everything works, remove the old directories: `sudo rm -rf /terraria /opt/terraria`. If you set `ZIP=` in an `instance.conf` to an absolute path under `/terraria`, change it to just the file name.
|
||||
|
||||
The existing `terraria` user keeps `/opt/terraria` as its home directory. That's harmless, because the script sets a per-instance home itself. To tidy it anyway, run `sudo usermod -d /var/lib/terraria terraria` after deleting `/opt/terraria`.
|
||||
|
||||
---
|
||||
|
||||
## Server zips
|
||||
|
||||
Put the official downloads in `/var/lib/terraria/dist`:
|
||||
|
||||
| Type | File name pattern | Where to get it |
|
||||
|---|---|---|
|
||||
| Vanilla | `terraria-server-*.zip` | terraria.org (the "PC Dedicated Server" download link) |
|
||||
| tModLoader | `tModLoader*.zip` | tModLoader's GitHub releases page (`tModLoader.zip`) |
|
||||
|
||||
**Rename tModLoader zips to include the version**, for example `tModLoader-v2026.07.3.0.zip`. GitHub always calls the file `tModLoader.zip`, so renaming it lets you keep several versions side by side and pin instances to specific ones.
|
||||
|
||||
Zips are only read, never changed, and one zip can serve any number of instances.
|
||||
|
||||
**tModLoader zips don't include .NET.** Each tModLoader instance downloads the .NET runtime it needs into `server/dotnet/` on its first start, so that start needs internet access and `curl`. The download is kept when you upgrade or re-unpack the instance. tModLoader checks the .NET version on every start and fetches a different one itself if a new release needs it.
|
||||
|
||||
Members of the `terraria` group can copy zips into `dist/` without `sudo`:
|
||||
|
||||
```bash
|
||||
scp tModLoader-v2026.07.3.0.zip you@yourserver:/var/lib/terraria/dist/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Creating an instance
|
||||
|
||||
```bash
|
||||
sudo terractl new <name> [vanilla|tmodloader] [port]
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
sudo terractl new survival # vanilla, next free port
|
||||
sudo terractl new calamity tmodloader # tModLoader, next free port
|
||||
sudo terractl new pvp vanilla 7800 # vanilla on port 7800
|
||||
```
|
||||
|
||||
If you don't give a port, the instance gets the next number after the highest port already used, starting at 7777.
|
||||
|
||||
This creates `/var/lib/terraria/instances/<name>/` with `instance.conf` and `serverconfig.txt`, but **does not start the server**. Before the first start, review `serverconfig.txt` (world size, difficulty, password). For a tModLoader instance, also add your mods first (see [Mods](#mods-tmodloader)): the world is generated on first start, and it should be generated with the mods loaded so their world content is created.
|
||||
|
||||
Instance names may contain letters, digits, `_`, `-` and `.`, and must not start with `.`.
|
||||
|
||||
### Quick start: a new modded server
|
||||
|
||||
```bash
|
||||
sudo terractl new calamity tmodloader
|
||||
sudo terractl mods calamity add ~/tmod-export # your mods, before the first start
|
||||
sudo nano /var/lib/terraria/instances/calamity/serverconfig.txt # optional: world size, difficulty
|
||||
sudo systemctl enable --now terraria@calamity
|
||||
sudo terractl attach calamity # watch it load and generate the world
|
||||
```
|
||||
|
||||
You can also skip `new` and just run `sudo systemctl start terraria@<name>`. That creates a **vanilla** instance with default settings; to switch it to tModLoader, change `TYPE` in its `instance.conf` and restart.
|
||||
|
||||
---
|
||||
|
||||
## Starting, stopping and boot
|
||||
|
||||
Instances are ordinary systemd services:
|
||||
|
||||
```bash
|
||||
sudo systemctl start terraria@calamity
|
||||
sudo systemctl stop terraria@calamity # saves the world, then exits
|
||||
sudo systemctl restart terraria@calamity
|
||||
sudo systemctl enable terraria@calamity # start at boot
|
||||
sudo systemctl disable terraria@calamity # don't start at boot
|
||||
sudo systemctl enable --now terraria@calamity # both at once
|
||||
systemctl status terraria@calamity
|
||||
```
|
||||
|
||||
To see all instances with their type, port and state:
|
||||
|
||||
```bash
|
||||
sudo terractl list
|
||||
```
|
||||
|
||||
Behaviour to be aware of:
|
||||
|
||||
- **Crashes restart automatically** after 10 seconds.
|
||||
- **A clean exit does not restart.** If you type `exit` in the server console, the server saves and stops, and stays stopped until you start it again.
|
||||
- **The first start of a tModLoader instance is slow.** It downloads .NET, loads the mods and generates the world, which can take several minutes.
|
||||
- **Stopping waits for the save.** The server gets up to 80 seconds to save and exit before systemd forces it to stop.
|
||||
|
||||
---
|
||||
|
||||
## The server console
|
||||
|
||||
Each server reads console commands (`save`, `say`, `kick`, `playing`, and so on) from its pipe, and its output goes to the systemd journal.
|
||||
|
||||
### Interactive: `attach`
|
||||
|
||||
```bash
|
||||
sudo terractl attach calamity
|
||||
```
|
||||
|
||||
This shows the last 30 lines of output and then follows it live. Anything you type is sent to the server, with arrow-key editing and history. **Ctrl-D** or **Ctrl-C** detaches, and the server keeps running.
|
||||
|
||||
`attach` will not send `exit`, since that would stop the server. Use `systemctl stop` to stop it.
|
||||
|
||||
The one visible difference from a real terminal: the server's `:` prompt only appears once a newline follows it.
|
||||
|
||||
### One-off commands: `cmd`
|
||||
|
||||
```bash
|
||||
sudo terractl cmd calamity save
|
||||
sudo terractl cmd calamity say Restarting in 5 minutes
|
||||
```
|
||||
|
||||
This is useful in scripts and cron jobs. The command's output appears in the journal.
|
||||
|
||||
### Logs only
|
||||
|
||||
```bash
|
||||
journalctl -u terraria@calamity -f # follow
|
||||
journalctl -u terraria@calamity -n 100 # last 100 lines
|
||||
journalctl -u terraria@calamity --since today
|
||||
```
|
||||
|
||||
tModLoader also writes its own logs to `/var/lib/terraria/instances/<name>/server/tModLoader-Logs/`:
|
||||
|
||||
- `Launch.log` covers the .NET download and startup.
|
||||
- `server.log` covers mod loading and gameplay.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Each instance has two config files for two different purposes.
|
||||
|
||||
### `serverconfig.txt`: Terraria's settings
|
||||
|
||||
This is Terraria's standard server config, read by the game itself. The generated default:
|
||||
|
||||
```ini
|
||||
world=/var/lib/terraria/instances/<name>/data/Worlds/<name>.wld
|
||||
worldpath=/var/lib/terraria/instances/<name>/data/Worlds
|
||||
autocreate=2 # create world if missing: 1=small 2=medium 3=large
|
||||
worldname=<name>
|
||||
difficulty=0 # 0=classic 1=expert 2=master 3=journey
|
||||
#seed=
|
||||
port=7777
|
||||
maxplayers=8
|
||||
password=
|
||||
motd=Welcome to <name>
|
||||
secure=1
|
||||
upnp=0
|
||||
language=en-US
|
||||
banlist=/var/lib/terraria/instances/<name>/data/banlist.txt
|
||||
```
|
||||
|
||||
`autocreate`, `worldname`, `difficulty` and `seed` only matter when the world file doesn't exist yet. Once the world has been created, changing them has no effect.
|
||||
|
||||
Changes take effect on restart. Every instance must use a different `port`.
|
||||
|
||||
To use an existing world, copy the `.wld` file (plus `.twld` for tModLoader worlds) into `data/Worlds/` and point `world=` at it.
|
||||
|
||||
### `instance.conf`: how the instance runs
|
||||
|
||||
The game never reads this file. The helper script reads it at every start.
|
||||
|
||||
```bash
|
||||
TYPE=tmodloader # vanilla | tmodloader
|
||||
ZIP= # zip to use; blank = newest matching zip at first install
|
||||
EXTRA_ARGS=() # extra server arguments, as a bash array
|
||||
```
|
||||
|
||||
| Setting | Effect |
|
||||
|---|---|
|
||||
| `TYPE` | Which server software runs. Changing it re-unpacks `server/` from the other kind of zip on the next start. `data/` and `serverconfig.txt` are kept. |
|
||||
| `ZIP` | Pins a specific zip from `/var/lib/terraria/dist` (a file name, or an absolute path). Changing it re-unpacks `server/` on the next start. If left blank, the newest matching zip is used at first install and **never upgraded automatically**. |
|
||||
| `EXTRA_ARGS` | Extra command-line arguments, e.g. `EXTRA_ARGS=(-disableannouncementbox)`. |
|
||||
|
||||
This file also marks the directory as an instance: `list` ignores directories without one, and `delete` refuses to remove them.
|
||||
|
||||
---
|
||||
|
||||
## Mods (tModLoader)
|
||||
|
||||
Mods only work on tModLoader instances. Each instance has its own separate set of mods:
|
||||
|
||||
```
|
||||
/var/lib/terraria/instances/<name>/data/Mods/
|
||||
├── enabled.json ["CalamityMod", "MagicStorage"]
|
||||
├── CalamityMod.tmod
|
||||
└── MagicStorage.tmod
|
||||
```
|
||||
|
||||
`enabled.json` lists which mods to load, using each file's name without `.tmod`. Every mod's dependencies must also be present and listed. Mod settings live in `data/ModConfigs/`.
|
||||
|
||||
You don't need to edit these by hand: `terractl mods` manages them and sets the file ownership correctly (see [Managing mods](#managing-mods)). The `Mods` folder is created automatically for tModLoader instances.
|
||||
|
||||
Players don't need to install mods themselves: tModLoader offers to download the server's mods when they join.
|
||||
|
||||
### Exporting mods from Windows
|
||||
|
||||
tModLoader on Windows keeps its files in these places:
|
||||
|
||||
| What | Where |
|
||||
|---|---|
|
||||
| Which mods are enabled | `Documents\My Games\Terraria\tModLoader\Mods\enabled.json` |
|
||||
| Workshop mods | `<Steam library>\steamapps\workshop\content\1281930\<id>\` |
|
||||
| Manually installed mods | `Documents\My Games\Terraria\tModLoader\Mods\` |
|
||||
| Mod settings | `Documents\My Games\Terraria\tModLoader\ModConfigs\` |
|
||||
|
||||
Workshop mods often contain **several builds**, in folders named after the tModLoader version they target (`2024.3`, `2025.3`, ...). The game loads the build from the highest folder that isn't newer than the running tModLoader.
|
||||
|
||||
`export-tmod-mods.ps1` applies the same rule. It's installed on the server at `/usr/share/terraria-server-manager/`; copy it to your PC first. It collects every enabled mod, a matching `enabled.json` and your mod settings into `Desktop\tmod-export`, laid out like the server's `data/` folder. Run it in PowerShell:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\export-tmod-mods.ps1 -MaxVersion 2026.7
|
||||
```
|
||||
|
||||
Set `-MaxVersion` to your tModLoader version as year.month. The full version is shown at the bottom-left of tModLoader's main menu, e.g. `v2026.07.3.0` → `2026.7`. For the preview branch, add `-TmlDir "$HOME\Documents\My Games\Terraria\tModLoader-preview"`.
|
||||
|
||||
The script prints which file it chose for each mod, and warns about any it couldn't find. It leaves missing mods out of `enabled.json`, because one missing file would stop the server loading any mods.
|
||||
|
||||
### Copying mods to the server
|
||||
|
||||
Copy the export folder to the server. `scp` is built into Windows 10 and 11:
|
||||
|
||||
```powershell
|
||||
scp -r "$HOME\Desktop\tmod-export" you@yourserver:
|
||||
```
|
||||
|
||||
This puts it in your home directory on the server. Then install the mods into the instance:
|
||||
|
||||
```bash
|
||||
sudo terractl mods calamity add ~/tmod-export
|
||||
sudo systemctl restart terraria@calamity # only if it's already running
|
||||
```
|
||||
|
||||
`add` copies the `.tmod` files and any `ModConfigs`, gives them to the `terraria` user, and adds them to `enabled.json`. For a new instance, do this **before the first start** so the world is generated with the mods loaded.
|
||||
|
||||
### Managing mods
|
||||
|
||||
```bash
|
||||
terractl mods <name> # list installed mods and whether each is enabled
|
||||
terractl mods <name> add <folder|file.tmod>... # install and enable
|
||||
terractl mods <name> disable <Mod>... # keep installed, but don't load
|
||||
terractl mods <name> enable <Mod>... # load again
|
||||
terractl mods <name> remove <Mod>... # uninstall
|
||||
```
|
||||
|
||||
`add` accepts `.tmod` files, a folder containing them, or an export folder with `Mods/` and `ModConfigs/` subfolders. Mod names are the file names without `.tmod`, e.g. `CalamityModMusic`.
|
||||
|
||||
Adding a mod that's already installed replaces it, which is how you update a mod. Changes take effect when the server restarts; the command reminds you if it's running.
|
||||
|
||||
The list also flags mods that are **enabled but missing**, because the server won't load any mods while one is missing.
|
||||
|
||||
`add` doesn't check dependencies, so remember to add them too. If one is missing, `server/tModLoader-Logs/server.log` says which.
|
||||
|
||||
---
|
||||
|
||||
## Versions and upgrades
|
||||
|
||||
### Players must match the server's version
|
||||
|
||||
- **Vanilla:** players need the same Terraria version as the server's zip. For example, `terraria-server-1458.zip` is Terraria 1.4.5.8.
|
||||
- **tModLoader:** players need exactly the same tModLoader version, including the same branch (stable or preview). Steam updates players' tModLoader automatically, usually monthly, so a server that was matching can become mismatched after an update.
|
||||
|
||||
Stable tModLoader and the latest vanilla Terraria can be based on different Terraria versions. That's fine, because every instance runs independently.
|
||||
|
||||
### Upgrading (or downgrading) an instance
|
||||
|
||||
1. Put the new zip in `/var/lib/terraria/dist`, with the version in its name.
|
||||
2. Set `ZIP=` to that file name in the instance's `instance.conf`.
|
||||
3. Restart the instance:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart terraria@calamity
|
||||
```
|
||||
|
||||
The helper sees that the zip has changed and re-unpacks `server/`. Nothing in `data/` is touched. To move back, set `ZIP=` to the old file.
|
||||
|
||||
**Pin `ZIP=` on modded instances.** Pinned instances never change version by accident, and you can see at a glance which version each one is on. New tModLoader versions can break older mods, so only upgrade a modded server once its mods support the new version.
|
||||
|
||||
### Re-unpacking the same version
|
||||
|
||||
If `server/` gets damaged or you want a clean copy:
|
||||
|
||||
```bash
|
||||
sudo terractl reinstall calamity
|
||||
sudo systemctl restart terraria@calamity
|
||||
```
|
||||
|
||||
For tModLoader, the downloaded .NET runtime and `tModLoader-Logs/` are kept. If you suspect .NET itself is damaged, use `--clean` to delete them too, so .NET is downloaded again on the next start:
|
||||
|
||||
```bash
|
||||
sudo terractl reinstall calamity --clean
|
||||
sudo systemctl restart terraria@calamity
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Deleting and restoring
|
||||
|
||||
```bash
|
||||
sudo terractl delete calamity # asks you to type the name
|
||||
sudo terractl delete calamity -y # no prompt
|
||||
sudo terractl delete calamity -y --no-backup # permanently, no backup
|
||||
```
|
||||
|
||||
This stops and disables the service, then removes the whole instance directory. Unless you pass `--no-backup`, it first archives the configs and `data/` to `/var/lib/terraria/instances/.deleted/<name>-<timestamp>.tar.gz`. `server/` is left out of the archive because it can be recreated from the zip.
|
||||
|
||||
To restore an instance:
|
||||
|
||||
```bash
|
||||
sudo tar -xzf /var/lib/terraria/instances/.deleted/calamity-20260928-134422.tar.gz -C /var/lib/terraria/instances
|
||||
sudo chown -R terraria:terraria /var/lib/terraria/instances/calamity
|
||||
sudo systemctl enable --now terraria@calamity # server/ is unpacked again on start
|
||||
```
|
||||
|
||||
`.deleted/` is never cleaned up automatically. Remove old archives yourself.
|
||||
|
||||
---
|
||||
|
||||
## Backups
|
||||
|
||||
Everything worth keeping is in `data/`, `instance.conf` and `serverconfig.txt`.
|
||||
|
||||
To back up a running server, save it first so the world file on disk is current:
|
||||
|
||||
```bash
|
||||
sudo terractl cmd calamity save
|
||||
sleep 10
|
||||
sudo tar -czf /root/calamity-$(date +%F).tar.gz -C /var/lib/terraria/instances \
|
||||
--exclude=calamity/server calamity
|
||||
```
|
||||
|
||||
Stopping the server first is the safest option. Terraria also keeps a `.bak` copy of each world alongside the world file.
|
||||
|
||||
---
|
||||
|
||||
## Permissions
|
||||
|
||||
The servers always run as the `terraria` user. Administration is simplest with `sudo`.
|
||||
|
||||
| Command | Who can run it | Notes |
|
||||
|---|---|---|
|
||||
| `new` | root (or `terraria`) | Run as root, it sets ownership of the new instance to `terraria` itself. |
|
||||
| `list` | root, or members of the `terraria` group | `/var/lib/terraria` is not readable by other users. |
|
||||
| Adding zips to `dist/` | root, or members of the `terraria` group | |
|
||||
| `attach` | root, or members of **both** `terraria` and `systemd-journal` | Needs to write to the console pipe and read the journal. |
|
||||
| `cmd` | root, or members of the `terraria` group | Writes to the console pipe. |
|
||||
| `reinstall` | root (or `terraria`) | |
|
||||
| `mods <name>` (list) | root, or members of the `terraria` group | |
|
||||
| `mods add/enable/disable/remove` | root (or `terraria`) | Run as root, it sets ownership of the files it installs to `terraria`. |
|
||||
| `delete` | root only | Checked by the script. |
|
||||
| `prepare`, `run` | Normally only the service | Run as root, they automatically switch to the `terraria` user, so no files end up owned by root. Any other user is refused. |
|
||||
| `stop` | Only the service | Needs the server's process ID from systemd. |
|
||||
| `systemctl start/stop/enable` | root | |
|
||||
| `journalctl -u terraria@...` | root, or members of `systemd-journal` or `adm` | |
|
||||
|
||||
To run the everyday commands without `sudo`:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG terraria,systemd-journal youruser # then log out and back in
|
||||
```
|
||||
|
||||
Members of the `terraria` group can read server files (useful for backups) but cannot change them. Files the service creates are readable, not writable, by the group.
|
||||
|
||||
### Avoiding root-owned files
|
||||
|
||||
The helper commands don't leave root-owned files behind, and `mods add` handles mods and ModConfigs. The remaining risk is **copying or creating other files in an instance directory as root**, such as worlds. The server can't write to root-owned files, so saving fails or tModLoader errors. After copying anything in, run:
|
||||
|
||||
```bash
|
||||
sudo chown -R terraria:terraria /var/lib/terraria/instances/<name>
|
||||
```
|
||||
|
||||
Alternatively, copy files as the `terraria` user to begin with:
|
||||
|
||||
```bash
|
||||
sudo -u terraria cp MyWorld.wld /var/lib/terraria/instances/calamity/data/Worlds/
|
||||
```
|
||||
|
||||
Editing an existing file with `sudo nano` keeps its owner, so it's fine.
|
||||
|
||||
---
|
||||
|
||||
## Running by hand for debugging
|
||||
|
||||
Stop the service first, so two copies of the same server don't run at once on the same port and world:
|
||||
|
||||
```bash
|
||||
sudo systemctl stop terraria@calamity
|
||||
sudo terractl run calamity # automatically runs as 'terraria'
|
||||
```
|
||||
|
||||
The server runs in your terminal and you can type commands into it directly. Type `exit` to stop it, then start the service again:
|
||||
|
||||
```bash
|
||||
sudo systemctl start terraria@calamity
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**tModLoader stops with `Aborted` right after "Launched Using Local Dotnet".**
|
||||
The ICU library is missing, so .NET aborts at startup. Fix it with `sudo apt install libicu-dev`, then restart the instance. To confirm, check that `ldconfig -p | grep -c libicu` prints more than 0.
|
||||
|
||||
**`ls: cannot access '.../dotnet/shared/Microsoft.NETCore.App'` on the first start.**
|
||||
Harmless. tModLoader looks for old .NET versions to clean up before any have been installed.
|
||||
|
||||
**The first tModLoader start fails while downloading .NET.**
|
||||
The server needs internet access and `curl` on its first start. See `server/tModLoader-Logs/Launch.log` for the exact error.
|
||||
|
||||
If the host has no internet access, you can copy the `dotnet` folder from another tModLoader instance that runs the same tModLoader version. Unpack the new instance first, then copy the folder in before starting it:
|
||||
```bash
|
||||
sudo terractl prepare <name> # unpacks server/ without starting
|
||||
sudo cp -a /var/lib/terraria/instances/other/server/dotnet /var/lib/terraria/instances/<name>/server/
|
||||
sudo systemctl start terraria@<name>
|
||||
```
|
||||
|
||||
**The server can't save, or you see "Permission denied" errors.**
|
||||
Some files are owned by root. Run `sudo chown -R terraria:terraria /var/lib/terraria/instances/<name>`.
|
||||
|
||||
**Players can't join a tModLoader server with a version-mismatch message.**
|
||||
The player's tModLoader version differs from the server's. See [Versions and upgrades](#versions-and-upgrades).
|
||||
|
||||
**Mods don't load.**
|
||||
Run `terractl mods <name>` to check for mods that are enabled but missing. Then check `server/tModLoader-Logs/server.log` for the cause. Common ones:
|
||||
- a dependency is missing from `data/Mods/`;
|
||||
- a mod name in `enabled.json` doesn't match its `.tmod` file name;
|
||||
- a mod build was made for a newer tModLoader than the server (re-export with `-MaxVersion`);
|
||||
- the files are owned by root.
|
||||
|
||||
**The server fails with "address already in use".**
|
||||
Two instances share a port, or a copy you started by hand is still running. Check with `sudo terractl list` and `pgrep -af 'tModLoader.dll|TerrariaServer'`.
|
||||
|
||||
**The service starts but you can't connect.**
|
||||
Check the port in `serverconfig.txt`, your firewall (TCP), and router port forwarding.
|
||||
|
||||
**The server isn't restarting after it stopped.**
|
||||
It exited cleanly, probably via `exit` in the console, so systemd leaves it stopped. Start it again with `systemctl start`.
|
||||
|
||||
**The world was created without mod content.**
|
||||
It was generated before the mods were added. Delete the world files in `data/Worlds/` (or point `world=` at a new name) and restart to generate a new one.
|
||||
|
||||
---
|
||||
|
||||
## Command reference
|
||||
|
||||
```
|
||||
terractl new <name> [vanilla|tmodloader] [port] Create an instance (not started)
|
||||
terractl list Show instances, type, port, state
|
||||
terractl attach <name> Interactive console (Ctrl-D detaches)
|
||||
terractl cmd <name> <command...> Send one console command
|
||||
terractl reinstall <name> [--clean] Re-unpack server/ on next start
|
||||
(--clean also re-downloads .NET)
|
||||
terractl mods <name> [list] Show installed mods
|
||||
terractl mods <name> add <folder|file.tmod>... Install and enable mods (and ModConfigs)
|
||||
terractl mods <name> enable|disable <Mod>... Change which mods load
|
||||
terractl mods <name> remove <Mod>... Uninstall mods
|
||||
terractl delete <name> [-y] [--no-backup] Stop, disable, back up and remove
|
||||
terractl --version Show the installed version
|
||||
|
||||
Used by the service:
|
||||
terractl prepare <name> Create dirs/configs, unpack zip if needed
|
||||
terractl run <name> Run the server
|
||||
terractl stop <name> <pid> Save and shut down via the console
|
||||
```
|
||||
|
||||
```
|
||||
systemctl start|stop|restart|status terraria@<name>
|
||||
systemctl enable|disable [--now] terraria@<name>
|
||||
journalctl -u terraria@<name> [-f] [-n N]
|
||||
```
|
||||
Reference in new issue
Block a user