Network boot a bunch of Raspberry Pi 3

Assumptions

  • Installed OS on server: Debian
  • Installed OS on clients: Raspbian
  • bootcode.bin installed on each SD-Card

Prerequisites

  • Install packages on server:

    dnsmasq nfs-kernel-server tcpdump
    
  • Modify the common cmdline.txt:

    dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=/dev/nfs \
    nfsroot=<server-ip>:/<nfs-root>,udp,nfsvers=3,rsize=32768,wsize=32768, \
    hard,intr rw ip=dhcp rootwait elevator=deadline
    

    With the following parameters:

    • server-ip: The IP address of your NFS server
    • nfs-root: The root directory of the exported NFS filesystem

    Note

    Use the nfsvers/rsize/wsize parameters for higher speed.

  • Put a copy of the complete /boot directory of a raspbian install into a directory with the name /tftpboot/rpi.

  • Add to /etc/dnsmasq.conf:

    port=0
    dhcp-range=<ip-range>,proxy
    log-dhcp
    enable-tftp
    tftp-root=/tftpboot
    pxe-service=0,"Raspberry Pi Boot   "
    dhcp-ignore=tag:!known
    dhcp-host=<mac-address>,<ip-address>
    dhcp-host=b8:27:eb:82:8f:f4,140.181.65.134 #landpi003
    

    With the following parameters:

    • ip-range: Range of IP addresses to listen to (e.g. 192.168.1.255)
    • mac-address: MAC address of client
    • ip-address: IP address of client

    Note

    Make sure to include the three spaces in the pxe-service name. Add one ‘dhcp-host’ line per managed client.

  • Modify /etc/exports:

    # Example export for network-booted raspberry pis
    /nfs/rpi *(rw,sync,no_subtree_check,no_root_squash)
    

    This location contains the complete / tree of a raspbian install.

Prepare raspberry pi

  • Program usb boot mode using the original SD-Card image:

    sudo su
    apt-get update
    apt-get install rpi-update
    BRANCH=next rpi-update
    echo program_usb_boot_mode=1 >> /boot/config.txt
    reboot
    
  • Check that this was successful:

    vcgencmd otp_dump | grep 16
    Should yield: 17:3020000a
    

    Remove the program_usb_boot_mode=1 line from /boot/config.txt

Prepare SD-card

  • Copy bootcode.bin from ‘next’ branch of rpi-update (hexxeh) to an otherwise empty SD-card:

    cfdisk /dev/mmcblk0 # Delete all partitions, and create a new one.
    sudo mkfs.vfat /dev/mmcblk0p1
    mount /dev/mmcblk0p1 /mnt
    cp bootcode.bin /mnt
    

    Assuming that your SD-card is mounted as mmcblk0.

Prepare server

  • Start watching for bootpc requests from raspberrypi:

    tcpdump -i eth0 port bootpc | grep b8:27
    
  • Add a line to /etc/dnsmasq.conf:

    dhcp-host=<mac-address>,<ip-address> #<hostname>
    Example:
    dhcp-host=b8:27:eb:12:3b:4c,192.168.1.3 #raspberrypi003
    
  • On the server start a watcher on tftp-requests:

    sudo tail -f /var/log/syslog | grep tftp
    

    Watch for lines like:

    dnsmasq-tftp[5790]: file /tftpboot/<serial-number>/start.elf not found
    

    Write down <serial-number>

  • Create a symbolic link for this serial number:

    cd /tftpboot
    ln -s rpi <serial-number>
    

    /tftpboot/rpi contains all /boot files (see above)

  • Modify /nfs/rpi/etc/rc.local:

    Add a line after # Set hostname based on serial number
    test ${_SN} == "<serial-number>" && hname=<hostname>
    
  • Copy the var directory:

    cd /nfs/rpi
    cp -r rpi <serial-number>
    
  • Reboot the raspberrypi It should come up now and boot from the server. You should be able to log in via ssh