Run Satisfactory on your own machine so you, your friends, and your family can play together.
This container runs the Satisfactory dedicated server and nothing else. The game is pre-installed, and all other concerns — backups, persistence, monitoring — are expected to be handled outside the container with mounted volumes.
The server needs three inbound bindings, and the image exposes all of them:
| Port | Protocol | Usage |
|---|---|---|
7777 | UDP | Game traffic, Lightweight Query API |
7777 | TCP | Server traffic, HTTPS API |
8888 | TCP | Reliable messaging (required as of patch 1.1.0.0) |
The examples below map all three; without 8888/tcp players can connect but
get stuck on the loading screen. If you change SERVERGAMEPORT, only the
7777 pair moves — the reliable port stays 8888.
Temporary test run (the server starts immediately and runs until you Ctrl-C):
docker run --rm -it -p 7777:7777/udp -p 7777:7777/tcp -p 8888:8888/tcp \
raykrueger/satisfactory-dedicated-server
Running with docker-compose:
# grab the docker-compose.yaml from this repo, then:
docker compose up -d
Saves live at /home/steam/.config/Epic/FactoryGame/Saved/SaveGames inside
the container. Mount a volume (or bind mount) there and nothing is ever lost
when the container is recreated:
docker run -d \
-v satisfactory-saves:/home/steam/.config/Epic/FactoryGame/Saved/SaveGames \
-p 7777:7777/udp -p 7777:7777/tcp -p 8888:8888/tcp \
raykrueger/satisfactory-dedicated-server
The server keeps 3 rotating autosaves in that directory.
All options are environment variables:
| Variable | Default | Description |
|---|---|---|
SERVERGAMEPORT | 7777 | Port the game listens on (UDP and TCP; the reliable port is always 8888/tcp) |
NUMPLAYERS | 4 | Maximum players (rendered into Game.ini) |
CONNECTION_TIMEOUT | 30 | Connection timeout in seconds (rendered into Engine.ini) |
STEAMUPDATE | (empty) | Set to true to run steamcmd and update the game at boot |
STEAMARGS | (empty) | Extra steamcmd args, e.g. -beta <branch> (only used when STEAMUPDATE=true) |
USERNAME / USERID | steam / 1010 | User the server process runs as |
At boot, gomplate renders the template files in
config/ into the server's config directory, so NUMPLAYERS and
CONNECTION_TIMEOUT take effect without touching game files.
By default the container starts the game exactly as baked into the image (the
latest tag is rebuilt nightly). Set STEAMUPDATE=true to force a
steamcmd update at boot, or simply pull the new image.
steam user, not root.The systemd/ directory has units that run the container under systemd, with optional timers that start it in the morning and stop it at night:
satisfactory.service runs the container in the foreground (--rm,
--pull always, all three ports, saves at /var/lib/satisfactory/data),
stops it with SIGINT so the server saves and exits cleanly, and restarts
it if it crashes.satisfactory-start.timer / satisfactory-stop.timer start it at 06:00
and stop it at midnight (host local time) via
satisfactory-stop.service.Adjust the save path, ports, and schedule in the units to taste, then:
sudo mkdir -p /var/lib/satisfactory/data
sudo cp systemd/* /etc/systemd/system/
sudo systemctl daemon-reload
Run on demand:
sudo systemctl start satisfactory
sudo systemctl stop satisfactory
Turn the daily schedule on / off:
sudo systemctl enable --now satisfactory-start.timer satisfactory-stop.timer
sudo systemctl disable --now satisfactory-start.timer satisfactory-stop.timer
Logs: journalctl -u satisfactory.
A Makefile is included for testing and tinkering:
make run # build and run the container
make shell # build and drop into a bash shell in the container
The container uses gomplate for config variable
replacement and gosu to drop privileges to
the steam user at runtime.
Content type
Image
Digest
sha256:b899535f9…
Size
1.8 GB
Last updated
about 6 hours ago
docker pull raykrueger/satisfactory-dedicated-server