Setting up a Laravel Homestead box

I spend a lot of time in the Larachat Slack channel, and one of the most common questions/topics is getting Laravel running locally in a proper dev environment on their machine.

There are a few different moving parts that enable a local dev environment to work, it's easy to see why new developers might get confused. I recently got hold of a spare Mac Mini, so I installed the new and shiny Mac OS High Sierra, and created a clean user account to write this 'from scratch' tutorial.

Prerequisites

Anyone should be able to follow along and create a local dev environment, but you will need to have some idea about how to use the command line to move around the file system and run basic commands. It's also worthwhile making sure you have Mac's developer tools installed.

We will be setting up a local Laravel install, using the Homestead Vagrant box, which runs on VirtualBox.

This article is up-to-date as of October 2017, using the following software and versions:

  • Mac OS 10.13.1 (High Sierra)
  • VirtualBox 5.1.28
  • Vagrant 2.0.0

Mac Developer Tools OS Upgrade

The Mac Mini I'm using for this tutorial already had Sierra, with developer tools installed. I ran the High Sierra upgrade, and the developer tools broke. This happened last time I ugpraded too, so if you've recently upgraded and found that things like git aren't working, or your /usr/local/bin permissions are weird, follow this blog post and you should be good.

High Sierra and NFS

At the time of writing, NFS sharing is currently broken with Homestead, but there is a fix being trialled by the developers. If you're using NFS, you may want to check for any updates around this.

1. Download and Install VirtualBox

In order to setup our local dev environment, we will make use of a virtual machine. VirtualBox is a piece of free, open source software by Oracle, and it runs on all of the major Operating Systems.

Download VirtualBox and run the packaged installer. Once complete, you then have the ability to host virtual machines on your computer (you may need to reboot).

2. Download and Install Vagrant

So, we already have the ability to run virtual machines - what do we need next? Well, in order to make it easier to reproduce an environment, we'll make use of Vagrant. Whilst we could spin up a Linux virtual machine and spend an age configuring it manually, we can use automated tools to do 99% of the heavy lifting for us, and set the box up in a predictable way. This also means that you can share your 'Vagrant Files' and a friend or colleague can provision a virtual box which is identical to your own, all with a single command or two.

You can download Vagrant from their website, and again, run the binary installer.

3. Install Homestead

I mentioned above that using Vagrant, we can repeatedly and easily spin up virtual machines that are automatically configured from a base template. So, we need a template - this means installing the operating system, required software (PHP, nginx, MySQL, etc...) and configuring it all. Fortunately, we don't need to start from scratch - we can use Homestead!

Homestead is a pre-configured Vagrant box: it is a Ubuntu box that runs PHP7, Nginx, MariaDB, Composer, Node and more (full list here).

In order to install it, run the following command: vagrant box add laravel/homestead

The download may take a few minutes, depending on your connection speed, and should go something like this:

Dev-Mac-Mini:~ dev$ vagrant box add laravel/homestead
==> box: Loading metadata for box 'laravel/homestead'
    box: URL: https://vagrantcloud.com/laravel/homestead
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) parallels
2) virtualbox
3) vmware_desktop

Enter your choice: 2
==> box: Adding box 'laravel/homestead' (v3.1.0) for provider: virtualbox
    box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/3.1.0/providers/virtualbox.box
==> box: Successfully added box 'laravel/homestead' (v3.1.0) for 'virtualbox'!

4. Setup Homestead

We're now at a point where we have VirtualBox installed, which Vagrant can use to power virtual machines, and we have a Vagrant 'template' called Homestead - which will run our local development environment.

The next thing we need to do is setup our Homestead configuration. This will define what sites we have running on the box, as well as things like CPU/Memory resource limits.

Clone the Homestead repo

First we will clone the Homestead repo from GitHub which has all the relevant files, and then move to its directory:

Dev-Mac-Mini:~ dev$ git clone https://github.com/laravel/homestead.git ~/Homestead

Cloning into '/Users/dev/Homestead'...
remote: Counting objects: 2491, done.
remote: Compressing objects: 100% (31/31), done.
remote: Total 2491 (delta 22), reused 35 (delta 17), pack-reused 2443
Receiving objects: 100% (2491/2491), 454.94 KiB | 1.20 MiB/s, done.
Resolving deltas: 100% (1453/1453), done.

