[Debian-Sarge] Tunneling NFS over SSH

Last Update: 27-09-2006 @ ~21:40
Reason: Added fixed ports for nfs server to make life easy :)


The goal of this howto is building a NFS server that works on a SSH tunnel. This way all traffic between your hosts and the file server is encrypted and thus more secure :)
Normally you should enter a password every time you try to establish a SSH connection but since we could be mounting at bootup we will use ssh-keygen to create a keypair so we can login without entering a password. We will, however, limit that login session to executing just 1 command ;)
We will use a new clean Debian Sarge install to begin with.

In this howto I will use the fictional domain "linux.lan".

Installing Software

We will start with the NFS server.

apt-get -y install nfs-kernel-server

First configure it to run on fixed ports, this will make building a firewall much easier but equally important it aids in simpler client mounts.

echo "STATDOPTS=--port 2231" > /etc/default/nfs-common
echo "options lockd nlm_udpport=2232 nlm_tcpport=2232" >> /etc/modules.conf
echo "RPCNFSDCOUNT=8 RPCMOUNTDOPTS='-p 2233'" > /etc/default/nfs-kernel-server

Thats it, now we can use port 2233 later on when we mount the shares :) check if it worked with rpcinfo -p. If nlockmgr still uses random ports it is a compiled in setting. Configure this in grub/lilo as kernel parameters:
"lockd.udpport=2232 lockd.tcpport=2232".

Create a new user called sleeper to use for setting up the ssh tunnel from other hosts. We will generate a key for this account so you can login with a keyfile instead of typing your password everytime. The account will also be restricted to execute 'sleep' trough this way. Other commands will simply fail.

adduser sleeper
su sleeper

Now switch over to a client that will use our fileserver.
First we need a key:

ssh-keygen -t rsa -b 2048

(use defaults and NO passphrase!)

Now copy the .pub file to the homedir of sleeper on the server:

scp -P 12345 ~/.ssh/id_rsa.pub sleeper@

Now back to the server: As the 'sleeper' user we need to configure/install the key:

mkdir ~/.ssh
cd ~/.ssh
mv ../id_rsa.pub ./id_rsa.pub
cat id_rsa.pub >> authorized_keys
chmod 600 authorized_keys

Add this to the beginning of authorized_keys (before ssh-rsa [...]):
client="client.linux.lan",command="/bin/sleep 600d"
substitute "client" with the correct hostname of your client, or use ip numbers.
(but make sure every entry stays on 1 line!)

Every client that needs access to the fileserver needs to store his security data (from the id_rsa.pub file) in the authorized_keys file, so you should repeat this for every host.

Mounting NFS over SSH on your clients

Issue these commands to start the tunnels for nfs and mountd:
(syntax: ssh -f -c encyption -L localport:nfsserver:nfsport -l username nfsserver remotecommand)
Also note that the portnumber for mountd is different with every restart of the NFS server... Keep that in mind.

ssh -f -i /root/.ssh/id_rsa -c blowfish -L 61001: -l sleeper sleep 600d
ssh -f -i /root/.ssh/id_rsa -c blowfish -L 62001: -l sleeper sleep 600d

This creates a connection that will stay alive for almost 2 years... :)
Now edit your fstab and mount:

echo "localhost:/export/data /mnt nfs tcp,rsize=8192,wsize=8192,intr,rw,bg,nosuid,port=61001,mountport=62001,noauto" >> /etc/fstab mount /mnt

Ofcourse we need some mountable folders (shares) defined on the NFS server:

mkdir /export
mkdir /export/data
mkdir /export/www-virtual
mkdir /export/www-conf
mkdir /export/mail-virtual
mkdir /export/mail-conf

Add them to /etc/exports:
Notice the ip address is the nfs server itself? Its because youll mount them from localhost when you have established the ssh tunnel.

Some security settings since we dont want anyone from outside our network to access the server:

echo "portmap: ALL" > /etc/hosts.deny
echo "portmap:" > /etc/hosts.allow

Restart NFS:

/etc/init.d/nfs-kernel-server restart

Thats it ! You can now mount the filesystem on your clients without the need to supply a password. And ofcourse all traffic will be encrypted :)
Share this page:

Suggested articles

10 Comment(s)

Add comment


From: Chadversary

Thank you. I was attempting to have my home server perpetually mounted onto a roaming laptop. Sshfs was insufficient for the task at hand, and this was exactly what I was looking for.

From: linportal

While this is all useful information, it's quite complex to set up. There's much easier solution if you want secure (encrypted) remote file access and it's called sshfs. Quick and simple setup, you'll find it useful, I'm sure.


I would advise using the -N option of recent ssh versions to keep the connection open without running a command.
With this option you can set the sleeper user's shell to /bin/false. Thereby restricting command execution even further.

Another great util for this setup is autossh, which automatically reconnects ssh after a connection is lost.


I agree with comments that this is a bit too involved and that sshfs makes a great alternative for a remote solution.

From: Hans Ekbrand

Claiming that sshfs is more useful is inaccurate and IMHO not a way to thank the author of this excellent HOWTO.

Try, as root,

# mknod foo c 1 3

in a sshfs-mounted directory before you say that sshfs is "more useful".

That being said, I love sshfs when operating on ordinary files.

From: TheFatherMind

In the log I was seeing....

refused mount request from for /export/data (/export/data): illegal port 33146

I fixed this by adding "insecure" into the /etc/exports argument list...


Note I bound it to localhost ( because this share was strictly for piping there was no local area network.

From: Hans Ekbrand

Thanks TheFatherMind for that additional hint. On Lenny, "insecure" is needed.

From: Nicola Tuveri

You can read the details here: http://www.tldp.org/HOWTO/NFS-HOWTO/security.html#NFS-SSH
The short version is that doing this any user that is able to connect to the server with ssh can tunnel NFS to a computer where she/he has root permissions, and from there she/he can access the exported filesystem spoofing UIDs/GIDs and overcoming permissions.

From: Strod

There is a fundamental difference. In the webpage you referenced, they are establishing the ssh tunnels with these commands:

     ssh root@ -L 250:localhost:2049  -f sleep 60m

   ssh root@ -L 251:localhost:32767 -f sleep 60m

In this page, they are using:

ssh -f -i /root/.ssh/id_rsa -c blowfish -L 61001: -l sleeper sleep 600d 

ssh -f -i /root/.ssh/id_rsa -c blowfish -L 62001: -l sleeper sleep 600d 

 The difference I'm pointing out is that in the above commands the ssh tunnels are logging into the server as root, while in the latter ones they are doing it as the very restricted user "sleeper".

So in the second case the privileges you have on the shares are limited to what sleeper can do even if you are root on the client. (And yes, I have tested this).

From: psych787

After following the above howto, something like this may be more suitable for everyday use

 FSTAB Entry:

localhost:/ /mount/directory nfs4 retrans=3,timeo=250,retry=0,soft,tcp,rsize=8192,wsize=8192,rw,fg,port=61001,mountport=62001,noauto

 Mount Command:

kdesu -c "ssh user@machine -i /path/to/keyfile -c aes256-cbc -f -o ExitOnForwardFailure=yes -L 61001: -L 62001: -N ; mount /mount/directory 2>&1 | xmessage -file -"

UnMount Command:

kdesu -c "umount -f /mount/directory ; sleep 0.1 ; umount -f /mount/directory ; sleep 0.1 ; umount -f /mount/directory ; sleep 0.4 ; umount -f /mount/directory ; sleep 0.1 ;  umount -f -l /mount/directory | xmessage -file -"