Skip to content
Products
AI Website Builder New VPS Hosting Cloud Servers Web Hosting Dedicated Servers Domains
Company
About Documentation Support Center Contact Get Started Login Client Area
ALL SYSTEMS OPERATIONAL
Hosting

Migrating a Magento Store to a VPS: Orders, Stock & Reindexing

Getwebup 7 min read

WordPress migrations are mostly copy-paste-and-pray. Magento migrations punish that approach. A live Magento store has search indexes, a crypt key tied to every encrypted field in the database, and a cron-driven queue that quietly breaks if it goes stale for even a day. Move the files and database without handling those three things and you'll have a store that loads fine, takes orders fine, and then silently fails to send order emails or show correct stock. Here's how to move a live Magento store to a VPS without any of that happening.

Why a Magento Move Is Not "Just Another WordPress Migration"

If you've migrated WordPress or WooCommerce before, the instinct is to zip the files, export the database, import it, and repoint DNS. That gets a Magento store maybe 60% of the way there. The rest trips people up because Magento keeps state outside the obvious places:

  • The crypt key. Magento encrypts payment tokens, some customer data, and API credentials using a key stored in app/etc/env.php. Copy the database without the matching env.php, and every encrypted value becomes unreadable garbage - saved cards stop working, some admin settings blank out.
  • Search indexes live outside MySQL. Since Magento 2.4, product search runs on Elasticsearch or OpenSearch, not MySQL full-text search. If the new server doesn't have a matching search engine configured, your storefront search returns nothing - the site looks broken even though the database imported cleanly.
  • Generated code and static assets aren't meant to be copied. The var/generation, var/cache, and pub/static folders are build output, not source. Copying them from an old PHP version or Magento build onto a new server is a common cause of white screens after migration - regenerate them instead.

Before You Start: The Checklist

  • Confirm the target VPS has a PHP version Magento actually supports for your version (Magento 2.4.6+ needs PHP 8.1-8.3) and the required extensions: bcmath, intl, soap, sodium, xsl.
  • Have Elasticsearch or OpenSearch installed and reachable on the new server, matching the version your Magento release requires.
  • Copy app/etc/env.php from the old server - don't regenerate it. The crypt key inside it must match the one used to encrypt existing data.
  • Note your last order ID, current stock counts for top SKUs, and active payment gateway credentials (Razorpay, PayU, Stripe, etc.) for a post-migration sanity check.
  • Composer access on the new server so you can reinstall dependencies cleanly instead of copying vendor/ wholesale.

Step 1: Freeze the Store

Put the old store into maintenance mode for the final sync window so nothing changes mid-transfer:

php bin/magento maintenance:enable

Note the last order ID and current stock levels for your top SKUs before you go further - this is your reconciliation checkpoint once the new server is live.

Step 2: Move Code the Right Way

Don't rsync the whole document root. Pull the source from version control (or the deployed archive) and skip build artifacts entirely:

rsync -avz --exclude 'var/' --exclude 'generated/' --exclude 'pub/static/' \
  --exclude 'vendor/' /path/to/old/site/ user@new-vps:/path/to/new/site/

Media - product images, uploaded files under pub/media - is real data, not build output, so sync that folder in full:

rsync -avz /path/to/old/site/pub/media/ user@new-vps:/path/to/new/site/pub/media/

Then, on the new server:

composer install --no-dev

Step 3: Migrate the Database

Magento's database is bigger and slower to move than a typical WordPress one, mostly because of the EAV (Entity-Attribute-Value) tables that store product data as thousands of narrow rows instead of a few wide ones. Dump with compression, and exclude log tables you don't need:

mysqldump -u dbuser -p --single-transaction \
  --ignore-table=magento.customer_log \
  --ignore-table=magento.report_event \
  magento | gzip > magento-db.sql.gz

On the new server, create the database and user first, then import:

gunzip < magento-db.sql.gz | mysql -u dbuser -p magento

For very large catalogs (50k+ products), this import can take well over an hour. Run it inside screen or tmux so a dropped SSH session doesn't kill it halfway through.

Step 4: Point the App at Its New Home

Copy the original app/etc/env.php into place (keep that crypt key), then update the base URLs to match the new environment - either directly in core_config_data via the CLI:

php bin/magento setup:store-config:set --base-url="https://yourdomain.com/"
php bin/magento setup:store-config:set --base-url-secure="https://yourdomain.com/"

Run the upgrade script to apply any schema/data patches, then set production mode:

