"... and no one shall work for money, and no one shall work for fame; But each for the joy of the working, and each, in his separate star, shall draw the thing as he sees it, for the god of things as they are"



Installing an NFS Client on a Raspberry Pi 2


This page describes how to configure the Raspberry Pi 2 as an NFS Client and a remote Linux PC as an NFS Server so that the contents of a directory on the remote Linux box are visible on the Raspberry Pi. This page is part of a series of web pages which describe how to install C# and Mono on the Raspberry Pi 2 and also how to configure a useful remote compilation and debugging toolchain for it.

The previous page in this series described the installation and configuration of MonoDevelop on a remote Ubuntu Linux PC. This PC, known in this documentation as the Development PC, will be used to create C# projects and remotely compile them to executable form. The primary purpose of mapping a directory on the Development PC into the Raspberry Pi is to ensure that any executable code created remotely is instantly and automatically available to run on the Raspberry Pi without any user interaction. In short, a pleasant working environment with remote compilation and execution is achieved by creating an executable on the Development PC using a nice IDE and having NFS automatically move that file over to a mapped directory on the Raspberry Pi where it can be run.

The Development PC needs to be able to provide the files in a directory to the Raspberry Pi. This means the Development PC needs to act as an NFS server and the Raspberry Pi needs to be configured as an NFS Client. To set this up I followed (in general) the instructions on these two pages: https://help.ubuntu.com/community/SettingUpNFSHowTo and http://askubuntu.com/questions/8534/share-files-and-printer-between-two-ubuntu-boxes/8573#8573. The specific steps taken are outlined below.

Setting up the Development PC as an NFS Server

Setting up the Ubuntu host (hereinafter referred to as the "Development PC") as an NFS server requires you to be the root user. Rather than prefacing every command by sudo you may wish to just become the root user by issuing the sudo -s command once before starting.

In the examples below, the user on the Development PC is dtree and its home directory is /home/dtree. All projects for the Raspberry Pi created in MonoDevelop are located below the /home/dtree/RBerrySharp/CSharpCode subdirectory. The actual executables generated by MonoDevelop will be much lower in that tree, for example the executable of the HelloWorldTest project is in the location: /home/dtree/RBerrySharp/CSharpCode/HelloWorldTest/bin/Debug/HelloWorldTest.exe.

I have lots of projects and rather than map the bin/Debug directory of each project individually over to the Raspberry Pi I chose to create every project below the CSharpCode directory and then just map the entire directory over to the Raspberry Pi. I then created a small shell script on the Raspberry Pi (discussed later) which I can invoke to run appropriate executable for each project in its location in the CSharpCode tree.

First on the Development PC (as root) we install the required packages...

apt-get install nfs-kernel-server 

Create an export filesystem:

mkdir -p /export/RP2NFS

Make sure the permissions are 777

chmod 777 /export/RP2NFS

Mount the directory we wish to map into the export filesystem

mount --bind /home/dtree/RBerrySharp/CSharpCode /export/RP2NFS

Edit the line in the /etc/default/nfs-kernel-server file to say


Confirm the /etc/idmapd.conf file has the lines

Nobody-User = nobody
Nobody-Group = nogroup

Add the line below to /etc/exports file is IP address of the Raspberry Pi and you can get this by issuing an ipaddr show command on the Raspberry Pi.


Restart the nfs server

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

Set portmap lockdown and deny all in /etc/hosts.deny by adding the line below to that file

rpcbind mountd nfsd statd lockd rquotad : ALL 

Allow a specific IP in /etc/hosts.allow by adding the line below to that file

rpcbind mountd nfsd statd lockd rquotad : 

Restart the nfs server

service nfs-kernel-server restart

edit /etc/fstab so it mounts our filesystem automatically by adding the line

/home/dtree/RBerrySharp/CSharpCode   /export/RP2NFS    none    bind  0  0

At this point the Development PC is prepared to serve the contents of the /home/dtree/RBerrySharp/CSharpCode subdirectory to an NFS client at IP address The next task is to set up an NFS Client on our Raspberry Pi.

Setting up the Raspberry Pi 2 as an NFS Client

The user on the Raspberry Pi is pi and its home directory is /home/pi. We will map the exported CSharpCode directory into our local filesystem in the /home/pi/CSharpCode directory. Once mapped, we will have local access on the Raspberry Pi to all files in the Development PC's /home/dtree/RBerrySharp/CSharpCode subdirectory. This mapped file system will be fully read-write by both parties. Any changes, by either the Development PC or the Raspberry Pi, to the files in this tree will be immediately reflected to the other party by NFS.

Install the nfs client (as root on the Raspberry Pi 2)

apt-get install nfs-common 

Make a mount point for the nfs drive offered from the Development PC

mkdir /home/pi/CSharpCode 

Mount the exported NFS drive. The IP address is the address of the Linux Development PC (configured to use a static IP address)

mount -t nfs -o proto=tcp,port=2049 /home/pi/CSharpCode

We should be good to go. We can test this by running a quick ls -l ~/CSharpCode command to see if the Development PC's files are now present and also by running an exe from a known project which was previously compiled over on the Development PC to see if the remotely compiled files are executable


Unmount the file system. We want this mapped filesystem to automatically mount up when the Raspberry Pi boots.

umount /home/pi/CSharpCode

edit the /etc/fstab so we mount automatically by adding the line   /home/pi/CSharpCode   nfs    auto  0  0

Reboot now to test this


At this point you should be able to create a new project (HelloWorldTest in this example) over on the Development PC, compile it and then switch to the Raspberry Pi and run that projects executable with a command like: mono ~/CSharpCode/HelloWorldTest/HelloWorldTest/bin/Debug/HelloWorldTest.exe. If you cannot do this you should figure out what is going wrong before proceeding to the next step. Any changes on the Development PC should always instantly appear and be executable over on the Raspberry Pi.

Running CSharp Executables On the Mapped Drive with a Shell Script

As mentioned in previous sections, rather than mapping each output directory from the C# projects on the remote Development PC, a entire directory tree with multiple projects was brought over. In order to execute the executable of a remotely compiled project either the current directory has to be changed to a many levels deep subdirectory or the files have to be prefixed with a path before execution. This is rather tedious and so, as a shortcut, I have created a number of shell scripts to do the job for me.

For example a project named RPICSIOTest will have an output directory when mapped onto the Raspberry Pi 2 of /home/pi/CSharpCode/RPICSIOTest/RPICSIOTest/bin/Debug/. I create a file in the CSharpCode subdirectory named runRPICSIOTest which contains the following contents ...

#! /bin/sh

mono /home/pi/CSharpCode/RPICSIOTest/RPICSIOTest/bin/Debug/RPICSIOTest.exe

... and this means that I can run that project executable with a simple command ./runRPICSIOTest. Every project has its own shell script. This may seem like a rather trivial convenience - however in the next page in this series we will implement remote debugging and the command line for that is a bit more complex. You will definitely want to create an equivalent debugRPICSIOTest to initiate the debugging rather than typing in all the command line options each time.


The contents of this web page are provided "as is" without any warranty of any kind and without any claim to accuracy. Please be aware that the information provided may be out-of-date, incomplete, erroneous or simply unsuitable for your purposes. Any use you make of the information is entirely at your discretion and any consequences of that use are entirely your responsibility. All source code is provided under the terms of the MIT License.