← Back to Blog

Move WordPress to a VPS: A Tested Migration, DNS Cutover and Rollback Plan

Published · by RS Computers

WordPress Migration VPS

To move WordPress to a VPS, copy the files and database, test the destination using the real hostname before changing DNS, then freeze writes for the final copy and direct traffic to the new server. Keeping the domain and URL structure unchanged avoids many unnecessary SEO problems. A site accepting orders, comments or uploads needs a plan for those writes during the switch.

A quiet brochure site can often remain readable throughout a move. An active shop may need a short maintenance window unless you build and test a more advanced replication and traffic-switching system. This guide describes a controlled migration with a rollback plan, not an unconditional promise of zero downtime.

StageWhich copy accepts real writes?Condition for moving on
RehearsalOld site onlyThe isolated destination passes content, file and application checks
Final synchronizationNeither copyLatest database and uploads are present at the destination
CutoverNew site onlyPublic traffic reaches the new server and important transactions work
ObservationNew site onlyBackups, scheduled jobs and normal traffic are verified before retiring the old copy

Keeping one authoritative writer is the principle behind the procedure. It avoids the harder problem of merging two sets of orders or uploads afterwards.

What we tested in the WordPress migration lab

On 11 October 2026, we created a synthetic WordPress site in a Debian 13 container on our Linux test VPS. The environment used PHP 8.4.26, MariaDB 11.8.6 and WordPress 7.1.3 as reported by the installed tools. Two directories and two databases represented the old and new sites. This tested file copying, database export/import, serialized URL replacement, maintenance commands, core checksums and a local HTTP preview. It did not test a public DNS switch, a live payment gateway or a production TLS certificate.

CheckObserved result
Database export and importThe destination retained the synthetic published post
URL replacementDry run and real run each reported six replacements
Serialized optionIts nested URL changed correctly to HTTPS
Core integrityInitial extraction failed checksums; native tar extraction passed on both copies
Local previewThe destination served the synthetic post using the intended hostname
Database integrityA second isolated copy passed wp db check; both published test posts were present
File comparisonThe dry run found only a directory timestamp difference after copying, with configuration excluded

The useful lesson was that a successful copy command alone did not prove that the site was ready. Keep a content check and an integrity check in the process.

Prepare the destination before touching DNS

You need SSH or equivalent export access on the old host, a new VPS with a web stack, a destination database, and control of the domain's DNS. SSH is already installed on the RS Computers Debian VPS image; use the supplied access to prepare your web stack. This guide assumes a single WordPress installation. Multisite, large stores and sites with external object storage need a migration plan specific to their configuration.

Match the PHP version and extensions to your plugins. Set up the web server's virtual host for the real domain, arrange a valid HTTPS certificate, and check filesystem ownership. DNS-based certificate validation can help obtain a certificate before switching traffic. Do not disable certificate verification as a substitute for getting TLS right.

Use the WordPress VPS hosting guide for the initial stack and Debian security guide for access controls. The steps below assume WP-CLI is installed on both systems using its official installation instructions. Run WordPress commands as the account owning the site, not root.

Inventory the domain's A, AAAA, MX and TXT records. Changing a website address should not accidentally move mail. If lowering the existing DNS TTL for the migration, do it at least one old TTL interval beforehand; cached answers already issued retain their previous lifetime.

Write down the parts a file copy will miss

As the site owner, run these commands from the existing WordPress directory and save the results privately:

wp core version
wp plugin list --status=active
wp cron event list --fields=hook,next_run_gmt

We checked these commands in the lab. The plugin list helps identify PHP and extension requirements; the scheduled-event list helps identify jobs that should run on only one copy. Also inventory host-level cron jobs, Redis or another object cache, SMTP credentials, payment webhooks, media stored outside the server and any IP allowlists at third-party services.

The database and wp-content directory do not necessarily contain every dependency. A copied site can render its homepage while emails, scheduled exports or offloaded images are broken. For a provider-managed source, ask which settings and services belong to the old hosting environment.

Take a backup outside the public web directory

In these examples, replace paths, hostnames and the account deploy with your real values. On the old server, as the site owner:

cd /var/www/site
umask 077
mkdir -p ~/migration
wp db export ~/migration/site.sql --single-transaction
tar -czf ~/migration/site-files.tar.gz .

Keep both files off the server as well. Database dumps contain private information and must not sit at a publicly accessible URL. The --single-transaction export is useful for transactional tables, but it does not make changing files and all database engines an atomic backup. Avoid schema changes during the export. A final write freeze still matters.

The WP-CLI export documentation describes the command and database options. Verify that the files exist and are nonempty before treating the backup as complete.

Copy files and import into a separate destination database

