WordPress Migration Checklist for Zero-Downtime Cutovers

Start with the cutover plan, not the copy job
The safest WordPress migration checklist treats DNS, cache, logins, and checkout as one move. If you copy the files first and deal with the rest later, you usually end up with mixed content, stale pages, or a short but visible outage.
For sites that need a cleaner move, a Hostperl VPS gives you enough control to stage, test, and cut over without guessing. This guide assumes you are moving a live WordPress site to a fresh server and want a low-risk sequence.
ssh root@203.0.113.10Run that from your local computer. The address 203.0.113.10 is a documentation example and must be replaced with your server’s real public IP. If your hosting provider gave you a default non-root login, use that account with the same IP instead.
Once you are in, confirm the operating system before you install packages or edit services.
cat /etc/os-releaseThat command runs on the VPS as root. You will use the result to follow the correct package and firewall path for Ubuntu, Debian, AlmaLinux, or Rocky Linux.
Prepare the new VPS for the migration
Do the setup work before you touch the site files. You want a stable admin session, current packages, a working firewall, and time sync. That prevents the most common post-migration surprises.
On Ubuntu and Debian, update the server and install the tools you will use for the migration. Run these commands on the VPS as root:
apt update
apt -y upgrade
apt -y install rsync unzip curl mariadb-client php-cli php-mysql
apt -y install ufw chronyOn AlmaLinux and Rocky Linux, run the equivalent commands on the VPS as root:
dnf -y update
dnf -y install rsync unzip curl mariadb php-cli php-mysqlnd
'dnf -y install firewalld chrony'After installation, confirm the tools are present:
rsync --version
php -v
mysql --version
systemctl status chronyd --no-pagerIf you are moving a store or a busy content site, also review package update handling on VPS servers so your maintenance window does not collide with a broken dependency chain.
Create a non-root admin and keep root open
Do not migrate a live site while logged in as root only. Create a sudo user, test it, and keep the original root shell open until the new login works. That way, if SSH permissions go wrong, you still have a recovery path.
On Ubuntu and Debian, run this on the VPS as root:
adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.sshOn AlmaLinux and Rocky Linux, use the wheel group instead:
useradd -m deploy
passwd deploy
usermod -aG wheel deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.sshCopy your public key into place, then lock down ownership and permissions. Replace the sample key path with the key file from your local machine:
cat ~/.ssh/id_ed25519.pub | ssh root@203.0.113.10 'cat >> /home/deploy/.ssh/authorized_keys'
ssh root@203.0.113.10 'chown -R deploy:deploy /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys'Open a second terminal on your local computer and test the new login before you continue:
ssh deploy@203.0.113.10
sudo -v
pwdIf that works, keep both sessions open. You can now use the deploy account for the rest of the migration and leave root as a fallback until the site is stable.
Set up the web stack for the incoming site
Most WordPress moves land on Nginx or Apache with PHP-FPM. Nginx usually fits a lean VPS well, while Apache still makes sense for some plugin-heavy or legacy setups. If you want the tradeoff explained in operational terms, see Nginx vs Apache for VPS hosting in 2026.
On Ubuntu and Debian, install Nginx, PHP-FPM, and MariaDB client tools as needed:
apt -y install nginx php-fpm php-mysql mariadb-clientOn AlmaLinux and Rocky Linux, use:
dnf -y install nginx php-fpm php-mysqlnd mariadbEnable the services and confirm they start at boot:
systemctl enable --now nginx
systemctl enable --now php-fpmCheck the status from the VPS as the non-root sudo user:
systemctl status nginx --no-pager
systemctl status php-fpm --no-pagerMove the WordPress files and database
If you need to freeze content, put a temporary maintenance banner on the old site first. Then take a final database dump and file copy. By the time you switch DNS, the migration should be quiet.
On the old server, create a compressed database dump. Replace the database name and credentials with your own values:
mysqldump -u wpuser -p --single-transaction --routines --triggers wordpressdb | gzip > wordpressdb.sql.gzCopy the archive and the WordPress files to the new host from your local computer or from the source server if you prefer a direct server-to-server move:
rsync -aH --delete /var/www/example.com/ deploy@203.0.113.10:/opt/myapp/Restore the database on the new VPS as root or with sudo access:
gunzip < wordpressdb.sql.gz | mysql -u root -p wordpressdbCreate the target database and user first if needed. On the new VPS, use:
mysql -u root -p
CREATE DATABASE wordpressdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'strong-password-here';
GRANT ALL PRIVILEGES ON wordpressdb.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;Then update wp-config.php with the new database name, user, and password. Use the editor you know best, but keep the file permissions strict afterward.
cd /opt/myapp
nano wp-config.php
chmod 640 wp-config.phpFor many sites, the hardest part is not the transfer itself. It is the cleanup afterward: URLs, image paths, and stale caches. If you need a safe live-site search and replace process, Hostperl’s live-site search and replace guide is the right companion to this checklist.
Configure firewall rules before you expose the site
Open only the ports you need, then test the web server locally before you publish it. That sequence avoids accidental lockouts and lowers the chance of exposing unfinished configuration.
On Ubuntu and Debian with UFW, run this on the VPS as root:
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
ufw status verboseOn AlmaLinux and Rocky Linux with firewalld, run:
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
firewall-cmd --list-allIf SELinux is enforcing on AlmaLinux or Rocky Linux, leave it that way unless you have a specific reason to change it. For web content in a custom path such as /opt/myapp, label the directory so Nginx or Apache can read it:
dnf -y install policycoreutils-python-utils
semanage fcontext -a -t httpd_sys_content_t '/opt/myapp(/.*)?'
restorecon -Rv /opt/myappTest WordPress before you switch DNS
Use the local hosts file on your laptop to point example.com to the new server IP for a dry run. That lets you test the site without changing public DNS yet.
On your local computer, add a temporary hosts entry:
sudo sh -c 'echo "203.0.113.10 example.com www.example.com" >> /etc/hosts'Replace 203.0.113.10 with the new VPS IP once you use this in practice. Then visit the site in a browser and check:
- Home page loads without mixed-content warnings
- WordPress admin login works
- Media uploads open correctly
- Checkout, forms, and password reset emails still function
From the VPS as the non-root sudo user, check the web server and PHP logs if anything looks off:
sudo journalctl -u nginx -n 50 --no-pager
sudo journalctl -u php-fpm -n 50 --no-pager
tail -n 50 /var/log/nginx/error.logIf you run WooCommerce, test a cart add, checkout page, and order confirmation page. That is the real functional smoke test, not just a homepage curl.
Enable HTTPS and finish the cutover
Install a certificate only after the site responds correctly on the new server. For Let's Encrypt, use Certbot with the web server you actually chose.
On Ubuntu and Debian, for Nginx:
apt -y install certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.comOn AlmaLinux and Rocky Linux, for Nginx:
dnf -y install certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.comCertbot should redirect HTTP to HTTPS and store renewal files under /etc/letsencrypt/. Confirm the timer or cron job exists:
systemctl list-timers | grep certbot || true
certbot renew --dry-runNow update DNS at your registrar or DNS host. Lower the TTL ahead of the move if you can, then switch the A and AAAA records to the new VPS. If your move includes nameserver changes, do that after the site is stable, not during the content transfer.
If DNS is part of a wider domain refresh or migration, Hostperl’s IP and DNS resources are useful for planning record changes and avoiding stale propagation assumptions.
Post-cutover checks you should not skip
The migration is not finished when the homepage loads. Run through these checks from both the server and a client machine:
On the VPS:
systemctl status nginx php-fpm --no-pager
ss -tulpn | grep -E ':80|:443'
mysqladmin -u root -p ping
php -vOn your local computer:
curl -I https://example.com
curl -s https://example.com | head
Then verify the site survives a reboot:
rebootAfter the VPS comes back, reconnect and confirm the services still start automatically. If you use a cache plugin, clear it after the reboot so you are not testing stale content.
Troubleshooting the most common migration failures
1) White screen or PHP fatal error
Diagnostic command:
tail -n 100 /var/log/nginx/error.log
journalctl -u php-fpm -n 100 --no-pagerExpected clue: missing extension, wrong PHP version, or permission denied. Fix by installing the required PHP package or correcting ownership on the WordPress directory.
2) Database connection error
Diagnostic command:
mysql -u wpuser -p -h localhost wordpressdbExpected clue: access denied or unknown database. Correct the credentials in wp-config.php and confirm the database exists.
3) HTTPS works but some images show HTTP
Diagnostic command:
grep -R "http://example.com" -n /opt/myapp | headExpected clue: old absolute URLs in content or theme settings. Run a safe search-and-replace, then clear all caches.
4) Mail notifications stop after the move
Diagnostic command:
php -i | grep -i sendmail
sudo tail -n 50 /var/log/maillog 2>/dev/null || sudo tail -n 50 /var/log/mail.logExpected clue: the site used local mail on the old host. Reconfigure SMTP for transactional mail before you announce the migration complete.
Use Hostperl for the next site move
A careful WordPress migration checklist saves time for agencies, store owners, and anyone who cannot afford a messy cutover. If you want a VPS that gives you room for staging, rollback, and proper verification, Hostperl VPS is a practical fit for this kind of work.
For customers managing more than one site, Hostperl’s support-led approach works well with launch windows, migrations, and post-cutover checks. If you are moving a larger account or planning repeat migrations, see the broader cPanel account migration guide for a related workflow.
If you are planning a WordPress move on a live site, Hostperl can help you choose the right VPS size, handle the cutover carefully, and keep rollback options open.
Start with Hostperl VPS if you want full control, or pair it with Hostperl shared hosting for smaller WordPress builds and simpler account management.
FAQ
How long should a WordPress migration stay in testing?
Long enough to verify login, checkout, forms, media, and HTTPS from an external client. For stores, keep testing open until you have at least one successful order flow.
Should I change DNS before or after the file copy?
After. Copy files, restore the database, test the site on the new server, then switch DNS.
Do I need to keep the old server online?
Yes, until you are confident the new server is stable and DNS has finished propagating. Keep backups and the old environment available for rollback.
What is the safest way to test without public DNS changes?
Use a temporary hosts file entry on your local computer so you can browse the new server privately.
