How to Install Factorio Dedicated Server on Ubuntu 24.04 VPS: Headless Multiplayer Setup
Factorio is a physics-heavy factory-building game where every belt, inserter and train is simulated in lockstep across all players. That simulation style makes the host's CPU and network the single biggest factor in multiplayer performance -- which is exactly why running your own headless dedicated server on a VPS is the gold standard for serious factories. This guide walks you from a fresh Ubuntu 24.04 VPS to a production Factorio server with systemd, autosaves, mods, whitelisting and a locked-down firewall -- in about 25 minutes.
Want a ready-to-play box? Deploy a fresh Ubuntu 24.04 VPS on our CloudCore Starter plan and follow this tutorial end to end. No payment surprises, flat monthly pricing, unmetered bandwidth.
Table of Contents
Why Self-Host a Factorio Server?
There are managed Factorio hosting services out there, but running the headless server on your own VPS wins on almost every dimension:
- Cost -- Managed Factorio hosts typically charge EUR 10-25 per month for a locked-down slot you cannot even SSH into. A CloudCore Starter VPS costs less, runs Factorio comfortably with room left for a Discord bot, an HTTPS status page and a Minecraft server on the side.
- Latency -- Factorio is a deterministic lockstep simulation: every client has to wait for every other client's inputs before the tick advances. The slowest player sets the UPS (updates per second). Choosing a VPS in a region close to your players -- and one with low jitter -- drops tick time dramatically. You get to pick the datacenter; managed hosts usually don't expose that choice.
- Mod freedom -- Managed panels often restrict which mods you can upload, cap mod count, or lag behind upstream Factorio releases by days or weeks. On your own VPS you drop any mod
.zipinto/opt/factorio/mods, flip the switch inmod-list.jsonand restart. You can also run experimental builds the same day they ship. - No slot limits -- Most panels sell "20-slot" or "40-slot" tiers. The headless server doesn't care -- you set
max_playersin a JSON file. Upgrade the VPS when your base outgrows the CPU. - Backups you control -- Saves live on disk. Rsync them to another host, snapshot them nightly, put them in S3, or ship them to Backblaze B2. Try that on a managed panel.
- SSH, systemd, journald -- Real logs, real process control, real debugging. When a mod deadlocks or UPS tanks, you can
journalctl -u factorio -fand see exactly what happened.
Prerequisites
Before you start, make sure you have:
- A VPS running Ubuntu 24.04 LTS with root or sudo access
- SSH access to the server
- A Factorio account that owns the game (required to download the headless build and -- for most map settings -- for players to connect)
- At least 2 GB of RAM (4 GB recommended, 8 GB+ for modded megabases)
- At least 5 GB of free disk (the headless binary is ~200 MB, saves are a few MB each but autosaves accumulate)
Recommended Plan: CloudCore Starter>
For a typical 4-8 player vanilla or lightly-modded server, the CloudCore Starter plan is the sweet spot:>
- 4 vCPU cores (Factorio is heavily single-threaded, but fast cores matter)
- 8 GB RAM
- 100 GB NVMe SSD
- Unmetered bandwidth, 1 Gbps port>
Pick a region near the majority of your players to keep tick latency low.
Connect to your server:
ssh root@your-server-ipStep 1: Update Ubuntu and Create a Dedicated User
Never run a public game server as root. Start by updating packages and creating a dedicated factorio system user that owns the binary and save files.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl tar xz-utils ca-certificatesCreate a non-login system user:
sudo useradd --system --create-home --home-dir /opt/factorio --shell /usr/sbin/nologin factorioThis creates the user factorio with its home directory at /opt/factorio and no login shell -- the account exists only to own files and run the systemd service.
If the kernel was upgraded, reboot before continuing:
sudo rebootStep 2: Download the Factorio Headless Build
The official headless build is served from factorio.com. The stable-channel URL always redirects to the latest release, so you can script this.
Switch to the factorio home directory and download the tarball:
cd /tmp
curl -L -o factorio-headless.tar.xz https://factorio.com/get-download/stable/headless/linux64Expected output (abbreviated):
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 204M 100 204M 0 0 28.1M 0 0:00:07 0:00:07 --:--:-- 32.4MExtract into /opt. The tarball contains a top-level factorio/ directory, so you extract into /opt and not /opt/factorio:
sudo rm -rf /opt/factorio
sudo tar -xJf factorio-headless.tar.xz -C /opt
sudo chown -R factorio:factorio /opt/factorioVerify the binary runs and reports its version:
sudo -u factorio /opt/factorio/bin/x64/factorio --versionExpected output (version will vary):
Version: 1.1.110 (build 64566, linux64, headless)
Binary version: 64
Map input version: 0.16.0-0
Map output version: 1.1.110-2Create the directories we'll need for saves, config and mods:
sudo -u factorio mkdir -p /opt/factorio/saves /opt/factorio/mods /opt/factorio/configStep 3: Create Your First Save
The headless server will not start without an existing save file. You generate one from the command line using the same engine the GUI uses.
Create a default map called world.zip:
sudo -u factorio /opt/factorio/bin/x64/factorio \
--create /opt/factorio/saves/world.zipExpected output:
0.000 2026-04-16 10:00:00; Factorio 1.1.110 (build 64566, linux64, headless)
0.001 Operating system: Linux (Ubuntu 24.04)
0.001 Program arguments: ...
0.045 Loading map-gen-settings... done.
1.234 Saving map as /opt/factorio/saves/world.zip
1.910 GoodbyeCustomizing the Map
Pass --map-gen-settings and --map-settings to control the generator (ore richness, biters, resource frequency):
sudo -u factorio /opt/factorio/bin/x64/factorio \
--create /opt/factorio/saves/peaceful-world.zip \
--map-gen-settings /opt/factorio/config/map-gen-settings.json \
--map-settings /opt/factorio/config/map-settings.jsonExample starter templates are shipped in the tarball at /opt/factorio/data/map-gen-settings.example.json and /opt/factorio/data/map-settings.example.json -- copy them into config/ and edit to taste.
Step 4: Configure server-settings.json
server-settings.json controls server name, description, visibility (public/lan/private), max players, password and mod-portal credentials. The example file ships with the tarball.
Copy the template:
sudo -u factorio cp /opt/factorio/data/server-settings.example.json \
/opt/factorio/config/server-settings.jsonEdit it:
sudo -u factorio nano /opt/factorio/config/server-settings.jsonA minimal production config looks like this:
{
"name": "My Factory Server",
"description": "Private group server hosted on vps-server.host",
"tags": ["vanilla", "coop"],
"max_players": 10,
"visibility": {
"public": false,
"lan": true
},
"username": "your-factorio-account",
"token": "your-factorio-account-token",
"game_password": "replace-me",
"require_user_verification": true,
"max_upload_in_kilobytes_per_second": 0,
"max_upload_slots": 5,
"minimum_latency_in_ticks": 0,
"ignore_player_limit_for_returning_players": true,
"allow_commands": "admins-only",
"autosave_interval": 10,
"autosave_slots": 5,
"autosave_only_on_server": true,
"non_blocking_saving": true,
"afk_autokick_interval": 0
}Key fields to understand:
visibility.public-- Set totrueto list the server on the public browser;falsekeeps it discoverable only via direct IP. Keep private unless you really want randoms connecting.username/token-- Your Factorio account credentials. The token (not the password) is fetched from your profile page. These are required for public listing and for the server to download mods from the mod portal on clients' behalf.game_password-- Connection password. Leave empty to disable.require_user_verification-- Forces joiners to have a legitimate Factorio account. Leavetrue.allow_commands--"admins-only"is the sane default."true"allows cheating;"false"disables all/ccommands.autosave_interval-- Minutes between autosaves. 10 is a good balance.autosave_only_on_server/non_blocking_saving-- Saves only happen on the server, and saving does not freeze the tick -- essential for larger bases.
Step 5: Define Admins, Whitelist and Banlist
Three small JSON files control who has admin powers and who can connect.
Admins
sudo -u factorio tee /opt/factorio/config/server-adminlist.json > /dev/null <<'EOF'
[
"your-factorio-username",
"friend-factorio-username"
]
EOFAdmins can promote players, kick, ban, and run all /c commands.
Whitelist (optional, strongly recommended for private groups)
sudo -u factorio tee /opt/factorio/config/server-whitelist.json > /dev/null <<'EOF'
[
"your-factorio-username",
"friend-factorio-username",
"another-player-username"
]
EOFWhen a whitelist file is present and passed via --use-server-whitelist, only these usernames can join. Combined with require_user_verification: true, this prevents griefing cold.
Banlist
sudo -u factorio tee /opt/factorio/config/server-banlist.json > /dev/null <<'EOF'
[]
EOFBans are easiest to add in-game via /ban <username> once you're running.
Step 6: Tune Autosave Behaviour
Factorio writes autosaves in rotation to /opt/factorio/saves/_autosave1.zip ... _autosaveN.zip. With autosave_slots: 5 and autosave_interval: 10, you get the last 50 minutes of history on disk automatically.
For off-box safety, add a simple nightly rsync cron that copies the save directory to another machine or object storage. Example for rsync to a backup host:
sudo -u factorio crontab -eAdd:
0 4 * rsync -az /opt/factorio/saves/ backup@backup-host:/backups/factorio/ 2>&1 | logger -t factorio-backupThis runs at 04:00 server time and tags output into the system log.
Step 7: Create the systemd Service
A systemd unit makes the server start on boot, restart on crash and log cleanly to journald.
Create the unit file:
sudo tee /etc/systemd/system/factorio.service > /dev/null <<'EOF' [Unit] Description=Factorio Headless Server Documentation=https://wiki.factorio.com/Multiplayer After=network-online.target Wants=network-online.target[Service] Type=simple User=factorio Group=factorio WorkingDirectory=/opt/factorio ExecStart=/opt/factorio/bin/x64/factorio \ --start-server /opt/factorio/saves/world.zip \ --server-settings /opt/factorio/config/server-settings.json \ --server-adminlist /opt/factorio/config/server-adminlist.json \ --server-whitelist /opt/factorio/config/server-whitelist.json \ --use-server-whitelist \ --server-banlist /opt/factorio/config/server-banlist.json \ --port 34197 Restart=on-failure RestartSec=5 KillSignal=SIGINT TimeoutStopSec=30
Hardening
NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=true ReadWritePaths=/opt/factorio
[Install] WantedBy=multi-user.target EOF
Reload systemd, enable on boot and start:
sudo systemctl daemon-reload
sudo systemctl enable factorio
sudo systemctl start factorioCheck status:
sudo systemctl status factorioExpected output (abbreviated):
● factorio.service - Factorio Headless Server
Loaded: loaded (/etc/systemd/system/factorio.service; enabled; preset: enabled)
Active: active (running) since Wed 2026-04-16 10:15:00 UTC; 5s ago
Main PID: 4242 (factorio)
Tasks: 9 (limit: 9451)
Memory: 380.0M
CGroup: /system.slice/factorio.service
└─4242 /opt/factorio/bin/x64/factorio --start-server ...Tail the live log:
sudo journalctl -u factorio -fYou should see:
Info ServerMultiplayerManager.cpp:878: Matching server connection resumed
Info ServerRouter.cpp:627: Starting a new multiplayer game as server
Hosting game at IP ADDR:({0.0.0.0:34197})Step 8: Open UDP 34197 in UFW
Factorio talks over UDP port 34197. TCP is not used for gameplay, so only UDP needs to be opened.
If UFW isn't installed or enabled yet, see our UFW firewall guide.
With UFW active, allow the port:
sudo ufw allow 34197/udp comment 'Factorio multiplayer'
sudo ufw reload
sudo ufw status verboseExpected output:
Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), deny (routed)
To Action From -- ------ ---- 22/tcp ALLOW IN Anywhere 34197/udp ALLOW IN Anywhere # Factorio multiplayer
From a client machine, verify the port is reachable:
nc -u -zv your-server-ip 34197nc will report "open" on reachable UDP endpoints -- though UDP reachability checks are imperfect, the real proof is successfully connecting with the game client via Multiplayer -> Connect to address.
Step 9: Install Mods the Right Way
There are two ways to run mods on a headless server. Pick one and stick with it.
Option A: Server-side mods via mod-list.json
Drop the .zip files (as downloaded from mods.factorio.com) into /opt/factorio/mods/:
sudo -u factorio cp ~/downloads/bobinserters_1.2.3.zip /opt/factorio/mods/
sudo -u factorio cp ~/downloads/LogisticTrainNetwork_2.0.0.zip /opt/factorio/mods/Edit (or create) mod-list.json in the same directory:
sudo -u factorio tee /opt/factorio/mods/mod-list.json > /dev/null <<'EOF'
{
"mods": [
{ "name": "base", "enabled": true },
{ "name": "bobinserters", "enabled": true },
{ "name": "LogisticTrainNetwork", "enabled": true }
]
}
EOFRestart the server so it reloads the mod tree:
sudo systemctl restart factorioJoining clients will be told which mods they need and, if they have Factorio account credentials active in their client, Factorio will auto-download matching versions from the mod portal.
Option B: Let the server fetch mods from the mod portal
If you set username and token in server-settings.json, the server itself can pull mods on demand. Still list them in mod-list.json with enabled: true; on startup, the server will download missing entries.
Mod settings
Per-mod settings live in /opt/factorio/mods/mod-settings.dat -- a binary file. The easiest way to edit settings is to join the server once, change settings in the in-game mod settings menu (runtime-global settings can be changed live by admins), then save.
Step 10: Upgrade to a New Factorio Version
Factorio updates break save compatibility across major versions (for example, 1.1.x -> 2.0.x). Always back up before upgrading.
Stop the server and back up:
sudo systemctl stop factorio
sudo cp -a /opt/factorio /opt/factorio.backup.$(date +%F)Download the new headless tarball:
cd /tmp
curl -L -o factorio-headless.tar.xz https://factorio.com/get-download/stable/headless/linux64Replace only the binary tree -- keep your saves, config and mods:
sudo tar -xJf factorio-headless.tar.xz -C /tmp/
sudo rsync -a --delete /tmp/factorio/bin/ /opt/factorio/bin/
sudo rsync -a --delete /tmp/factorio/data/ /opt/factorio/data/
sudo chown -R factorio:factorio /opt/factorioVerify the new version:
sudo -u factorio /opt/factorio/bin/x64/factorio --versionStart the server back up:
sudo systemctl start factorio
sudo journalctl -u factorio -fWatch for migration messages. If something is wrong, stop the service and roll back:
sudo systemctl stop factorio
sudo rm -rf /opt/factorio
sudo mv /opt/factorio.backup.YYYY-MM-DD /opt/factorio
sudo systemctl start factorioTroubleshooting
| Problem | Cause | Solution |
|---|---|---|
Error: cannot execute binary file: Exec format error | Wrong architecture tarball | You downloaded the wrong arch. Use the linux64 URL on x86_64 VPS. |
| Server starts but clients time out | UDP 34197 blocked upstream | Check UFW (sudo ufw status), provider firewall panel, and that --port 34197 is actually on the ExecStart line. |
Error: failed to save; Disk full | /opt or / out of space | Check df -h. Prune old autosaves in /opt/factorio/saves/. Expand the disk on your plan. |
Authentication error when clients join | require_user_verification: true but client is offline | Client needs a logged-in Factorio account. Disable verification only on LAN. |
| UPS drops under 50 | CPU-bound mega-base | Factorio is single-thread sensitive. Move to a plan with higher per-core clock, disable expensive mods, or reduce biter expansion. |
| Mods disappear after restart | Wrong ownership or malformed JSON | sudo chown -R factorio:factorio /opt/factorio/mods; validate mod-list.json with jq . /opt/factorio/mods/mod-list.json. |
Hosting game at IP ADDR:({0.0.0.0:34197}) but not listed publicly | visibility.public: false or token missing | Set visibility.public: true and supply username + token in server-settings.json. |
| Service keeps restarting | Save corrupted | Check journalctl -u factorio -n 200. Load the previous autosave: edit the unit's --start-server to point at _autosave1.zip. |
Useful log filters
# Live log
sudo journalctl -u factorio -fLast 200 lines
sudo journalctl -u factorio -n 200 --no-pagerOnly errors
sudo journalctl -u factorio -p err --no-pagerFAQ
Do I need to own Factorio to run the headless server?
Yes. The download URL at factorio.com requires an authenticated account that owns the game. Players joining also need licensed accounts when require_user_verification: true, which you should leave on.
How much RAM does a Factorio dedicated server need?
A fresh map with 2-4 players is happy on 2 GB. A typical mid-game base with 4-8 players uses 3-6 GB. Modded megabases (Krastorio, Space Exploration, Bob's + Angel's) can reach 10-14 GB. 4 GB covers most groups; 8 GB -- the CloudCore Starter default -- gives plenty of headroom.
What port does Factorio use?
UDP port 34197 by default. Change it with --port on the ExecStart line or in server-settings.json if you're running multiple servers on one VPS. Remember to open the new port in UFW.
How do I install mods on a headless server?
Put mod .zip files in /opt/factorio/mods/ and list them in mod-list.json with "enabled": true. Restart the service. Alternatively, supply your Factorio account username and token in server-settings.json and the server will download listed mods from the official portal on startup.
Can I run multiple Factorio servers on one VPS?
Absolutely. Copy the install tree to /opt/factorio2, give it its own save, config and systemd unit, and pick a different port (for example, 34198). Open the new port in UFW. The only real limit is CPU -- each server occupies ~1 core under load.
Is RCON available?
Yes. Add --rcon-port 27015 --rcon-password <your-password> to ExecStart. You can then send commands remotely with any RCON client, including scripted server-wide announcements or scheduled admin commands.
How do I reset the map without losing configs?
Stop the service, move the old save aside, generate a new one, start the service:
sudo systemctl stop factorio
sudo -u factorio mv /opt/factorio/saves/world.zip /opt/factorio/saves/world.old.zip
sudo -u factorio /opt/factorio/bin/x64/factorio --create /opt/factorio/saves/world.zip
sudo systemctl start factorioCan I hide my VPS IP from players?
Point a DNS A record (for example, factory.yourdomain.com) at the server and share that hostname. Players connect via the hostname instead of the raw IP. For truly hidden origin IPs you'd need a UDP proxy or game-specific anti-DDoS service -- uncommon for small private servers.
Next Steps
Your Factorio server is live. Here's what to build next:
- Run more game servers on the same box -- A CloudCore Starter VPS can comfortably host Factorio alongside other game servers. See our guides on installing a Minecraft server on Ubuntu and running a Valheim dedicated server on Ubuntu.
- Harden SSH and firewall further -- Walk through our UFW setup guide to rate-limit SSH, restrict admin access to your home IP, and log dropped packets.
- Automate off-box backups -- Ship
/opt/factorio/saves/to S3, Backblaze B2, or a second VPS using rsync over SSH. Factorio saves are small and compress further -- a full rolling week of backups is rarely more than a few hundred megabytes. - Read the official multiplayer docs -- The Factorio wiki Multiplayer page documents every CLI flag and
server-settings.jsonfield in detail; bookmark it for deeper customisation. - Monitor UPS and memory -- Install a lightweight agent (Netdata, node_exporter + Grafana, or Uptime Kuma for basic port checks) so you get alerted when the server crashes or UPS drops below 60.
Ready to launch your factory?>
Spin up a fresh Ubuntu 24.04 VPS on the CloudCore Starter plan and you'll be building belts with friends in under half an hour. Flat monthly price, unmetered bandwidth, and full root access -- everything Factorio's lockstep simulation needs to run smoothly.