{"id":148,"date":"2026-06-06T09:01:00","date_gmt":"2026-06-06T09:01:00","guid":{"rendered":"https:\/\/blog.offshorekaka.in\/?p=148"},"modified":"2026-08-27T05:39:06","modified_gmt":"2026-08-27T05:39:06","slug":"how-to-migrate-wordpress-to-offshore-hosting","status":"publish","type":"post","link":"https:\/\/offshorekaka.in\/blog\/how-to-migrate-wordpress-to-offshore-hosting\/","title":{"rendered":"How to Migrate WordPress to Offshore Hosting Safely"},"content":{"rendered":"<div class=\"ok-pro-panel\">\n<p><span class=\"ok-pro-kicker\">Tutorial<\/span><\/p>\n<h2>Copy first, switch last<\/h2>\n<p>A WordPress migration is four things: the files, the database, the config, and the URLs inside the database. Get all four right on the new server before you change DNS, and the switch itself is a non-event.<\/p>\n<p>The step people forget is the fourth one. WordPress stores absolute URLs all over the database, including inside serialised PHP data, and a plain find and replace on the SQL file corrupts that data in ways that only show up later.<\/p>\n<div class=\"ok-pro-grid\">\n<div class=\"ok-pro-card\"><strong>Time<\/strong><span>An hour for a normal site.<\/span><\/div>\n<div class=\"ok-pro-card\"><strong>Order<\/strong><span>Copy, test by IP, then DNS.<\/span><\/div>\n<div class=\"ok-pro-card\"><strong>Never<\/strong><span>sed the SQL file to change URLs.<\/span><\/div>\n<\/div>\n<\/div>\n<div class=\"ok-toc\"><strong>On this page<\/strong><a href=\"#export\">Export from the old host<\/a><a href=\"#import\">Import on the new one<\/a><a href=\"#config\">wp-config.php<\/a><a href=\"#urls\">The URLs inside the database<\/a><a href=\"#testip\">Test before DNS<\/a><a href=\"#switch\">Switching over<\/a><a href=\"#faq\">FAQ<\/a><\/div>\n<h2 id=\"export\">Export from the old host<\/h2>\n<p>Two things come across: everything under the web root, and the database.<\/p>\n<pre><code>tar czf site-files.tgz -C \/var\/www\/yourdomain.com .\nmysqldump --single-transaction --quick -u dbuser -p dbname &gt; site.sql<\/code><\/pre>\n<figure class=\"wp-block-image size-large ok-inline-visual\"><img decoding=\"async\" src=\"https:\/\/offshorekaka.in\/blog\/wp-content\/uploads\/2026\/08\/ok-db-export-import.webp\" alt=\"Terminal exporting a MySQL database to a file and importing it on the new server\" loading=\"lazy\" width=\"2296\" height=\"396\"><figcaption>Check the size after the export. A dump of a few kilobytes means it failed and printed the error somewhere you did not look.<\/figcaption><\/figure>\n<p>If you only have cPanel and no SSH, use the File Manager to compress the folder and phpMyAdmin to export the database. Same result, more clicking.<\/p>\n<p>Skip the cache directory while you are at it. It can be gigabytes, it regenerates on its own, and stale cache files on the new server cause confusing behaviour:<\/p>\n<pre><code>tar czf site-files.tgz --exclude='*\/cache\/*' -C \/var\/www\/yourdomain.com .<\/code><\/pre>\n<h2 id=\"import\">Import on the new one<\/h2>\n<p>Create the database and user first, then import:<\/p>\n<pre><code>mysql -u root -p -e \"CREATE DATABASE newdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;\"\nmysql -u newuser -p newdb &lt; site.sql<\/code><\/pre>\n<p>Extract the files, then set ownership. This is the step that causes the FTP credential prompt people spend an hour on:<\/p>\n<pre><code>tar xzf site-files.tgz -C \/var\/www\/yourdomain.com\nchown -R www-data:www-data \/var\/www\/yourdomain.com<\/code><\/pre>\n<p>Use <code>nginx<\/code> or <code>apache<\/code> as the owner on the RHEL family.<\/p>\n<h2 id=\"config\">wp-config.php<\/h2>\n<p>Update the four database lines to match what you just created:<\/p>\n<pre><code>define( 'DB_NAME', 'newdb' );\ndefine( 'DB_USER', 'newuser' );\ndefine( 'DB_PASSWORD', 'the-new-password' );\ndefine( 'DB_HOST', 'localhost' );<\/code><\/pre>\n<p>While you are in there, check the table prefix line matches the prefix in the dump. A site that was installed with a custom prefix and a <code>wp-config.php<\/code> that says <code>wp_<\/code> gives you a working database connection and an installation screen, which is a very confusing combination.<\/p>\n<h2 id=\"urls\">The URLs inside the database<\/h2>\n<p>If the domain is not changing, skip this section entirely. If it is changing, this is the part that matters.<\/p>\n<p>Use WP-CLI, and run it with <code>--dry-run<\/code> first:<\/p>\n<pre><code>wp search-replace 'https:\/\/old-domain.com' 'https:\/\/yourdomain.com' --dry-run<\/code><\/pre>\n<figure class=\"wp-block-image size-large ok-inline-visual\"><img decoding=\"async\" src=\"https:\/\/offshorekaka.in\/blog\/wp-content\/uploads\/2026\/08\/ok-staging-search-replace.webp\" alt=\"WP-CLI search-replace dry run showing a table of how many replacements would be made per table\" loading=\"lazy\" width=\"2296\" height=\"664\"><figcaption>A dry run shows you the tables and counts before anything is written.<\/figcaption><\/figure>\n<p>WP-CLI unserialises PHP data, changes the string, and reserialises it correctly. A plain <code>sed<\/code> on the SQL file changes the string but leaves the recorded string length wrong, so the data no longer unserialises. That breaks widgets, theme options and page builder layouts, usually a week later when you have forgotten what you changed.<\/p>\n<p>Run it for real once the dry run looks right, and do both the http and https variants of the old domain if the old site was ever served over plain HTTP.<\/p>\n<h2 id=\"testip\">Test before DNS<\/h2>\n<p>Do not change DNS to find out whether the migration worked. Point your own machine at the new server by adding a line to your hosts file:<\/p>\n<pre><code>203.0.113.10  yourdomain.com www.yourdomain.com<\/code><\/pre>\n<p>That is <code>\/etc\/hosts<\/code> on Linux and macOS, or <code>C:WindowsSystem32driversetchosts<\/code> on Windows. Now your browser sees the new server while everyone else still sees the old one.<\/p>\n<p>Walk the site properly. Homepage, a post, a category page, the search results, a contact form, and the dashboard. Log in and check that widgets and theme settings survived. Remove the hosts line when you are done.<\/p>\n<h2 id=\"switch\">Switching over<\/h2>\n<ol>\n<li>Lower the TTL a day ahead. See our <a href=\"https:\/\/offshorekaka.in\/blog\/dns-propagation-after-hosting-migration\/\">DNS propagation guide<\/a>.<\/li>\n<li>Do a final database export from the old site, so posts and orders from the last few hours come across.<\/li>\n<li>Change the A record. Our <a href=\"https:\/\/offshorekaka.in\/blog\/how-to-point-domain-to-offshore-hosting\/\">domain pointing guide<\/a> covers the detail.<\/li>\n<li>Issue the certificate on the new server once DNS resolves there.<\/li>\n<li>Leave the old server running for 48 hours.<\/li>\n<\/ol>\n<p>If the site takes orders or comments, put the old copy into read-only mode as soon as DNS changes, so nothing gets written to a database you are about to throw away.<\/p>\n<h2 id=\"test\">How to test<\/h2>\n<ol>\n<li>Homepage, a post, a category and a search result all load.<\/li>\n<li>Images load, which proves uploads came across and permissions are right.<\/li>\n<li>Log in to the dashboard.<\/li>\n<li>Submit a contact form.<\/li>\n<li>Check permalinks work on an inner page.<\/li>\n<li>Check robots.txt does not disallow everything.<\/li>\n<li>Confirm the certificate is valid.<\/li>\n<\/ol>\n<h2 id=\"trouble\">When something breaks<\/h2>\n<table>\n<thead>\n<tr>\n<th>What you see<\/th>\n<th>Why<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Error establishing a database connection<\/td>\n<td>Wrong credentials in wp-config.php<\/td>\n<td>Recheck all four lines and the table prefix<\/td>\n<\/tr>\n<tr>\n<td>Installation screen instead of your site<\/td>\n<td>Table prefix does not match the dump<\/td>\n<td>Set the correct prefix in wp-config.php<\/td>\n<\/tr>\n<tr>\n<td>Homepage loads, everything else 404<\/td>\n<td>Rewrite rules missing on the new web server<\/td>\n<td>Add <code>try_files<\/code> on nginx, or the rewrite rules on OpenLiteSpeed<\/td>\n<\/tr>\n<tr>\n<td>Asks for FTP credentials on plugin install<\/td>\n<td>Files not owned by the web server user<\/td>\n<td><code>chown -R<\/code> to the right user<\/td>\n<\/tr>\n<tr>\n<td>Widgets and theme settings lost<\/td>\n<td>URLs replaced with sed instead of WP-CLI<\/td>\n<td>Restore the database and redo with search-replace<\/td>\n<\/tr>\n<tr>\n<td>Images missing<\/td>\n<td>Uploads excluded, or wrong permissions<\/td>\n<td>List the archive to confirm, then fix ownership<\/td>\n<\/tr>\n<tr>\n<td>Mixed content warnings<\/td>\n<td>Old http URLs still in the database<\/td>\n<td>Run search-replace for http to https as well<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"checklist\">Checklist<\/h2>\n<ul>\n<li>Files and database both exported, and the sizes look sane.<\/li>\n<li>Database created as utf8mb4 and imported without errors.<\/li>\n<li>Ownership set to the web server user.<\/li>\n<li>wp-config.php credentials and table prefix correct.<\/li>\n<li>URLs changed with WP-CLI search-replace, never with sed.<\/li>\n<li>Whole site tested via a hosts file entry before DNS.<\/li>\n<li>Final database sync taken just before the switch.<\/li>\n<li>Certificate issued and old server left running for 48 hours.<\/li>\n<\/ul>\n<div class=\"ok-cta-box\">\n<p><strong>Want us to move it for you?<\/strong><\/p>\n<p>OffshoreKaka does free migrations onto our hosting, including the database URL work, and gives you a temporary hostname to check everything before DNS changes.<\/p>\n<p><a class=\"btn ok-cta-link\" href=\"https:\/\/offshorekaka.in\/offshore-web-hosting\/\">See the hosting plans<\/a><\/p>\n<\/div>\n<h2 id=\"faq\">FAQ<\/h2>\n<h3>Can a plugin do this instead?<\/h3>\n<p>Yes, and for a small site a plugin like Duplicator or All-in-One WP Migration is genuinely easier. They struggle on large sites, because the export has to be built and downloaded through PHP and it hits time and memory limits. Over about a gigabyte, do it manually.<\/p>\n<h3>Will migrating hurt my SEO?<\/h3>\n<p>Not if the URLs stay the same and there is no downtime. Google recrawls and finds the same content in the same places. The things that do damage are a robots.txt that came from a staging copy, URLs changing without redirects, and the site being unreachable during the switch.<\/p>\n<h3>Do I need to reissue the SSL certificate?<\/h3>\n<p>Yes. Certificates live on the server, not with the domain. The new server needs its own, and it usually cannot be issued until DNS points there. Our <a href=\"https:\/\/offshorekaka.in\/blog\/install-ssl-certificate-offshore-hosting\/\">SSL guide<\/a> covers the sequencing.<\/p>\n<h3>What about the email accounts?<\/h3>\n<p>Mailboxes do not come across in a website migration. If mail was on the old host, either move it separately or point MX at a dedicated mail provider. Our <a href=\"https:\/\/offshorekaka.in\/blog\/setup-business-email-on-offshore-hosting\/\">business email guide<\/a> covers the records.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You will learn a safe WordPress migration flow: backup, copy files, move database, test and then change DNS.<\/p>\n","protected":false},"author":1,"featured_media":1026,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-148","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"_links":{"self":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/148","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/comments?post=148"}],"version-history":[{"count":5,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/148\/revisions"}],"predecessor-version":[{"id":959,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/posts\/148\/revisions\/959"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/media\/1026"}],"wp:attachment":[{"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/media?parent=148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/categories?post=148"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/offshorekaka.in\/blog\/wp-json\/wp\/v2\/tags?post=148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}