Local development with Valet

I’ve used MAMP Pro with my team for local development for many years. It’s a convenient tool, but it’s often slow (especially the CLI) and often hangs or crashes. I’ve been looking around for alternatives for quite some time, so after it was recommended by Zuzana thought I’d take a look at Laravel’s local dev environment Valet.

Installing Valet

Valet installs a lightweight set of tools to run websites on your Mac via Homebrew. This feels like a good approach to me. I’m not sure we really need the complexity of virtual machines, the code we write tends to work fine on a Mac. Having tools locally installed via Homebrew is fast and convenient.

I started by updating Homebrew to make sure my local packages are up to date:

brew update

Then installed Valet globally via Composer, and installed it:

composer global require laravel/valet
valet install

MySQL

Next I need to install MySQL since this will no longer be available via MAMP:

brew install mysql@5.7
brew services start mysql@5.7

This has installed MySQL, I now want to secure the local root password (by default it is empty):

/usr/local/Cellar/mysql@5.7/5.7.25/bin/mysql_secure_installation

(please note the path to mysql_secure_installation may change depending on your version of MySQL).

Next, I want to connect to the database to install a copy of my own blog WordPress database for local testing. We use the excellent SequelPro for managing MySQL.

It’s easy enough to connect to localhost using the details:

  • MySQL Host: 127.0.01
  • Username: root
  • Password: (the secure password I set above)

This worked fine, I created a new database for my local test site and imported a recent SQL backup.

Serving a site

The default method to serve sites in Valet is to use valet park to serve all sub-folders in ~/Sites as websites via URLs in the format folder-name.test

For example, http://wordpress.test/ would serve a website with the document root of ~/Sites/wordpress

This isn’t really how we work, most projects have a “web” sub-folder inside a project to allow for files outside of the document root. So for setting up local sites I’ll need to use the valet link command to set each site up manually.

To create a link from ~/Sites/simonrjones.net/web for the host simonrjones.test it’s simple enough:

cd ~/Sites/simonrjones.net/web
valet link simonrjones

I can verify the sites setup in Valet via:

valet links

The final step is to ensure WordPress knows about this new local test URL, otherwise WordPress has a habit of redirecting to what it thinks is the correct blog URL.

I use the multi-environment config on my personal blog so this is easily achieved by changing the ‘domain’ value for the ‘development’ environment in the file wp-config.env.php

 'development' => [
        'domain' => 'simonrjones.test',

I can test this now via the URL http://simonrjones.test/ – which worked first time!

Testing with a more complex setup

Next, I tried this with one of our client’s WordPress multi-site installs, which is a little more complex. The site is hosted at WP Engine so it uses the standard wp-config.php setup (not multi-environment config).

CD’ing into the project folder and running valet link is enough to make the site run from a local *.test URL. However, trying to access the site doesn’t work and WordPress multi-site redirects the request to what it thinks is the correct URL.

I have WP CLI installed, so I tried to use this to update old site URLs to the new *.test ones, but I couldn’t see a way to reliably do this for multi-sites. So I went back to straightforward SQL!

UPDATE wp_options SET option_value='http://clientdomain.test' WHERE option_name='siteurl' OR option_name='home';

UPDATE wp_site SET domain='clientdomain.test' WHERE id=1;

UPDATE wp_sitemeta SET meta_value='http://clientdomain.test/' WHERE meta_key='siteurl';

UPDATE wp_blogs SET domain='clientdomain.test' WHERE blog_id=1;
UPDATE wp_blogs SET domain='site1.clientdomain.test' WHERE blog_id=2;
UPDATE wp_blogs SET domain='site2.clientdomain.test' WHERE blog_id=3;
UPDATE wp_blogs SET domain='site3.clientdomain.test' WHERE blog_id=4;
UPDATE wp_blogs SET domain='site4.clientdomain.test' WHERE blog_id=5;

UPDATE wp_2_options SET option_value='http://site1.clientdomain.test' WHERE option_name='siteurl' OR option_name='home';
UPDATE wp_3_options SET option_value='http://site2.clientdomain.test' WHERE option_name='siteurl' OR option_name='home';
UPDATE wp_4_options SET option_value='http://site3.clientdomain.test' WHERE option_name='siteurl' OR option_name='home';
UPDATE wp_5_options SET option_value='http://site4.clientdomain.test' WHERE option_name='siteurl' OR option_name='home';

In addition I had to set the wp-config.php setting to the default site URL

define('DOMAIN_CURRENT_SITE', 'clientdomain.test');

Finally, I had to setup additional URLs to serve the multi-site URLs in Valet:

valet link site1.clientdomain.test
valet link site2.clientdomain.test
valet link site3.clientdomain.test
valet link site4.clientdomain.test

The above appeared to serve the multi-site install from the different URLs. However, when I attempted to login to WordPress I was presented with a white screen of death.

I tried valet log and viewed the Nginx error log. Nothing. I refreshed the page a few times and WordPress came up. Navigating around most WordPress admin pages seemed to work, but I got the occassional slow page load or white page. On the front-end pages in sub-folders often seemed to not work on the first request. This is a little disoncerting. This may be caused by the complex WordPress setup, one of the installed plugins, or simply the fact it’s using Nginx and we’ve built these sites to work on Apache. It’s something I’ll have to look into.

Next steps

Valet certainly seems to be a useful tool and one that is very quick to setup. Things I’d like to look at next..

  • Review the secure HTTPS option in Valet
  • Take a look at Valet+, though it looks a little out of date compared with Valet.
  • Can we customise the webserver used so it more closely matches our production environment (we use Apache instead of Nginx FastCGI)?
  • Is there a WP CLI plugin to help change multi-site URLs? If not, we should write one!

If we can use a lightweight dev setup such as Valet it would be nice. Though as with everything in tech, it’s clearly not completely plain sailing! MAMP Pro is certainly easier to use and setup, though it’s the speed (web requests and CLI) which I’m starting to want improved more than MAMP appears able to offer.