Persistent Remote Filesystems With MacFUSE and sshfs
This article looks at a simple solution to a minor, but very annoying problem -- how to keep remote filesystems mounted across network outages, sleeps and reboots, with no input from the user. The discussion is tied to Apple's OS X operating system, but the principles apply to just about anything with a unix brain.The Trouble With Samba
One can mount remote filesystems all sorts of ways these days -- samba probably being the most common, at least in mixed operating environments. But to my mind, samba has some drawbacks:It's Big: Samba is a very big, very flexible package, ideal for file-sharing solutions in enterprise environments. But what if you're not an enterprise? What if you're just a home user with a simple consumer storage wotsit attached to your home network? Configuration and management of samba servers can be a pain in the ass.
It's
SlowNot-So-Fast: In part because of the flexibility that samba provides, it can often be difficult to tune a samba server for maximum performance, especially when you have samba clients with various operating systems, each requiring their own special tweaks. The result? Samba servers are reliable, but throughput suffers.It Re-Invents The Wheel: I'm a big fan of single-solution solutions. In other words, I prefer using one piece of software to solve multiple problems. It cuts down on administration time, limits exposure to security vulnerabilities, upgrade problems, and so forth. And in this case, the alternative (ssh) is ubiquitous, so why not use it?
The Client Perspective
Apple makes mounting samba fileshares pretty simple: hit command-K in the Finder and enter the server location, and voila. Keychain handles your authentication, if any, and for the most part, it just works. However, if (like me) you're on a laptop, and frequently moving around from home to random public wifi access points, you'll quickly get tired of the "Server Connection Interrupted" dialog you get whenever you change APs (or reconnect to the flakey one at your local café). And it also makes the software that relies on those server connections being present quite unhappy; iTunes in particular really doesn't like it when the network share that hosts its library file disappears.What we really need is a way to keep those remote filesystems mounted that can survive those network outages, and, ideally, know if it's at home or not so it can keep traffic on the local network for better performance. Fortunately, most of the work has been done for us.
Enter Google
Google has released MacFUSE, an implementation of the FUSE specification for OS X. While this alone is excellent, they've also helpfully released an sshfs (that's SSH Filesystem) implementation to go along with it. This allows us to use ssh, something we've got already in OS X, to mount a remote filesystem just like we do with samba. The key difference here is sshfs will detect network outages and remount the remote filesystem when networking is restored. How awesome is that? Very awesome. [ Note: There are other implementations of sshfs for OS X floating around; having tried a couple of them, I have found google's to be the most stable, feature-rich and well-documented. ]The Set-Up
To make our network shares completely transparent, we'll first need to configure ssh on the remote server to allow us to log in without a password. This is a piece of cake. On our OS X client computer, we'll open a terminal window and type this:Now we can test our login, and we should not longer be prompted for a password:
Install MacFUSE and sshfs
Now that ssh is ready, we can install the MacFUSE and sshfs packages. You can get them from Google here. Be sure to poke through the FAQ, as there are many helpful tidbits to be found there. Once we've got sshfs installed, we can move straight on to:The Mount Script
#!/bin/sh
# where to find the airport utility
AIRPORT=/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport
# the sshfs executable
SSHFS=/Applications/sshfs.app/Contents/Resources/sshfs-static-10.5
# Your home network's SSID, signalling that internal hostnames should resolve
HOMESSID=automagick
# function remount( mount_point, user, local_host, remote_host, path, volume_name )
#
# Uses sshfs to mount a remote filesystem, using either internal or external hostnames
# depending on what SSID airport is reporting.
#
function remount() {
VOLNAME=$1
USER=$2
LOCAL=$3
REMOTE=$4
REMOTEPATH=$5
TARGET="/Volumes/$VOLNAME"
if [ -d $TARGET ]
then
if [ "`/sbin/mount|/usr/bin/grep $TARGET`" ]
then
/usr/bin/hdiutil eject $TARGET
sleep 1
else
/bin/rmdir $TARGET
fi
fi
/bin/mkdir $TARGET
SSID=`$AIRPORT --getinfo| /usr/bin/sed -ne 's/^.*[[:space:]]SSID:[[:space:]]*\(.*\)/\1/p'`
if [ $SSID != "$HOMESSID" ]
then
HOST=$REMOTE
else
HOST=$LOCAL
fi
# XXX: We cannot use 'noappledouble' here if we want to host an iTunes library!
$SSHFS $USER@$HOST:$REMOTEPATH $TARGET -oreconnect,noappledouble,volname=$VOLNAME
}
remount 'automagick.us' 'greg' 'fileserv' 'example.automagick.us' '/usr/local/www'
You can download this script here. Save it somewhere handy, like /usr/bin, or in your Applications folder.
So what's going on here? Let's take it line-by-line. First, some configuration stuff:
# where to find the airport utility AIRPORT=/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport # the sshfs executable SSHFS=/Applications/sshfs.app/Contents/Resources/sshfs-static-10.5 # Your home network's SSID, signaling that internal hostnames should resolve HOMESSID=automagickThe AIRPORT and SSHFS variables are set to the location of the two command-line utilities our script will require. The first, airport, is a handy program that comes with Leopard. It displays information about the current state of the wireless networking client; we'll use it to figure out what access point we're connected to when the script runs. The second, SSHFS, is the command-line executable that comes as part of Google's sshfs package (mentioned in the FAQ; see?). Finally, we specify the name of our own access point, so the script will know to connect to the file server with it's internal server name instead of it's fully-qualified domain name when we're at home.
Next comes the remount() function, where most of the magic happens. Briefly, the function will figure out if the remote filesystem is already mounted, unmount it if it is, and prepare a mount point for sshfs to use. After that, it decides whether to use the internal network hostname or the fully-qualified domain name to reach the server. Finally, it uses sshfs to mount the filesystem.
At the bottom of the script is the line that calls the remount() function:A Note About Internal Vs. External Networks
Unfortunately, there's no simple solution for handling when we mount a filesystem at home, and then go out, or vice versa. That's because our location is only determined once -- when the script is run. Fortunately all we have to do is re-run the script when we transition in or out of our home network, and the filesystem will be remounted with the appropriate server name for our new location. [Note: There is a way to handle this situation as well; watch for updates.]Putting It All Together
So now we have a script that will mount our website's directory from our file server, regardless of where we are in the world. All that's left is to run the script. Presuming you saved the script to /usr/bin:So now we never have to mess with remote network shares again. As soon as we log in to our mac, the filesystems we specify at the bottom of our script will connect. If our network goes down, or we move access points, the filesystems will reconnect. And if we're at home, we'll keep all our traffic on our local network, making things even faster. Oh, and all our data is encrypted coming to and from the server.
License
All source code, tools and scripts on http://automagick.us is Copyright © 2007 - 2010 Greg Boyington, and licensed under aCreative Commons Attribution-Share Alike 3.0 United States License, except where otherwise noted.
