GWGridworks Guides
Home/Enshrouded/Server guides

Enshrouded dedicated server on Linux — the setup we actually run

Enshrouded Server guides updated 2026-10-17 4 min read

Enshrouded's dedicated server is a Windows program only — there is no native Linux build. If your always-on machine runs Linux, the realistic route is Proton, and the easiest way to get Proton right is the Docker image that bundles SteamCMD and Proton together. This page is that setup, at version 1.0.0.0, running on a home Linux box: the real compose file, the real config, the ports that matter, and the handful of gotchas that cost us the most time. Not a plan — a running server.

Why Linux + Proton

Keen ship enshrouded_server.exe, a Windows binary. You can run it on a Windows box, or under Proton on Linux. Ours lives on an always-on Linux server, so Proton it is. The image mbround18/enshrouded-docker:proton-latest does the heavy lifting: on first start it runs SteamCMD to pull the Windows depot of app 2278520 (about 8.6 GB of .exe and .dat files), then launches enshrouded_server.exe inside a Proton prefix.

The compose file

This is the whole thing — no secrets in it, the passwords live in enshrouded_server.json:

services:
  enshrouded:
    image: mbround18/enshrouded-docker:proton-latest
    container_name: enshrouded-server
    restart: unless-stopped
    stop_grace_period: 120s          # the server needs time to write the world on shutdown
    ports:
      - "15636:15636/tcp"
      - "15636:15636/udp"
      - "15637:15637/tcp"
      - "15637:15637/udp"
      - "13000:3000/tcp"             # image health endpoints (/live /ready /health); 3000 is taken on this host
    environment:
      TZ: "America/New_York"
      NAME: "Your Server Name"
      IP: "0.0.0.0"
      GAME_PORT: "15636"
      QUERY_PORT: "15637"
      SLOT_COUNT: "16"
      UPDATE_ON_START: "false"       # set true to let SteamCMD update on boot
      AUTO_UPDATE: "false"
      SCHEDULED_RESTART: "false"
      STOP_DELAY: "120"
      PROTON_NO_FSYNC: "1"           # force Proton off the fsync/esync path
      PROTON_NO_ESYNC: "1"
      HTTP_PORT: "3000"
    volumes:
      - /srv/media/enshrouded-game/enshrouded:/home/steam/enshrouded   # game files + world
      - /srv/media/enshrouded-game/proton:/home/steam/.proton          # persist the Proton prefix
      - /srv/media/enshrouded-game/proton_data:/home/steam/.proton_data

Ports — the one that matters

  • 15637 / UDP — the server port (queryPort). With Update #2 the server uses a single UDP

port, and the 1.0 readme calls queryPort "the port for the server." This is the one to forward.

  • 15636 / UDP — legacy game port. We map it too for older tooling; it is harmless but a forward

for it does nothing on 1.0.

  • 13000 / TCP — the image's health endpoints, remapped from 3000 because another app on this

host already owns 3000. Not needed for players.

Firewall: allow 15637/udp. For players outside your LAN you also need a router port-forward of 15637/udp to the host; LAN and VPN players reach it directly.

The config: enshrouded_server.json

It sits next to enshrouded_server.exe, is plain JSON, and is read only at boot — every change is a restart. The 1.0 readme (shipped as enshrouded_server_readme.txt) documents every key. The ones that matter:

KeyWhat it does
namethe server name shown in the Join list
saveDirectory / logDirectorywhere the world and logs are written (default ./savegame, ./logs)
ipleave at 0.0.0.0 unless you have a reason; a public IP here stops it starting
queryPortthe single server port, default 15637
slotCountmax players, 1–16
gameSettingsPresetDefault, Relaxed, Hard, Survival or Custom
userGroupsroles (Admin / Friend / Guest / Visitor) with per-role passwords and permissions
flameLevelFogRemovalnew in 1.0 — Flame level needed to place altars in the Shroud, default 11

