Migrate an existing site
Goal: you have a working Drupal site hosted somewhere else. When you’re done, its code, database, and files are on a Cloud Platform environment, verified, and ready for DNS cutover.
A hosting move keeps code and data intact and works for a modern Drupal site (Drupal 10 or 11). If your site is on Drupal 7, WordPress, or another CMS, rebuild it as a modern Drupal site first (for migrations, see drupal.org/docs), then move the hosting. For subscription setup and DNS administration, see docs.acquia.com.
What you’ll have when you’re done
Section titled “What you’ll have when you’re done”- The site’s code in the application’s Git repository, deployed to an environment.
- The database and user-uploaded files imported and verified.
- A cutover plan with DNS timing handled.
Prerequisites
Section titled “Prerequisites”- A Cloud Platform application (your subscription’s welcome material or docs.acquia.com covers creating one)
- acli installed and authenticated, and an SSH key registered
- A local copy of the site: codebase, database dump or working local install, and the user-uploaded files directory
Jump to a task:
- Run the pre-flight checklist
- Import the code
- Import the database
- Import the files
- Verify on non-production
- Cut over
-
Run the pre-flight checklist
Section titled “Run the pre-flight checklist”Work through these before importing anything; each one is cheaper to fix now than after cutover.
-
Composer-managed layout with
docroot/as the web root. Cloud Platform expects the drupal-recommended-project shape: top-levelcomposer.jsonandvendor/, Drupal insidedocroot/, contributed code indocroot/modules/contrib, custom code indocroot/modules/custom. A site that isn’t Composer-managed yet should be converted first; Migrating a Drupal website into a Composer-managed build on docs.acquia.com is the step-by-step. Patched core or module files must become actual patch files applied via Composer, or the firstcomposer updateerases them. -
User-uploaded files must not live in the repository. The platform stores files on a network filesystem outside the docroot and symlinks
docroot/sites/*/filesto it. Move anyfiles/directories out of what you’ll commit; they travel separately below. -
Incompatible modules. Some modules conflict with the platform outright, most famously Boost (it fights Varnish) and anything that sets a session cookie for anonymous users (it silently disables Varnish; see cookie pitfalls). Check yours against Modules and applications incompatible with Cloud Platform. Also swap the Database Logging module for core Syslog, and drop dev tooling (Devel,
views_ui) from production. -
InnoDB everywhere. Confirm no tables still use MyISAM:
SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLESWHERE TABLE_SCHEMA = 'mydb' AND ENGINE <> 'InnoDB'; -
What won’t transfer: server-level customizations (custom Apache/Nginx config, cron entries in the OS crontab, PHP extensions outside the platform’s set, direct MySQL server settings). Each needs a platform-native replacement: scheduled jobs for crontabs, per-environment settings for PHP and MySQL-session tweaks,
.htaccessfor rewrite rules.
-
-
Import the code
Section titled “Import the code”Two settings adjustments in
docroot/sites/default/settings.phpfirst:- Add the platform’s database require line at the end of the file (
acli api:environments:database-php-config-find myapp.dev my_dbreturns an environment’s PHP database configuration). This is what makes onesettings.phpwork on every environment: the platform injects the right credentials per environment, so nothing is hardcoded. Details in per-environment settings. - Remove any old host-specific database credentials, base URLs, or file-path settings from the previous host.
Then build and deploy. Your application comes with a Git repository, but environments run built code, and a Composer-managed repository typically ignores
vendor/anddocroot/core, so pushing it there as-is would deploy a tree the environment cannot serve.push:artifactrunscomposer installand commits the built result (vendor directories and scaffold files included, even though your repository ignores them). It pushes that commit to the branch the dev environment has deployed, which deploys it:Terminal window cd my-sitegit add docroot/sites/default/settings.phpgit commit -m "Add Cloud Platform database settings"acli push:artifact myapp.devIf your repository does commit
vendor/anddocroot/core, plaingit pushdoes the same job:- Add the application’s repository as a remote (the URL is on the application’s overview page, or via
acli). - Push your branch.
- Point the environment at it with
acli api:environments:code-switch(the code-workflow quickstart walks that flow).
- Add the platform’s database require line at the end of the file (
-
Import the database
Section titled “Import the database”From your local site directory, dump and push in one step:
Terminal window acli push:database myapp.devpush:databasereads your local site’s database and imports it into the chosen environment’s database. It names the target before it writes, and the confirmation defaults to yes, so read the environment name in the question rather than pressing Enter:$ acli push:database myapp.devOverwrite the my_db database on dev with a copy of the database from the current machine? (yes/no) [yes]:> yes✔ Creating local database dump✔ Uploading database dump to remote machine✔ Importing database dump into MySQL on remote machineThe local connection comes from
ACLI_DB_HOST,ACLI_DB_NAME,ACLI_DB_USER, andACLI_DB_PASSWORD(see the acli reference); most local stacks set them for you. If you’d rather stay in drush,drush sql:syncbetween a configured source alias and the Acquia alias does the same job (aliases viaacli remote:aliases:download); either way, rebuild caches afterwards:Terminal window acli remote:drush myapp.dev -- cr[success] Cache rebuild complete. -
Import the files
Section titled “Import the files”Uploaded files go to the environment’s network filesystem, not into git. Either push them with acli:
Terminal window acli push:files myapp.devOverwrite the public files directory on dev with a copy of the files from the current machine? (yes/no) [yes]:> yes✔ Pushing public files directory to remote machineor rsync directly for more control over a large files directory, swapping
myapp.dev@[ssh-host]for the environment’s SSH URL, thessh_urlfield thatacli api:environments:find myapp.devprints (shaped like[email protected]):Terminal window rsync -avz ./files/ myapp.dev@[ssh-host]:/mnt/files/myapp.dev/sites/default/files/Both are incremental: a second run copies only what changed, and neither deletes files that exist only on the environment.
The platform maintains the
docroot/sites/default/filessymlink into the environment’s network filesystem automatically. The mount point behind that symlink varies by platform generation, which is why the rsync target above is the stable/mnt/files/[site].[env]/path rather than whatever the symlink resolves to. -
Verify on non-production
Section titled “Verify on non-production”On the Dev or Stage environment (
myapp.devormyapp.test), before any DNS change:- Site health:
acli remote:drush myapp.dev -- statusreports bootstrap, database, and Drupal version; then click through the site on its Acquia-provided domain. - Files arrived: spot-check media-heavy pages; a page with broken images means step 4 missed a directory.
- Errors: watch the PHP error log while browsing (tail logs); a migrated site’s first pageviews surface missing modules and bad paths immediately.
- Caching behaves: anonymous pages should show
X-Cache: HITon the second request; see fix stale content for the header-reading routine. This is also the moment to enable memcached and install Acquia Purge, per the platform’s own pre-launch checklist. - Background work: recreate the old host’s cron entries as scheduled jobs and confirm they log output.
Repeat the import against prod when dev checks out (push the same branch or promote code, then re-run steps 3 and 4 against
myapp.prodwith fresh data if content changed in the meantime). - Site health:
-
Cut over
Section titled “Cut over”DNS is administered wherever your domains live, and domain/SSL setup on the platform side is on docs.acquia.com (Managing domains, SSL). Two timing notes that save real pain:
- Lower your DNS TTL to 5–10 minutes a few days before cutover, so the switch propagates fast; restore it after.
- Cloud Platform autoscales, but scaling takes a moment to take effect, and rapid changes in traffic can outrun it. So if you expect a significant change in traffic around launch, notify Acquia Support in advance.
Keep the old host running until traffic has fully drained and the new site has survived a day of production load.
When something goes wrong
Section titled “When something goes wrong”Broken images after import
the files landed outside the symlinked path, or a multisite directory was missed; re-check the /mnt/files/[site].[env]/sites/[sitedir]/files target in step 4.
White screen or database errors on first load
the require line from step 2 is missing or not last in settings.php, or old host credentials are still being read.
Everything is slow compared to the old host
the site probably isn’t caching; work through fix stale content to see whether responses are cacheable at all.
Next steps
Section titled “Next steps”- Ship code to environments: the day-to-day deploy workflow now that the site lives here.
- Manage configuration: get the migrated site’s configuration into the repository, and importing on deploy.
- Run scheduled jobs and per-environment settings: replacing what the old host’s crontab and php.ini did.
- How caching works: the biggest behavioral difference from generic hosting.
Was this page helpful?
What went wrong?
Still stuck? Contact Acquia Support (opens in a new tab)