Dev-Mac-Mini:~ dev$ cd ~/Homestead
Dev-Mac-Mini:Homestead dev$ 

Configure Homestead.yaml

There is now a folder in your home directory called Homestead. For my development environment, I prefer to have a single Homestead box, and all of my projects live on it. It's possible to create per-project Homestead machines, but this won't be covered here (find more information on that here).

Run the following command to create the required files: bash init.sh

Open the Homestead.yaml file using Vi/Vim, Nano or a GUI editor, and copy the following:

---
ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/code
      to: /home/vagrant/code

sites:
    - map: example.dev
      to: /home/vagrant/code/example/public

databases:
    - example

From the top: we first assign an IP address to our machine, then give it some RAM and CPU. You are free to increase or decrease these, I normally stick with the defaults and increase them only as needed. For those on a less powerful machine, you can also lower the memory usage, but if you plan on using Nginx, PHP, MySQL and more, don't lower it too much! Finally, we ensure the provider is set to virtualbox (Vagrant can use other virtualisation software too, not just VirtualBox).

Next we define our SSH keys, which will automatically be provisioned on to the box, allowing us to login over SSH like a normal server.

Note: If you don't have SSH keys, type ssh-keygen in Terminal and hit enter a few times to create a passwordless key

Folder Mapping

Once running, you will have two operating systems running on your machine. Each of these has its own file structure. We will write our code on our local OS (Mac, in this case), but we want the Homestead box to serve these files. For this to work, we create a map.

folders:
    - map: ~/code
      to: /home/vagrant/code

sites:
    - map: example.dev
      to: /home/vagrant/code/example/public

The folders directive specifies that we will have a folder called code on our Mac, in the home directory. On the Homestead box, this folder will be available at /home/vagrant/code. For our setup, you will only need one folders map, as all of our projects will go in to the local code folder.

Now Homestead knows where your files are, it needs to know where the public folder is (in order to serve Laravel), as well as what domain you want to use. I tend to use '.app' or '.dev' versions of the live site. So danwalker.dev would by development version of this website, pick whatever you'd like. The example folder in your ~/code folder doesn't exist, but we'll create that shortly.

Single Folder Map vs Per-Project

It was pointed out to me by someone in Larachat that using a single folder (~/code in our example) for multiple projects can cause performance issues in some cases, best practice is advised to do file mapping per project. Personally I haven't seen any performance issues on my 2015 MacBook Pro (i5/8GB), but maybe on less powerful systems you will. I'll continue to use one folder as it works for me and many others that I know, without issue. YMMV.

5. Edit /etc/hosts

We told Homestead to host a website with a domain of example.dev, but this domain doesn't exist or do anything right now. We need to add an override to our host machine so that the domain points to your virtual machine. We can do this by editing the /etc/hosts file (which requires sudo rights).

Dev-Mac-Mini:Homestead dev$ sudo nano /etc/hosts
Password:

192.168.10.10 example.dev

6. Composer Setup

At this point, we're almost much good to go. All we need to do is create our Laravel project files! If you haven't got Composer yet, you'll need to install that first (if you've already got it, skip ahead) on your local machine - or you can use the version of Composer that's inside Homestead.

I have Composer installed on my host machine for a number of reasons, but if you don't have it installed, it's easiest to just use the copy that's inside your new virtual machine. To do that, simply vagrant up followed by vagrant ssh, and interact with Composer inside your virtual machine. Using the Homestead bundled version of Composer is often a safer bet as version mismatches are less likely to crop up.

We'll add the Laravel installer package to my local machine's version of Composer in my case:

Dev-Mac-Mini:~ dev$ sudo composer global require "laravel/installer"
Password:

7. Create your Laravel project

Now we'll create that ~/code directory we discussed earlier, and add our example project:

Dev-Mac-Mini:~ dev$ cd ~; mkdir code; cd code
Dev-Mac-Mini:code dev$ laravel new example.dev
Crafting application...
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 68 installs, 0 updates, 0 removals       
  - Installing laravel/framework (v5.5.13): Downloading (100%)         
  - Installing fideloper/proxy (3.3.4): Downloading (100%)
        
[output truncated]         
  
