Menu
 

Game Server Docker Guide: Docker Compose Files for 14 Games

Run a Game Server in Docker: Images, Ports and Compose Files for 14 Games

Last updated: 4 October 2026 · Every image below was checked against its own repository on this date, and three of them were booted on a test machine

To run a game server in Docker, find your game in the table below, copy the compose file from its section and start it with docker compose up -d. Three lines decide whether players can join and whether the world survives: game ports published with /udp, the world folder mounted from the host, and a stop_grace_period long enough for the server to save. Nearly every file on this page has this shape:

services:
  game:
    image: IMAGE:TAG                  # from the table, pinned to a tag
    restart: unless-stopped
    stop_grace_period: 2m             # time to save before Docker kills it
    mem_limit: 8g                     # a hard ceiling, sized from peak use
    ports:
      - "PORT:PORT/udp"               # write the protocol; most games use UDP
    volumes:
      - ./data:/PATH/IN/CONTAINER     # the world lives on the host

The table: image, ports, volume and RAM for every game

Ports are the container side. Keep the host side identical unless you know the game copes with a different number (several do not, see the port section below). RAM figures are marked: docs means the image or the developer states it, measured means our own boot, estimate means our planning figure where the image documents nothing.

Game Image Ports and protocol Persistent volume (container path) RAM to give it Native Linux server
Valheim ghcr.io/community-valheim-tools/valheim-server 2456/udp, 2457/udp (2458/udp with crossplay) /config (worlds, backups), /opt/valheim (server files) 4 GB minimum, 8 GB recommended (docs); 1.4 GB idle on a new world (measured) Yes
Palworld ghcr.io/pocketpairjp/palserver (official) 8211/udp /pal/Package/Pal/Saved 16 GB, over 32 GB recommended; 8 GB boots but risks out of memory crashes (docs) Yes
Satisfactory wolveix/satisfactory-server 7777/udp, 7777/tcp, 8888/tcp /config 8 to 16 GB (docs) Yes
Project Zomboid danixu86/project-zomboid-dedicated-server 16261/udp, 16262/udp (27015/tcp only for RCON) /home/steam/Zomboid JVM heap set by MEMORY; limit 1 to 2 GB above it (estimate: 6 to 8 GB) Yes
Enshrouded mornedhels/enshrouded-server 15637/udp /opt/enshrouded 16 GB on the host (docs) No
Terraria (vanilla, TShock tags) ghcr.io/beardedio/terraria 7777/tcp /config 1 to 2 GB; 590 MB with a small world (measured) Yes
Factorio factoriotools/factorio 34197/udp, 27015/tcp (RCON) /factorio 2 GB; 330 to 350 MB on a new map (measured) Yes
Vintage Story devidian/vintagestory 42420/tcp and 42420/udp /gamedata 2 to 4 GB for a small group (estimate) Yes
Rust didstopia/rust-server 28015/udp, query port/udp, 28016/tcp (RCON), 28082/tcp (companion app) /steamcmd/rust At least 4 GB or it exits on its own (docs); plan 8 GB or more (estimate) Yes
ARK: Survival Ascended acekorneya/asa_server:2_1_latest 7777/udp, 7777/tcp, 27020/tcp (RCON) /home/pok/arkserver plus its ShooterGame/Saved 16 GB per instance (docs) No
V Rising trueosiris/vrising 9876/udp, 9877/udp /mnt/vrising/server, /mnt/vrising/persistentdata 4 to 8 GB (estimate) No
Core Keeper escaping/core-keeper-dedicated None in relay mode; one UDP port in direct connect mode /home/steam/core-keeper-data, /home/steam/core-keeper-dedicated 2 to 4 GB (estimate) Yes
7 Days to Die vinanrra/7dtd-server 26900/tcp, 26900/udp, 26901/udp, 26902/udp /home/sdtdserver/.local/share/7DaysToDie, config and server files folders 8 GB or more (estimate) Yes
Minecraft Java itzg/minecraft-server 25565/tcp /data Heap set by MEMORY (1 GB default); limit at least 1 GB above it (measured) Yes

Conan Exiles is not in the table. Its Enhanced dedicated server, released in May 2026, has a native Linux build (Steam lists a Linux depot and a Linux server executable for app 443030), but no independently maintained image has become the standard for it yet.

"No" in the last column means the developer ships the dedicated server for Windows only. Those images run the Windows build under a compatibility layer inside the Linux container. It works, but plan for the cost: more RAM than the same server would need natively, a slower first start while the compatibility layer sets itself up, and the occasional break after a game update until the image maintainer catches up. The V Rising and Enshrouded sections below show what that looks like.

The shared mechanics, measured on real boots

Everything in this section was checked by booting three images on a Linux test machine on 4 October 2026: the Valheim image with a 4 GB memory cap, the Factorio image with a 2 GB cap, and the vanilla Terraria image. Each was started, stopped gracefully, deleted with docker compose down, started again from the same folders, and checked for its world.