Create a blank destination database and a database user with privileges only for that site using your chosen control panel or database administration method. Prepare the destination directory with ownership assigned to the site account, and create that account's ~/migration directory. On the old host, use rsync over SSH; first confirm the destination host key:

rsync -av --exclude=wp-config.php --exclude=.maintenance \
  /var/www/site/ deploy@NEW_SERVER_IP:/var/www/site/
scp ~/migration/site.sql deploy@NEW_SERVER_IP:~/migration/site.sql

The trailing slash on the source means copy its contents. These commands intentionally exclude the old database configuration and WordPress maintenance marker. Our lab tested the same file-copy exclusions locally; the cross-host transfer requires your SSH access and paths.

On the new host, create its own wp-config.php with the new database credentials. Copy any intentional custom configuration from the old site after reviewing it, including table prefix, salts and application constants. Preserve the old prefix if the database uses something other than wp_. Do not paste production passwords into a shared transcript or this example.

Configuration valueWhat belongs on the new server
DB_NAMEThe destination database you created for this site
DB_USER and DB_PASSWORDCredentials authorized for that destination database
DB_HOSTThe destination database host or socket arrangement, which may differ from the old host
$table_prefixThe prefix used by the imported tables
WP_HOME and WP_SITEURL, if explicitly definedThe intended public URLs; these constants can override database option values

Edit the file in a private session and make it readable by the site's PHP process without granting unnecessary access to other users. Never solve a permission error by making the whole site world-writable. Database configuration and filesystem ownership must match the web stack you chose.

Then, as the destination site owner:

cd /var/www/site
wp db import ~/migration/site.sql
wp option get home
wp option get siteurl
wp post list --fields=ID,post_title,post_status
wp core verify-checksums

The two URL options should show the intended public address. Compare important content with the source. Importing overwrites data in the selected database, so check the destination config before running it. See the import reference.

In our lab, checksum verification found truncated filenames after the initial WP-CLI core download. Re-extracting the official WordPress release with the system tar tool and repeating the copy resolved it. We verified both source and destination afterwards. If you see a mismatch, investigate it; do not assume that a similar-looking failure has the same cause or overwrite a live site's custom files blindly.

Check more than a successful import message

On the destination, as the site owner:

wp db check
wp post list --post_type=post --post_status=publish --format=count

The first command checks the database tables; the second gives a count you can compare with the source. Our second lab copy returned successful table checks and two published posts. A matching post count is only a quick check: inspect recent content, users, media and plugin-specific records as well. The WP-CLI database-check reference explains its scope.

From the old server, this dry run shows remaining file differences and destination-only files. Replace the address and paths before running it:

rsync -avni --delete --exclude=wp-config.php --exclude=.maintenance \
  /var/www/site/ deploy@NEW_SERVER_IP:/var/www/site/

The n in -avni means dry run, so this command does not copy or delete files. The i displays the kinds of changes. Review any *deleting entries before deciding how to reconcile them; do not remove the dry-run flag blindly. Confirm that destination-only cache or environment files are intentional and that the source and destination paths are correct. Our local comparison found only a directory timestamp change. See the rsync manual.

Keep URLs unchanged unless a change is intentional

A server move that retains the domain, protocol and paths usually does not need a global URL replacement. Avoid changing the site address to a temporary IP just to preview it. WordPress's migration handbook distinguishes changing servers from changing site URLs.

If you are deliberately changing HTTP to HTTPS, or changing domain, preview a replacement on the destination first. Replace the example URLs with the exact old and new values:

wp search-replace 'http://example.com' 'https://example.com' \
  --all-tables-with-prefix --skip-columns=guid --dry-run

Review the listed tables and counts. Take a fresh destination database export, then repeat without --dry-run only if the changes are correct. WP-CLI handles serialized values; a plain SQL text replacement can corrupt them. We tested a serialized option containing a nested URL and confirmed that the resulting value remained readable. See search-replace documentation.

Preview with the real hostname before switching traffic

Once the new web server has a valid certificate for the domain, run this from your computer. Replace the documentation IP with the destination address:

curl --resolve example.com:443:203.0.113.10 \
  -I https://example.com/

This connects to the selected IP while retaining the hostname for HTTP and TLS. It bypasses normal DNS for this request. In our lab we checked the HTTP equivalent using seo.test:80:127.0.0.1 and confirmed that the page contained the test post. That local HTTP result does not validate your public HTTPS setup.

Use a temporary hosts-file entry for a full browser preview if needed, and remove it afterwards. Check login, images, permalinks, search, uploads, forms and scheduled tasks. Keep emails and payment actions disabled or in their documented test modes on the preview copy. Do not allow both sites to send scheduled notifications or process the same jobs.

Freeze writes, make the final copy, then change DNS

