On some projects we have a mixture of OSX and Windows development machines. Normally, this isn’t a problem because we develop inside a VM so we don’t need to worry about inconstancies between our development environments and production. The issue is that OSX machines do much better if you’re using nfs instead of the virtualbox provider. Unfortunately, Windows doesn’t support NFS natively so we need to have some way to determine if the machine is running on an OSX host.

Add the following line to the very bottom of your Vagrantfile:

module OS
  def OS.mac?
     (/darwin/ =~ RUBY_PLATFORM) != nil
  end
end 

This allows us to quickly determine if the host is OSX (darwin) or not by using a simple if statement within our Vagrantfile:

if (OS.mac?)
  // mac specific code here
else
  // Windows specific code here
end

Now we can change our synced_folder from what it normally looks like:

v.vm.synced_folder "./", "/var/www", id: "vagrant-root"

to:

if (OS.mac?)
  v.vm.synced_folder "./", "/var/www", id: "vagrant-root", :create=>true, :nfs=>true
else
  v.vm.synced_folder "./", "/var/www", id: "vagrant-root"
end

You can now vagrant up and work in your development VM with a speed increase (my Symfony setup takes about 10% of the time it did as before).

The issue we run into with this system is when we try to run our provisioning script inside our VM:

==> devel: /tmp/vagrant-shell: line 1: /var/www/ansible/provision.sh: Permission denied
The SSH command responded with a non-zero exit status. Vagrant
assumes that this means the command failed. The output for this command
should be in the log above. Please read the output to determine what
went wrong.

The issue stems from the fact that nfs uses the permissions from OSX so you end up with permissions that MIGHT look like this:

drwxr-xr-x 1 vagrant vagrant     544 Aug 19 15:12 ansible
drwxr-xr-x 1 vagrant vagrant     374 Aug 19 15:12 application
drwxr-xr-x 1 vagrant vagrant     136 Aug 19 15:12 assets
-rwxr-xr-x 1 vagrant vagrant     116 Aug 19 15:12 composer.json
-rw-r--r-- 1 vagrant vagrant   17936 Aug 19 15:12 composer.lock
-rwxr-xr-x 1 vagrant vagrant 1075456 Aug 19 15:12 composer.phar
drwxr-xr-x 1 vagrant vagrant     136 Aug 19 15:12 data
drwxr-xr-x 1 vagrant vagrant     306 Aug 19 15:12 docs
drwxr-xr-x 1 vagrant vagrant     340 Aug 19 15:12 library
drwxr-xr-x 1 vagrant vagrant     544 Aug 19 15:12 public
-rw-r--r-- 1 vagrant vagrant      28 Aug 19 15:12 README.md
drwxr-xr-x 1 vagrant vagrant     238 Aug 19 15:12 schema
drwxr-xr-x 1 vagrant vagrant     272 Aug 19 15:12 scripts
-rwxr-xr-x 1 vagrant vagrant      91 Aug 19 15:12 search.sh
drwxr-xr-x 1 vagrant vagrant     374 Aug 19 15:12 tests
-rw-r--r-- 1 vagrant vagrant     747 Aug 19 15:12 Vagrantfile
drwxr-xr-x 1 vagrant vagrant     102 Aug 19 15:12 vendor

This can actually be different depending on when your account was created and what your default permissions are.

The quick fix is to run chmod -R 777 . in your project directory but if new files are added you have to run that command over and over again (and we have). To fix this problem where going to use vagrant-bindfs which is described by it’s GitHub page as:

A Vagrant plugin to automate bindfs mount in the VM. This allow you to change owner, group and permissions on files and, for example, work around NFS share permissions issues.

Installation is simple:

vagrant plugin install vagrant-bindfs

Then we just need to change our mount configuration to look like the following:

if (OS.mac?)
  devel.vm.synced_folder "./", "/vagrant-nfs", id: "vagrant-root", :create=>true, :nfs=>true
  devel.bindfs.bind_folder "/vagrant-nfs", "/var/www",
    perms: "u=rwx:g=rwx:o=rwx",
    create_as_user:true
else
  devel.vm.synced_folder "./", "/var/www", id: "vagrant-root"
end

To explain this a little bit we’re mounting our project at /vagrant-nfs using NFS. And then we’re using bindfs to remap the /vagrant-nfs directory to /var/www/ (where we tell Apache to look for our repo) with all the permissions set.