The Factorio server behind this site is one container and one compose file. Factorio Server Manager runs inside it: a web UI that downloads the headless server, manages saves and mods, and starts and stops the game process. Server administration is a browser tab.
Credit where it is due: Factorio Server Manager is Tricade’s work, carrying on the OpenFactorioServerManager project. Everything pleasant about running this server - the mod portal login, the save management, the graceful shutdown - is their code. Star the repo if you run a factory.
Here’s the full path, from a box that has Docker to a factory your friends can join.
1. Write the compose file
This is the whole deployment:
services:
manager:
image: ghcr.io/tricade/factorio-server-manager:0.17.5
restart: unless-stopped
stop_grace_period: 3m
environment:
FACTORIO_VERSION: stable
FSM_COOKIE_SECURE: "true"
ports:
- "34197:34197/udp"
volumes:
- fsm-data:/opt/fsm-data
- factorio-data:/opt/factorio
volumes:
fsm-data:
factorio-data:Every line that is not boilerplate earned its place:
- Pin the image to an exact release tag. The manager only changes when you decide it does.
- Named volumes.
factorio-dataholds the game and saves,fsm-dataholds the manager state. Explicit names keep the compose project prefix out, so a backup job can address them directly. FSM_COOKIE_SECURE: "true", because the UI will only ever be served over HTTPS.
⚠️ Do not skip
stop_grace_period: 3m. On SIGTERM the manager asks Factorio for a clean save-and-stop and needs up to 165 seconds. The Docker default of 10 seconds kills the game mid-save, which is how maps die.
Then bring it up:
docker compose up -d2. Point DNS at it - carefully
The UI rides your reverse proxy over HTTPS like any other web app. Game traffic does not: it is UDP on 34197, and an HTTP proxy like Traefik cannot route it. That’s why the compose file publishes the port straight on the host.
It also means the DNS record for the game must be a DNS-only A record pointing at the machine.
⚠️ A CNAME to a proxied hostname resolves to the Cloudflare edge, which accepts your packets and tells no one. If the UI loads fine but nobody can join, this is the first thing to check.
If a firewall fronts the box, open the game port explicitly:
sudo ufw allow 34197/udp3. Log in and burn the bootstrap credential
The manager generates an admin credential on first start and writes it into the volume. Read it out:
docker compose exec manager cat /opt/fsm-data/initial-admin-password.txtLog in with it, change the password, and the file deletes itself. Until you do, the bootstrap credential is lying around - do this first, not eventually.
4. Install the game and pin the version
From the UI, download the headless server and create (or upload) a save. Version pinning matters twice here:
- The manager image is pinned to an exact release tag in the compose file.
- The Factorio version is pinned in the UI after install, because the server
version must match the players’ clients.
stablein the compose file is only the first-install default.
Mods, save uploads, and restarts all happen in the UI from here on. The compose file changes only when the manager itself gets an upgrade, which is exactly how often I want to think about it.
5. Back up the volumes
Because the volumes have explicit names, a backup is one command with no compose context needed:
docker run --rm -v factorio-data:/data -v "$PWD":/backup \
alpine tar czf /backup/factorio-data.tgz -C /data .Run it on a schedule, and test a restore once before you trust it.
Verify
docker compose ps # ✅ the manager container is up
ss -lun | grep 34197 # ✅ the game port listens on UDPThen join from a Factorio client: Multiplayer → Connect to address with
your-host:34197. If the UI works but the join times out, go back to step 2 - it’s
almost always the proxied DNS record.