JoinGG

Docker for game servers: what it buys and what it costs

Isolation and reproducible rebuilds against networking complexity and a real risk of discarding data. When containers repay the overhead.

SweetMask · 6 min read

Containers solved a real problem for web services: ship the application and its dependencies as one artefact, run it anywhere, throw it away and start again. Game servers get some of that and pay for it in places the tutorials rarely mention.

What you actually gain

Dependency isolation. Older Source servers want 32-bit libraries that a modern distribution has to be talked into installing. Some games want a specific glibc. Running three games on one box without containers means one machine's package list is the union of three sets of requirements, and upgrading the host for one breaks another. In containers, each brings its own.

Reproducible rebuilds. A server that has drifted over two years of manual fixes is a server nobody can rebuild. A Dockerfile is the rebuild, written down. When the disk dies you are restoring data, not archaeology.

Clean separation on one machine. Four game servers, four containers, four sets of files, one host. No shared directory somebody deletes, no port collision you discover at peak time, and resource limits per container rather than one game eating the box.

Straightforward rollbacks. Tag an image, update, and if the update breaks the game, run the previous tag. Compare that with restoring a directory from backup while players wait.

What it costs

Networking is the hard part. Game servers speak UDP, need specific ports, and frequently need to know their own public address to advertise it correctly. Docker's default bridge network does neither of those things naturally.

The bridge NATs everything, which means the container sees a private address and may announce it, and UDP port mapping through the bridge adds a small amount of latency and a docker-proxy process per port. For a game where milliseconds are the product that is a real consideration.

The common answer is --network host, which drops the isolation and gives the container the host's network stack directly. It works, it is fast, and it means you have given up one of the main reasons to use containers in the first place. Most production game-server setups end up here anyway.

Persistence is not automatic. A container is disposable; a game world is not. Every world file, config, plugin and log has to live in a volume or a bind mount, and the failure mode of getting it wrong is that a routine docker compose up discards a week of progress. This is the single most common way people lose data with containers, and it is silent until it is catastrophic.

Image sizes are not small. A Source game server is several gigabytes. Baking the game files into an image makes an enormous image that has to be rebuilt on every game update. Downloading them at container start makes a small image and a slow, network-dependent boot. Neither is comfortable; most setups mount the game files as a volume and use the image only for the runtime, which again gives up part of the promise.

When it is clearly worth it

SituationContainers
Several different games on one machineStrong yes
One game, one server, one boxUsually not worth it
A test instance you rebuild oftenStrong yes
Rented shared hosting with a panelNot your decision
A community with more than one adminYes — reproducibility is the point
Chasing the lowest possible latencyHost networking or bare metal

The dividing line is roughly whether anyone other than you will ever need to rebuild the thing. A single server you administer alone gains little from a Dockerfile; a community where three people take turns and one of them is on holiday gains a great deal.

The Pterodactyl question

Most people who run game servers in containers are not writing Dockerfiles. They are running Pterodactyl, which is a control panel that puts every server in a container and hides all of the above behind a web interface.

That is a genuinely good trade for most operators. You get the isolation, the per-server resource limits, the file manager and the user permissions, without owning the networking decisions. The cost is that you now run a panel — a daemon, a database, a web application, and their updates — and that stack is a bigger surface than the game server it manages.

If you rent from a host, there is a fair chance you are already using it without knowing; a very large share of shared game hosting is Pterodactyl with a skin on it. That is worth knowing when you compare providers, because it means the feature list you are choosing between is often the same software configured differently. What actually differs between hosting tiers is usually resources and support, not the panel.

Things that break specifically in containers

Time and cron inside the container. Scheduled restarts written as cron jobs inside a container often do not run, because the container runs one process and no cron daemon. Schedule from the host, or from the panel.

Signals and shutdown. A game server killed with SIGKILL does not save. Containers stop with SIGTERM and then, after a grace period, SIGKILL — and the default grace period is ten seconds, which is not enough for a large world to write out. stop_grace_period exists for this reason and is the setting most people discover after losing a world.

File ownership. Bind mounts preserve numeric user IDs, not names. A container running as UID 1000 writing into a host directory owned by a different UID produces permission errors that look like corruption. It is the second most common container problem after volumes.

The query port again. Mapping the game port and forgetting the query port produces the invisible server described in the difference between the two, and containers make it easier to do by accident because ports are declared in a file rather than opened in a firewall.

A reasonable default

If you want the benefits without the sharp edges:

  • One container per game server, --network host
  • Game files and world data in a bind mount outside the container
  • The image contains the runtime and the update script, not the game
  • stop_grace_period set to something honest for your game — 60 seconds is not excessive
  • Backups taken from the host, on the mounted directory, on a schedule that does not depend on the container being healthy

That configuration is not architecturally pure. It is what works, and it keeps the property that actually matters: when the machine dies, you can rebuild it from a file you have, rather than from memory.

The short version

Containers are worth it for isolation and reproducibility, and they cost you networking simplicity and a real risk of discarding data you meant to keep. For one server on one box the overhead usually is not repaid. For several games, several admins, or anything you rebuild regularly, it is repaid quickly.

And if you are renting rather than running the metal, there is a good chance the decision has already been made for you — check what the panel is before comparing feature lists, because much of the market is the same software underneath.

Tags
hostingdockerops
Share

SweetMask

Published · 6 min read

All articles

Keep reading

Guides

Skyblock Servers, and Why the Format Refuses to Die

A map with a tree and forty blocks of dirt became one of the most played formats in multiplayer Minecraft. What the servers added, and which of the two Skyblocks you are joining.

· 7 min read