# Source: network-boot-raspberry-pi.adoc

*Note: This file could not be automatically converted from AsciiDoc.*

== Network boot your Raspberry Pi

You can set up a DHCP/TFTP server which will allow you to boot a Raspberry Pi 3 or 4 from the network. 

The instructions assume that you have an existing home network, and that you want to use a Raspberry Pi for the *server*. You will also need an additional Raspberry Pi 3 or 4 as a *client* to be booted. Only one SD Card is needed because the client will be booted from the server after the initial client configuration.

NOTE: Due to the huge range of networking devices and routers available, we can't guarantee that network booting will work with any device. We have had reports that, if you cannot get network booting to work, disabling STP frames on your network may help.

=== Configure a network boot client

==== Raspberry Pi 3 Model B

NOTE: This section only applies to the Raspberry Pi 3 Model B, as network boot is enabled on the Raspberry Pi 3 Model B+ at the factory.

Before the Raspberry Pi 3 Model B will network boot it needs to be booted from an SD Card with a config option to enable USB boot mode. This will set a bit in the OTP (One Time Programmable) memory in the Raspberry Pi SoC that enables network booting. Once this is done, the Raspberry Pi 3B will attempt to boot from USB, and from the network, if it cannot boot from the SD card.

Install Raspberry Pi OS Lite, or Raspberry Pi OS with desktop, on the SD card in the usual fashion. Next, enable USB boot mode with the following command:

[source,console]
----
$ echo program_usb_boot_mode=1 | sudo tee -a /boot/firmware/config.txt
----

This adds `program_usb_boot_mode=1` to the end of xref:config_txt.adoc#what-is-config-txt[`/boot/firmware/config.txt`]. Reboot the Raspberry Pi with `sudo reboot`. Once the client Raspberry Pi has rebooted, check that the OTP has been programmed with:

[source,console]
----
$ vcgencmd otp_dump | grep 17:
17:3020000a
----

Ensure the output `0x3020000a` is correct.

The client configuration is almost done. As a final step, disable USB booting. Run the following command:

[source,console]
----
$ sudo nano /boot/firmware/config.txt
----

Remove the line that contains the text `program_usb_boot_mode=1`. Finally, shut the client Raspberry Pi down with `sudo poweroff`.

==== Raspberry Pi 4 Model B

Network boot can be enabled on the Raspberry Pi 4 using the `raspi-config` tool. First, run `raspi-config` as follows:

[source,console]
----
$ sudo raspi-config
----

Within `raspi-config`, choose `Advanced Options`, then `Boot Order`, then `Network Boot`. You must then reboot the device for the change to the boot order to be programmed into the bootloader EEPROM. Once the Raspberry Pi has rebooted, check that the boot order is now `0xf21`:

[source,console]
----
$ vcgencmd bootloader_config
----

For further details of configuring the Raspberry Pi 4 bootloader, see xref:raspberry-pi.adoc#raspberry-pi-bootloader-configuration[Raspberry Pi Bootloader Configuration].

=== Ethernet MAC address

Before configuring network boot, make a note of the serial number and mac address so that the board can be identified by the TFTP/DHCP server.

On Raspberry Pi 4 and later flagship models, the MAC address is programmed at manufacture and there is no link between the MAC address and serial number. Both the MAC address and serial numbers are displayed on the bootloader xref:raspberry-pi.adoc#boot-diagnostics[HDMI diagnostics] screen.

To find the Ethernet MAC address, run the following command:

[source,console]
----
$ ethtool -P eth0
----

To find the serial number, run the following command:

[source,console]
----
$ grep Serial /proc/cpuinfo | cut -d ' ' -f 2 | cut -c 9-16
----

=== Configure a network boot server

Plug the SD card into the server Raspberry Pi, and then boot the server. The client Raspberry Pi will need a root file system to boot from: we will use a copy of the server's root filesystem and place it in  `/nfs/client1`:

[source,console]
----
$ sudo mkdir -p /nfs/client1
$ sudo apt install rsync
$ sudo rsync -xa --progress --exclude /nfs / /nfs/client1
----

Regenerate SSH host keys on the client filesystem by chrooting into it:

[source,console]
----
$ cd /nfs/client1
$ sudo mount --bind /dev dev
$ sudo mount --bind /sys sys
$ sudo mount --bind /proc proc
$ sudo chroot .
$ rm /etc/ssh/ssh_host_*
$ dpkg-reconfigure openssh-server
$ exit
$ sudo umount dev sys proc
----

Find the settings of your local network. You need to find the address of your router (or gateway), which can be done with:

[source,console]
----
$ ip route | awk '/default/ {print $3}'
----

Then run:

[source,console]
----
$ ip -4 addr show dev eth0 | grep inet
----

You should see output similar to the following:

----
inet 10.42.0.211/24 brd 10.42.0.255 scope global eth0
----

The first address is the IP address of your server Raspberry Pi on the network, and the part after the slash is the network size. It is highly likely that yours will be a `/24`. Also note the `brd` (broadcast) address of the network. Note down the output of the previous command, which will contain the IP address of the Raspberry Pi and the broadcast address of the network.

