Engineering Field guide

Move a game server to another VPS with minimal downtime

Migrate a dedicated game server to another VPS with zero downtime: two-phase rsync staging, save delta transfers, and service validation.

Move a game server to another VPS with minimal downtime

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:

bash
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:

bash
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:

bash
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:

bash
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:

bash
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:

bash
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:

bash
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:

bash
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.

Sources#