Two things people get wrong: the top-level "password" key is legacy (it quietly builds a "default" group around it) — set passwords per role under userGroups instead. And there is no gamePort key that does anything; queryPort is the only port the server reads.

A trimmed, password-free shape:

{
  "name": "Your Server Name",
  "saveDirectory": "./savegame",
  "logDirectory": "./logs",
  "ip": "0.0.0.0",
  "queryPort": 15637,
  "slotCount": 16,
  "gameSettingsPreset": "Default",
  "userGroups": [
    { "name": "Admin",  "password": "pick-a-strong-one", "canKickBan": true,  "canAccessInventories": true,  "canEditWorld": true, "canEditBase": true, "canExtendBase": true,  "reservedSlots": 0 },
    { "name": "Friend", "password": "another-strong-one", "canKickBan": false, "canAccessInventories": true,  "canEditWorld": true, "canEditBase": true, "canExtendBase": false, "reservedSlots": 0 },
    { "name": "Guest",  "password": "one-more", "canKickBan": false, "canAccessInventories": false, "canEditWorld": true, "canEditBase": false, "canExtendBase": false, "reservedSlots": 0 }
  ]
}

The gotchas that actually bit us

  1. Host port 3000 was already taken — so the image's health endpoint moved to 13000. If you skip

this, the container starts but its /health is unreachable, which looks like a broken server.

  1. The Proton prefix was being rebuilt on every recreate — mount .proton and .proton_data

to real directories, or it reprovisions for minutes on every restart.

  1. The launcher hardcodes WINEESYNC/WINEFSYNC — Proton's own script honours PROTON_NO_FSYNC=1

and PROTON_NO_ESYNC=1, so set both to force it off that path.

  1. A too-fast shutdown corrupts or loses progress — the server writes the world on exit. Hence

stop_grace_period: 120s and STOP_DELAY=120. Never docker kill it.

  1. There is no console and no remote API — a server is administered by editing

enshrouded_server.json and restarting. Everything below is a restart.

  1. Updates: we run staged 1.0 files with UPDATE_ON_START=false / AUTO_UPDATE=false. Set them

true to let SteamCMD pull patches on boot.

Where everything lives

PathWhat
enshrouded/the game files (enshrouded_server.exe, ~8.6 GB of .dat) and enshrouded_server.json
enshrouded/savegame/world0.ksdthe whole world
enshrouded/savegame/backup/the image's rolling backups
enshrouded/logs/server logs
proton/, proton_data/the Wine/Proton prefix

Backups

world0.ksd under savegame/ is the entire world. Copy savegame/ before any update or config change, and keep a copy before any world-file surgery — we once had to migrate a save slot from a legacy hex id to world0.ksd, and a pre-migration copy is what made that safe.

First session — what actually happened

We ran it with two players the night it went up — an adult (Magius) and a kid (jacksontutterow40) — with no changes to the default config. The server log tells the story:

  • Both connected and played. Two player slots filled, replication reporting OperatingNormally.
  • Disconnects were clean. On exit the server sent a final client save to each player, received

the ack, then removed them — and world0.ksd updated on save, so nothing was lost.

  • Latency was low — 11–35 ms ping throughout, consistent with a same-network session.
  • One harmless warning on each disconnect: `[session] Remove player from session. Not found in

online game info`. It appears at teardown and does not touch the save — don't chase it.

So the join flow, the password/role handling under userGroups, and the shutdown save all worked first time, with no workarounds. The part still unverified from here is connecting from outside the network (a router forward of 15637/udp) — that gets filled in the first time someone joins remotely.

Sources

  • The official enshrouded_server_readme.txt shipped with the server files, version 1.0.0.0 —

the authoritative reference for every config key.

  • The Docker image: mbround18/enshrouded-docker.

Guide changelog

What has changed in this guide, newest first.

  • 2026-10-17Published from a live 1.0 server (Docker + Proton) with a first-session writeup: two players, clean save, 11–35 ms.