Finally, note down the address of your DNS server, which is the same address as your gateway. You can find this with:

[source,console]
----
$ cat /etc/resolv.conf
----

Configure a static network address on your server Raspberry Pi via the `systemd` networking, which works as the network handler and DHCP server.

To do that, you'll need to create a `10-eth0.netdev` and a `11-eth0.network` like so:

[source,console]
----
$ sudo nano /etc/systemd/network/10-eth0.netdev
----

Add the following lines:

----
[Match]
Name=eth0

[Network]
DHCP=no
----

Then create a network file:

[source,console]
----
$ sudo nano /etc/systemd/network/11-eth0.network
----

Add the following contents:

----
[Match]
Name=eth0

[Network]
Address=10.42.0.211/24
DNS=10.42.0.1

[Route]
Gateway=10.42.0.1
----

At this point, you will not have working DNS, so you will need to add the server you noted down before to `systemd/resolved.conf`. In this example, the gateway address is 10.42.0.1.

[source,console]
----
$ sudo nano /etc/systemd/resolved.conf
----

Uncomment the DNS line and add the DNS IP address there. Additionally, if you have a fallback DNS server, add it there as well.

----
[Resolve]
DNS=10.42.0.1
#FallbackDNS=
----

Enable `systemd-networkd` and then reboot for the changes to take effect:

[source,console]
----
$ sudo systemctl enable systemd-networkd
$ sudo reboot
----

Now start `tcpdump` so you can search for DHCP packets from the client Raspberry Pi:

[source,console]
----
$ sudo apt install tcpdump dnsmasq
$ sudo systemctl enable dnsmasq
$ sudo tcpdump -i eth0 port bootpc
----

Connect the client Raspberry Pi to your network and power it on. Check that the LEDs illuminate on the client after around 10 seconds, then you should get a packet from the client "DHCP/BOOTP, Request from ..."

----
IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from b8:27:eb...
----

Now you need to modify the `dnsmasq` configuration to enable DHCP to reply to the device. Press +++<kbd>+++CTRL + C+++</kbd>+++ to exit the `tcpdump` program, then type the following:

[source,console]
----
$ echo | sudo tee /etc/dnsmasq.conf
$ sudo nano /etc/dnsmasq.conf
----

Then replace the contents of `dnsmasq.conf` with:

----
# Note: comment out port if you want DNS services for systems on the network.
port=0
dhcp-range=10.42.0.255,proxy
log-dhcp
enable-tftp
tftp-root=/tftpboot
pxe-service=0,"Raspberry Pi Boot"
----

Where the first address of the `dhcp-range` line is, use the broadcast address you noted down earlier.

Now create a `/tftpboot` directory:

[source,console]
----
$ sudo mkdir /tftpboot
$ sudo chmod 777 /tftpboot
$ sudo systemctl enable dnsmasq.service
$ sudo systemctl restart dnsmasq.service
----

Now monitor the `dnsmasq` log:

[source,console]
----
$ journalctl -f
----

You should see something like this:

----
raspberrypi dnsmasq-tftp[1903]: file /tftpboot/bootcode.bin not found
----

Next, you will need to copy the contents of the boot folder into the `/tftpboot` directory.

First, press *CTRL + C* to exit the monitoring state. Then type the following:

[source,console]
----
$ cp -r /boot/firmware/* /tftpboot
----

Since the tftp location has changed, restart `dnsmasq`:

[source,console]
----
$ sudo systemctl restart dnsmasq
----

==== Set up NFS root

This should now allow your Raspberry Pi client to attempt to boot through until it tries to load a root file system (which it doesn't have).

At this point, export the `/nfs/client1` file system created earlier, and the TFTP boot folder.

[source,console]
----
$ sudo apt install nfs-kernel-server
$ echo "/nfs/client1 *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
$ echo "/tftpboot *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
----

Restart RPC-Bind and the NFS server in order to have them detect the new files.

[source,console]
----
$ sudo systemctl enable rpcbind
$ sudo systemctl restart rpcbind
$ sudo systemctl enable nfs-kernel-server
$ sudo systemctl restart nfs-kernel-server
----

Edit `/tftpboot/cmdline.txt` and from `root=` onwards, and replace it with:

----
root=/dev/nfs nfsroot=10.42.0.211:/nfs/client1,vers=3 rw ip=dhcp rootwait
----

You should substitute the IP address here with the IP address you have noted down. Also remove any part of the command line starting with `init=`.

Finally, edit `/nfs/client1/etc/fstab` and remove the `/dev/mmcblk0p1` and `p2` lines (only `proc` should be left). Then, add the boot partition back in:

[source,console]
----
$ echo "10.42.0.211:/tftpboot /boot/firmware/ nfs defaults,vers=3 0 0" | sudo tee -a /nfs/client1/etc/fstab
----

If it doesn't boot on the first attempt, keep trying. It can take a minute or so for the Raspberry Pi to boot, so be patient.