php bin/magento setup:upgrade
php bin/magento deploy:mode:set production

Finally, re-register cron - Magento's own queue for order emails, indexers, and scheduled price rules depends on it, and it does not survive a file copy:

php bin/magento cron:install

Step 5: Rebuild Indexes and Cache Before You Cut Over

This is the step people skip, and it's the one that causes "the store works but search/stock/prices are wrong" reports the next morning. Indexes are derived data - they don't travel with a database dump the way you'd expect, and stale ones serve stale storefront data.

php bin/magento indexer:reindex
php bin/magento cache:flush

Check indexer status before you consider the migration done:

php bin/magento indexer:status

Every row should read Ready, not Reindex required. If Elasticsearch/OpenSearch isn't reachable yet, the catalog search indexer will fail silently here - fix that connection before moving on, not after customers start complaining that search returns nothing.

Step 6: DNS Cutover and the First 30 Minutes After

Lower your domain's DNS TTL to 300 seconds a day or two before the cutover so the switch propagates fast. Once the new server is verified working end-to-end, point the A record at the new VPS and take the old store out of maintenance mode only after DNS has fully moved - keeping both live briefly with the old server in maintenance mode prevents orders splitting between two databases.

For the first half hour after cutover, place a test order yourself with a real (small) payment, and confirm: the order appears in the admin panel, the confirmation email sends, stock decrements, and the payment gateway's dashboard shows the transaction matching the order ID in Magento.

Common Migration Failures

SymptomCauseFix
Checkout completes but no confirmation emailCron wasn't re-registered on the new serverRun php bin/magento cron:install and verify with crontab -l
Product images 404 on the frontendpub/media wasn't synced, or permissions are wrongRe-sync the media folder; chown -R www-data:www-data pub/media
"Invalid Form Key" on every form submitSession/cookie domain mismatch after the URL changeClear var/session and browser cookies; confirm base URLs match the live domain exactly
Storefront search returns nothingElasticsearch/OpenSearch not installed or unreachable on the new serverInstall the matching search engine version, set it in Stores > Configuration > Catalog Search, then reindex
Saved cards/API keys fail after loginenv.php was regenerated instead of copied, so the crypt key changedRestore the original env.php from the old server; a mismatched key can't be recovered after the fact

Prevention: Keep the Next Migration Boring

  • Keep a documented copy of env.php's crypt key in your password manager, separate from routine backups, so a future move never depends on finding the right old server.
  • Schedule a full mysqldump and media backup nightly via cron, not just relying on hosting-panel snapshots - a plain SQL dump is what actually restores cleanly onto a different server.
  • Pin your PHP, Elasticsearch/OpenSearch, and Magento versions in a short README in the repo, so the next migration starts from a known-good target instead of guesswork.
  • Test the full indexer and cron setup on a staging copy before every major migration - reindexing failures are much cheaper to catch there than on the live store.

Frequently asked questions

Can I just copy the vendor and generated folders from the old server instead of rebuilding them?

You can, but it's risky if the PHP version or Magento patch level differs even slightly between servers. Running composer install --no-dev and letting Magento regenerate var/generation and pub/static avoids mismatched compiled code that causes white screens after migration.

Do I need Elasticsearch or OpenSearch on the new VPS before I import the database?

Yes. Since Magento 2.4, catalog and storefront search depend on Elasticsearch or OpenSearch rather than MySQL. If it's not installed and configured under Stores > Configuration > Catalog Search before you reindex, search will silently return no results even though the rest of the store works.

Why did my saved customer data or API keys break after migration?

Almost always because app/etc/env.php was regenerated on the new server instead of copied from the old one. Magento encrypts sensitive fields with the crypt key stored in that file - a new key can't decrypt data that was encrypted with the old one, and there's no way to recover it after the fact.

How long should I keep the old server running after cutover?

At least a few days. Keep it in maintenance mode (not powered off) so you can pull the original env.php, media files, or a fresh database dump if you spot a discrepancy during reconciliation. Lowering DNS TTL to 300 seconds beforehand keeps the actual cutover window short.

My storefront loads but stock counts and prices look outdated - what's wrong?

Indexes are derived data that don't travel with a database dump. Run php bin/magento indexer:reindex followed by php bin/magento cache:flush, then confirm with php bin/magento indexer:status that every indexer shows Ready rather than Reindex required.

#magento #store-migration #ecommerce #reindexing #vps #elasticsearch

Keep reading

Chat with Support