Server Configuration
Configure a hosted server, including the global server config and per-session server profiles.
This guide covers how to configure a hosted server, including the global server config file and per-session server profiles, and how to run a dedicated (headless) server.
Running a Dedicated Server
creation_server is the headless server: the same server the game runs when you host from the menu, without the game attached. It has no window and needs no GPU, so it runs on a plain Linux or Windows machine.
Run it from a folder laid out like the game’s — it reads saves/, instances/, server_config/, server_profiles/ and certs/ from the working directory and writes to logs/:
creation_server --save <name> [--port <n>] [--profile <name>] [--upnp]
| Option | Meaning |
|---|---|
--save <name> | The save under saves/ to host. Required; create the world in the game first. |
--port <n> | TCP port to listen on. Defaults to 42069, the port the in-game host menu uses. |
--profile <name> | The server profile under server_profiles/ to apply (see Server Profiles). |
--upnp | Open the port on your router with UPnP and listen on the machine’s LAN address. Without it the server listens on every interface and port forwarding is up to you. |
Players join with the machine’s address and port from the Join via IP menu. Steam P2P hosting and the host’s automatic operator status are game-only: on a dedicated server, operators come from server_config.yaml and the profile.
Stop it with Ctrl-C. The server finishes saving every world before it exits, the same as closing a hosted game.
The Steam library
The server links the Steam API (it validates session tickets under auth-mode: steam), so the Steam
library has to sit next to the binary:
| Platform | File |
|---|---|
| Windows | steam_api64.dll beside creation_server.exe |
| Linux | libsteam_api.so beside creation_server |
Both ship in the server download. If you build from source instead, copy the library out of the build
output (target/<profile>/steam_api64.dll on Windows; on Linux it is written to
target/<profile>/build/steamworks-sys-*/out/libsteam_api.so). The Linux binary carries an $ORIGIN
runpath, so a copy beside it is found with no LD_LIBRARY_PATH to set.
On the first launch of a save the server writes a self-signed certificate to certs/server/, and logs
a couple of “Failed to read server data file” / “Error loading biome IDs” errors while it generates the
world for the first time. Both are expected on a brand-new save.
Global Server Config
File: server_config/server_config.yaml
This file sets the default behaviour for every server session. Any value here can be overridden on a per-profile basis (see Server Profiles below).
Authentication Mode
auth-mode: steam
Controls how the server verifies player identity at login.
| Value | Behaviour |
|---|---|
steam | Players must be logged into Steam. The server verifies their identity using a Steam session ticket. Player saves are tied to the player’s Steam account. |
offline | No verification — the server trusts whatever name the client provides. Suitable for private LAN sessions or local testing only. |
Note: In
steammode, operator permissions (see below) must use the player’s Steam ID, not their display name. Steam IDs appear in the server log when a player connects.
Operators
operators:
- 76561198000000000
- 76561198000000001
A list of player IDs that have operator-level permission. Operators can use privileged chat commands such as /kick, /ban, /mute, and /teleport.
- In steam mode: use the player’s Steam ID (a 17-digit number shown in the server log on login).
- In offline mode: use the player’s login ID (the save ID sent at login, shown in the server log) — not the display name, which can be changed freely and is never used for permission checks.
Operator lists from profiles are added to this list — they never replace it. A player in either list has operator access.
Security: operator commands are disabled by default under
offlineauth, because offline mode does not verify identity — any connecting player could claim a configured operator’s login ID and gain operator powers. On a public server, usesteamauth so operator identity is verified. See Offline Operators below to re-enable them on a trusted private server.
Automatic Operators
You do not have to list yourself here to be an operator on a server you run:
- The player who hosts the server is automatically granted operator for that session. This is resolved from your own identity when you start hosting and is not stored in the save or the profile — so it applies whichever profile you host under, and hosting a world you downloaded from someone else grants operator to nobody but you. It is subject to the same rules above: under
offlineauth it still requiresallow-offline-operators(see below), and understeamauth it just works. - In singleplayer, the local player is always an operator; no configuration is needed.
To grant operator to other people persistently (co-admins), add them to the operators: list here or in a profile, as described above.
Offline Operators
allow-offline-operators: false
| Value | Behaviour |
|---|---|
false (default) | Under offline auth, all operator commands are refused — even for configured operators — because player identity cannot be verified. Has no effect under steam auth, where operators always work. |
true | Honor the operators: list under offline auth. Only enable this on a trusted LAN/private server where you control who can connect, since a malicious client can impersonate any operator’s login ID. |
When operators are configured but disabled by this default, the server logs a warning at startup explaining how to enable them or switch to Steam auth.
Chat
chat:
log-messages: true
slowdown-ms: 500
announce-player-connections: true
history-size: 20
max-message-chars: 256
| Field | Default | Description |
|---|---|---|
log-messages | true | Write chat messages to the server log file. |
slowdown-ms | 500 | Minimum time in milliseconds a player must wait between chat messages. Defaults to 500 (about two messages/second) to curb flooding; set 0 to disable the limit. |
announce-player-connections | true | Broadcast a message to all players when someone joins or leaves. |
history-size | 20 | Number of recent messages sent to a player when they join mid-session. 0 disables replay. |
max-message-chars | 256 | Maximum character length of a single chat message. Maximum allowed value is 4096. |
Friendly Fire
pvp:
friendly-fire: false
| Field | Default | Description |
|---|---|---|
friendly-fire | false | Whether players can damage each other, and each other’s tamed creatures. |
Every player in a world counts as an ally of every other one — there is no party to join and nothing to
invite anyone to, the world is the team — and a tamed creature is an ally of its owner. With
friendly-fire: false, no player-sourced damage reaches an ally: melee swings, arrows and other
projectiles, thrown flasks and every other AoE zone, granted combat verbs, and damage dealt from a mod’s
Lua script are all covered by the same rule.
Ambient hazards are unaffected either way. Lava, rot gas, an ash storm and any other hazard that belongs to the world rather than to a player still hurt everyone standing in it.
Operators can flip the setting for the rest of the session with /pvp <on|off>, which overrides the
value here until the server restarts.
Rate Limiting
rate-limiting:
packets-per-second: 150
burst-size: 50
chunk-packets-per-second: 1000
chunk-burst-size: 1024
violation-limit: 1000
Controls how aggressively the server throttles clients that send packets too quickly. These defaults are suitable for normal play and generally do not need to be changed.
Chunk requests get their own, looser token bucket (chunk-*) because a client legitimately requests one chunk per position in its render distance all at once while a world loads — a burst the general limit would reject. The server also validates that each requested chunk is near the player’s actual position, so a looser chunk bucket does not expose the server to far-away chunk-flooding.
| Field | Default | Description |
|---|---|---|
packets-per-second | 150 | Sustained packet rate a client is allowed to send. |
burst-size | 50 | How many extra packets a client can send in a short burst before throttling begins. |
chunk-packets-per-second | 1000 | Sustained chunk-request (code 300) rate a client is allowed to send, on a separate bucket from the general limit. |
chunk-burst-size | 1024 | How many chunk requests a client can send in a short burst — sized to cover a full render-distance initial load. |
violation-limit | 1000 | Number of throttled (excess) packets allowed before the client is disconnected. |
Connection Limits
connection-limits:
max-connections: 256
max-connections-per-ip: 8
handshake-timeout-seconds: 30
idle-timeout-seconds: 120
Bounds how many clients may connect and how long a silent connection is tolerated, so a flood of connections or stalled peers can’t exhaust server resources. These defaults suit normal play and rarely need changing. Unlike the chat and rate-limiting blocks, connection-limits is a global-only setting — it is not a profile override.
| Field | Default | Description |
|---|---|---|
max-connections | 256 | Maximum concurrent client connections. Peers beyond this are dropped immediately after the TCP accept, before the TLS handshake. Set to 0 to disable the cap. |
max-connections-per-ip | 8 | Maximum concurrent connections from a single source, so one client can’t fill every slot. On a direct (TCP/TLS) server that source is the peer’s IP address; on a Steam P2P server it is the connecting Steam account. Set to 0 to disable. |
handshake-timeout-seconds | 30 | Seconds a freshly connected client may stay silent before sending its login request (code 600) before being disconnected. |
idle-timeout-seconds | 120 | Seconds an in-game client may stay silent before being disconnected. In-game clients send movement packets ~60×/second, so this only reaps dead/stalled connections. |
Mob Limits
mob-limits:
- spawn-group: Neutral
limit: 50
- spawn-group: Hostile
limit: 50
Sets a cap on how many mobs of each group can exist in the world at once, and doubles as the allow-list for natural spawning: a mob whose spawn-group has no entry here is never chosen by the natural spawner, so it will not spawn on its own (it can still be summoned or spawned by scripts/structures). The spawn-group value is matched against a mob’s own spawn-group case-insensitively — Hostile, hostile, and HOSTILE are the same group. Neutral and Npc always exist as groups even with no entry here, but still need an entry to spawn naturally. You can add as many entries as needed — one per spawn group.
The shipped roster uses three naturally-spawning groups — Neutral, Hostile, and Elite. The example ships Neutral and Hostile; Elite is intentionally held out until an elite mob is authored, because the spawner picks a group uniformly and an empty group wastes the spawn attempt. Boss and Npc are deliberately left out: a group with no entry is never drawn by the spawner, which is what a placed boss set-piece and a one-time authored NPC want (leaving them in would make the world randomly spawn bosses and named NPCs). When a mob declares a spawn-group (and spawn-rules) with no matching mob-limits entry, the server logs a warning at load naming the group, since it will otherwise silently never spawn.
An entry takes exactly spawn-group and limit; any other key fails that entry at load with a named error. A bad entry skips only itself, so the rest of your limits still apply — but a skipped entry means that group never spawns naturally, so read the log if a mob stops appearing.
Renamed in this version. This key was
type:in earlier versions. An un-migratedserver_config.yamllogs an error naming the old key and skips that entry (which silently disables natural spawning for that group), so rename it when you upgrade.
Required Client Mods
required-client-mods:
- SomeTexturePack
- AnotherClientMod
A list of client-only mod names (e.g. a texture pack marked side: client) that a connecting client must have installed, even though the server itself never loads them. They are advertised to the client during the connection handshake and reuse the same mod-compatibility warning dialog as the instance check. Defaults to empty (no extra client mods required).
Server Profiles
Server profiles let you save different server configurations and switch between them when hosting a session. This is useful if you host the same world for different audiences — for example, a private session for friends and a public session — without editing the global config each time.
Each profile is a folder inside server_profiles/:
server_profiles/
my_profile/
config.yaml ← settings that override server_config.yaml
data.yaml ← auto-managed: muted and banned players
Profiles are created automatically when you select a new profile name in the host menu.
Profile Config (config.yaml)
A profile’s config.yaml overrides specific values from server_config/server_config.yaml. Any field you omit is inherited from the global config — you only need to specify what you want to change.
All available overrides:
# Override authentication mode for this profile.
# "steam" or "offline". Inherits global value if omitted.
auth-mode: steam
# Additional operators for this profile. These are added to (not replacing)
# the global operators list in server_config.yaml.
operators:
- 76561198000000000
chat:
log-messages: true
slowdown-ms: 500
announce-player-connections: true
history-size: 20
max-message-chars: 256
rate-limiting:
packets-per-second: 150
burst-size: 50
chunk-packets-per-second: 1000
chunk-burst-size: 1024
violation-limit: 1000
All fields are optional. A completely empty config.yaml is valid — it simply inherits everything from the global config.
Profile Data (data.yaml)
This file is managed automatically by the server. It stores the list of muted and banned players for this profile. You should not edit it by hand unless you need to manually remove a ban or clear a muted player list when the server is offline.
muted-players:
- 76561198000000000
banned-players:
76561198000000001: 'Reason for ban'
Bans and mutes are profile-scoped — banning a player under one profile does not ban them under a different profile.
Example: Public vs. Private Profiles
server_profiles/public/config.yaml
auth-mode: steam
chat:
slowdown-ms: 2000
max-message-chars: 128
server_profiles/private/config.yaml
auth-mode: offline
chat:
announce-player-connections: false
Both profiles share the global operator list. The public profile adds chat rate limiting and Steam auth. The private profile uses offline mode and skips join/leave announcements. Note that allow-offline-operators is a global server_config.yaml setting, not a profile override — set it there (see above), not in a profile’s config.yaml, where it would be ignored.
Operator Commands Reference
Operators can run the following commands in chat:
| Command | Description |
|---|---|
/kick <player> | Disconnect a player from the server. |
/ban <player> [reason] | Permanently ban a player from the current session’s profile. |
/unban <player> | Remove a ban from the current profile. |
/mute <player> | Prevent a player from sending chat messages. |
/unmute <player> | Restore a player’s chat access. |
/pvp <on|off> | Toggle friendly fire for the session — whether players can damage each other and each other’s tamed creatures, across every damage source. Overrides pvp: friendly-fire: until the server restarts. |
/teleport <player> (alias /tp) | Teleport to another player. |
/noclip | Toggle noclip movement for yourself. |
/capability (alias /cap) | Show a player’s capabilities and where each one comes from. /capability grant <name> [player] and /capability revoke <name> [player] add or remove a persistent grant — useful for testing capability-gated content such as the double_jump and air_dash movement verbs without first authoring the gear that grants them. |
/rollcatch [count] | Roll the fishing catch table for the water you are standing in and report a tally of what came up, without granting anything. Content tool for tuning catch tables — see Fish Configuration. |
/list | Show all currently connected players. |
/seed | Show this world’s numeric seed (read-only). It reproduces a world only at the same game version and mod set; a new seed is a new world. |
/help | Show available commands. |
Operator status is granted through the operators: list and the automatic host grant described above — there is no in-chat /op or /deop command. /list, /seed and /help are available to everyone, not just operators.
Player arguments can be the player’s display name or their player ID. In steam auth mode, the player’s display name is their Steam persona name.
A <player> argument is matched against player IDs first (the verified, unique key), then against display names. Display names are unique per server — a login is refused if its display name is already in use (compared case-insensitively) — so a name resolves to at most one player. Matching the verified key first means a player cannot receive a command aimed at someone’s player ID by taking that ID as their display name. If an argument still matches more than one online player, the command fails and lists the candidates instead of guessing; target them by their exact player ID. /mute, /unmute, /ban and /unban also accept a bare player ID so offline players can be targeted.
Last updated