1. Persistent data: bind mount a folder you can see

A container is disposable. docker compose down deletes it, and every image update replaces it. Anything the server writes inside the container and not inside a mounted folder is gone at that moment, including your world. Every compose file on this page therefore mounts a host folder (a bind mount, written as ./data:/factorio) onto the path where the image keeps saves and config.

We prefer bind mounts over named volumes for game servers because you can see the files: copying a world in from your PC, editing a config file, zipping a backup or restoring one is an ordinary file operation on the host. A named volume works too, but keeps the files in the engine's own storage directory, which makes each of those jobs more awkward.

The catch is ownership. Most images do not run the game as root inside the container; they run it as a fixed user ID, and that user must be allowed to write into your folder. The IDs differ per image:

  • Factorio runs as UID 845. Its documentation tells you to chown 845:845 the folder first. In our boot the current entrypoint, which starts as root, ran chown -R factorio:factorio /factorio itself before dropping to that user, so a fresh folder worked without the manual step. Do it anyway on an existing folder you copied in, it costs nothing.
  • Valheim defaults to PUID=0, so the server runs as root inside the container and writes with whatever permissions the host folder has.
  • Satisfactory, Core Keeper and 7 Days to Die default to PUID=1000, Enshrouded to 4711, and the current ARK image tag to 7777. The ARK image fixes its IDs at build time, so there you change the folder, not the variable.

If you run a rootless container engine, expect the files on the host to show a large owner number. In our rootless test the Factorio files appeared as owned by 100844: that is UID 845 inside the container, mapped through the user's subordinate ID range. That is expected, and it means you edit those files through the engine (or as root) rather than as your own user.

Wrong ownership usually fails silently. In the Valheim 1.0 permissions bug (see the Valheim section) the server kept running, the container looked healthy, and no world was being saved. After your first boot, check that save files appear and change on the host.

2. Publishing ports: UDP is not the default

Most game traffic is UDP. In a compose file a port written without a protocol, such as "7777:7777", is published as TCP only. The game then starts, logs that it is listening, and nobody can join, because the UDP packets never reach it. Always write the protocol: "2456-2457:2456-2457/udp". When a game needs the same number on both protocols (Satisfactory 7777, Vintage Story 42420, 7 Days to Die 26900) you list it twice, once per protocol.

Two more rules:

  • Keep host and container numbers the same unless you have a reason. Several games advertise their own port to the server browser or to a relay. The V Rising image documentation says it plainly: if you map a different external port, the server becomes invisible in the list and only direct connect works. Change the port inside the game's config and publish the same number on both sides instead.
  • Check UDP with a UDP tool. netstat -tnl and ss -tln list TCP only. Use ss -uln (or netstat -tulpn) to see whether the UDP port is open on the host. A Core Keeper issue covered later is exactly this mistake.

For a test on your own machine you can bind a port to the loopback address, "127.0.0.1:2456:2456/udp", so nothing outside the machine can reach it. That is what we did for every boot on this page. For a real server you publish on all interfaces and then forward the same UDP ports on your router.

3. Restart policy

restart: unless-stopped brings the server back after a crash or a host reboot, and leaves it down if you stopped it yourself. That is the right default for a game server. One exception: images that use a start mode to run a one-off job and then exit. The 7 Days to Die image documents that you must never combine restart: unless-stopped with its install-only, update-only or backup-only modes, because the container would loop through the job forever.

4. Stopping cleanly: the grace period is the save window

This is the setting that loses worlds. When you run docker compose stop, down, or reboot the host, the engine sends SIGTERM to the container's main process and waits. If the process has not exited when the wait ends, it sends SIGKILL, which cannot be caught, so nothing gets saved. The default wait is 10 seconds. Most game servers save their world on a clean shutdown, and on a large world that save can take longer than 10 seconds. Here is what we measured:

Image Stop signal handling Measured stop Result
Factorio Server catches SIGTERM: logs Received SIGTERM, shutting down, then Saving map as /factorio/saves/_autosave1.zip 2.3 s total (save itself under 0.1 s on a new map) Save file timestamp updated; exit code 143
Valheim Image's supervisor stops the server, which runs a full world save before closing the socket 7.7 s and 9.1 s on two stops (world save 1.1 s on a new world) Five new save files written; exit code 0
Terraria (vanilla) Server ignores SIGTERM; it only saves on the exit console command 10.3 s, ending in StopSignal SIGTERM failed to stop container ... resorting to SIGKILL World file unchanged; exit code 137

Look at the Valheim numbers. A world that had existed for two minutes needed 9.1 seconds to stop, against a 10 second default. A world with weeks of building in it will not fit. That is why the Valheim image documents --stop-timeout 120, the Project Zomboid image's compose file sets 120 seconds with a comment explaining that 10 seconds kills the server mid-save, Enshrouded sets 90 seconds, Core Keeper 2 minutes and the ARK image 210 seconds. In compose the setting is stop_grace_period; it is described in the Docker compose services reference. A long grace period costs you nothing when the server exits quickly: the engine stops waiting as soon as the process is gone.

