Steve Grunwell

Open-source contributor, speaker, and electronics tinkerer

A home sitting on a midwestern, prairie homestead.

Simplify Project On-boarding with Laravel Homestead

Despite working on Liquid Web’s Managed WordPress and Managed WooCommerce hosting products, a fair amount of the development work I do these days has very little to do with WordPress. In fact, my main project right now is using Laravel, and it’s the sixth Laravel application (depending on how you count projects) I’ve worked on in just under two years at the company.

Laravel’s an incredibly powerful application framework with a thriving ecosystem. Thanks to tools like Composer and Packagist, I have access to thousands of libraries, extensions, and utilities to help me build the best applications possible. Even out of the box, the framework has support for (among many other things) multiple database and caching engines, event-driven architecture, and websockets, giving me a strong foundation for building modern web applications.

Of course, incorporating multiple platforms and tools into a single application can make on-boarding new team members more difficult. How do you make sure they’re running the right versions of PHP, your RDBMS of choice, Redis, and more?

Easy environments with Laravel Homestead

While containerization is all the rage right now, I’m still a huge fan of Laravel Homestead, the official virtual machine for Laravel development.

Homestead comes with the most common tools for Laravel sites right out of the box: the latest versions of PHP, MySQL, Postgres, and more. Homestead maintainer (and friend of mine) Joe Ferguson works hard to keep Homestead up-to-date, lean, and well-suited for Laravel development.

Laravel Homestead enables the virtual machine to be installed on a per-project basis, which (in my opinion) is highly-preferable to one global installation. The machine can be installed, tailored to the needs of the current project, then disposed of once it’s no longer needed.

Adding Laravel Homestead to a project

To add Laravel Homestead to a project, it’s a matter of adding it as a development dependency via Composer:

Once the package is installed, we need to do a few more things to set up our Homestead box:

First, ensure that both Vagrant and a supported provider (VirtualBox, VMWare, etc.) are installed on your machine — Homestead defines a Vagrant virtual machine, but the provider is what’s actually running the VM.

Next, we’ll run the Homestead installer:

This will create a few files in your project:

  • after.sh (additional steps to run after provisioning)
  • aliases (custom aliases and functions that will be imported into the vagrant user’s shell environment)
  • Homestead.yaml (the Homestead configuration — more on this in a moment)
  • Vagrantfile (the actual Vagrant configuration)

All but one of these files — after.sh should be added to your project’s .gitignore file, as we don’t want them to be versioned. Homestead may take care of adding these for you, but all of the following should be in your .gitignore file:

Why do we exclude these files? Not every environment will have a Vagrant configuration (production, CI environments, staging, etc.), and different users might have different host machine configurations.

Before we do anything else, let’s take a look at the Homestead.yaml file, as this defines how Homestead should work.

Understanding Homestead.yaml

By default, your Homestead.yaml file will look something like this:

Some of the settings will seem pretty self-evident: in this file, my Vagrant box will be available at 192.168.10.10 and utilize 1 CPU core with 2GB of RAM. My host machine (e.g. my Mac) uses Virtualbox as its provider, and my SSH public key — which lives in ~/.ssh/id_rsa.pub will be imported.

The next node is folders:, which tells the virtual machine that /Users/steve/Sites/my-test-app should be available at /home/vagrant/code within the Homestead box. If I needed multiple directories to be mapped, I could add more entries under this heading.

sites: describes how Homestead’s web server (nginx by default, but Apache is available) will be configured. In the default code above, accessing https://homestead.testfrom my host machine will resolve to the public directory of my Laravel application.

Next up, we come to the database: key: this is a list of one or more databases that should automatically be created when the box is provisioned. Most applications will only need one database, and the default .env.example file that ships with Laravel already has the credentials (homestead/secret) configured.

The last of the defaults, name: and hostname:will define the name of the virtual machine and the VM’s hostname, respectively. By default, Homestead will attempt to determine these based on the project directory name.

Starting our Homestead VM

Once we’re satisfied with the Homestead.yaml file, we can finally start up our new virtual machine by running vagrant up. Vagrant will handle downloading the base box and applying all of Homestead’s customizations, giving you a full-featured development environment in a few minutes (or less)!

Once the virtual machine has been provisioned, we’ll run vagrant ssh to SSH into the server. From here, all of our work — running tests, compiling JavaScript, etc. — will be done within Homestead.

