Skip to content

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.

  • 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.

Jump to a task:

  1. 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-level composer.json and vendor/, Drupal inside docroot/, contributed code in docroot/modules/contrib, custom code in docroot/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 first composer update erases 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/*/files to it. Move any files/ 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.TABLES
      WHERE 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, .htaccess for rewrite rules.

  2. Two settings adjustments in docroot/sites/default/settings.php first:

    1. Add the platform’s database require line at the end of the file (acli api:environments:database-php-config-find myapp.dev my_db returns an environment’s PHP database configuration). This is what makes one settings.php work on every environment: the platform injects the right credentials per environment, so nothing is hardcoded. Details in per-environment settings.
    2. 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/ and docroot/core, so pushing it there as-is would deploy a tree the environment cannot serve.

    push:artifact runs composer install and 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-site
    git add docroot/sites/default/settings.php
    git commit -m "Add Cloud Platform database settings"
    acli push:artifact myapp.dev

    If your repository does commit vendor/ and docroot/core, plain git push does 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).
  3. From your local site directory, dump and push in one step:

    Terminal window
    acli push:database myapp.dev

    push:database reads 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.dev
    Overwrite 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 machine

    The local connection comes from ACLI_DB_HOST, ACLI_DB_NAME, ACLI_DB_USER, and ACLI_DB_PASSWORD (see the acli reference); most local stacks set them for you. If you’d rather stay in drush, drush sql:sync between a configured source alias and the Acquia alias does the same job (aliases via acli remote:aliases:download); either way, rebuild caches afterwards:

    Terminal window
    acli remote:drush myapp.dev -- cr
    [success] Cache rebuild complete.
  4. Uploaded files go to the environment’s network filesystem, not into git. Either push them with acli:

    Terminal window
    acli push:files myapp.dev
    Overwrite 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 machine

    or rsync directly for more control over a large files directory, swapping myapp.dev@[ssh-host] for the environment’s SSH URL, the ssh_url field that acli api:environments:find myapp.dev prints (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/files symlink 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.

  5. On the Dev or Stage environment (myapp.dev or myapp.test), before any DNS change:

    • Site health: acli remote:drush myapp.dev -- status reports 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: HIT on 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.prod with fresh data if content changed in the meantime).

  6. 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.

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.

Was this page helpful?