Terraria shows the other failure: a server that does not react to the signal at all. The grace period does not help there, because no amount of waiting makes it save. You attach to the console and type exit, which in our test printed Saving before exit..., wrote the world (keeping the previous one as .wld.bak) and exited with code 0. If a stop always takes exactly as long as your grace period and ends with exit code 137, your server is in this category.

To check an image yourself: start it, note the timestamp of the save files, run time docker compose stop, then compare timestamps and run docker inspect --format '{{.State.ExitCode}}' NAME. Exit code 137 means it was killed.

5. Memory limits: a cap at or below what the game needs gets it killed

A memory limit (mem_limit: 4g in compose, or deploy.resources.limits.memory as in the Satisfactory file below) is a good idea on a shared machine: it stops one runaway server from pushing the whole host into swap. But the limit is a hard wall. When the processes in the container try to use more, the kernel's out of memory killer ends them. It does not slow the game down or make it save; it kills it, mid-tick, with no log line from the game itself.

We proved this on purpose by starting the Factorio image with a 150 MB cap (with swap set to the same value, so it could not spill into swap). The server loaded its mods, the log ended with the single word Killed, and docker inspect reported:

status=exited exit=137 oom=true restarts=0

That OOMKilled field is the one to check whenever a container dies with no explanation in its own log:

docker inspect --format '{{.State.OOMKilled}} {{.State.ExitCode}}' NAME
docker stats --no-stream

Do not go by the exit code alone: our Palworld and Minecraft test servers were killed this way with exit codes 0 and 255, because each image's wrapper outlived the game process.

Size the limit from what the game uses at its busiest, not at idle. At idle our Valheim boot used 1.4 GB and Factorio about 350 MB, but both grow with world size, explored area, players and mods. For Java servers (Project Zomboid, Minecraft) the container limit must sit clearly above the heap you give the JVM, because the JVM uses memory outside the heap as well; a limit equal to the heap is a container that will be killed under load. Our Minecraft test measured 400 to 430 MiB outside a 1 to 1.5 GB heap with nobody online, so give the container at least 1 GB more than the heap. For the Windows-only games running under a compatibility layer, use the image's documented figure (16 GB for ARK and for Enshrouded's host) as a floor, not a target. If you set mem_limit without setting swap, the engine may let the container use swap on top of the limit; set memswap_limit to the same value if you want the cap to be exact.

6. Updates: most images update the game on start, some do not

There are two separate things to update: the image (the scripts, the base system, sometimes the game) and the game files. How each image handles the game differs, and it matters on patch day when clients update and your server does not:

Image How the game gets updated
ValheimChecks on every start and then every 15 minutes while nobody is online (UPDATE_CRON). Our second start spent about 90 seconds verifying the install before the server came up.
Palworld (official)Game is baked into the image tag. Back up, change the tag in the compose file, start again.
SatisfactoryOn every start, unless SKIPUPDATE=true.
Project ZomboidBaked into the image; pull a newer image, or set FORCEUPDATE=true to run SteamCMD on start.
EnshroudedInstalled on first start; later checks on the UPDATE_CRON schedule you set.
TerrariaBaked into the image tag (for example vanilla-1.4.5.8); pull the new tag.
FactorioBaked into the image; docker compose pull then start again.
Vintage StoryBaked into the image; pull the new tag.
RustOn every start; optional automatic update checking with RUST_UPDATE_CHECKING=1.
ARK: Survival AscendedScheduled checks inside the container when UPDATE_SERVER=TRUE.
V RisingSteamCMD runs on every start.
Core KeeperSteamCMD runs on every start.
7 Days to DieOnly when you start with START_MODE=3; normal mode 1 does not update.
MinecraftDownloads the version you set in VERSION on start (latest by default).

Pinning matters too. :latest moves under you on the next pull; a version tag does not. For a server your friends rely on, pin a tag, read the image's release notes before you move it, and take a backup first.

7. Backups: stop the server, then copy the folder

A copy of a world taken while the server is writing it can be inconsistent. The safe routine with a bind mount is three commands:

docker compose stop
tar czf world-$(date +%F).tar.gz ./data
docker compose start

Some images also back up for you while running. The Valheim image zipped the world on every start in our test (worlds-20261004-164231.zip in /config/backups) and hourly by default; its documentation is honest that a backup taken mid-save can capture a half-written world, which is why it retries when it detects one. Built-in backups are a good second line. The copy you take with the server stopped, stored somewhere other than the same disk, is the first.

8. First boot takes longer than you think

Our timings, on a fast home connection, image already pulled:

  • Valheim: 9 minutes 29 seconds from up to Opened Steam server. Eight of those minutes were the server download, 2.19 GB for the current 1.0 build (the image documentation still says about 1 GB). The server process started about 40 seconds after the download finished and reported ready about 80 seconds after it. Second start: 130 seconds, most of it the update check.
  • Factorio: under 6 seconds from up to changing state from(CreatingGame) to(InGame), including creating a new map. Second start: 3.3 seconds, loading the saved map.
  • Terraria: a small world generated in about 22 seconds; with an existing world the server was listening 7 seconds after start.

