On this page
Moving a busy WordPress network is not primarily a file-copying problem. It is a consistency problem: uploads, database writes, scheduled jobs, and DNS caches must agree about which server owns production.
This walkthrough builds a containerized destination, rehearses the move, and preserves a working source until validation passes. “Without downtime” is a design goal, not a guarantee: avoiding lost writes may require a brief publishing freeze or database replication engineered for your workload.
Inventory the network before moving anything
Start with URL coverage and write ownership. Record every mapped domain, subdirectory site, upload location, cron task, PHP extension, and external integration. Include payment callbacks and background imports; a homepage check cannot prove a network migration succeeded.
Use the Sitemap URL Extractor below to turn each public sitemap into a migration checklist. Extract child sitemaps separately when an index points to them. The tool helps identify representative pages and missing sections, but sitemaps do not include private dashboards, checkout endpoints, or every redirect.
Build a baseline manifest containing status codes, canonical URLs, and representative media links. Record current TLS coverage and DNS TTLs. Lower relevant TTLs ahead of the move, allowing the previous TTL to expire before cutover; changing a TTL during the migration does not invalidate existing caches.
Consult the WordPress documentation for network-specific behavior. Match the destination PHP version and required extensions before considering any upgrades. Migration and modernization are separate changes with separate rollback risks.
Build a destination with persistent state
Keep application files and database storage outside disposable container layers. Persist the complete WordPress directory initially, especially custom plugins, must-use plugins, and network upload layouts. Later, move toward immutable application images once the migration is stable.
This minimal Compose fragment illustrates persistence, not a complete public hosting stack. Put it behind a TLS reverse proxy, replace image tags with tested versions or digests, and provide a supported Docker Compose installation. The password files must already exist with restricted permissions.
services:
db:
image: mariadb:11.4
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD_FILE: /run/secrets/db_password
MARIADB_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
secrets:
- db_password
- db_root_password
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:php8.3-apache
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- ./wordpress:/var/www/html
ports:
- "127.0.0.1:8080:80"
volumes:
db_data:
secrets:
db_password:
file: ./secrets/db_password
db_root_password:
file: ./secrets/db_root_passwordTransfer the existing configuration deliberately rather than assuming environment variables will rewrite an imported wp-config.php. Preserve multisite constants, salts, table prefixes, and trusted proxy handling. Do not expose database ports publicly. See the Docker documentation for Compose secrets and persistent volumes.
Size storage for the working database, uploads, temporary import space, and backups. Check available inodes too: many small thumbnails can exhaust filesystem metadata before capacity runs out.
Rehearse with an isolated copy
Take an initial consistent database export and copy files while production stays live. For transactional InnoDB tables, a single-transaction export avoids holding a long global read lock; nontransactional tables require a different consistency plan. Freeze schema changes during the export.
The following commands assume WP-CLI runs as the site owner on each host. Replace the SSH destination with your actual host, and keep exports outside the public web root. The documentation-range address is illustrative.
# Source: run from the WordPress directory
wp db export /srv/migration/network.sql --single-transaction
rsync -a ./wp-content/ deploy@192.0.2.20:/srv/site/wordpress/wp-content/
scp /srv/migration/network.sql deploy@192.0.2.20:/srv/migration/network.sql
# Destination: run in the prepared WordPress environment
wp db import /srv/migration/network.sql
wp site list --fields=blog_id,urlConfirm file ownership inside the container, including the web server's numeric user ID. An apparently successful transfer can leave uploads unreadable or unwritable. Keep the staging environment inaccessible to crawlers and casual visitors using authentication or network restrictions, not robots.txt alone.
Test production hostnames using a local hosts override or curl resolution overrides rather than changing stored URLs. This avoids unnecessary serialized-data replacements and catches host routing problems. Stop staging cron execution and outbound email; do not allow copied jobs to charge customers or deliver notifications.
Validate routes, media, and background work
Choose representative requests across every site: an article, archive, search, login, upload, and privileged dashboard action. Exercise subdomain mappings and custom domains independently. Confirm that certificates cover the names browsers will actually request.
curl --resolve example.com:443:192.0.2.20 -sS -o /dev/null -w '%{http_code} %{time_total}
' https://example.com/
curl --resolve example.com:443:192.0.2.20 -I https://example.com/wp-content/uploads/example.jpgUse a real existing upload path when testing media. These checks require a valid certificate for the production hostname; do not suppress certificate validation to make a broken deployment appear healthy. Follow Let's Encrypt guidance when arranging certificate issuance before public routing changes.
Revisit the sitemap extraction tool to compare expected public routes against observed responses. Treat redirect correctness and canonical consistency as separate checks: a successful status code can still serve the wrong site.
Verify object-cache namespaces, database connectivity, scheduled events, SMTP delivery, and application error logs. Flush destination caches without purging evidence needed for debugging. Keep a written pass/fail checklist rather than relying on visual impressions from one browser session.
Cut over with one authoritative writer
A DNS change alone cannot prevent split-brain writes. Some clients will continue reaching the old address after others reach the new one. Choose an explicit ownership strategy and practice it during the rehearsal.
For a manageable network, briefly pause publishing and other writes, stop workers, export the final database, and synchronize changed uploads. Import and validate the destination before enabling its workers. Keep reads available from a known consistent snapshot if the application supports that operating mode.
For uninterrupted write availability, use tested replication and a controlled database promotion process instead. That requires version compatibility, replication lag monitoring, and a reliable way to stop old writers. It is not accomplished by running two independent WordPress databases behind different DNS answers.
Once the destination is authoritative, configure the old edge to proxy requests to it while caches expire, preserving host and HTTPS information safely. Disable old application workers. Monitor error rates and write success, not merely uptime. The hosting collection covers related operating tasks.
Rollback before accepting new writes is straightforward: return traffic to the preserved source. After new writes arrive, first reconcile or transfer those changes; reverting DNS blindly loses content and orders. Retain restricted backups and old storage until the observation period closes.
Key takeaways
- Use URL inventories and rehearsed checks to validate every site, not just the network homepage.
- Preserve persistent volumes and application configuration while keeping database access private.
- Test production hostnames, certificates, uploads, and scheduled work before public routing changes.
- Maintain one authoritative writer throughout cutover; DNS alone provides no consistency guarantee.
- Define rollback around actual write ownership, and keep the source recoverable until destination behavior is proven.
Reach designers & developers at work
Put your product next to the tools people use every day. One sponsor per placement, no tracking pixels.
Become a sponsor