Generating optimized autoload files
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
> @php artisan key:generate
Application key [base64:*******] set successfully.
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Package manifest generated successfully.
Application ready! Build something amazing.

8. Boot + Fin

Once you've generated your application files (or downloaded/imported your project), you should now be able to boot your Vagrant box (which lives in the Homestead directory) and browse to your site.

Dev-Mac-Mini:code dev$ cd ~/Homstead; vagrant up
Bringing machine 'homestead-7' up with 'virtualbox' provider...
==> homestead-7: Checking if box 'laravel/homestead' is up to date...
==> homestead-7: Clearing any previously set forwarded ports...
==> homestead-7: Clearing any previously set network interfaces...
==> homestead-7: Preparing network interfaces based on configuration...
    homestead-7: Adapter 1: nat
    homestead-7: Adapter 2: hostonly
==> homestead-7: Forwarding ports...
    homestead-7: 80 (guest) => 8000 (host) (adapter 1)
    homestead-7: 443 (guest) => 44300 (host) (adapter 1)
    homestead-7: 3306 (guest) => 33060 (host) (adapter 1)
    homestead-7: 5432 (guest) => 54320 (host) (adapter 1)
    homestead-7: 8025 (guest) => 8025 (host) (adapter 1)
    homestead-7: 27017 (guest) => 27017 (host) (adapter 1)
    homestead-7: 22 (guest) => 2222 (host) (adapter 1)
==> homestead-7: Running 'pre-boot' VM customizations...
==> homestead-7: Booting VM...
==> homestead-7: Waiting for machine to boot. This may take a few minutes...
    homestead-7: SSH address: 127.0.0.1:2222
    homestead-7: SSH username: vagrant
    homestead-7: SSH auth method: private key
==> homestead-7: Machine booted and ready!
==> homestead-7: Checking for guest additions in VM...
==> homestead-7: Setting hostname...
==> homestead-7: Configuring and enabling network interfaces...
==> homestead-7: Mounting shared folders...
    homestead-7: /vagrant => /Users/dev/Homestead
    homestead-7: /home/vagrant/code => /Users/dev/code
==> homestead-7: Running provisioner: file...
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: inline script
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: inline script
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: inline script
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: /var/folders/6l/nplc6qrd1qg2ngvppqqmtm8c0000gp/T/vagrant-shell20170928-1272-zn6lhp.sh
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Creating Certificate: example.dev
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Creating Site: example.dev
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Checking for old Schedule
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Restarting Nginx
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Creating MySQL Database: example
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Creating Postgres Database: example
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Clear Variables
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: script: Update Composer
==> homestead-7: You are already using composer version 1.5.2 (stable channel).
==> homestead-7: Running provisioner: shell...
    homestead-7: Running: /var/folders/6l/nplc6qrd1qg2ngvppqqmtm8c0000gp/T/vagrant-shell20170928-1272-184vox8.sh
Dev-Mac-Mini:Homestead dev$ 

Voila:

Screen-Shot-2017-09-28-at-21.12.44-1

When you try and browse to your project, you first hit the hosts file which returns the IP address. Your browser connects to this IP address, which is a virtual machine running on your machine, and Nginx is the one listening for connections. The request your browser makes is passed (by Nginx) to Laravel, which generates the page and sends it all back to your browser. Magic.

Wrap-up

Hopefully this tutorial covered everything you needed to get going with your own local Laravel development setup, but if there was anything missing or that doesn't work for you, drop me an email or leave a comment below.

Adding Additional Websites

In order to add a new website to your local dev environment, simply:

  1. Create a /etc/hosts entry for your domain
  2. Create your project (i.e. cd ~/code; laravel new myblog)
  3. Add a map (and database, if needed) to ~/Homestead/Homestead.yaml
  4. Run a vagrant halt followed by a vagrant up --provision

Sequel Pro

I highly recommend downloading Sequel Pro for connecting to your Homestead box's MySQL server. It gives you a great GUI for interacting with the database and is free to use (funded by donations).

Sequel Pro

Advanced Topics

Homestead can have more advanced setups in terms of port-forwarding, software, services and more - if you want do anything extra with Homestead then be sure to check out the official documentation.

Enjoy reading?

Get notified about new posts!