Skip to content

2. Create and push your Dockerfile

Create a Dockerfile for your game server. The file itself is straightforward — most of the time is spent testing it against your game binary.

Your Dockerfile must contain an ENTRYPOINT (or equivalent) that launches the game server process. Make sure the command is correct — an invalid entrypoint will prevent the container from starting.

The image should include everything the server needs at runtime — game binaries, third-party libraries (anti-cheat, Steam SDK, etc.), and any other dependencies.

Here is a minimal template that works for most situations:

FROM ubuntu:20.04
# copy your server files
COPY . /home/MyGame/
# add a non-root user
RUN useradd -m gameuser
# set permissions on the launch script
RUN chmod 777 /home/MyGame/GameServer.sh
USER gameuser
# launch the game server
ENTRYPOINT ["/home/MyGame/GameServer.sh", "-log"]

The networking mode you select when creating your application determines whether you need EXPOSE directives in your Dockerfile.

BridgeHost
Port conflictsNone — each container has its own network namespacePossible — all containers share the host’s ports
DockerfileMust include EXPOSE directivesNo EXPOSE — ports come from environment variables
PerformanceSlight overhead from NAT translationMarginally faster — no NAT layer
Typical use caseDefault choice for most game serversUseful when you need consistent port handling with existing infrastructure

If you’re unsure, bridge networking is the safer default. You can always switch later by editing the application in the admin panel.

Bridge networking lets multiple containers bind to the same internal port without conflicting on the host. The orchestrator allocates an ephemeral host port (range 32 768 – 60 299) and maps it to each container port automatically. See Docker’s bridge networking documentation for a deeper dive.

Add EXPOSE lines to your Dockerfile for every port the server binds to:

# add these lines at the end of your Dockerfile
EXPOSE 1024/udp
EXPOSE 7777/udp

With host networking, the container shares the node’s network stack. To avoid port collisions, the orchestrator allocates ephemeral ports (range 32 768 – 60 299) and injects them as environment variables. See Docker’s host networking documentation for a deeper dive.

Do not add EXPOSE lines to your Dockerfile. Instead, your entrypoint script must read the injected port variables at startup. The variable pattern is:

GAMEYE_PORT_{protocol}_{containerPort}

For example:

VariableMeaning
$GAMEYE_PORT_UDP_7777The ephemeral host port mapped to UDP 7777
$GAMEYE_PORT_TCP_80The ephemeral host port mapped to TCP 80

Example entrypoint script (GameServer.sh):

#!/bin/bash
"$UE4_PROJECT_ROOT/MyGame/Binaries/Linux/GameServer" MyGame \
-port=$GAMEYE_PORT_UDP_7777 \
-GameServerQueryPort=$GAMEYE_PORT_UDP_1024 \
"$@"
status=$?
if test $status -eq 0; then
echo "Server exited normally"
else
echo "Server exited with code: $status"
fi
echo "Done"

Build your image locally and tag it:

Terminal window
docker build -t mygame/server:v1.0.0 .

Test it to make sure the server starts correctly, then push it to Docker Hub:

Terminal window
docker push mygame/server:v1.0.0

If you configured the Docker Hub webhook in step 1, the push automatically notifies the orchestrator to pull the new image onto nodes.

  • Use unique tags — Every image you push should have a distinct tag (e.g. a build number or git SHA). Never reuse tags.
  • Keep images lean — Follow the Docker best practices for writing Dockerfiles to reduce image size and build time.
  • Version everything — The orchestrator uses tags to decide which image to pull. Clear versioning makes rollbacks fast and predictable.

With your image on Docker Hub, pick the path that fits your workflow: