Andrew Welch · Insights · #devops #frontend #homestead

Published , updated · 5 min read ·


Please consider 🎗 sponsoring me 🎗 to keep writing articles like this.

Local Development with Vagrant / Homestead

A local devel­op­ment envi­ron­ment with Vagrant/​Homestead allows you to work on projects more safe­ly and effectively

Homestead Prairie Schooner

Home­stead is a pro­vi­sion­ing tool which sets up a local devel­op­ment envi­ron­ment that allows you to work on web­dev projects with­out fear. You get a mod­ern stack with every­thing you need for devel­op­ment, includ­ing an array of fan­tas­tic debug­ging tools.

We’re going to talk about why I use Home­stead for local devel­op­ment, but before we get into the nuts and bolts, let’s talk about why we use a local devel­op­ment envi­ron­ment to begin with.

N.B.: Although Craft CMS is ref­er­enced in this arti­cle, Home­stead works well for any kind of web devel­op­ment with any kind of CMS or dev stack (Lar­avel, Node­JS, whatevs).

You don’t work on a car’s engine while it’s running, barreling down the highway at 100km/h

In the bad old days, web devel­op­ment was done com­man­do, edit­ing .html files direct­ly on the serv­er. Then peo­ple start­ed real­iz­ing this was a bad idea, and files were edit­ed local­ly, and then copied down to the serv­er using an FTP app after some rudi­men­ta­ry testing.

The prob­lem is that mod­ern web devel­op­ment isn’t just edit­ing markup any­more. Mod­ern web devel­op­ment is on a col­li­sion course with soft­ware engi­neer­ing & infor­ma­tion archi­tec­ture. Some would argue — I think quite right­ly — that we’re already there.

Car Servicing Engine

That means we have to be seri­ous about our tool­ing. We need to have a way to design, devel­op, and debug our projects using mod­ern tools, in a way that does­n’t inter­fere with the pub­lic-fac­ing website.

The Mul­ti-Envi­ron­ment Con­fig for Craft CMS arti­cle talks more in-depth about how to set up Craft CMS for this type of set­up where you have local devel­op­ment, staging, and live pro­duc­tion environments.

If you’re not using some kind of local devel­op­ment envi­ron­ment, you will find it increas­ing­ly dif­fi­cult to stay up to speed. So let’s do it.

Link Why Vagrant/Homestead?

There are as many ways to set up a local devel­op­ment envi­ron­ment as there are to skin a cat. The rea­son I’m par­tial to using Home­stead to set up my local devel­op­ment envi­ron­ment is that it cre­ates an entire­ly sep­a­rate vir­tu­al machine (VM) inside of your computer.

This has sev­er­al advantages:

  • You can install what­ev­er you want in your Home­stead VM with­out affect­ing your actu­al computer
  • You can eas­i­ly cre­ate and destroy as many VMs as you want, so an oops” moment means min­utes, not hours
  • You get a real™ Lin­ux box that mir­rors your pro­duc­tion serv­er as close­ly as possible
  • You get all of the tools you need pre-installed, with­out hav­ing to add them in piecemeal

Hav­ing some­thing that close­ly mir­rors a pro­duc­tion envi­ron­ment means few­er unex­pect­ed sur­pris­es when you deploy to pro­duc­tion, and it means you spend less time on the meta-work” of get­ting your devel­op­ment envi­ron­ment working.

The fact that you can cre­ate a pre-pro­vi­sioned VM quick­ly and eas­i­ly means that you can devel­op with­out fear. If you roy­al­ly screw up your devel­op­ment envi­ron­ment, no big deal, you just spin up anoth­er one.

Here’s what it looks like:

Homestead Vagrant Virtualbox

Home­stead VM

Home­stead is a Vagrant box (along with some set­up & pro­vi­sion­ing scripts). Vagrant is pro­vi­sion­ing soft­ware that uses a pre­con­fig­ured box” to set up a Vir­tu­al Machine from a provider. The provider” is what actu­al­ly runs the VM, and can be either Vir­tu­al­Box (which is free), VMware (which is not free), or Par­al­lels (which is also not free).

I’m going to assume that you’re cheap like me, and you’re going to use Vir­tu­al­Box, because it’s free. But any of the three will do, and in fact, VMware offers sig­nif­i­cant­ly bet­ter per­for­mance than the free Vir­tu­al­Box, so you might con­sid­er giv­ing it a go.

So Homestead is the recipe, Vagrant is the chef, and VirtualBox is the waiter that serves you up the scrumptious dish.

