How Laravel Valet Works Exactly

#

Developers tend to love messing about with their local development environments to see what fits their project requirements and workflow best. Since its launch in 2016, Laravel Valet has quickly become a popular choice and it has become my go-to environment when developing locally on my Mac because of its ease of use and speed. Unfortunately, Laravel Valet is for Mac only. If you’re on Windows, you’re out of luck but may want to check out Matt’s post on WordPress development on Windows.

Valet differs from other dev environments because it chooses to run its stack directly on your Mac instead of offloading the environment to a virtual machine or Docker. It relies on native installations of PHP, Nginx, MySQL, and DnsMasq installed using Homebrew which is what makes it so fast.

In this article, we’re going to take a look behind the scenes to see how Valet works and what is going on in the background when you run Valet commands.

Installation

As part of the Valet installation process you need to:

  • Install PHP using Homebrew (brew install php)
  • Install the laravel/valet Composer package (composer global require laravel/valet)
  • Run the valet install command

So what happens when the valet install command is run? Well, we’re going to use the Valet GitHub repository in this article to discover what is going on behind the scenes.

The main valet bash file is the first code to be invoked when we run a valet command. It basically handles invoking Ngrok if the share command is used or it uses PHP to run the cli/valet.php file. Taking a look in the cli/valet.php file we can see this file does some setup work and registers all of the other Valet commands. If you take a look you can see the install command does a bunch of stuff:

$app->command('install', function () {
    Nginx::stop();

    Configuration::install();
    Nginx::install();
    PhpFpm::install();
    DnsMasq::install(Configuration::read()['tld']);
    Nginx::restart();
    Valet::symlinkToUsersBin();

    output(PHP_EOL.'<info>Valet installed successfully!</info>');
})->descriptions('Install the Valet services');

We’re going to take a look at some of the more interesting parts of how Laravel Valet is set up, starting with Nginx.

Nginx

If you look at the install methods of the Nginx class you can see that it creates a global nginx.conf at /usr/local/etc/nginx/nginx.conf. The nginx.conf includes a valet.conf file which is significant as this config is used to serve all Valet sites. Looking in valet.conf you’ll notice that Nginx is proxying requests to PHP using FastCGI as you might expect:

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass "unix:VALET_HOME_PATH/valet.sock";
    fastcgi_index "VALET_SERVER_PATH";
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME "VALET_SERVER_PATH";
}

The VALET_SERVER_PATH is resolved to the server.php file located in the root of the Valet install. Configuring Nginx with a single vhost and forwarding all requests to the server.php file is important as it handles a unique aspect of Laravel Valet: drivers.

Drivers

The concept of “Drivers” in Laravel Valet is a pretty genius idea. Instead of having to configure Nginx configs across different sites to get them to work properly, a “driver” is simply a PHP file that is used by Valet to determine what type of site a given request is looking for and how to serve it. Out of the box Valet has drivers for a bunch of popular applications (e.g. Laravel, WordPress, Drupal, Statamic, Craft, etc.).

A driver file works by using three methods to determine:

  1. If this driver should be used to serve the current request
  2. If the request is for a static file
  3. The path to the front controller of the site (usually index.php)

For example, the WordPressValetDriver uses the serves() method to check for the existence of a wp-config.php file:

/**
 * Determine if the driver serves the request.
 *
 * @param  string  $sitePath
 * @param  string  $siteName
 * @param  string  $uri
 * @return bool
 */
public function serves($sitePath, $siteName, $uri)
{
    return file_exists($sitePath.'/wp-config.php') || file_exists($sitePath.'/wp-config-sample.php');
}

Going back to the server.php file you can see this file does a few things to process a request:

  • It loads the Valet config.json file (which contains the TLD and any paths created by the valet park command)
  • It generates the site path, name, URI etc.
  • It then passes this info to the relevant driver which uses it to either serve a static file or load the front controller

If you’re interested, you can have a look at the ValetDriver class to see how the driver is used to process a request.

DnsMasq

Another really nice feature of Valet is that it proxies all requests on the *.test domain to your local machine using DnsMasq. This means that you don’t ever need to worry about updating /etc/hosts to point your sites at 127.0.0.1 anymore.

From the DnsMasq class we can see that it does this by creating a file in /etc/resolver with the name of the TLD (test by default) and the content:

nameserver 127.0.0.1

This will tell Mac to use our local DnsMasq install as the nameserver for *.test domains. Then it updates the main DnsMasq config to load ~/.config/valet/dnsmasq.conf. Finally, it creates the valet dnsmasq.conf file with the following content:

address=/.test/127.0.0.1
listen-address=127.0.0.1

DnsMasq is now configured to send all requests for *.test domains to Valet.

Over to You

Although we’ve taken a peek behind the curtain of Valet’s internals there are still plenty of Valet features we haven’t covered here, including:

  • “Securing” sites using self-signed certificates
  • Sharing sites using Ngrok
  • Using .valet-env.php for site-specific env variables

I’d encourage you to keep looking at the Laravel Valet source code to see how these features are implemented. I actually think it’s an important part of a developer’s job to understand what is happening behind the scenes when you use tools like Valet, not just to make you a more informed developer, but also so that you can be better prepared to debug issues when things go wrong. Knowledge is power after all.

Do you use Laravel Valet? Have you ever looked at the source code for the open-source tools you use? Do you think you should? Let us know in the comments.

About the Author

Gilbert Pellegrom

Gilbert loves to build software. From jQuery scripts to WordPress plugins to full blown SaaS apps, Gilbert has been creating elegant software his whole career. Probably most famous for creating the Nivo Slider.