At the end of the day, exiting the SSH session and running vagrant halt will spin down the virtual machine, ready for whenever you come back to the project. If you’re done on the project for a while, you may destroy it with vagrant destroy. If you’ve made changes to the Homestead.yaml file, you may re-provision the VM by running vagrant provision.

Customizing Laravel Homestead for a project

Now that we have a per-project instance of Laravel Homestead, let’s tailor the installation process to our project.

Contributing documentation

Whether a project has multiple team members working on it or is open-source and looking for contributors, starting with a strong contribution guidelines document is important. Typically, this will be stored in the root of the project as CONTRIBUTING.md.

An example of a current project I’m working on gives other developers everything they need to know to get started:

Four steps. That’s all it takes to get this environment up and running. A recent addition to our team went through this and exclaimed “wait, that’s it? That’s all I need to do to get started?!”

Of course, getting on-boarding down to that few steps requires a bit of work:

Composer scripting

There are a few scripts I always like to add to my Laravel projects’ composer.json file: starting with this one-liner:

This script will do the following anytime someone runs composer install:

  1. Check to see if a local .env file exists. If one does, do nothing more.
  2. If a .env file doesn’t exist, copy .env.example (which comes with Laravel installations out of the box) to .env, then run php artisan key:generate to populate the APP_KEY environment variable in the newly-created .env file.

This saves developers a step when setting up the project: as soon as they run composer install to get all of their vendor dependencies in place, a .env file will be created (based on the [versioned] .env.example template) and application key generated automatically.

The other item I like to add to the “scripts” section of composer.json is:

This is just an alias for php vendor/bin/homestead make, which just feels a little cleaner.

Leveraging the after.sh script

The after.sh script is my secret weapon when setting up a project. Laravel Homestead will automatically look for this file and execute it after the rest of the Homestead VM has been built. My after.sh file often looks like this:

There are comments peppered throughout explaining exactly what’s happening, but generally speaking I’m using the script to do common setup steps like installing & building npm dependencies, running database migrations, and anything else that a developer might otherwise have to do.

There are two special items in my after.sh script, though:

First, Laravel Homestead will normally start users in the /home/vagrant directory after running vagrant ssh. Since that’s almost always immediately proceeded by cd ~/code, this command simply scripts the process. Now, when a user SSHs into the VM, they’re automatically started in the /home/vagrant/code directory.

The other line automatically sets up Laravel’s default cron job, which is needed for Laravel’s task scheduling features. This can be handled by Homestead automatically, but I prefer to explicitly include in in after.sh since the Homestead.yaml file will be different for each copy of the application.

Depending on the project, the after.sh file can range from convenient (for example, seeding a database) to crucial (installing third-party dependencies). Thanks to the after.sh file, we can handle all of it automatically!

User-specific settings

If there are scripts you want to run after Homestead has been provisioned that not all developers on the project might want/need, you might consider adding these to a user-customizations.sh file, which I’ve written about before. These can be really helpful if, for example, you have strong opinions on Vim v. Nano as a default editor.

What else does your project need?

A solid on-boarding process can make all the difference whether you’re bringing on new members to a project or looking for contributions: if people can spin up your application easily, they’re far more likely to get involved. With Laravel Homestead (and maybe a little extra scripting), you can make the process as simple as possible.

Previous

Automatic, Whole-Home Time Machine Backups

Next

Paid Support for Legacy Libraries

5 Comments

  1. I tried running this but unfortunately Vagrant blows up with the following error (after a huge Ruby stacktrace):

    Stderr from the command:

    bash: line 5: /sbin/ifdown: No such file or directory
    bash: line 19: /sbin/ifup: No such file or directory

    Not sure if those relate to host or guest.

  2. It seems that Homestead (via Vagrant) is broken on Ubuntu 18.04 and 18.10 then. If you use the version from the repositories (2.0.2) you have to SSH into the VM, install ifupdown and then re-provision. If you use the version from the Vagrant website (2.2.3), you get the warning about the NIC and a 502 gateway error when trying to access the VM from the host.

  3. Niels P

    Thanks Steve. Pretty old post, but still one of the best help I found to streamline our team’s development workflow with Laravel and homestead.
    Quick question: While playing with this setup I ran into problems with the ‘npm install’ command. Not sure why, but it kept breaking with a ‘ENOENT: no such file or directory’ error. After some googleing I found some remarks that when collaborating on a project it is better to run ‘npm ic’, to actually install the versions from the package-lock file, instead of grabbing the latests versions. What’s your thought on that? Thanks!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Be excellent to each other.