Pi4 iSCSI Boot Shim

Network-boot Raspberry Pi 3, 4, or 5 over Ethernet or WiFi — iSCSI root, kexec, or USB disk mode
Part of scsipub — block devices over the internet, one click, no account

A minimal Linux distribution for Raspberry Pi 3B/3B+, 4, and 5 that boots over the network, connects to an iSCSI target, and hands off to the operating system stored there. The Pi needs no local OS — the shim is a single kernel file served via TFTP with everything baked in.

The shim pairs directly with scsipub.com, which streams disk images (Alpine, memtest86+, blank scratch volumes) over iSCSI on demand. Point the shim at a scsipub target and the Pi boots that image with no local storage.

Boot modes

🔌

pivot_root (default)

Mount the iSCSI root partition and switch_root into it. Works with any target OS — no iSCSI support required in the target.

kexec

Load a kernel from the iSCSI boot partition and kexec into it. Deploy new kernels without updating TFTP — just write to the iSCSI disk.

💾

USB disk

Expose the entire iSCSI LUN as a USB mass storage device over the Pi's USB-C port. Connect a laptop to browse or image the disk.

pivot_root caveat: In pivot_root mode the target OS runs under the shim's kernel. Only hardware supported by the shim's kernel config is available to the target — USB peripherals, GPIO, camera, etc. may not work if the driver isn't built in. kexec mode avoids this by booting the target's own kernel. If you need a specific driver added to the shim kernel and it doesn't significantly increase the image size, get in touch.

Download

Two image variants are built by CI. Both produce the same bootstrap SD card; the difference is the TFTP kernel served to the Pi after netboot is configured.

VariantImage.gzIncludes
WiFi + Ethernet (recommended) ~19 MB BCM43455 WiFi driver, firmware, wpa_supplicant, Ethernet
Ethernet-only ~13 MB Wired Ethernet only — smaller TFTP footprint

WiFi + Ethernet (recommended)

Image.gz (TFTP kernel) sdcard.img (bootstrap SD)

Ethernet-only (smaller)

Image.gz (TFTP kernel) sdcard.img (bootstrap SD)
FilePurpose
Image.gz TFTP kernel with embedded initramfs — the only file your TFTP server needs
sdcard.img Bootstrap SD card — flash once to configure EEPROM for netboot

The SD card image contains the same kernel as Image.gz (with the initramfs embedded), so each variant has its own SD card image. Use the WiFi SD card if you need WiFi during bootstrap or plan to serve the WiFi kernel via TFTP.


Step 1 — Write the SD card

Write sdcard.img to a micro SD card. The Pi can boot from this SD card permanently — or you can remove it later and the Pi will fall through to TFTP netboot automatically.

On first boot from SD:

Raspberry Pi Imager (recommended)

  1. Download and install Raspberry Pi Imager.
  2. Choose Use custom and select the downloaded sdcard.img.
  3. Select your SD card as the target and click Write.
Alternative: balenaEtcher

Download balenaEtcher, open sdcard.img, select drive, flash.

Alternative: dd (Linux / macOS)
sudo dd if=sdcard.img of=/dev/sdX bs=4M status=progress
sync

Replace /dev/sdX with your SD card device. Use lsblk to identify it.

WiFi users: Before ejecting the SD card, place a wpa_supplicant.conf file on the boot partition with your WiFi credentials. The shim will copy it at boot and use WiFi for iSCSI.

Insert the SD card into the Pi and power on. The shim boots, updates the EEPROM if needed (one-time reboot), then proceeds to bring up the network and connect to iSCSI. The SD card can stay in permanently or be removed — without it, the Pi falls through to TFTP netboot on next power cycle.


Step 2 — Set up the TFTP server (optional)

If you leave the SD card in the Pi, TFTP is not needed — the Pi boots the shim directly from the card. TFTP is for SD-less operation: remove the SD card and the Pi fetches boot files over the network instead.

The Pi firmware fetches multiple files over TFTP — not just the kernel. All boards need config.txt, the matching device tree blob, overlays, cmdline.txt, and the kernel. GPU firmware requirements differ: Pi3 fetches bootcode.bin, start.elf, and fixup.dat; Pi4 fetches start4.elf + fixup4.dat (bootcode is in the EEPROM); Pi5 has everything in its EEPROM and fetches only the kernel and DTB.

TFTP directory layout