Know your ready line before you debug a "server not showing up". For Valheim it is Opened Steam server (preceded by Game server connected); for Factorio it is the InGame state change. If you try to join before that line, nothing is wrong yet.

Valheim

The image is ghcr.io/community-valheim-tools/valheim-server, the continuation of the long-standing community image (the old Docker Hub name, lloesche/valheim-server, shows over 35 million pulls). The repository has about 2,370 stars and released v1.4.0 on 20 September 2026. It runs the native Linux server, updates it, backs it up, and supports BepInEx and ValheimPlus. Configuration is environment variables. This is the file we booted, with the test binding to 127.0.0.1 removed:

services:
  valheim:
    image: ghcr.io/community-valheim-tools/valheim-server:latest
    container_name: valheim
    cap_add:
      - sys_nice
    ports:
      - "2456-2457:2456-2457/udp"
    volumes:
      - ./config:/config
      - ./data:/opt/valheim
    environment:
      SERVER_NAME: "My Server"
      WORLD_NAME: "Dedicated"
      SERVER_PASS: "change-me-5plus"
      SERVER_PUBLIC: "true"
    restart: unless-stopped
    stop_grace_period: 2m
    mem_limit: 8g

Notes: SERVER_PASS must be at least 5 characters or the server refuses to start. sys_nice is optional and only removes a thread priority warning. With CROSSPLAY=true the server also uses 2458/udp; extend the range to 2456-2458. Mounting /opt/valheim keeps the 2 GB server download between container rebuilds.

The gotcha: the issue "Valheim 1.0: ensure_permissions strips the execute bit from per-world directories, silently breaking all world saves with PUID/PGID". Valheim 1.0 stores each world as a folder instead of a single file. Older images, when run with a non-root PUID, applied file permissions to those folders, the server logged UnauthorizedAccessException and kept running with no world loaded. It is fixed in current images, but if you set PUID, pull a current image before letting a 1.0 server convert an old world, and keep a backup: the conversion is one way. For the game side of setup see our Valheim dedicated server guide.

Palworld

Pocketpair publishes an official image, ghcr.io/pocketpairjp/palserver, with a sample compose file in its pocketpairjp/palworld-dedicated-server-docker repository. Each image tag is a game build. The sample pins one, publishes 8211/udp, mounts a small helper.sh from the same repository (it fixes ownership of the save folder, then starts the server) and keeps all saves and config under ./Saved. Game settings live in Saved/Config/LinuxServer/PalWorldSettings.ini, not in environment variables, and an update means backing up, changing the tag and starting again. Pocketpair asks for 16 GB of RAM and recommends more than 32 GB; 8 GB boots but makes out of memory crashes more likely. The community image thijsvanloef/palworld-server-docker adds settings as environment variables, built-in backups and scheduled updates. Our Palworld server in Docker walkthrough compares the two and boots the community image with measured RAM.

Satisfactory

wolveix/satisfactory-server: about 2,070 stars, nearly 4 million Docker Hub pulls, last release v1.9.10, last commit July 2026. It downloads the native Linux server into /config/gamefiles on every start, keeps saves and blueprints in /config/saved, and backs up saves when the container starts. Configuration is environment variables plus the in-game server manager. Compose, following the image's documentation:

services:
  satisfactory-server:
    container_name: satisfactory-server
    hostname: satisfactory-server
    image: wolveix/satisfactory-server:latest
    ports:
      - "7777:7777/tcp"
      - "7777:7777/udp"
      - "8888:8888/tcp"
    volumes:
      - ./satisfactory-server:/config
    environment:
      - MAXPLAYERS=4
      - PGID=1000
      - PUID=1000
      - STEAMBETA=false
    restart: unless-stopped
    stop_grace_period: 1m
    deploy:
      resources:
        limits:
          memory: 8G
        reservations:
          memory: 4G

The stop grace period is our addition: the image forwards the stop to the server as SIGINT and waits for it, and a minute leaves room for a late-game save. Raise the 8 GB limit as the factory grows; the image documentation warns you may need to.

The gotcha: the issue "1.0 API Connection Issue (FIX INSIDE)", the most discussed in the repository with over 170 comments. Since 1.0 the server's API runs over TCP on the game port, so 7777 must be published and forwarded as both UDP and TCP; people who forwarded only UDP, or still used the old pre-1.0 ports, could see the server but not claim or join it. The current compose adds 8888/tcp for the messaging port. If you get stuck on that one, read our Satisfactory port 8888 fix.

Project Zomboid

danixu86/project-zomboid-dedicated-server, built from the Danixu repository: about 380 stars, 210,000 pulls, commits as recent as 1 October 2026, and it now builds Build 42 by default because Build 42 is the stable branch. The older Renegade-Master image has more pulls but has not been updated since June 2024, so we do not recommend it. Configuration is environment variables, which the entrypoint writes into the server INI. From the repository's compose file:

