Using Laravel's Homestead for Drupal Projects

Boundless fields of wheat in the east of Ukraine

For a long time now, I’ve preferred Vagrant for local development. My starting point of choice for using Vagrant on a project has been the excellent trusty32-lamp VM, maintained by Andrew Berry. However, with Ubuntu 14.04 reaching end of life, Andrew thought to merge the best of trusty32-lamp VM with Laravel’s Homestead. Thus, in a beautiful instance of open source collaboration, it was so.

Homestead is a similarly fashioned Vagrant box, maintained by the Laravel community, built on Ubuntu 18.04. The result of the marriage is a feature packed, ready to go local development environment that includes multiple versions of PHP, your choice of NGINX or Apache, Xdebug support, profiling with XHProf and XHGui, your choice of MySQL or MariaDB, and so much more.

Let’s look at how you would get set up with Homestead for your Drupal project.

tldr;

If you’re the type to dive into code rather than wade through an article, and you’ve worked with Vagrant before, run this, and take the box for a spin. It sets up a stock Drupal 8 site, ready to install. The database name is drupal_homestead, the root database user and password to install Drupal is homestead / secret.

$ composer create-project m4olivei/drupal-project:8.x-dev drupal_homestead
$ cd drupal_homestead
$ vendor/bin/homestead make
$ vagrant up

Onwards.

Preliminaries

I’m kind of assuming that you’ve worked with Vagrant before, but if you haven’t, fear not! Homestead makes the world of Vagrant very approachable. You’ll just need some software before continuing. You’ll need to install a VM provider, eg. VirtualBox, VMWare, Parallels or Hyper-V. I use VirtualBox, as it’s free and the most straightforward to install. Also, you’ll need Vagrant.

Composer all the things

One really nice thing about Homestead is it can be installed and setup as a composer package. This means that you can easily add and share a Homestead local setup with everyone on your project via version control.

We’ll start with a clone of the Composer Drupal project and add Homestead to it. If you’re adding Homestead to an existing project, skip this step.

$ composer create-project drupal-composer/drupal-project:8.x-dev drupal_homestead --no-interaction
$ cd drupal_homestead
$ git init .
$ git add .
$ git commit -m "Initial commit"

Now that we have a Drupal site to add Homestead to, change into your project directory (wherever your root composer.json file is) and continue by requiring the laravel/homestead package:

$ composer require laravel/homestead --dev

Home at last

At this point, we’re ready to setup Homestead for our project. Homestead comes with a handy console application which will scaffold some files that are required to provision the Vagrant box. Run the following:

$ vendor/bin/homestead make

This will copy a handful of files to your project directory:

  • Homestead.yaml
  • Vagrantfile
  • after.sh
  • aliases

At the very least we’ll want to make tweaks to Homestead.yaml. By editing Homestead.yaml we can easily customize the Vagrant box to our liking. In a typical Vagrant box setup, you would edit the Vagrantfile directly, but here, Homestead exposes the essentials to customize on a per project basis in a much more palatable form. Open up the Homestead.yaml file in your editor of choice. As of this writing, it’ll look something like this:

ip: 192.168.10.10
memory: 2048
cpus: 1
provider: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
    - ~/.ssh/id_rsa
folders:
    -
        map: /Users/m4olivei/projects/drupal_homestead
        to: /home/vagrant/code
sites:
    -
        map: homestead.test
        to: /home/vagrant/code/public
databases:
    - homestead
name: drupal-homestead
hostname: drupal-homestead

It’s worth highlighting a couple things here. If you have better than a single core machine, bump the cpus to match. For my 2013 Macbook with a core i7, I’ve set this to cpus: 4. The VM won’t suck CPU when it’s idle, so take advantage of the performance.

Next folders lists all the folders you wish to share with your Homestead environment. As the files change on your local machine, they are kept in sync between your local machine and the Homestead environment *.

folders:
    -
        map: /Users/m4olivei/projects/drupal_homestead
        to: /home/vagrant/code

Here all the files from /Users/m4olivei/projects/drupal_homestead will be shared to the /home/vagrant/code folder inside the Vagrant box. 

Next sites, as you might guess, lists all of the websites hosted inside the Vagrant box. Homestead can be used for multiple projects. I prefer to keep it to a single project per VM, especially since Drupal codebases tend to be so huge, so we’ll just keep the one site. Homestead ships with the option to use either NGINX or Apache as the web server. The default is NGINX, but if you prefer Apache, like I do, you configure that using the type property.

sites:
    -
        map: drupal-homestead.local
        to: /home/vagrant/code/web
        type: "apache"
        xhgui: "true"

Notice I’ve also changed the map property to drupal-homestead.local. That’s for a couple of reasons. First, I want my domain to be unique. Homestead always starts you with a homestead.test domain, assuming you may use the same Homestead instance for all your projects, but that’s not the case for per-project setups. Second, I’ve used .local as the TLD to take advantage of mDNS. Homestead is configured to work with mDNS**, which will mean that you shouldn’t have to mess around with your /etc/hosts file (see caveats), which is nice. I also changed the to property to reflect the web root for our project. Composer Drupal project sets that up as <project root>/web. Finally, I’ve added xhgui: "true" to my site configuration. We’ll talk more about that later.

Next, we’ll customize the database name:

databases:
    - drupal_homestead

Homestead will create an empty database for you when you first up the box. Homestead can also automatically backup your database when your Vagrant box is destroyed. If you want that feature, simply add backup: true to the bottom of your Homestead.yaml.

