Move over Java...


PHP is the new market leader:

Source: Jelastic

Lessons learned from an Acquia migration


Acquia is a popular Drupal hosting service, but I was surprised at how many "gotchas" I encountered when migrating a number of sites to their environment.  I've listed them below (in no particular order) in case others find it useful.  Note: some of these are general Drupal issues rather than Acquia specific.

If you run into a cache issue (i.e. data is correct in the appropriate database table but doesn't show correctly in the UI and clearing caches via the Drupal admin UI doesn't work) you may need to clear memcache

If you're using drush sql-query in your post-db-copy Acquia Cloud Hook, you need to include the --database parameter for a multisite:



drush @$site.$target_env sql-query "select * from node;" --database=$db_name

Make sure to disable modules before deleting them (especially Boost, since Acquia Purge will complain).  If, for whatever reason, that option isn't available, you can manually remove the database entry: delete from system where name = 'boost';

The default Developer role doesn't work with Acquia Dev Desktop 2.  You need to provide at least Senior Developer access.

It's not obvious how to change the Acquia Cloud list label:
  1. Login to Acquia Cloud
  2. Go to the Subscriptions tab
  3. Select the Subscription you would like to edit
  4. Click Edit
  5. Change the name

BlazeMeter is restricted to 40 tests and a 30-day trial.  Unlike other add-ons (which are not trials and don't have expiration dates), the BlazeMeter limited trial begins when you activate the add-on so be careful to activate it only when you are about to go live and need to run the required load test.  Also, if you have more than 40 sites, you can combine sites in a single test by including multiple site URLs.

When using Acquia Dev Desktop 2, previous installations of an older version of Drush may cause problems.  On Windows, check your PATH environment variable and on OS X check your ~/.bash_profile file for non-DevDesktop references to Drush and remove them.


Acquia Search issues: 1, 2, 3

In Acquia Dev Desktop 2, the common git error "Cannot push missing reference (4:-11)" is vague and unhelpful.  It basically means you need to do a git pull before a git push.

Stage File Proxy does not support subfolders within your Drupal user files directory. Any images or other files within subfolders will not be displayed correctly in the RA environment.  Update: This is possibly fixed in latest dev

New Relic is incompatible with PHP 5.6.  Use PHP 5.5 instead.

Multisites require additional New Relic configuration.  The sample settings.php Acquia snippet didn't work for me so I ended up using:

if (extension_loaded('newrelic')) {
  $exploded_path = explode('/', dirname(__FILE__));
  $site_domain = array_pop($exploded_path);
  newrelic_set_appname($_ENV['AH_SITE_ENVIRONMENT'] .'_'. $site_domain, '', 'true');

Note: "Custom app names defining individual sites are initialized later in the Drupal bootstrap process, so New Relic can not report on Drupal modules, views, and hooks on a per-domain basis when this method is used. This data is only available for the environment as a whole"

Make sure to use the Acquia Dev Desktop 2 version 27 July 2015 or later to fix a Drush/OpenSSL bug.

If using the Acquia Drupal distribution profile, the status report may indicate there's a Drupal core update available when in fact you are running the latest core.  This is a known issue and "As a result, we often recommend moving away from the profile."

You may encounter periodic fatal errors (white screens) as a result of updating modules like CTools or Rules (for example, Fatal error: Class 'RulesAbstractPlugin' not found in /.../docroot/sites/all/modules/contrib/rules/includes/ on line 11).  You need to download and run registry_rebuild to fix it.

Acquia cron commands are limited to 255 chars.  If you have a longer command, put it in a shell script and reference that instead.

Cloud hook scripts created on Windows machines don't have their executable bit set.  Here's the fix.

Cloud hook will revert all features on code deploy.  To keep an override (such as disable CSS/JS aggregation), use the "Lock" mechanism as described in the "Living with Overrides" section here.

Always include a version (e.g. "version = 7.x-1.0") with your Feature (otherwise the module_filter display is messed up).

The Acquia documentation for incompatible modules is incomplete.  Use this version instead.

Acquia Dev Desktop 2 uses a .gitignore default that prevents settings.php from being sent.  Create a sites/.gitignore file and add this line: !*/settings*.php

If you add a new site to an existing multisite Acquia Dev Desktop 2, you need to do an immediate code pull from dev after pushing to dev the very first time so your local settings.php file will be updated with the Acquia dev database credentials.

If memcache does not appear to be running or working, run /update.php

In Acquia purge, "the standard domain detection often can detect too many domains and may cause cross-site purging".  You need to identify the Acquia purge domains because otherwise it purges pages for all domains in a docroot!  Add this to your settings.php file:

if (isset($_SERVER['HTTP_HOST']) && (!empty($_SERVER['HTTP_HOST']))) {
  $conf['acquia_purge_domains'] = array($_SERVER['HTTP_HOST']);

The self-signed cert in Acquia Dev Desktop 2 still throws a Chrome intercept warning so it's probably easiest just to disable HTTPS when working locally.

It's not currently possible for a single environment to have multiple elastic load balancers (ELBs) so you'll need to unify all your multisite sites into a single cert: 1, 2

Features sometimes adds a "project = " line in the info file which causes the Drupal update check to look for it on  Remove that line if it exists.

img style is stripped when using the "Limit allowed HTML tags" in /admin/config/content/formats/filtered_html  See 1, 2, 3


From Acquia tech support: "You cannot (or rather should not) point an A record (e.g. a bare domain like at an ELB's IPs because they are ephemeral. The bare domain has to point with an A record to the IP of the active balancer."

The core overlay module affects performance and can be a security risk.  Disable it.

rsync has a ~260 char filename limit (including path!) on Windows which can break Acquia Dev Desktop 2: 1, 2

Acquia Dev Desktop 2 local shortcuts and symbolic links should be excluded from git.  Create/edit a sites/.gitignore file and add these lines:


Private files require additional configuration.

You can use the @sites alias, but it needs to come after the Acquia docroot alias.  For example:  drush @sites cc all

Ad-blocking add-ons can affect page loading so check incognito mode before filing a help ticket.

The server time was 7 hours off of our local time so when we created a cron job to run at 10pm we were surprised to discover it was actually running at 3pm local time (during peak site traffic).  So, remember to run date on the server to check the time and adjust your cron jobs accordingly.

If you need SSL/TLS for your apex domain (aka "bare" or "naked" domain), such as, you'll need to purchase a managed DNS service that supports ALIAS or ANAME records.  Acquia has a great (albeit buried) guide for Amazon's Route 53 service.

If you use SSL/TLS for your site and you use the acquia_purge module, you need to add a rather buried setting to your settings.php file.

If you use webform and a private file system path is configured, you need to add an additional settings.php setting to avoid zero-byte webform result downloads

If you use the Remote Administration (RA) service and Acquia Cloud Hooks you'll likely run into conflicts.  Disable your hooks in the RA environment with:

if [ "$AH_SITE_ENVIRONMENT" != "ra" ]; then
# your code here...

VAAMP - quickstart


This is a quickstart guide for getting up and running with VAAMP (VirtualBox, Alpine Linux, Apache, MySQL, and PHP).  For more details, see the full tutorial.

One-time Setup

1. Download and install VirtualBox

2. Download and extract the VAAMP zip file

3. Open VirtualBox and choose File > Import appliance... and browse to the AlpineLinux.ovf file from Step 2

4. Once the import completes, click the VirtualBox Start button

5. Edit your hosts file and add the following to the bottom: adminer.local.dd logs.local.dd

6. Browse to http://adminer.local.dd/ and verify the Adminer MySQL application displays.

7. Browse to http://logs.local.dd/ and verify the Pimp my Log application displays.

8. Create a file called vaampkey.txt and copy the contents of into it.

9. Install an sshfs client:

OS X: Install osxfuse and sshfs by following this guide
Windows: Download and install (note: the installer may warn you about missing components but they will be automatically downloaded and installed as part of the sshfs installation process).  Also, the install may require a computer restart. 
Red Hat: sudo yum install fuse-sshfs 
Ubuntu: sudo apt-get install sshfs

10. Open sshfs and click the + Add button

11. Now, enter the following information:
  • Drive Name = vaamp
  • Host =
  • Port = 22
  • Username = www
  • Authentication method = PrivateKey
  • PrivateKey = YOUR/PATH/TO/vaampkey.txt
  • Directory = /usr/local/sites
  • Drive Letter = V
12. Then click Save and then Mount (note: you MUST click Save first due to bug #85)

Add a new site

In this example, I'll install a Wordpress site.

A.  Edit your hosts file and add the following to the bottom: mywordpress.local.dd

B. Open your V: drive and extract the latest Wordpress version into it.

C. Rename the wordpress folder to mywordpress.local.dd

D. Browse to http://adminer.local.dd/ and create a new database and user.

E. Browse to http://mywordpress.local.dd/ and follow the setup wizard

VAAMP - part 3


In this three-part series, I'll walk you through setting up a cross-platform LAMP server for local development.  I'll be using VirtualBox, Alpine Linux, Apache, MySQL, and PHP so I've nicknamed it VAAMP.


VirtualHost, shared folder, and DNS setup



If you don't want to manually perform all the steps below, you can just download the VirtualBox appliance here.


At this point we have a basic LAMP server running in VirtualBox.  Unfortunately, it's not especially useful for local development.  Creating and editing files via a command line interface is clunky and we're currently limited to running only a single local website.  Let's fix all that!

1.  Make sure to follow Part 1 and Part 2 of this guide and login as root

2.  Install a few needed packages by running this command:

apk add git sudo mysql-client php-phar php-openssl

3.  Next, install the Composer PHP dependency manager by running these commands:

curl -sS | php

mv composer.phar /usr/local/bin/composer

4.  Now we need to configure Apache to support multiple websites via VirtualHosts.  We could create separate config entries for each website but that gets rather tiresome so a more elegant solution is to use a single wildcard VirtualHost to support unlimited websites.  Also, we'll want to tweak the Apache configuration to support .htaccess files and run under a non-root account.

mkdir /usr/local/sites

adduser -D www www && echo "www:web-master" | chpasswd

sed -i '/^ProxyPassMatch\W/d' /etc/apache2/httpd.conf
sed -i '/^DirectoryIndex\W/d' /etc/apache2/httpd.conf
sed -i 's/AllowOverride\sNone/AllowOverride All/Ig' /etc/apache2/httpd.conf
sed -i 's/^User\sapache/User www/' /etc/apache2/httpd.conf
sed -i 's/^Group\sapache/Group www/' /etc/apache2/httpd.conf
sed -i 's/^user\s=\snobody/user = www/' /etc/php/php-fpm.conf
sed -i 's/^group\s=\snobody/group = www/' /etc/php/php-fpm.conf

cat <<EOT>> /etc/apache2/httpd.conf
  ServerName local.dd
  ServerAlias *.local.dd
  UseCanonicalName Off
  VirtualDocumentRoot "/usr/local/sites/%0"
  RewriteEngine On
  RewriteRule ^/(.*\.php(/.*)?)$ fcgi://{SERVER_NAME}/\$1 [P]
  DirectoryIndex index.htm index.html index.php
  ErrorLog /var/www/logs/error.log
  CustomLog /var/www/logs/access.log vhost_combined

5. Basically, the commands above set Apache/PHP to run as the www user and will redirect any *.local.dd http request to a corresponding *.local.dd folder in /usr/local/sites  Let's go ahead and test it out by moving adminer into its own site

mkdir /usr/local/sites/adminer.local.dd && mv /var/www/localhost/htdocs/adminer.php /usr/local/sites/adminer.local.dd/index.php

6. Then we set the proper permissions and restart Apache/PHP

chown -R www:www /usr/local/sites

/etc/init.d/apache2 restart
/etc/init.d/php-fpm restart

7.  Before we can load http://adminer.local.dd/ in our browser, though, we need to tell our computer what it is since that domain isn't a valid Internet address.  Follow these instructions to add this line to the bottom of your hosts file: adminer.local.dd

8.  Okay, let's try it out!  Open a browser window and go to http://adminer.local.dd/   You should see the Adminer login screen:

9.  You're probably thinking "Umm...we loaded Adminer in Part 2 of this series.  What's the big deal?"  Well, in addition to this Adminer website, we can now run additional separate websites in our virtual machine.  As an example, let's install Drupal.  As a prerequisite we'll need a database so let's set one up now.  In the Adminer screen, type root for the Username and then click Login

10. Next, click Create new database

11. Type mydrupalsite for the name and choose utf8_general_ci for the collation type:

12. Click the Save button and click the Privileges link

13. Click the Create user link, provide a username and password, click the All privileges checkbox, and then click Save

14. Now that we have a database for our Drupal site, let's download Drupal and set it up.  Since Apache/PHP runs as the www user, we need to switch accounts first:

sudo su - www

15. There are a couple ways to install Drupal, but I prefer using a Drupal automation tool called Drush.  Let's install the latest version:

composer global require drush/drush:dev-master

16. Now that Drush is installed, let's add it to our PATH so we can reference it anywhere on the command line:


ln -s /home/www/.composer/vendor/drush/drush/drush /usr/local/bin/drush

sudo su - www

drush --version

16. Although we can use Drush to perform the entire Drupal install, I'm just going to use it to download Drupal and then walk through the rest of the steps manually so you can follow along:

cd /usr/local/sites/ && drush dl drupal && mv drupal-* mydrupalsite.local.dd

17. Use the instructions in Step 7 to add the following to your computer's hosts file: mydrupalsite.local.dd

18. Load http://mydrupalsite.local.dd/ in your browser and follow the Drupal installation wizard (when prompted for database credentials, use the database name/username/password from steps 10-13 above)

19. You should now have Drupal running inside your virtual machine.  Woot!

20. Your next question is probably "Great, but how do I access the files now?"  Well, normally you would set up a VirtualBox shared folder to synchronize the websites directory with a folder on your local machine but unfortunately Alpine Linux doesn't support the VirtualBox guest additions yet so we need another approach.  Although you could do something like FTP, Syncthing, etc., the most elegant solution I've found is sshfs.

Note: since this virtual machine isn't accessible from anything but the host, we'll forsake some security in lieu of convenience by using a pre-generated ssh keypair.

If you feel more comfortable, you can delete the /home/www/.ssh folder and setup your own keypair.  
21. Switch back to the Alpine Linux virtual machine command line, make sure you're in the www account (by typing whoami), add then add the pre-generated public key:

mkdir ~/.ssh && chmod 700 ~/.ssh && cd ~/.ssh && curl -s > authorized_keys && chmod 600 authorized_keys

22. On your host machine, create a file called vaampkey.txt and copy the contents of into it.

23. Now you need to install the sshfs client:

OS X: Install osxfuse and sshfs by following this guide
Windows: Download and install (note: the installer may warn you about missing components but they will be automatically downloaded and installed as part of the sshfs installation process).  Also, the install may require a computer restart. 
Red Hat: sudo yum install fuse-sshfs 
Ubuntu: sudo apt-get install sshfs

24. Open sshfs and click the + Add button

25. Now, enter the following information:
  • Drive Name = vaamp
  • Host =
  • Port = 22
  • Username = www
  • Authentication method = PrivateKey
  • PrivateKey = YOUR/PATH/TO/vaampkey.txt
  • Directory = /usr/local/sites
  • Drive Letter = V
26. Then click Save and then Mount (note: you MUST click Save first due to bug #85)

27. You can now add/update/delete website files via your V: drive!

28. Last but not least, we need an easy way to check the server logs.  I like Pimp my Log so let's use that.

mkdir /usr/local/sites/logs.local.dd

cd /usr/local/sites/logs.local.dd

git clone .

29.  Now we need to turn on PHP logging by exiting the www user account and logging into the root account and then running:

sed -i 's/^;error_log\s=\sphp_errors\.log/error_log = /var/log/apache2/php_errors.log/' /etc/php/php.ini

/etc/init.d/php-fpm restart

touch /var/log/apache2/php_errors.log

30. Finally, we need to add the following line to our computer's hosts file logs.local.dd

31. When you load http://logs.local.dd/ in your browser you should see a welcome page:

32. Click Configure Now and then click No when asked if you want to protect the log website with an admin account (note: normally this is an important security measure, but since no one can access this virtual machine except our host, we forego the extra overhead)

33. The wizard should detect your Apache and PHP setup.  Click Continue

34. The wizard should detect your Apache logs.  Click Continue

35. The wizard should detect your PHP logs.  Click Continue

36. That's it!  Click Pimp My Logs Now to see your logs.

If you've made it this far, congratulations!  I hope you enjoyed the experience and learned a few things along the way that may help you discover and configure your preferred local development experience.

P.S. Check out the quickstart guide for a handy reference.