Vagrant - NFS shared folders for Mac/Linux hosts, Samba shares for Windows

[Edit: I'm not using rsync shared folders (a new feature in 1.5+) instead of SMB/NFS - please see this post for more info: rsync in Vagrant 1.5 improves file performance and Windows usage].

[Edit 2: Some people have reported success using the vagrant-winnfsd plugin to use NFS in Windows.]

I've been using Vagrant to provision local development and testing VMs for a couple years, and on my Mac, NFS shared folders (which are supported natively by VirtualBox) work great; they're many, many times faster than native shared folders. To set up an NFS share in your Vagrantfile, just make sure the nfs-utils package is installed on the managed VM, and add the following:

    config.vm.synced_folder "~/Sites/shared", "/shared",
      :nfs => !is_windows,
      id: "shared"

Note: See JJG-Ansible-Windows to see how you can get the is_windows variable.

Regular shared folders (just like above, but without the :nfs option) work well if you just need to access a file or two from time to time within the VM, but are abysmal for any file operation performance—doubly so if you're trying to run any typical PHP application (like Drupal or Wordpress) from within the shared folder; the VM needs to access hundreds of files per page request, and slow individual file access makes the overall operation abysmally slow! (For more on VM filesystem performance, see Mitchell Hashimoto's excellent post Comparing Filesystem Performance in Virtual Machines).

On Windows, NFS is not really an option; you might be able to find hackish ways to get NFS working (like this or this), but it's not worth the effort at this point in time. Additionally, I investigated using a Windows shared folder on your PC, and connecting to it by mounting it with samba on the VM, but doing that resulted in worse performance than VirtualBox's native shared folder support!

VirtualBox shared folder performance with Vagrant - samba NFS native and virtualbox shares
Your results may vary. This was unscientific, only two runs after a cache clear using each method.

The best solution for performance (on Windows) is to have your code live within the VM's disk image—if you do this, VirtualBox's filesystem caching will give a nice speed boost, and performance should be close to native. Unfortunately, if your code lives within the VM, you have to log into the VM to access the code, or you have to use some sort of SFTP utility to manage files. Definitely not ideal.

For the benefit of my co-workers who are forced to use Windows at work, I decided to set up a Samba share within the VM to which the Windows host could connect via a mapped drive (making file access/management work like a native Windows filesystem, albeit with slightly slower-than-native access from the Windows side. For our development workflow, this made our Drupal sites load in milliseconds instead of many seconds, which sped up our development greatly.

Here's how to set up your VM (these instructions assume CentOS, but setup would be similar for other Linux flavors) to create a samba share that can be mounted from Windows (or Mac/Linux... but like I said earlier, I like keeping my Mac set up with NFS, since that allows the best of both worlds):

  1. Install samba: sudo yum -y install samba samba-common cifs-utils
  2. Start samba and make it run on boot: sudo service smb start, then sudo chkconfig smb on
  3. Add something like the following to the bottom of /etc/samba/smb.conf, then restart samba (sudo service smb restart).
    [shared]
    path = /shared
    public = yes
    browseable = yes
    writable = yes
    guest ok = yes
    guest only = yes
    guest account = root

Security note/warning: These samba share settings are highly insecure. The only reason I use these settings is so the windows users don't need to use a username/password, or worry about file permissions (much) when operating on files within the share via Windows. If you aren't using private VM networking, or are doing anything on a non-local server, you should use more secure settings.

If you have a restrictive firewall on the VM (some people don't worry about such things for development VMs...), you'll also need to open ports 137, 138, 139, and 445 (make note of the UDP/TCP differences below):

sudo iptables -A INPUT -m state --state NEW -p udp --dport 137 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p udp --dport 138 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 139 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p tcp --dport 445 -j ACCEPT
sudo iptables -A INPUT -m state --state NEW -p udp --dport 445 -j ACCEPT

Once samba is restarted and the firewall is open, you can map a network drive from Windows Explorer, using the path \\[ip-address-of-vm]\shared. You won't need to enter a username or password, it should just open up the drive and allow you to use whatever code editor/file management you normally use in Windows.

If you want to map the drive on a Mac (though, as I said earlier, NFS is probably a better option for Mac users), go to the Finder and press Command-K (Go > Connect to Server...), and connect to Server Address smb://[ip-address-of-vm]/shared.

As I said earlier, accessing the samba share in Mac OS X / Windows incurs a little performance penalty (doing git operations/full search on a large directory will be slower), but it's well worth the price to allow Windows users to load pages in a reasonable amount of time!

Comments

Great write-up! This confirms everything that I was afraid of with using Vagrant's synced folders for Symfony2 development on Windows. Your solution is much better than just dealing with the slow page load times.

My goal is to have Puppet setup the guest samba share during provisioning. And then have Vagrant auto-map a Windows drive letter to the share. I know the Puppet part is possible, but I'm unsure about Vagrant being able to map a network drive. We shall see!

Is there any way to disable shared folders completely ? I tried a suggestion I found somewhere to add a
config.vm.synced_folder '../data', '/vagrant_data', disabled: true
to the config file but apparently it's ignoring it.
Thanks :-)