WordPress migration process

For small websites

Use plugins like:

  • Duplicator
  • Updraft
  • WP Migrate

For large websites

First log in to the server console as the root user.

1. Copy files from source to destination

# Case A: files in different servers
rsync -avzhP --delete user@host:/path/to/source/ /path/to/destination/

# Case B: iles in same server
rsync -avzhP --delete /path/to/source/ /path/to/destination/

Note

Use --dry-run to test the transfer before actually doing it.

Use -e "ssh -p 27777" to change server SSH connection port.

The trailing slashes in the directories are important so that the contents of the source directory are copied inside the target directory and not the source directory itself!

2. Fix files permissions in destination

Fix ownership of all files and folders:

# Fix ownership of all files and folders
chown -R user:user /home/user/public_html/

Fix the ownership and rights of the root directory:

# Fix the ownership and rights of the root directory

# Case A (preferred, CGI Access not enabled)
chown user:user /home/user/public_html/
chmod 755 /home/user/public_html/

# Case B (CGI Access enabled)
chown user:nobody /home/user/public_html/
chmod 750 /home/user/public_html/

Note

Recommended file permissions:

Root directory, usually public_html:
/                    755 (755 under user:user or 750 under user:nobody)
/wp-admin:           755
/wp-includes:        755
/wp-content:         755
/wp-content/themes:  755
/wp-content/plugins: 755
/wp-content/uploads: 755
/.htaccess:          644
/index.php:          644
/wp-config.php:      640

3. Dump source database

For small databases use phpMyAdmin export function with the gzip compression enabled.

For larger databases:

## Case A with the mysql command line utility
mysqldump db_name >> db_name.sql

## Case B with the wpcli utility
# Go to the source directory first
wp db export db_name.sql

4. Create destination database (if necessary)

If the destination database does not exist,. ie this is a new installation:

  • create the database,
  • create a user with a password,
  • assign that user all the necessary privileges to the database

5. Edit the wp-config.php file

Edit the wp-config.php file to reflect the correct database name, database user and database user password. 

/**
 * MySQL database settings. 
 */

define('DB_NAME', 'db_name
define('DB_USER', 'db_user');
define('DB_PASSWORD', 'passwrd');
define('DB_HOST', '127.0.0.1');
define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');

$table_prefix = 'tblprfx_';

6. Import source database to destination database

For small databases use phpMyAdmin import.

For larger databases:

First drop all database tables in destination database from PHPMyAdmin.

Then:

## Case A, with the mysql utility

# Enter mysql mode
mysql

# Select the database to use
> use db_name; 

# Import the database 
> source /absolute/path/to/db_name.sql;

# Exit mysql
> exit;

## Case B with the wpcli utility

# Again usage of wpcli is just as good
# Go to the target directory first
wp db import db_name.sql

7. Rename destination urls

Only necessary when the url changes.

Use WPCLI for this:

# Become the correct user if not already
su user

# Do the url rename
wp search-replace https://old.url https://new.url --precise --all-tables

Note

Leaving out the trailing slashes in the urls helps search and replace more cases. 

8. Edit the .htaccess file

The WordPress .htaccess rewrite might need some tweaking in the RewriteBase and RewriteRule parts if the source was in a subdirectory and the destination isn't or vice versa.

For instance here is the WordPress core part:

# BEGIN WordPress
# The directives (lines) between "BEGIN WordPress" and "END WordPress" are
# dynamically generated, and should only be modified via WordPress filters.
# Any changes to the directives between these markers will be overwritten.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /subdirectory
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectory/index.php [L]
</IfModule>
# END WordPress

Also search for all instances of the /subdirectory in it to replace them accordingly.