services:
  zomboid:
    image: danixu86/project-zomboid-dedicated-server:latest
    restart: unless-stopped
    stop_grace_period: 120s
    environment:
      - SERVERNAME=servertest
      - ADMINPASSWORD=change-me
      - MEMORY=6144m
      - PUBLIC=false
    ports:
      - "16261:16261/udp"
      - "16262:16262/udp"
    volumes:
      - ./data:/home/steam/Zomboid
      - ./workshop-mods:/home/steam/pz-dedicated/steamapps/workshop
    mem_limit: 8g

The 120 second grace period comes straight from the repository, whose entrypoint catches SIGTERM, types quit into the server console and waits for the world to save. Add "27015:27015/tcp" only if you want RCON from outside.

The gotcha: this repository has its issue tracker switched off, so this one is from its own documentation. ADMINPASSWORD is mandatory on the very first start or the server fails, and the server prints every launch argument in clear text, so the admin password ends up in your container log. Set it for the first boot, then remove it from the compose file. Also from the same docs: mods install on the second start, not the first, and SERVERNAME must not contain spaces or the admin user fails. Our Project Zomboid Docker page goes deeper on this one game.

Enshrouded

Enshrouded has no native Linux server. mornedhels/enshrouded-server runs the Windows build under a compatibility layer and publishes two tags built on different layers. It has about 270 stars, 415,000 pulls, release 1.7.2 in June 2026 and commits into July 2026, which made it the more active choice over the other popular image, whose last commit was January 2026. Configuration is environment variables that map onto enshrouded_server.json.

services:
  enshrouded:
    image: mornedhels/enshrouded-server:latest
    container_name: enshrouded
    hostname: enshrouded
    restart: unless-stopped
    stop_grace_period: 90s
    ports:
      - "15637:15637/udp"
    volumes:
      - ./game:/opt/enshrouded
    environment:
      - SERVER_NAME=Enshrouded Server
      - UPDATE_CRON=*/30 * * * *
      - BACKUP_CRON=0 * * * *
      - PUID=4711
      - PGID=4711
    mem_limit: 16g

The image's own example also passes /dev/ntsync into the container. Its comment says to add that device only if your kernel supports it (6.14 or newer); on an older kernel the device does not exist and the container cannot be created, so we left it out above. The image also warns that an update temporarily needs up to twice the game's disk space.