Choose a quiet period and tell the people operating the site. Pause checkout, comments, imports, background jobs and integrations that can write data. WP-CLI's maintenance command is one tool:

wp maintenance-mode activate
wp maintenance-mode status

The built-in WordPress maintenance marker expires after about ten minutes in the standard core behavior. It is not a durable freeze for a long migration, and it does not prove every integration has stopped writing. Use a controlled web-server or application maintenance arrangement for longer work. See the maintenance command reference.

With writes stopped, repeat the final file synchronization and database export/import. If you made an intentional URL replacement, repeat that transformation on the fresh destination database. Check the copied content once more. Change the relevant A and AAAA records together, accounting for any CDN or proxy in front. Leave the old endpoint unable to accept new writes while DNS answers expire.

When the destination is ready, deactivate its maintenance mode if active and enable its scheduled jobs. Confirm external requests reach it. A low TTL helps but cannot guarantee an exact switchover time for every client.

Keep search visibility and background jobs working

After the switch, check the site's intended indexing setting from its WordPress directory:

wp option get blog_public

Our lab returned 1. For a public site, investigate an unexpected 0, especially if the preview copy had search indexing discouraged. This option is only one layer: also inspect the rendered robots meta tag, response headers, robots.txt and SEO-plugin settings. Make sure a temporary preview password or noindex rule has not followed the site into production.

Preserve the same canonical hostname, URL paths and HTTPS behavior. Check a small set of important pages, an old article, an image and a URL that should return 404. Watch web-server errors and crawl activity after the move. Google's hosting-move guidance recommends testing the new infrastructure and monitoring the transition. A hosting change with unchanged URLs does not need a Change of Address request.

Inspect the scheduled-event list again and confirm that the mechanism triggering those jobs is active on the new site. Default WP-Cron is triggered by page loads; an old host may instead have used a system scheduler. Do not leave the old scheduler running against an old copy while the new one sends the same emails or imports the same feed. Listing events with WP-CLI does not execute them or prove that the external scheduler is working.

Fix common migration failures by their layer

ProblemFirst things to inspect
Error establishing a database connectionDestination credentials, database host, service status and grants; do not overwrite the old database while troubleshooting
Homepage works but article URLs return 404Apache rewrite support or the Nginx WordPress routing rules; copying .htaccess does not configure Nginx
Redirect loop or repeated switch between HTTP and HTTPSPublic URL settings, reverse-proxy scheme handling, TLS termination and cached redirect rules
Missing images or uploads that failCopied uploads, path case, PHP-user permissions and any external media-storage credentials
Some visitors still see the old siteCached DNS answers, an unchanged AAAA record, browser hosts-file entries and CDN origin configuration
Forms work but no email arrivesSMTP settings, credentials and outbound connectivity; a successful local form submission is not proof of delivery

RS Computers blocks outbound port 25 on a new VPS and opens it on request. If your WordPress setup depends on sending directly over that port, account for this before cutover. An authenticated mail relay uses its own documented submission settings; verify delivery with a test mailbox you control.

Make rollback a data decision

Before the new site accepts writes, rollback can mean restoring the old DNS records and reopening the old site. After new orders, uploads or comments arrive, changing DNS back alone can strand that new data. Freeze writes again and reconcile the databases and files before switching back.

Our lab re-imported the saved database into the destination and confirmed that the test post remained present. A real restore rehearsal should also check media, plugin data and the application's important transactions. Keep the old host until you have verified traffic, backups and scheduled tasks on the new one.

RS Computers provides VPS and VDS hosting in Kosovo, the Netherlands and Ireland. For a migration with unusual plugins or a busy store, contact our team to discuss the work. Setup and migration assistance are scoped to the particular site.

Frequently asked questions

Will moving WordPress to a VPS hurt SEO?

A hosting move does not require changing public URLs. Preserve paths, working HTTPS, canonical tags and indexability, and check for errors after the switch. A migration cannot guarantee unchanged rankings.

Can I move WooCommerce without stopping orders?

Keeping orders available throughout requires a tested method to preserve writes and route traffic consistently. A final maintenance window is usually simpler than reconciling orders written independently to two copies.

Should I change nameservers during the move?

Only if you also intend to move DNS hosting. Updating the website's address records at the existing DNS provider is often sufficient. Preserve mail and verification records.

Do I need to use Google's Change of Address tool for new hosting?

No, when the domain and public URLs remain the same. Check the new hosting, preserve indexability and monitor errors. A separate domain change is a different migration.

Why did the old site come back after I tested the new one?

A hosts-file entry or curl's resolve option affects only that test client or request. It does not change public DNS. Remove local overrides when testing the public cutover so they do not hide a routing mistake.

← All articles

Chat on Telegram