====== Raspberry Pi Zero W with the root FS mounted over NFS ======
I like to run my Raspberries with the root FS mounted remotely (eg: over NFS, and this is easy to do when the machine has an ethernet socket and a wired connection.
Doing the same thing over wireless, however, is not so simple, so here's a guide to what you need to do.
**Note**: whether "NFS root over wireless" is a __sensible__ thing to do or not, I don't know until I've been able to try it for a while, so I'll post an update here (and edit this comment) once I've had a chance to try it out in practice.
===== Overview =====
To get the root file system mounted over NFS across a wireless link, you need to do the following things(not necessarily in sequence, but they all have to be in place at the end for the whole thing to work):
- create an initramfs for the Pi Zero to use at boot time
- configure the Pi Zero to boot using the initramfs
* this is necessary so that you can...
- set up wpa_supplicant (in the initramfs) to connect to the wireless network
- ensure that all files necessary for the wireless interface hardware to work are present in the initramfs
- put the root FS image you want to run from onto an NFS server
* (you might need to set up an NFS server too, but that's outside the scope of this discussion - if you need to find out how to set up an NFS server, there are plenty of articles on the Internet to help you)
- configure the Pi Zero to expect its root FS to be on NFS
I was surprised that I couldn't find an article like this already on the Internet, explaining how to do this. There were several helpful documents which either encouraged me to try (suggesting that it was at all possible), or pointed me at different steps in the right direction, but nobody seemed to have written up "how to start from a Pi Zero W and a standard Raspbian image, and end up with an NFS-mounted root FS over wireless". So, here we are.
The instructions assume that you want to end up running [[https://downloads.raspberrypi.org/raspbian_lite_latest|Raspbian Stretch]] on the Pi Zero W.
Some of the articles I found useful along the way were:
* Getting the Raspberry Pi to use an initramfs: https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=10532
* Getting the wireless interface configured from the running initramfs: https://ubuntuforums.org/showthread.php?t=1853554
* Creating an initramfs: https://manpages.debian.org/jessie/initramfs-tools/initramfs-tools.8.en.html
I also found a very interesting article about running a Raspberry Pi Zero without an SD card at all, which I hadn't even believed to be possible: https://dev.webonomic.nl/how-to-run-or-boot-raspbian-on-a-raspberry-pi-zero-without-an-sd-card
Some people have even created Pi Zero clusters, booting Pies without SD cards involved: https://www.raspberrypi.org/forums/viewtopic.php?f=49&t=199994
Those last articles didn't really help with my objective of running root NFS over wireless, but I'm leaving them here as placeholders just in case you (or I, at some later date) find them useful anyway.
**Note** that some of the steps explained below are best run **on** the Raspberry Pi Zero itself (or at least, on a Raspberry Pi running the exact version of Raspbian which you are trying to end up with), so it can be a good start to download [[https://downloads.raspberrypi.org/raspbian_lite_latest|Raspbian]] and copy it to an SD card which you can then boot your Pi Zero from (unless you already have a working Pi Zero, in which case simply use that).
Perform all the following steps as root.
Personally I recommend just doing 'sudo bash' at the start.
So, step by step...
==== Configuring and creating the initramfs ====
Creating an initramfs is very easy under Raspbian, and this is one of the steps best done on the Pi Zero itself.
All the tools you need should already be installed (because they get used whenever you update certain packages on the machine), so you just need to edit the configuration files and then build the initramfs.
=== Configuration files ===
These are found under **/etc/initramfs-tools** and need adjusting or creating as follows:
- Modify **initramfs.conf** to contain:MODULES=netboot (instead of MODULES=most)
BOOT=nfs (instead of BOOT=local)
DEVICE=wlan0
- Modify **modules** and place at the end:brcmfmac
brcmutil
cfg80211
rfkill
- Create **hooks/nfsroot** (you can actually name it anything you like, so long as it's a file under **hooks**) with the content:#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/grep /bin
copy_exec /sbin/lsmod /sbin
copy_exec /sbin/ifconfig /sbin
copy_exec /sbin/wpa_supplicant /sbin
tail -n+4 /etc/wpa_supplicant/wpa_supplicant.conf >${DESTDIR}/etc/wpa_supplicant.conf
cp /lib/firmware/brcm/brcmfmac43430-sdio.txt ${DESTDIR}/lib/firmware/brcm
mkdir -p ${DESTDIR}/var/run/wpa_supplicant
* This step assumes that you already have a file **/etc/wpa_supplicant/wpa_supplicant.conf** on your running system, containing something like:ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="Notwork"
psk=5ec8def3d30ba1487e2308e55fc81cc8ea82253c0fd850f0d2b3d06f81d03014
}
* See my notes on [[.RaspberryZeroW|getting started with the Pi Zero W]] regarding how to create this file, if you need to.
* Create **scripts/nfs-top/wifi** (again, call it whatever you like, so long as it lives in **scripts/nfs-top**):#!/bin/sh
PREREQ="udev"
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
if grep -q splash /proc/cmdline; then
/bin/chvt 1
fi
sleep 3
if grep -q splash /proc/cmdline; then
/sbin/usplash -c &
sleep 1
fi
/sbin/wpa_supplicant -Dwext -iwlan0 -c /etc/wpa_supplicant.conf &
sleep 5
ipconfig wlan0 &
=== Build the initramfs ===
Once the above initramfs configuration files are in place, you can build the initramfs itself with the command:
* update-initramfs -c -k all
The output will be something similar to:update-initramfs: Generating /boot/initrd.img-4.14.62+
W: Possible missing firmware /lib/firmware/brcm/brcmfmac4373-sdio.bin for module brcmfmac
W: Possible missing firmware /lib/firmware/brcm/brcmfmac4356-sdio.bin for module brcmfmac
W: Possible missing firmware /lib/firmware/brcm/brcmfmac43430a0-sdio.bin for module brcmfmac
W: Possible missing firmware /lib/firmware/brcm/brcmfmac43341-sdio.bin for module brcmfmac
W: Possible missing firmware /lib/firmware/brcm/brcmfmac4373.bin for module brcmfmac
The script creates an initramfs file in **/boot** with a name as shown above (which depends on the current kernel at the time you obtained or last upgraded your copy of Raspbian).
That's all there is to building an initramfs - it's quite a complicated thing, but the **update-initramfs** script makes it very simple to build.
**Note**: if you encounter any documentation explaining how to build an **initrd**, walk slowly away and find something more up-to-date. **initrd** was an earlier method of achieving the same thing as **initramfs**, but the tools involved are different, and no current release of Raspbian will use an **initrd**.
The **update-initramfs** script leaves the file in the correct place to be used during the boot process, however you should note the exact filename it tells you it's creating, because you'll need it in the next step.
==== Configure the Pi Zero to load the initramfs during the boot sequence ====
Add the following to the end of **/boot/config.txt** on the SD card you'll be booting the Pi Zero from:# Load an initrd
initramfs initrd.img-4.14.62+ followkernel
Just make sure the filename corresponds to whatever **update-initramfs** created for you above.
That's it.
==== Make the root FS available from an NFS server ====
There are several ways of going about this, but I would recommend:
- Download [[https://downloads.raspberrypi.org/raspbian_lite_latest|Raspbian Stretch]], either onto your NFS server, or onto any machine which can write to the NFS server over a network
- Loopback mount the 'root' partition from the image (you can use kpartx to expose the partitions from inside the image, and just mount the one you want)
- Copy the files in the 'root' partition into a suitable directory which can be exported from the NFS server
If you already have a working Pi Zero W (perhaps with installed and configured applications, which you'd like to keep), then instead of the above:
- Shut down the Pi and remove the SD card
- Put the SD card into your NFS server, or another machine which can write to the NFS server over a network
- Mount the 'root' partition and copy the files from it into a directory which can be exported from the NFS server
Whichever way you go about doing this, __make sure you copy the files with the correct **numeric** User IDs and Group IDs__ (for example, using rsync with the --numeric-ids option). It is essential that the files in the image have the ownerships corresponding to those in /etc/passwd in the Raspberry image, and not those on your NFS server.
Once you've got the files you want in a suitable directory, add it to **/etc/exports** on the NFS server (or however else you configure what your server exposes to its clients):/srv/PiZeroW 192.168.0.0/16(rw,async,no_subtree_check,no_root_squash,no_all_squash)
==== Configure the Pi Zero to mount its root FS over NFS ====
**/boot/cmdline.txt** is the file which tells the Raspberry how to start up.
As standard, it probably contains something very close to:dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=c7928a26-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
To start with the root FS mounted over NFS, change this to:dwc_otg.lpm_enable=0 smsc95xx.turbo_mode=N console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=192.168.36.11:/srv/PiZeroW,tcp rw ip=dhcp rootfstype=nfs elevator=deadline fsck.repair=yes rootwait
Obviously (?), change the IP address to that of your NFS server, followed by the pathname of the NFS exported directory which contains your desired root file system.
Note that if your NFS server itself is running Debian Stretch, or a similarly recent version of NFS, you probably need to add **,vers=3** to the **nfsroot=** parameter:dwc_otg.lpm_enable=0 smsc95xx.turbo_mode=N console=serial0,115200 console=tty1 root=/dev/nfs nfsroot=192.168.36.11:/srv/PiZeroW,tcp,vers=3 rw ip=dhcp rootfstype=nfs elevator=deadline fsck.repair=yes rootwait
=== Alternatively, depending on your DHCP server... ===
The above **cmdline.txt** file specifies where to find the NFS server and which share to mount for the root FS. Obviously, if you have several Pies on your network, you'll want to make sure they each mount different shares.
If you're running ISC's DHCP server (or another which can do the same thing), you can change the **cmdline.txt** file to just:dwc_otg.lpm_enable=0 smsc95xx.turbo_mode=N console=serial0,115200 console=tty1 root=/dev/nfs ip=dhcp rootfstype=nfs elevator=deadline fsck.repair=yes rootwait and then in your **dhcpd.conf** on the DHCP server specify:option root-path = concat("192.168.36.11:/srv/", binary-to-ascii(16, 8, ":", substring(hardware,1,6)));
This specifies the IP address of the NFS server, but then provides the name of the share to mount for the root FS based on the MAC address of the Raspberry Pi. Obviously this is going to be different for each one on your network, so with a single generic **cmdline.txt** on every SD card, you can boot multiple Pies without them all trying to mount the same file system.
The NFS shares should be named **/srv/b8:27:eb:25:92:5b** etc, according to the MAC addresses of your particular Pies. Note that any leading zeros should be omitted from the share name, so if the MAC address of your Pi is **b8:27:eb:05:02:0b** you would need to have a share named **/srv/b8:27:eb:5:2:b**.
==== Finally ====
After following all the above steps with the SD card installed in the Raspberry Pi, simply reboot and watch the system start up, load its initramfs, configure the wireless interface and obtain an IP address, then mount the root FS over NFS and finally end up at the familiar command prompt:Raspbian GNU/Linux 9 raspberrypi tty1
raspberrypi login:
==== Closing comments ====
I haven't yet started from a fresh SD card and followed the above steps in order to make sure they are complete (and I have a strong suspicion that while they work, a few bits might be redundant, especially the **root=/dev/nfs** entry in **/boot/cmdline.txt** and the **BOOT=nfs** and **DEVICE=wlan0** entries in **initramfs.conf**), so I plan to go through them and check that they are complete (and, as far as possible, not over-complicated), and once that is done, this comment will be removed (or at least edited).
----
[[.:|Go up]]\\
Return to [[:|main index]].