/srv/tftp/
  config.txt                # Pi firmware config
  cmdline.txt               # Kernel command line
  Image.gz                  # Kernel with embedded initramfs
  bootcode.bin              # Pi3 second-stage bootloader (Pi4/5 ignore)
  start.elf                 # Pi3 GPU firmware (Pi4/5 ignore)
  fixup.dat                 # Pi3 GPU memory fixup (Pi4/5 ignore)
  start4.elf                # Pi4 GPU firmware (Pi3/5 ignore)
  fixup4.dat                # Pi4 GPU memory fixup (Pi3/5 ignore)
  bcm2837-rpi-3-b.dtb       # Pi3 Model B device tree
  bcm2837-rpi-3-b-plus.dtb  # Pi3 Model B+ device tree
  bcm2837-rpi-3-a-plus.dtb  # Pi3 Model A+ device tree
  bcm2837-rpi-zero-2-w.dtb  # Pi Zero 2 W device tree
  bcm2711-rpi-4-b.dtb       # Pi4 Model B device tree
  bcm2711-rpi-400.dtb       # Pi 400 device tree
  bcm2711-rpi-cm4.dtb       # Pi Compute Module 4 device tree
  bcm2711-rpi-cm4s.dtb      # Pi CM4S device tree
  bcm2712-rpi-5-b.dtb       # Pi5 device tree
  bcm2712d0-rpi-5-b.dtb     # Pi5 D0 stepping device tree
  bcm2712-rpi-500.dtb       # Pi 500 device tree
  overlays/                 # DT overlays from config.txt
    miniuart-bt.dtbo
    dwc2.dtbo               # Pi4 USB gadget (optional)
The DTBs must be served from TFTP. The Pi firmware patches the device tree at runtime with per-board data (MAC address, serial number, memory layout, clock rates). They cannot be built into the kernel.

Copy all files from the SD card's boot partition to your TFTP root — it contains everything the firmware needs.

dnsmasq (simple, recommended for small setups)

# /etc/dnsmasq.conf
enable-tftp
tftp-root=/srv/tftp

ISC DHCP + tftpd-hpa

