A reliable Factorio update starts with a recoverable old environment. Keep the old executable, untouched save, exact mods and settings together before a newer build opens the factory. Replacing the binary later does not undo changes already written into a save.
This workflow is for an existing directly installed Factorio 2.x headless server on Ubuntu 24.04, following our setup guide. It assumes service factorio, program directory /opt/factorio and runtime data /srv/factorio. Container images and managed instances have different deployment controls; preserve the same recovery boundaries using their supported workflow rather than copying these filesystem paths.
Agree on the exact destination#
Record the current server and client builds, expansion choice, enabled mod releases and startup settings. Then choose the full destination version and verify that the required mods support it. “Latest” is a moving download target, not a reproducible deployment specification.
Wube's download page separates stable and experimental builds. A branch change deserves its own rehearsal: the 2.1 experimental announcement explicitly says upgraded saves and blueprints cannot be downgraded to 2.0. Preserve a participating client's blueprint library and user data before that client changes branch too.
Get the exact old and proposed installers from Wube and retain their release names. Compare downloaded files with available official release checksums. Keep an independent SHA-256 inventory for your recovery set. A locally computed hash records file identity; it establishes authenticity only when compared with a trusted value.
Do not describe reinstalling the same release as a successful update. Acceptance needs distinct recorded old/new versions and the intended new executable actually running.
Freeze a complete recovery set#
Schedule a stop and tell players which progress will be included. Inspect the effective service first:
sudo systemctl cat factorio
/opt/factorio/bin/x64/factorio --version
sudo systemctl stop factorio
sudo systemctl is-active factorio
sudo journalctl -u factorio -n 100 --no-pager
An inactive service is expected after stopping. Continue only after the log confirms normal shutdown and saving without a forced kill or storage failure. If the stop failed, investigate before archiving a directory the process may still be changing.
For this layout, archive both program and runtime directories under a unique private recovery directory:
(
set -e
sudo install -d -o root -g root -m 700 /var/backups/factorio
factorio_backup=$(sudo mktemp -d /var/backups/factorio/pre-update.XXXXXX)
sudo tar -czf "$factorio_backup/environment.tar.gz" \
-C / opt/factorio srv/factorio
sudo chmod 600 "$factorio_backup/environment.tar.gz"
sudo tar -tzf "$factorio_backup/environment.tar.gz" >/dev/null
sudo sha256sum "$factorio_backup/environment.tar.gz"
printf '%s\n' "$factorio_backup"
)
The guarded block stops on failure and prints its recovery directory. Continue only after it succeeds; record the path and checksum privately. This archive assumes the real data resides in those directories: separately include external config files, followed symlink targets or mounted storage if your installation uses them. Retain the unit, drop-ins, service user identity and ownership requirements. Config files and runtime data can contain credentials; copy the set securely off the server without publishing it.
An archive that lists successfully is only a readable archive. Verify restoration into a separate location, ownership, expected save names and available old installer before treating it as a recovery point.
Rehearse on an isolated factory copy#
Extract the destination installer into a different program directory. Prepare a separate writable runtime directory containing the copied save, exact proposed mod ZIPs, mod-list.json, mod-settings.dat and required configuration. Keep this set distinct from production. Mod migrations can change world state when the environment changes; removing a failing mod just to finish loading is a different migration.
Make the test config's write-data point to that isolated runtime and its read-data to the new installation. Audit startup scripts, absolute save paths and symlinks too. Use explicit --config, --mod-directory and --start-server SAVE options from the command reference. An explicit copied save avoids accidentally choosing another factory through latest-save loading.
Prefer a separate test machine. If sharing a host, select unused game/RCON ports, restrict access and disable public/LAN visibility in the copied settings. Never bind the production ports or use its runtime directory. Do not post copied authentication tokens in the rehearsal log.
Use a matching test client to join the intended factory. Inspect important trains, production chains, inventories and mod behavior. Save under a new name, stop normally, restart that explicit test save and reconnect. Retain migration messages and both versions. A service that merely starts has not passed this check.
Cut over from a fresh stop#
Rehearsal data may now be behind the real factory. Stop production normally again, take a fresh recovery set and migrate a copy of that latest authoritative save with the already validated destination build and mod set. Keep players out until validation is complete.
Change the existing unit's selected executable and data paths deliberately. Reload systemd if its definition changed, then inspect the running process, startup log and selected save. Check the game's actual listening UDP port, join from a matching client, save, restart and reconnect. Save the exact old/new build numbers with the cutover record.
Do not combine this window with unrelated operating-system upgrades or speculative performance changes. Fewer simultaneous changes make a failed acceptance result easier to diagnose.
Before starting, check sudo systemctl show factorio -p ExecStart: drop-ins, including selected-save.conf from the save-selection guide, can override the base unit. Update the configuration that actually selects the executable, data and save.
Restore the old environment if acceptance fails#
Stop the failed new instance and preserve its logs and data separately. Reinstall the exact old program, restore the untouched old runtime, mod set, settings and service configuration, and verify account ownership. Select the pre-update save explicitly for the first restart. Keep newer saves outside any directory searched by --start-server-load-latest.
The installation reference also matters for very old factories: forward loading can require intermediate releases. It does not provide a general downgrade mechanism. If the only remaining save has already migrated, keep it intact and investigate a supported forward repair or another older backup.
When administering supported instances through Nexardo on your own Linux infrastructure, retain a separate recovery set for every factory. Panel controls do not prove save compatibility or automatically adopt this manual systemd installation.
After rollback, verify the old build, factory, client join, save and restart again. Progress made after the recovery point is absent from that restored factory. State that tradeoff before reopening the server; do not promise to merge newer progress backwards into an incompatible save.