Finally, we’ll want to add some services. We’ll need mongodb for profiling with xhprof and xhgui. I also like to use MariaDB, rather than MySQL, and Homestead nicely supports that. Simply add this to the bottom of your Homestead.yaml:

mongodb: true
mariadb: true

In the end, we have a Homestead.yaml that looks like this:

ip: 192.168.10.10
memory: 2048
cpus: 4
provider: virtualbox
authorize: ~/.ssh/id_rsa.pub
keys:
    - ~/.ssh/id_rsa
folders:
    -
        map: /Users/m4olivei/projects/drupal_homestead
        to: /home/vagrant/code
sites:
    -
        map: drupal-homestead.local
        to: /home/vagrant/code/web
        type: "apache"
        xhgui: "true"
databases:
    - drupal_homestead
name: drupal-homestead
hostname: drupal-homestead.local
mariadb: true
mongodb: true

There are plenty more configurations you can do. If you want to learn more, see the Homestead documentation.

Fire it up

With all our configuration done, we’re ready to fire it up. In your project directory simply run:

$ vagrant up

On your first time running this, it will take quite a while. It needs to first get the base box, which is a pretty hefty download. It then does all of the provisioning to install and configure all the services necessary. Once it’s finished, visit http://drupal-homestead.local in your browser and you’ll be greeted by the familiar Drupal 8 install screen. Yay!

Features

You get a lot all nicely configured for you with Homestead. I’ll highlight some of my favourites, having come from trusty32-lamp VM. I’m still exploring all the Homestead goodness.

Xdebug

Xdebug comes bundled with Homestead. To enable it, SSH into the Vagrant box using vagrant ssh and then run:

$ sudo phpenmod xdebug
$ sudo systemctl restart php7.3-fpm

Once enabled, follow your IDE’s instructions to enable debugging.

Profiling with Tideways (xhprof) and xhgui

Every now and again, I find it useful to have a profiler for weeding out poorly performing parts of code. Homestead comes bundled with Tideways and xhgui that make this exercise straightforward. Simply append a xhgui=on query string parameter to any web request and that request and any that follow are profiled. To read the reports navigate to /xhgui, eg. for our configuration above, http://drupal-homestead.local/xhgui.

Xhgui compare runs
Comparing runs of the articles page of Umami

Database snapshots

Here's another of my favourite features. From the documentation:

Homestead supports freezing the state of MySQL and MariaDB databases and branching between them using Logical MySQL Manager. For example, imagine working on a site with a multi-gigabyte database. You can import the database and take a snapshot. After doing some work and creating some test content locally, you may quickly restore back to the original state.

Homestead documentation

I’ve found this to be a huge time saver for instances where I need to work on issues that only manifest with certain application state stored in the database. Load the database with the errant application state, create a branch using sudo lmm branch errant-state, try your fix that processes and changes that application's state and if it doesn’t work, sudo lmm merge errant-state to go back and try again.

Portability and consistency of Vagrant

This is more of a benefit of Vagrant than Homestead, but your local dev environment becomes consistent across platforms and sharable. It solves the classic works-on-my-machine issue without being overly complicated like Docker can be. Homestead does add some simplicity to the configuration over just using Vagrant.

Moar

There are many more features packed in. I mentioned the ease of choosing between Apache and NGINX. Flipping between PHP versions is also easy to do. Front-end tooling including node, yarn, bower, grunt and gulp are included. Your choice of DBMS between MySQL, MariaDB, PostgreSQL and Sqlite is made incredibly easy. Read more about all the features of Homestead in the Homestead documentation.

Caveats

* File sharing

By default, the type of share used will be automatically chosen for your environment. I’ve personally found that for really large Drupal projects, it’s better for performance to set the share type to rsync. Here is an example of that setup:

folders:
    -
        map: /Users/m4olivei/projects/drupal_homestead
        to: /home/vagrant/code
        type: "rsync"
        options:
          rsync__exclude: [".git/", ".idea"]
          rsync__args: ["--verbose", "--archive", "--delete", "-z", "--chmod=g+rwX"]

An rsync share carries some added maintenance overhead. Namely, you need to ensure that your running vagrant rsync-auto to automatically detect and share changes on the host up to the Vagrant box. If you need to change files in the Vagrant box, you would kill any vagrant rsync-auto process you have running, vagrant ssh into the box, make your changes, and then on your host machine run vagrant rsync-back before running vagrant rsync-auto again. Not ideal, but worth it for the added performance gain and all the joys of Vagrant local development. There are other options for type including nfs. See the Homestead documentation for more details, under “Configuring shared folders”.

** DNS issues

A handful of times I’ve run into issues with mDNS where the *.local domains don’t resolve. I’ve seen this after running vagrant up for the first time on a new vagrant box. In that case, I’ve found the fix to be to simply to reload the vagrant box by running vagrant up. In another instance, I’ve found that *.local domains fail to resolve after using Cisco AnyConnect VPN. For this case, it sometimes works to reload the vagrant box, and in others, I’ve only been able to fix it by restarting my machine.

Acknowledgments

Big thanks to the following individuals for help with this article:

  • Andrew Berry for porting features from trusty32-lamp VM to Homestead and also for technical and editorial feedback.
  • Matt Witherow for technical and editorial feedback.
  • Photo by Polina Rytova on Unsplash

If you enjoyed this Article, you may also enjoy...

Matt Oliveira

Thumbnail
Matt loves building websites, being outside and active, and spending time with his family.