All of this runs as a vir­tu­al machine (VM) inside of your com­put­er. Noth­ing that is in this VM can hurt your actu­al com­put­er, it’s com­plete­ly sep­a­rate and insulated.

Russian Matryoshka Doll

You have your own lit­tle serv­er inside your com­put­er, and com­bined with a set­up as described in the Data­base & Asset Sync­ing Between Envi­ron­ments in Craft CMS arti­cle, you have a mobile envi­ron­ment that you can use any­where. Even with­out Inter­net access.

What’s more, if you work with oth­er peo­ple, the deter­min­is­tic way in which Home­stead pro­vi­sions your VM means you can ensure that they also have the exact same local devel­op­ment envi­ron­ment that you do.

Con­sis­ten­cy in tool­ing amongst your team means less fric­tion, and few­er problems.

Link Becoming a Homesteader

So enough talk! Let’s get a Home­stead envi­ron­ment. If you pre­fer video instruc­tions, check out the Set­up Craft CMS on Vagrant Home­stead YouTube video.

First, you’ll need to down­load and install:

Both of them come with native installers for Mac, Win­dows, and Lin­ux. You don’t need to do any kind of set­up for either of them, just install them. Then we need to add the laravel/homestead box to Vagrant via the following:

vagrant box add laravel/homestead

Next up we’ll need to install Home­stead by cloning the repo:

git clone https://github.com/laravel/homestead.git Homestead

…and check­ing out the desired ver­sion (v5.1.0 is the lat­est as of this writing):

cd Homestead
git checkout v5.1.0

Tan­gent: A word about ver­sions. As we men­tioned ear­li­er, Home­stead comes in two parts, the Home­stead Vagrant box, and then the scripts that com­pose Home­stead itself. There’s a sep­a­rate ver­sion num­ber for each. As of this writ­ing, the lat­est ver­sion of the Home­stead Vagrant box is 2.0.0, and the lat­est ver­sion of Home­stead itself is 5.1.0. Just some­thing to keep in mind when updat­ing Home­stead.

Final­ly, the first time we install Home­stead, we also need to ini­tial­ize it from the Homestead direc­to­ry. On Mac/​Linux, we do:

bash init.sh

…and on Win­dows, we do:

init.bat

This cre­ates a Homestead.yaml file in the Homestead/ direc­to­ry. This is the file we’ll be using to con­fig­ure our Home­stead set­up. Here’s a sim­ple exam­ple (edit your Homestead.yaml file to suit your own needs, using this as a guide):

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

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: /Users/andrew/webdev/sites
      to: /home/vagrant/sites
      type: nfs

sites:
    - map: nystudio107.dev
      to: /home/vagrant/sites/nystudio107/public

    - map: craft3.dev
      to: /home/vagrant/sites/craft3/public

databases:
    - nystudio
    - craft3

variables:
    - key: APP_ENV
      value: local

# blackfire:
#     - id: foo
#       token: bar
#       client-id: foo
#       client-token: bar

# ports:
#     - send: 93000
#       to: 9300
#     - send: 7777
#       to: 777
#       protocol: udp

What this will do is pro­vi­sion our VM to have 2048mb of mem­o­ry, and use 1 vir­tu­al CPU. A decent rule of thumb is to use 1/​8th of your com­put­er’s RAM to ded­i­cate to the VM.

We’re using mariadb instead of mysql because it does­n’t have the annoy­ing issue with Craft CMS 2.x that MySQL 5.7 does. Mari­aDB does­n’t whine about Warn­ing: Using a pass­word on the com­mand line inter­face can be inse­cure, and it’s a more active codebase.

Don’t wor­ry, Mari­aDB a 100% drop-in replace­ment for MySQL, and it’s 100% com­pat­i­ble (it’s a fork of the same code­base, by the orig­i­nal author of MySQL). If for some rea­son you real­ly don’t want to use Mari­aDB, just omit this line, and it’ll use MySQL by default.

folders allows you to map direc­to­ries from your com­put­er to your VM. This lets you use native edi­tors like Sub­lime or Php­Storm to edit your code, while also allow­ing the VM to access the files as well.

Remem­ber, the VM is effec­tive­ly a sep­a­rate com­put­er, so this direc­to­ry map­ping is a bridge between the two. So you can edit the same files either on your com­put­er, or in the VM. A key set­ting is to use nfs as the type because its a more per­for­mant way to do this file sharing/​syncing.

sites lets you set up map­pings from a domain name to a direc­to­ry on the VM where the web­site lives. You can add as many as you want in the same VM.