# /etc/dhcp/dhcpd.conf
next-server 192.168.1.1;       # TFTP server IP
# Install tftpd-hpa
sudo apt install tftpd-hpa
# Copy the entire SD card boot partition content to TFTP root
sudo cp -r /mnt/sdcard/* /srv/tftp/
Tip: The Pi EEPROM's default TFTP path includes the serial number as a subdirectory (e.g. /abcdef01/Image.gz). You can either create per-Pi directories or configure the EEPROM to request a flat path. See the RPi network boot docs.

Step 3 — Create the iSCSI target

The iSCSI target presents a disk image to the Pi. This disk image has the same partition layout as a real SD card — a FAT boot partition and an ext4 root partition.

Create a disk image

Use any Raspberry Pi OS image (or your own). The image must have at least two partitions: p1 (FAT, boot) and p2 (ext4, root).

# Example: create a 16 GB sparse image and write a Pi OS image to it
truncate -s 16G /srv/iscsi/pi4-root.img
sudo dd if=raspios.img of=/srv/iscsi/pi4-root.img bs=4M conv=notrunc

targetcli (Linux, recommended)

sudo targetcli
/> backstores/fileio create pi4-root /srv/iscsi/pi4-root.img
/> iscsi/ create iqn.2024-01.local:pi4-root
/> iscsi/iqn.2024-01.local:pi4-root/tpg1/luns/ create /backstores/fileio/pi4-root
/> iscsi/iqn.2024-01.local:pi4-root/tpg1/ set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1
/> saveconfig
/> exit

TrueNAS / Synology / Windows

Create a new iSCSI target and LUN through the web UI. Use the disk image as the backing store. The IQN and portal IP are needed for the DHCP configuration.


Step 4 — Configure DHCP

The shim reads iSCSI parameters from standard DHCP options. Configure your DHCP server to provide option 17 (root-path) with the iSCSI URI.

dnsmasq

# iSCSI target URI (option 17)
dhcp-option=17,iscsi:192.168.1.10:::1:iqn.2024-01.local:pi4-root

# Boot mode (option 224, optional — defaults to pivot)
#   pivot  — switch_root into iSCSI root
#   kexec  — kexec kernel from iSCSI boot partition
#   usb    — expose iSCSI disk over USB-C
dhcp-option=224,pivot

ISC dhcpd

option root-path "iscsi:192.168.1.10:::1:iqn.2024-01.local:pi4-root";

# Optional: boot mode
option local-proxy-config "pivot";
Replace 192.168.1.10 with your iSCSI server IP and iqn.2024-01.local:pi4-root with your actual target IQN.
Kernel cmdline overrides (for testing without DHCP changes)

You can pass iSCSI parameters directly on the kernel cmdline instead of (or in addition to) DHCP. Edit cmdline.txt on the SD card or the TFTP server's boot config:

console=ttyAMA0 earlycon iscsi.ip=192.168.1.10 iscsi.target=iqn.2024-01.local:pi4-root iscsi.port=3260 iscsi.mode=pivot

Cmdline values take precedence over DHCP-supplied options.


WiFi support

The WiFi variant (~19 MB Image.gz vs ~13 MB without) includes the BCM43455 driver, firmware, and wpa_supplicant. The shim prefers Ethernet if available and falls back to WiFi when no wired interface is found.

WiFi credentials can come from three sources (in priority order):

SourceHow
SD card Place wpa_supplicant.conf on the FAT boot partition before first boot
Kernel cmdline Add wifi.ssid=MyNetwork wifi.psk=MyPassword to the TFTP cmdline
Build-time Bake /etc/wpa_supplicant.conf into the rootfs for site-specific images
Example wpa_supplicant.conf
network={
    ssid="MyNetwork"
    psk="MyPassword"
}
Note: WiFi is used for iSCSI traffic, not for booting the shim itself. The Pi firmware's netboot only works over Ethernet (TFTP) on all supported boards. The shim boots via Ethernet TFTP, then uses WiFi to reach the iSCSI target.

How it works

Pi3/4/5 boot ROM        TFTP Server              iSCSI Target
    |                       |                        |
    |--- DHCP discover ---->|                        |
    |<-- IP + next-server --|                        |
    |                       |                        |
    |--- TFTP config.txt -->|                        |
    |--- TFTP *.dtb ------->|  (firmware patches     |
    |--- TFTP overlays/ --->|   MAC, serial, memory) |
    |--- TFTP Image.gz ---->|                        |
    |<-- boot files --------|                        |
    |                       |                        |
    [kernel boots, shim init starts]                 |
    |                                                |
    |--- DHCP (option 17 = iSCSI URI) ------------->|
    |                                                |
    |--- iSCSI login ------>|----------------------->|
    |<-- block device ------|<-----------------------|
    |                                                |
    [pivot_root / kexec / USB mode]                  |

The kernel (Image.gz) has the entire root filesystem embedded as an initramfs — no separate initrd file. The TFTP server also serves config.txt, device tree blobs, and overlays that the Pi firmware needs before it can start the kernel. The simplest setup: copy the contents of the SD card boot partition to the TFTP root.


Troubleshooting

Pi does not netboot after SD card bootstrap

Check that the EEPROM was flashed successfully (serial console shows [init] EEPROM flashed). Verify the TFTP server is running and reachable. The Pi requests Image.gz (or the filename set in DHCP filename option) from the next-server IP.

Shim boots but iSCSI fails

The serial console (or HDMI splash screen) shows progress. Common issues:

If the Pi has a USB-C connection to a computer, it will present a help disk with setup instructions when boot fails.

WiFi does not connect

Verify wpa_supplicant.conf is on the SD card boot partition (FAT) or that wifi.ssid= and wifi.psk= are on the kernel cmdline. The shim waits 30 seconds for WiFi association before giving up.

Saving space — Ethernet-only image

The WiFi stack adds ~6 MB to Image.gz (13 MB → 19 MB). If all your Pis are wired, use the Ethernet-only download from the eth-only branch for a smaller TFTP image. Both variants produce the same SD card bootstrap image.


Related projects

scsipub (parent project) — streams disk images over iSCSI on demand. One click, no account, no VPN, no VM. Pick an image (Alpine, memtest86+, blank scratch volume), get session credentials with a unique IQN and CHAP login, and mount it as a local block device on Linux, Windows, or macOS. Copy-on-write layering gives each session its own isolated volume.

This shim is the "Pi-side" client for scsipub: combine it with a scsipub target and a Raspberry Pi becomes a diskless machine that boots whatever image you picked on the web.

ESP32 iSCSI USB Bridge — turns an ESP32-S3 into a wireless-to-USB storage bridge. The device connects to WiFi, logs into an iSCSI target, and presents it to any USB host as an ordinary flash drive. No drivers or software needed on the host side.

Use it to give legacy devices (smart TVs, car stereos, thin clients) transparent access to network storage, or as a standalone iSCSI-to-USB adapter alongside the Pi3/4/5 shim in a diskless deployment.


© Defensible Logic · Source · Built with Buildroot + RPi kernel 6.19