Migrating a game server to a higher-tier VPS or alternative hosting provider often causes extensive downtime for your gaming community. If an administrator halts the process and attempts to package an 80 GB server directory into a tar archive before transmitting it across the network, players face hours of disconnected downtime, while file permission errors (chown) frequently disrupt startup.
This article outlines a production migration protocol that minimizes downtime through phased rsync staging, dependency pre-flight validation, and clean network cutover.
Preparing target VPS dependencies and system libraries#
The most common migration failure occurs when transferring files to a fresh VPS lacking core runtime dependencies. Verify and configure prerequisites on the target machine before initiating changes on the source server.
Create a dedicated service user with matching UID parameters on the target host:
sudo useradd -u 1001 -m -s /bin/bash gameserver
sudo mkdir -p /opt/gameserver
sudo chown -R gameserver:gameserver /opt/gameserver
Install 32-bit compatibility runtimes and synchronization utilities required by SteamCMD game engines:
sudo dpkg --add-architecture i386
sudo apt update && sudo apt install -y lib32gcc-s1 lib32stdc++6 rsync curl
Phase 1: Pre-synchronizing static assets online#
The bulk of any game server installation consists of engine executables, textures, audio packs, and workshop maps. These files account for 95% of disk utilization but remain immutable during gameplay.
Execute the initial baseline transfer from the source host while the server remains active. The --exclude flag protects live save directories and rotating log files from transient desynchronization:
rsync -avz -P --numeric-ids \
--exclude="saved" \
--exclude="saves" \
--exclude="*.log" \
/opt/gameserver/ gameserver@NEW_SERVER_IP:/opt/gameserver/
The --numeric-ids flag preserves exact POSIX ownership parameters across different hosts, while -z enables transparent compression across the WAN link.
Phase 2: Service stop and final volatile save sync#
Once the bulk static payload resides on the target VPS, broadcast a planned maintenance alert (at 15-minute and 5-minute intervals) and gracefully terminate the game daemon.
Stop the systemd unit on the source host:
sudo systemctl stop gameserver
sudo systemctl is-active gameserver || echo "Process stopped"
Perform the final delta transfer containing dynamic state (world saves, player inventories, sqlite databases). Because this delta is typically under a few hundred megabytes, the transfer completes in under 60 seconds:
rsync -avz -P --delete --numeric-ids \
/opt/gameserver/ gameserver@NEW_SERVER_IP:/opt/gameserver/
The --delete argument cleans up orphaned temporary files on the target, guaranteeing byte-level directory parity.
Migrating systemd configuration and network cutover#
Transfer the systemd service definition to the destination server:
scp /etc/systemd/system/gameserver.service root@NEW_SERVER_IP:/etc/systemd/system/
On the new VPS, reload systemd, enable the service, and verify startup:
sudo systemctl daemon-reload
sudo systemctl enable --now gameserver
sudo systemctl status gameserver --no-pager
Confirm that the engine is listening on the designated game port:
ss -ulnp | grep 27015
Following verified startup, update your domain's DNS A-record or broadcast the new connection coordinates to players.
For fleet operations across multiple nodes, modern workflows in a unified server management platform orchestrate these migration steps through declarative container profiles without requiring manual OS-level interventions.




