Factorio is the easiest dedicated server on this whole blog. No SteamCMD, no anti-cheat, no 12 GB download. The official headless build is a single tarball you grab straight from factorio.com, and a fresh world idles under 1 GB. It only gets hungry once someone builds a megabase.

TL;DR:

# grab the official headless build (no Steam account needed)
adduser --disabled-password --gecos "" factorio && sudo -iu factorio
curl -L https://factorio.com/get-download/stable/headless/linux64 -o factorio.tar.xz
tar -xJf factorio.tar.xz            # extracts to ./factorio/

cd factorio
./bin/x64/factorio --create saves/myworld.zip
cp data/server-settings.example.json server-settings.json   # edit it
./bin/x64/factorio --start-server saves/myworld.zip \
  --server-settings server-settings.json

Details below.

Get the headless build

There's no Steam dependency — the headless server is a free, separate download. Do it as an unprivileged user:

apt update && apt install -y xz-utils curl
adduser --disabled-password --gecos "" factorio
sudo -iu factorio

curl -L https://factorio.com/get-download/stable/headless/linux64 -o factorio.tar.xz
tar -xJf factorio.tar.xz
cd factorio

That stable URL always points at the current stable release. To pin a version, swap stable for the exact number, e.g. .../1.1.110/headless/linux64. The headless build is self-contained — it doesn't need the graphical game installed.

Create a world

The server needs a save to host. Generate one (with default map settings) before first launch:

./bin/x64/factorio --create saves/myworld.zip

Want custom map gen — ore richness, water, cliffs? Write a map-gen-settings.json (there's an example in data/) and pass --map-gen-settings. For an existing single-player save, just copy its .zip into saves/ and host that.

server-settings.json

Copy the example and edit it. This is where the name, description, visibility and admin list live:

cp data/server-settings.example.json server-settings.json

The fields that matter:

{
  "name": "Diengdoh Factorio",
  "description": "Friendly EU co-op. Stable channel.",
  "max_players": 0,
  "visibility": { "public": true, "lan": true },
  "username": "",
  "token": "",
  "game_password": "changeme",
  "require_user_verification": true,
  "autosave_interval": 10,
  "autosave_slots": 5,
  "admins": ["YourFactorioName"]
}
  • public: true lists you on the official matchmaking server browser. That requires a real factorio.com account — put your username and a server token (from your factorio.com profile, not your password) in username/token. No account or don't care about the public list? Set public: false and players join by direct IP.
  • max_players: 0 means unlimited.
  • autosave_interval is minutes. Factorio autosaves are cheap and have saved me more than once — keep it tight.
  • admins are matched by in-game username and can run /promote, /ban etc. without RCON.

Run it and open the port

./bin/x64/factorio --start-server saves/myworld.zip \
  --server-settings server-settings.json

Factorio needs exactly one UDP port, 34197:

ufw allow 34197/udp

That's it. No TCP for the game itself. Firewall basics: /ufw-firewall-rules-ubuntu/.

RCON for remote console

Want to run commands without being in-game? Add RCON on a TCP port:

./bin/x64/factorio --start-server saves/myworld.zip \
  --server-settings server-settings.json \
  --rcon-port 27015 --rcon-password "use-a-real-one"
ufw allow from 203.0.113.10 to any port 27015 proto tcp   # your IP only

Same rule as always — never expose RCON to the open internet.

Mods

Mods are just zip files. Drop them into the mods/ folder next to the save dir and the server loads them on start:

mkdir -p mods
# copy each Mod_1.2.3.zip into mods/

Every connecting client must have the same mods at the same versions or they're rejected at the door — that's the number one "my friend can't join" cause. To pull mods server-side automatically you can add your factorio.com username/token and let it sync, but I prefer dropping the exact zips in manually so versions are pinned. Factorio writes a mods/mod-list.json you can edit to enable/disable without deleting files.

systemd unit

# /etc/systemd/system/factorio.service
[Unit]
Description=Factorio Headless Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=factorio
WorkingDirectory=/home/factorio/factorio
ExecStart=/home/factorio/factorio/bin/x64/factorio \
  --start-server /home/factorio/factorio/saves/myworld.zip \
  --server-settings /home/factorio/factorio/server-settings.json
Restart=on-failure
RestartSec=10
# graceful: let it finish writing the autosave on stop
KillSignal=SIGINT
TimeoutStopSec=30

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now factorio
journalctl -u factorio -f

SIGINT gives the server a chance to save before exit instead of dropping the last few minutes of progress. More on units in /systemd-service-unit-file/.

Gotchas

  • Mod version mismatch. Clients are rejected unless their mods match exactly. Pin versions; don't let half your players auto-update.
  • public: true with no token. If you set public but leave username/token empty, the server logs an auth error and never shows in the browser. Either fill them in or go public: false.
  • Megabase RAM. A fresh map is tiny; a thousand-hour factory with bots everywhere can hit several GB and chew CPU on UPS (updates per second). If your server tanks to 30 UPS, that's the factory, not the network.
  • Updating. There's no in-place updater for headless — you download the new tarball and extract over the install (saves and mods live in their own dirs, so they survive). Stop the service first.
  • Wrong working dir. Launch from the install root or it won't find data/. The systemd WorkingDirectory handles that.

Verify

# port bound?
ss -tulpn | grep 34197

# hosting and ready?
journalctl -u factorio --no-pager | grep -i "Hosting game"

# watch joins
journalctl -u factorio -f | grep -i "joined the game"

In game: Multiplayer → Connect to address → <your-ip>:34197, enter the password. If the public list is on and your token's valid, it'll also show in the browser within a minute.

Lighter than the SteamCMD beasts on this blog — if you want the heavier survival kind next, see Enshrouded or 7 Days to Die.


Related posts