databases lets you tell Home­stead to cre­ate the mysql data­bas­es for you. Again, you can have as many data­bas­es as you like in the same VM.

Then we need to tell our com­put­er where to find these sites by them to our hosts file, which is at /etc/hosts on Mac/​Linux, and at C:\Windows\System32\drivers\etc\hosts on Windows:

192.168.10.10 nystudio107.dev
192.168.10.10 craft3.dev

The eas­i­est way to edit the hosts file on a Mac is just doing: sudo nano /etc/hosts which will bring up a very sim­ple edi­tor. Since this is a sys­tem file, you’ll need to enter your admin pass­word to edit it.

On Win­dows, you sim­i­lar­ly need to edit the hosts file with admin rights. For exam­ple, run Notepad with right click > run as admin and then edit the hosts file.

If you get tired of edit­ing your hosts file man­u­al­ly, you can always use the host­sup­dater Vagrant plu­g­in to do it for you.

Final­ly, let’s do a lit­tle bit of set­up that isn’t strict­ly nec­es­sary, but it’ll make your dai­ly life with Home­stead a lot nicer.

Home­stead is a spe­cif­ic type of Vagrant box; so we could use the stan­dard Vagrant com­mands when work­ing with our Home­stead box. But it’s much more con­ve­nient to set up a com­mand that works specif­i­cal­ly with our Home­stead environment.

On the Mac do this to edit your Bash pro­file: nano ~/.bash_profile and add this to the end of it:

function homestead() {
    ( cd ~/Homestead && vagrant $* )
}

Make sure to tweak the ~/Homestead path in the func­tion to the loca­tion of your actu­al Home­stead installation.

While you’re in there, if you want the com­mand line prompt to tell you what git repo & branch you’re cur­rent­ly in, add this to the end of your ~/.bash_profile too:

parse_git_branch() {
     git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \[\033[32m\]\w\[\033[33m\]\$(parse_git_branch)\[\033[00m\] $ "

You’ll have to close your Ter­mi­nal win­dow and re-open it for the changes to your ~/.bash_profile to take effect, so do that now.

On Win­dows, cre­ate a homestead.bat batch file any­where on your machine with the fol­low­ing contents:

@echo off

set cwd=%cd%
set homesteadVagrant=C:\Homestead

cd /d %homesteadVagrant% && vagrant %*
cd /d %cwd%

set cwd=
set homesteadVagrant=

Make sure to tweak the exam­ple C:\Homestead path in the script to the actu­al loca­tion of your Home­stead instal­la­tion. After cre­at­ing the file, add the file loca­tion to your PATH

There’s plen­ty more you can do with Home­stead, includ­ing installing it via Com­pos­er on a per-project basis, and more. Check out the Home­stead Doc­u­men­ta­tion for fur­ther details.

Link Ladies & Gentlemen, start your engines

Phew! That was a lot of set­up work, but thank­ful­ly we only have to do it once. Let’s fire up our VM! Type:

homestead up

What actu­al­ly hap­pens is the homestead com­mand changes the cur­rent work­ing to where we installed Home­stead, and then maps the rest of the argu­ments to vagrant because of the com­mand we set up earlier.

The way Vagrant works is that if there is a Vagrantfile in the cur­rent work­ing direc­to­ry when you exe­cute the vagrant com­mand, it assumes you want to work with that VM, and it uses it.

So set­ting up that homestead com­mand saved us from hav­ing to switch to the Homestead/ direc­to­ry (or know the Vagrant machine ID) each time we want to do some­thing with it. That’s all.

The first time you do homestead up it’ll take a bit of time, and you will have to enter your admin pass­word to allow the nfs direc­to­ry map­ping to work.

Smooth Sailing

After that, though, it’s smooth sail­ing. I gen­er­al­ly just leave my VM run­ning all the time, since I use it every day, and it has very lit­tle CPU/​battery impact when it’s just idling in the background.

I set it up so that every project I work on lives in the same VM. Spin­ning up a new project just involves adding the appro­pri­ate lines to the sites and databases in the Homestead.yaml file, adding the domain name to the hosts file, and then pro­vi­sion­ing the VM by doing:

homestead reload --provision

Don’t wor­ry, nei­ther homestead reload nor homestead reload --provision will affect your files or data­bas­es stored on your VM.

All of the data­bas­es that Home­stead cre­ates for you have the fol­low­ing credentials:

  • User: homestead
  • Pass­word: secret

So you’ll want to enter that into your mul­ti-envi­ron­ment con­fig so that you can access your data­base. By far the eas­i­est way to pull your pro­duc­tion data­base down is to do so via Craft-Scripts, as dis­cussed in the Data­base & Asset Sync­ing Between Envi­ron­ments in Craft CMS article.

If you want to access your web­site that’s run­ning from your VM, just put the domain name in your web brows­er, and away you go, e.g.: nystudio107.dev

The web­sites that you spec­i­fied via sites in the Homestead.yaml file result in the cor­re­spond­ing Nginx .conf files for the vir­tu­al hosts in /etc/nginx/sites-available (and a sym­link in /etc/nginx/sites-enabled). You can edit them as you see fit, but they will be reset if you do a homestead up --provision or homestead reload --provision.

If you want to ssh into your VM, just type:

homestead ssh

…and you’re in! No pass­words or any­thing. It’s a real Lin­ux box, run­ning Ubun­tu 16.04 (at the time of this writ­ing), so you can install what­ev­er you like.

One thing you’re going to need to install if you’re run­ning Craft 2.x is the mycrypt pack­age for PHP. mycrypt is dep­re­cat­ed as of PHP 7.1 (though it still works), and Craft 3.x does­n’t use it, but we need this lega­cy pack­age for Craft 2.x. So let’s install it. 

While we’re at it, let’s install Imagemag­ick as well, for doing our image trans­forms and such. Home­stead comes with GD installed by default, but we can eas­i­ly add Imagemag­ick too. From inside of your VM, sim­ply do:

sudo apt-get install php7.1-mcrypt php-imagick

Impor­tant: If, when installing things, it ever asks you whether you want to replace an exist­ing .conf file, always say No (or just hit the Return key, which defaults to the safest option).

You can install oth­er stuff, too!

Let’s say you want to play around with using .webp images as per the Cre­at­ing Opti­mized Images in Craft CMS arti­cle; just install cwebp on your VM via:

sudo apt-get install webp

…and away you go. If you want to edit your files to, you know, actu­al­ly do some devel­op­ment work, just do that how­ev­er you nor­mal­ly would.

The files are auto­mat­i­cal­ly synced between your com­put­er and your VM. Edit them in Sub­lime or Php­Storm on your com­put­er. Edit them in nano or vim on your VM. Home­stead does­n’t care.

If you do plan to use Php­Storm for local devel­op­ment, check out the Using Php­Storm with Vagrant / Home­stead arti­cle for how to set that up.

Link Homestead Like a Pro

Now that we have Home­stead up and run­ning, here are a few tips I’ve found that can make it real­ly sing. You don’t have to do any of these things, they are com­plete­ly option­al, but some will make your life on the trail much easier.

American Gothic Homestead

We’re already using nfs for our direc­to­ry map­ping, which is great, because oth­er­wise Vir­tu­al­Box can be pret­ty slow at sync­ing files. There is, how­ev­er, one annoy­ing side-effect, which is that all of your shared files will look like this:

vagrant@homestead /htdocs/nystudio107 (develop) $ ls -al gulpfile.js
-rw-r--r-- 1 501 dialout 11269 Feb 15 04:51 gulpfile.js

What’s going on here is that it’s using the UID and GID from your com­put­er in the VM; and it has dif­fer­ent users and groups than your com­put­er does. If you’re unfa­mil­iar with Unix users, groups, and per­mis­sions, check out the Hard­en­ing Craft CMS Per­mis­sions arti­cle for a primer.

So in this case, there’s no user with the UID of 501 in the VM, and the staff GID on my com­put­er hap­pens to be the GID of the dialout user on my VM.

While this is mild­ly annoy­ing to look at, it can become a real prob­lem with per­mis­sions some­times. So let’s fix it. To do so, we’ll use the vagrant-bindfs Vagrant plu­g­in; just install it on your com­put­er via:

vagrant plugin install vagrant-bindfs

Home­stead will auto­mat­i­cal­ly use this Vagrant plu­g­in if it is present, so there’s no need to alter your Vagrantfile. Then reload your VM con­fig with:

homestead reload

…and all will be well with the universe:

vagrant@homestead /htdocs/nystudio107 (develop) $ ls -al gulpfile.js
-rw-r--r-- 1 vagrant vagrant 11269 Feb 15 04:51 gulpfile.js

Next up, there’s a handy shell script in the Homestead/ fold­er called after.sh. This script is exe­cut­ed after Home­stead has fin­ished pro­vi­sion­ing the VM, so you can add what­ev­er you want to it, and it’ll be exe­cut­ed after a homestead up --provision or homestead reload --provision.

As a for-instance, I use cus­tomized ver­sions of the Nginx .conf files for my web­sites, set up via Nginx-Craft. These nor­mal­ly would get reset to their defaults after a homestead up --provision or homestead reload --provision. so we can stash the cus­tomized ver­sions in the setup/sites direc­to­ry inside the Homestead/ fold­er, and restore them via after.sh:

# -- Copy over customized nginx configs
# As per: https://laracasts.com/discuss/channels/requests/homestead-provision-deletes-custom-nginx-settings

# define your sites config directory located on your host machine
SITES=/home/vagrant/setup/sites/*

# copy every site file from /home/vagrant/setup/sites/ to your Nginx sites-available folder
yes | sudo cp -rf $SITES /etc/nginx/sites-available

# enable each site by creating a symbolic link to each file
for p in $SITES
do
    FILE=$(basename $p)
    sudo ln -s /etc/nginx/sites-available/$FILE /etc/nginx/sites-enabled/
done

# restart the nginx service
sudo service nginx restart

We’ll also need to add an addi­tion­al direc­to­ry to our folders in Homestead.yaml map­ping too:

- map: /Users/andrew/Homestead/setup
      to: /home/vagrant/setup
      type: nfs

Make sure you change the first path to point to your Homestead/setup directory.

Next, let’s make some tweaks to our nfs mounts to speed them up when deal­ing with lots of files (such as git repos, node_​modules fold­ers, etc.). Add this to the bot­tom of your Vagrant file:

# Speed up NFS as per: https://www.jverdeyen.be/vagrant/speedup-vagrant-nfs/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    # …
    config.vm.synced_folder "/Users/andrew/webdev/sites", "/home/vagrant/sites", type: "nfs",  mount_options: ['rw', 'vers=3', 'tcp', 'fsc' ,'actimeo=2']
end

Change the paths to be what­ev­er you set your folders to be in your Homestead.yaml file. Note that the first direc­to­ry is the direc­to­ry on your com­put­er, the sec­ond direc­to­ry is the direc­to­ry in your VM. Then reload your VM with:

homestead reload

One final tip relat­ed to per­for­mance, here are some tweaks you can make by adding this to the bot­tom of your Vagrantfile:

# As per https://www.mkwd.net/improve-vagrant-performance/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    # …
    config.vm.provider "virtualbox" do |v|
        # change the network card hardware for better performance
        v.customize ["modifyvm", :id, "--nictype1", "virtio" ]
        v.customize ["modifyvm", :id, "--nictype2", "virtio" ]

        # enable IO APIC so that the virtual machine can make use of the additional cores
        v.customize ["modifyvm", :id, "--ioapic", "on"]
    end
end

# Speed up VirtualBox i/o as per: https://joeshaw.org/terrible-vagrant-virtualbox-performance-on-mac-os-x/
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
    # …
    config.vm.provider "virtualbox" do |v|
        v.customize [
            "storagectl", :id,
            "--name", "SATA Controller",
            "--hostiocache", "on"
        ]
    end
end

Then restart your VM with:

homestead reload

Link So What’s the Bad News?

So what are the down­sides to using a Home­stead VM? If you’ve read this far, you’re aware that there’s some set­up work involved. But giv­en that this is a one-time thing, and it installs mod­ern ver­sions of every­thing you’ll need in one shot, I haven’t found this to be burdensome.

Pick an after­noon, get a cup of cof­fee, and spend a lit­tle upfront time mak­ing the rest of your work­ing life better.

Cup Of Coffee

The oth­er down­side to a VM is that it can be slow­er than if you use native” local devel­op­ment envi­ron­ments such as Valet, Mamp, or what have you.

These native” tools install the devel­op­ment envi­ron­ment on your com­put­er itself, so there’s no VM lay­er to go through. I’ve found that the con­ve­nience and func­tion­al­i­ty offered by an actu­al VM is worth it; not to men­tion the time saved by hav­ing it match your pro­duc­tion envi­ron­ment, and not hav­ing to tin­ker around with some odd­ball setup. 

In gen­er­al, local devel­op­ment para­dox­i­cal­ly can often be slow­er than your pro­duc­tion serv­er regard­less of what tool you use. That’s because you’re run­ning things like XDe­bug, dev­Mode is on, templateCaching is off, and in gen­er­al things are set up for development/​debugging rather than performance.

Your mileage, of course, may vary. Use what­ev­er tool works; half of the bat­tle is just the fact that you’re using some­thing for local development.

Tool up. Be awesome.