The gotcha: the issue "High server load messages / low CPU utilization". Players see the in-game high server load warning while the host CPU is mostly idle. In that thread it was reported on Linux and on Windows Server hosts with plenty of cores and RAM, with one report saying it starts as soon as a second player joins. This is the cost of the compatibility layer: the thread ends without a single setting that removes it, and the options it offers (switching to the image's other tag, or ntsync on a kernel that has it) are things to try, not a fix. Plan for more CPU headroom than the player count suggests. For the game side, see our Enshrouded server setup guide.

Terraria

ghcr.io/beardedio/terraria (also on Docker Hub as beardedio/terraria, 1.6 million pulls, about 140 stars, last commit 28 September 2026). Tags exist for vanilla (vanilla-latest, currently 1.4.5.8) and TShock (tshock-latest). It does not cover tModLoader; that needs a separate image. The other big name, ryshe/terraria, still has over 10 million pulls but its source repository is no longer public, so there is no issue tracker to check; we went with the maintained one. Configuration is the standard serverconfig.txt in /config, which the image creates on first start. This is the file we booted:

services:
  terraria:
    image: ghcr.io/beardedio/terraria:vanilla-latest
    container_name: terraria
    ports:
      - "7777:7777/tcp"
    volumes:
      - ./config:/config
    environment:
      world: myworld.wld
    tty: true
    stdin_open: true
    restart: unless-stopped
    mem_limit: 2g

The world file must already exist in ./config; to create one without the interactive menu, start it once with command: ["-autocreate", "2", "-world", "/config/myworld.wld"] instead of the world variable (1 small, 2 medium, 3 large). tty: true is required: without it the server throws a System.NullReferenceException on world load, which is the image's issue #7.

The gotcha: the issue "[Feature/Fix] Graceful shutdown support: Vanilla server ignores SIGTERM and gets killed by SIGKILL (Fix script included)". We reproduced it exactly: docker stop waited 10.3 seconds, killed the server with exit code 137, and the world file was byte for byte unchanged. The issue is closed, but the image's start script still hands the signal straight to the server, so treat it as current. Before any stop, attach and save:

docker attach terraria
exit
# the server prints "Saving before exit..." and the container stops cleanly
# to leave the console without stopping, press Ctrl+P then Ctrl+Q

That path saved the world and exited with code 0 in our test. A host reboot will still kill it unsaved, so keep the server's autosave on. More on the game side in our Terraria dedicated server guide.

Factorio

factoriotools/factorio: 29.4 million Docker Hub pulls, about 1,440 stars, last commit 22 September 2026. Native Linux headless server, configured through JSON files in /factorio/config (created on first start) plus a few environment variables. This is the file we booted, minus the test binding:

services:
  factorio:
    image: factoriotools/factorio:stable
    container_name: factorio
    ports:
      - "34197:34197/udp"
      - "27015:27015/tcp"
    volumes:
      - ./data:/factorio
    environment:
      - DLC_SPACE_AGE=true
    restart: unless-stopped
    stop_grace_period: 30s
    mem_limit: 2g

The image enables the Space Age DLC mods (space-age, quality, elevated-rails) by default; set DLC_SPACE_AGE=false if your group plays the base game. On first start, with the default server-settings.json, the log shows Matching server connection failed: Error when creating server game: Missing token.: the default config asks to be listed publicly without a factorio.com token. The server still runs and accepts direct connections; either add your username and token or set public visibility to false to silence it. RCON on 27015/tcp gets a random password written to /factorio/config/rconpw; leave the port unpublished if you do not use it.

The gotcha: the issue "Docker image 'stable' tag consistently behind in version compared to actual stable". The reporter found that pulling stable gave 2.0.8 when 2.0.9 was the current stable release, and had seen the same one-version lag before, so clients that had already updated could not join. Before blaming your network after a game update, compare the version in the server log (Factorio 2.0.77 in our boot) with the client, and if needed pin the exact version tag the client runs. Our Factorio headless server guide covers the game settings.

Vintage Story

No image dominates here. We chose devidian/vintagestory: about 58,600 pulls, the most of the actively maintained options, and a version bump within days of each game release (1.22.6 in July 2026). The game is baked into the image; the server data folder is set with VS_DATA_PATH, and you configure the server through serverconfig.json in that folder after the first start.

services:
  vsserver:
    image: devidian/vintagestory:latest
    container_name: vsserver
    restart: unless-stopped
    stop_grace_period: 1m
    volumes:
      - ./gamedata:/gamedata
    ports:
      - "42420:42420/tcp"
      - "42420:42420/udp"
    environment:
      VS_DATA_PATH: /gamedata/vs
    mem_limit: 4g

The image's own example publishes 42420:42420 without a protocol, which is TCP only. Vintage Story 1.20 and later also use UDP on the same port, so we publish both; see our Vintage Story port guide. The image also documents that since 1.20 the whitelist is on by default, so you cannot join a fresh server until you either add yourself or set "StartupCommands": "/whitelist off" for the first login.

The gotcha: the issue "No reaction on docker compose down". The server used to ignore the stop signal, so every down and every restart killed it and lost the last minutes of play. The maintainer fixed it by starting the server with an exec entrypoint and a SIGINT stop signal, both visible in the current Dockerfile. The lesson applies to any small image: check that a stop produces the server's own shutdown messages before you trust it with a world.

Rust

didstopia/rust-server: about 1.19 million pulls, 272 stars, a large refactor in May 2026 and a Docker Hub rebuild in August 2026. It installs or updates the native Linux server on every start, keeps everything under /steamcmd/rust, and is configured with environment variables. On stop it catches the signal and sends quit over web RCON, which saves the map, so keep RCON enabled.

services:
  rust-server:
    image: didstopia/rust-server:latest
    container_name: rust-server
    restart: unless-stopped
    stop_grace_period: 2m
    ports:
      - "28015:28015/udp"
      - "28017:28017/udp"
      - "28016:28016/tcp"
      - "28082:28082/tcp"
    volumes:
      - ./rust_data:/steamcmd/rust
    environment:
      - RUST_SERVER_NAME=My Rust Server
      - RUST_SERVER_IDENTITY=docker
      - RUST_SERVER_SEED=12345
      - RUST_SERVER_WORLDSIZE=3500
      - RUST_SERVER_MAXPLAYERS=50
      - RUST_SERVER_QUERYPORT=28017
      - RUST_RCON_PASSWORD=change-me
    mem_limit: 12g

We set the query port explicitly so you know which UDP port to forward; the image leaves it blank by default and documents 28016 as the fallback, which is also the RCON number on TCP. Change RUST_RCON_PASSWORD from its default of docker before the server is reachable. 28082/tcp is only for the companion app.

The gotcha: straight from the image's own troubleshooting section: if you can reach the RCON web interface but not the game, you published 28015 as TCP instead of UDP. The repository's own run script publishes 28015 on both protocols, which hides the mistake until someone copies only the TCP line. The same section says that if the server exits by itself after seemingly starting fine, the container or Docker VM has less than 4 GB of RAM. See our Rust dedicated server setup for the game settings.

ARK: Survival Ascended

ARK: Survival Ascended has no native Linux server; the images run the Windows build under a compatibility layer. We chose the image behind the POK manager, acekorneya/asa_server: about 250 stars, release v2.1.8 in July 2026, commits as recent as 1 October 2026, and the 2_1_latest tag rebuilt the same day. The other well-known image has slightly more pulls (87,000 against 76,000) but its last release was November 2025. Configuration is environment variables for the basics plus the usual GameUserSettings.ini and Game.ini. Trimmed from the image's documented compose file:

services:
  asaserver:
    image: acekorneya/asa_server:2_1_latest
    container_name: asa_my_instance
    restart: unless-stopped
    stop_grace_period: 210s
    environment:
      - INSTANCE_NAME=my_instance
      - TZ=Europe/London
      - API=FALSE
      - RCON_ENABLED=TRUE
      - UPDATE_SERVER=TRUE
      - SAVE_WAIT_SECONDS=60
      - MAP_NAME=TheIsland
      - SESSION_NAME=My_ASA_Server
      - SERVER_ADMIN_PASSWORD=change-me
      - SERVER_PASSWORD=
      - ASA_PORT=7777
      - RCON_PORT=27020
      - MAX_PLAYERS=20
      - CLUSTER_ID=cluster
      - MOD_IDS=
    ports:
      - "7777:7777/tcp"
      - "7777:7777/udp"
      - "27020:27020/tcp"
    volumes:
      - ./ServerFiles/arkserver:/home/pok/arkserver
      - ./Instance_my_instance/Saved:/home/pok/arkserver/ShooterGame/Saved
      - ./Cluster:/home/pok/arkserver/ShooterGame/Saved/clusters
    mem_limit: 16G

The image documentation's sample still shows the older 2_0_latest tag, which has not been rebuilt since February 2025; 2_1_latest is the maintained one and runs as UID 7777, so run chown -R 7777:7777 on the folders first. The 210 second grace period is the image's own formula (twice SAVE_WAIT_SECONDS plus 90): on stop it runs and verifies two world saves before letting the server exit, and it needs RCON enabled for that.

The gotcha: from the image's troubleshooting section, a log line about Allocator Stats for binned2 are not in this build means the host's memory mapping limit is too low, and the server will crash or fail to start. It is a host setting, not a container one:

sudo sysctl -w vm.max_map_count=262144
echo "vm.max_map_count=262144" | sudo tee -a /etc/sysctl.conf

Our ARK: Survival Ascended server setup covers the game side.

V Rising

V Rising ships a Windows-only server. trueosiris/vrising runs it under a compatibility layer on Ubuntu: about 376 stars, 520,000 pulls, last commit April 2026. SteamCMD updates the server on every start, settings live in ServerHostSettings.json and ServerGameSettings.json under persistentdata/Settings, and environment variables starting with HOST_SETTINGS_ or GAME_SETTINGS_ override single values. The image catches SIGTERM, forwards it to the server and waits for it to exit.

services:
  vrising:
    image: trueosiris/vrising
    entrypoint: ["/bin/bash", "-c", "sed -i 's/\\r//g' /start.sh && exec /bin/bash /start.sh"]
    environment:
      - TZ=Europe/Paris
      - SERVERNAME=My V Rising Server
      - HOST_SETTINGS_ListOnSteam=true
      - HOST_SETTINGS_ListOnEOS=true
    volumes:
      - ./server:/mnt/vrising/server
      - ./persistentdata:/mnt/vrising/persistentdata
    ports:
      - "9876:9876/udp"
      - "9877:9877/udp"
    restart: unless-stopped
    stop_grace_period: 1m
    mem_limit: 8g

The gotcha: the issue "exec /start.sh: no such file or directory". After an image rebuild in February 2026 the start script inside the image had Windows (CRLF) line endings, as users found in that thread, and every container failed instantly with that misleading message. The maintainer's documented workaround is the entrypoint line above, which strips the stray carriage returns before running the script; keep it until the image notes say otherwise. This is patch-day breakage that has nothing to do with your setup. The same documentation adds that a password-protected server cannot be joined through Steam, only through the in-game list; its warning about a different external port is in the port section above. Game-side setup is in our V Rising dedicated server guide.

Core Keeper

escaping/core-keeper-dedicated: 455,000 pulls, about 237 stars, release 2.8.1 in February 2026. Core Keeper has a native Linux server; the image also runs on ARM through Box64. SteamCMD updates the server on every start, and configuration is environment variables in a core.env file.

services:
  core-keeper:
    image: escaping/core-keeper-dedicated:latest
    container_name: core-keeper-dedicated
    restart: unless-stopped
    stop_grace_period: 2m
    volumes:
      - ./server-files:/home/steam/core-keeper-dedicated
      - ./server-data:/home/steam/core-keeper-data
    env_file:
      - path: core.env
        required: false
    mem_limit: 4g

There is no ports section on purpose. By default the server uses Steam Datagram Relay: players join with the Game ID the server writes to GameID.txt, traffic goes through Steam's relays, and you forward nothing. Setting SERVER_PORT switches the server to direct connect mode, and only then do you publish that port as UDP. Read the ID with docker exec core-keeper-dedicated cat /home/steam/core-keeper-dedicated/GameID.txt.

The gotcha: the issue "I set SERVER_PORT but the port does not open". The user checked with netstat -tnl, which shows TCP only, while Core Keeper listens on UDP; with netstat -tulpn the port was open. The remaining connection timeouts were fixed by a later game version that changed direct connect. Two lessons: check UDP with a UDP tool, and in direct connect mode players still join with the Game ID, not an IP and port. See our Core Keeper server setup.

7 Days to Die

vinanrra/7dtd-server: 3.1 million pulls, about 323 stars, release v0.9.3 in January 2026 and an image rebuild on 4 October 2026. It wraps LinuxGSM, so it brings backups, crash monitoring and mod installers. The game's own settings live in sdtdserver.xml in the server files folder; the container is driven by environment variables. On stop the image runs LinuxGSM's stop command, which shuts the server down cleanly.

services:
  7dtdserver:
    image: vinanrra/7dtd-server
    container_name: 7dtdserver
    environment:
      - START_MODE=1
      - VERSION=stable
      - PUID=1000
      - PGID=1000
      - TimeZone=Europe/London
      - BACKUP=NO
      - MONITOR=NO
    volumes:
      - ./7DaysToDie:/home/sdtdserver/.local/share/7DaysToDie/
      - ./LGSM-Config:/home/sdtdserver/lgsm/config-lgsm/sdtdserver
      - ./ServerFiles:/home/sdtdserver/serverfiles/
      - ./log:/home/sdtdserver/log/
      - ./backups:/home/sdtdserver/lgsm/backup/
    ports:
      - "26900:26900/tcp"
      - "26900:26900/udp"
      - "26901:26901/udp"
      - "26902:26902/udp"
    ulimits:
      nofile:
        soft: "10240"
        hard: "10240"
    restart: unless-stopped
    stop_grace_period: 2m
    mem_limit: 12g

The first run installs the server (use START_MODE=0 or 3 on a fresh folder). The web admin and telnet ports (8080 to 8082 TCP) are optional; leave them unpublished unless you need them, and never expose telnet to the internet.

The gotcha: the issue "[BUG] Server doesn't update properly". In the normal START_MODE=1 the container only starts the server; it does not update it. After a game patch, clients on the new build get a version mismatch while the server happily reports the old one. The documented fix: set START_MODE=3 (update, then start), run it once, then set it back to 1. Back up first if you switch between stable and experimental, which the image documentation warns about in capitals.

Minecraft

For Minecraft Java the standard image is itzg/minecraft-server, with over 434 million pulls, about 14,400 stars and a release on 25 September 2026. It downloads the server type and version you ask for on start (vanilla, Paper, Fabric, Forge and modpacks), keeps everything in /data, listens on 25565/tcp, and needs EULA: "TRUE". Set the heap with MEMORY and give the container at least a gigabyte more. It has enough depth for its own page, so we wrote one: Minecraft server in Docker.

When Docker at home is the wrong tool

Docker makes a game server reproducible: the same compose file gives the same server on any Linux box. It does not make your home connection a good place to host from.

Public IP and port forwarding

Players outside your house need to reach your public IP on the game's UDP ports. Many home connections no longer have a public IPv4 address at all: the provider shares one address between many customers (carrier-grade NAT), and no router setting will forward a port through that. Even with a public address you must forward every UDP port in the table above on your router, keep the host's local address fixed, and hope the address does not change between sessions. Core Keeper's relay mode and Valheim's crossplay mode avoid forwarding, but most games on this page do not have that option.

DDoS and your home address

Running a public server publishes your home IP to every player and to the server browser. A player with a grudge can flood that address, and when they do, the whole household loses its internet, not just the game. Home routers and residential connections have no filtering for this. If the server is public, or might become popular, that risk is real.

Patch-day breakage

When a game updates, clients update automatically and your server does not, or it does and the image's scripts break. The V Rising, Factorio, 7 Days to Die and Valheim gotchas above are all this kind. Each one waits on a volunteer maintainer, and each one is an evening of your group not playing. The Windows-only games under a compatibility layer break more often than native ones.

Your time

Count the hours: reading the image docs, getting ownership right, finding why nobody can connect (it is nearly always a UDP port), sizing memory, scripting backups, then doing the update dance every patch. If you enjoy that, Docker is a great way to do it. If you want to manage several servers or let other people run their own, a web panel helps more than raw compose files; we compared the self-hosted options in game server panels compared. And if what you want is to play, read our notes on shared VPS lag versus dedicated cores before you rent a cheap box to run these containers on.

Skip the setup. If you would rather spend the evening playing than forwarding ports and watching logs, you can rent a ready-made server for any of these games: see the game servers we host.

Tired of fighting this issue every patch?

Run a managed Hosting server with us. We handle the patches, mod-version pinning, save backups, and DDoS protection. Set up in minutes, multiple datacenter regions, no contract.

See Hosting hosting plans →
Top