//Servers

Seamless SaaS Migration: From Hyperscalers to Managed VPS

Guide to moving a SaaS from AWS/Azure/GCP to a managed VPS with minimal downtime, data sync, DNS cut‑over, and validation steps.

6 min read
Seamless SaaS Migration: From Hyperscalers to Managed VPS

Moving a SaaS product from a public-cloud hyperscaler (AWS, Azure, GCP) to a managed VPS such as AtoZNode can lower costs and give you tighter control over the environment. The main challenge is keeping the service online while the underlying infrastructure changes. This guide presents a step-by-step path that minimises interruption, synchronises data, switches DNS, and validates the new setup.

1. Plan the Migration Window and Inventory

Even when you aim for zero-downtime, reserve a short maintenance window (15–30 minutes) for the final cut-over. During this window you should:

  • List every component: web servers, application servers, databases, caches, message queues, storage buckets, and third-party APIs.
  • Document current resource sizes (CPU, RAM, disk) and network requirements (ports, bandwidth).
  • Identify data that changes frequently, such as user-generated content or transaction logs.
  • Prepare a rollback plan in case the new environment behaves unexpectedly.

2. Replicate the Environment on the Managed VPS

Set up a new VPS that mirrors your production stack. The following commands cover both Debian/Ubuntu (apt) and AlmaLinux/Rocky/RHEL (dnf). If you use a different distribution, adjust the package names accordingly.

2.1 Install Base Packages

# Debian/Ubuntu (apt)
sudo apt update                     # Refresh package index
sudo apt install -y nginx python3-pip git curl  # Install web server, Python, Git, curl

# AlmaLinux/Rocky/RHEL (dnf)
sudo dnf check-update               # Refresh metadata
sudo dnf install -y nginx python3-pip git curl  # Install same set of tools

These commands pull the latest package lists and then install the essential services required for most SaaS stacks.

2.2 Clone Application Code

# Debian/Ubuntu and AlmaLinux/Rocky/RHEL
git clone https://github.com/your-org/your-saas.git /var/www/your-saas
cd /var/www/your-saas
git checkout main                 # Or the branch you deploy from

Placing the repository in /var/www keeps it separate from system files. Change the path if your organization uses a different convention.

2.3 Set Up Virtual Environments and Dependencies

# Create a Python virtual environment
python3 -m venv venv
source venv/bin/activate

# Install required Python packages
pip install -r requirements.txt

A virtual environment isolates your app’s dependencies from the system Python packages, simplifying future upgrades.

2.4 Configure the Database

For relational databases (MySQL, PostgreSQL) you have two options:

  1. Spin up a managed database instance on the same VPS provider and point the app to it.
  2. Replicate the existing cloud database using native replication (e.g., MySQL binlog replication) and promote the replica later.

Choose the method that matches your DB engine. The goal is to have a read-write replica ready before the cut-over.

3. Synchronise Data Continuously

Run the new VPS in parallel with the old environment and keep data in sync to avoid a data gap at switchover.

3.1 File Storage

If your SaaS stores uploads on a shared file system (e.g., S3), mount the same bucket on the VPS using s3fs or configure the app to read directly from the bucket. For on-premises storage, use rsync with the --delete flag in a cron job:

# Example rsync (run every 5 minutes)
rsync -az --delete /var/www/your-saas/uploads/ user@cloud-instance:/var/www/your-saas/uploads/

This command copies new and changed files (-a archive mode, -z compression) and removes files that no longer exist on the source (--delete).

3.2 Database Replication

For MySQL, set up a replica on the VPS:

# On the source (cloud) master
SHOW MASTER STATUS;   # Note File and Position values

# On the VPS (replica)
mysql -u root -p
CHANGE MASTER TO
  MASTER_HOST='cloud-db-host',
  MASTER_USER='replica_user',
  MASTER_PASSWORD='replica_password',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=12345;
START SLAVE;

The CHANGE MASTER TO statement tells the replica where to pull binlog events. After START SLAVE, the VPS database stays in sync.

4. Test the New Environment Thoroughly

Before moving live traffic, run a full suite of checks:

  • Functional tests – Execute your automated integration tests against the VPS endpoint.
  • Performance profiling – Use tools like ab or wrk to verify response times under load.
  • Security validation – Run ufw status (Ubuntu/Debian) or firewall-cmd --list-all (AlmaLinux/Rocky) to confirm only required ports are open.

Point a staging subdomain (e.g., staging.yourdomain.com) to the VPS IP and let a small group of internal users perform smoke testing.

5. Perform the Cut-Over with Minimal Impact

5.1 Reduce Write Activity

Just before the DNS switch, place the application into a “read-only” mode for a few seconds. This can be as simple as toggling a feature flag or displaying a maintenance page. The goal is to ensure no new writes occur while the final data sync runs.

5.2 Final Data Sync

Run a one-time synchronization to capture any changes that occurred during testing.

# For files
rsync -az --delete /var/www/your-saas/uploads/ user@cloud-instance:/var/www/your-saas/uploads/

# For MySQL (stop writes, then lock tables)
mysql -u root -p -e "FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS;"
# Note the File and Position, then run mysqldump
mysqldump -u root -p --single-transaction --master-data=2 \
  --all-databases > /tmp/full_dump.sql
# Transfer dump to VPS and import
scp /tmp/full_dump.sql user@vps:/tmp/
ssh user@vps "mysql -u root -p < /tmp/full_dump.sql"
# Release lock on source
mysql -u root -p -e "UNLOCK TABLES;"

The FLUSH TABLES WITH READ LOCK command pauses writes, ensuring the dump captures a consistent snapshot.

5.3 Update DNS

Change the A record for your domain to point to the new VPS IP. Reduce the TTL (time-to-live) to 300 seconds a few hours before the migration so that resolvers pick up the change quickly.

Tip: If you use a CDN (e.g., Cloudflare), update the origin IP in the dashboard rather than editing DNS directly.

5.4 Verify Live Traffic

After DNS propagation, monitor the following for at least 10 minutes:

  • HTTP 200 responses from the new server.
  • Database replication lag (should be zero).
  • Error logs for any unexpected exceptions.

If issues appear, you can revert the DNS record to the old IP within the TTL window.

6. Decommission the Old Cloud Resources

Once you’re confident the VPS handles production traffic, clean up the original cloud setup:

  1. Stop and snapshot any remaining instances for archival purposes.
  2. Delete storage buckets that are no longer needed.
  3. Terminate the cloud database to stop billing.

Keeping a snapshot for a week provides a safety net in case an obscure bug surfaces later.

Conclusion

Moving a SaaS application from a hyperscaler to a managed VPS can be done with minimal downtime. By replicating the environment, synchronising data continuously, testing thoroughly, and executing a short, well-planned DNS cut-over, you can transition users smoothly while gaining the cost and control benefits of a VPS. Adapt these steps to your specific stack and you’ll achieve a smooth migration with minimal disruption to your customers.

migrationsaasvpsdnsdata‑synchronizationdatabase‑replicationlinuxcloud‑to‑vps

Try it on your own server

Follow along on a Cloud VPS with full root access, or read the step-by-step knowledge base guides.