Create a New Raspberry Pi Boot Image From Scratch#

Introduction#

Normal operation for setting up a new Raspberry Pi is to use the provided pre-built image. See Commissioning a new Raspberry Pi as an Agent Server.

This page is only needed if you want to create a completely new SD card image, perhaps because a new version of Raspberry Pi OS has been released.

Tip

Images can also be built automatically using the Build SD Card Image GitHub Actions workflow. The resulting image will be attached to the corresponding GitHub Release.

To trigger the build, go to Actions → Build SD Card Image → Run workflow, enter the release tag (e.g. v0.3.0), and click Run workflow.

If you just want to update the agent version on an existing image, see Updating an Existing Raspberry Pi Boot Image.

Prerequisites#

You will need:

  • A computer running Linux with sudo privileges

  • A microSD card of at least 16GB capacity

  • A microSD card reader connected to your computer

  • A Raspberry Pi 4 or 5 (see Recommended Server Hardware)

  • A USB stick of at least 8GB capacity to store the backup image

Step 1: Image the microSD Card with Raspberry Pi OS#

  1. Download the latest ‘Raspberry Pi OS Lite’ image from the Raspberry Pi website. The Lite version is the last option on the linked page.

  2. Use lsblk to get a list of block devices before inserting the microSD card.

  3. Insert the microSD card and use lsblk again to identify the device name (e.g. /dev/sdb).

  4. Uncompress the downloaded image:

    cd ~/Downloads
    unxz ./2025-12-04-raspios-trixie-arm64-lite.img.xz
    
  5. Write the image to the microSD card. Replace /dev/sdX with the actual device name. Be careful as this will overwrite the specified device.

    sudo dd if=./2025-12-04-raspios-trixie-arm64-lite.img of=/dev/sdX bs=4M status=progress conv=fsync
    

Step 2: Configure the Raspberry Pi OS Image#

These steps must be done before the first boot.

  1. Mount the microSD card boot partition:

    mkdir sdcard-bootfs
    sudo mount /dev/sdX1 sdcard-bootfs
    cd sdcard-bootfs
    
  2. Enable SSH:

    sudo touch ssh
    
  3. Create a user local with password local:

    echo "local:$(echo local | openssl passwd -6 -stdin)" | sudo tee userconf.txt
    
  4. If you need a static IP address, edit cmdline.txt:

    sudo vim cmdline.txt
    # add " ip=<your_static_ip_address>" at the end of the single line
    
  5. Unmount the boot partition:

    cd ..
    sudo umount sdcard-bootfs
    sudo umount /dev/sdX  # there may be a second mount point
    rmdir sdcard-bootfs
    

Step 3: First Boot and Connect to Internet#

  1. Insert the microSD card into your Raspberry Pi and power it on.

  2. SSH into the Raspberry Pi. The username is local and the password is local. You may need to check your router for the assigned IP address or use the static IP set above.

  3. If you do not have internet access, temporarily connect to WiFi:

    sudo raspi-config
    # Select "System Options" -> "Wireless LAN"
    # Enter your SSID and password
    
  4. Update the system:

    sudo apt update
    sudo apt upgrade -y
    sudo apt install -y git vim
    
  5. Record the Raspberry Pi’s MAC address:

    ip link show eth0
    # look for "link/ether xx:xx:xx:xx:xx:xx"
    

Step 4: Install and Configure USB/IP#

  1. Load the kernel modules and configure them to load at boot:

    sudo modprobe usbip_core
    sudo modprobe usbip_host
    echo -e "usbip-core\nusbip-host" | sudo tee /etc/modules-load.d/usbip.conf
    
  2. Install the usbip package:

    sudo apt install -y usbip
    
  3. Create a systemd service for usbipd:

    echo "[Unit]
    Description=USB/IP Daemon
    After=network.target
    
    [Service]
    Type=forking
    ExecStart=/usr/sbin/usbipd -D
    Restart=on-failure
    
    [Install]
    WantedBy=multi-user.target" | sudo tee /etc/systemd/system/usbipd.service
    
    sudo systemctl enable --now usbipd.service
    

Step 5: Install the Agent#

curl -fsSLO https://raw.githubusercontent.com/DiamondLightSource/dra-usbip-driver/main/scripts/install-agent.sh
sudo bash install-agent.sh

Verify:

sudo systemctl status dra-usbip-agent
curl http://localhost:13240/devices

Step 6: Install the Pico MAC Sender (optional)#

This service monitors USB ports for a Raspberry Pi Pico and sends the Pi’s MAC address to its OLED display. Useful for commissioning without a monitor or keyboard.

curl -fsSLO https://raw.githubusercontent.com/DiamondLightSource/dra-usbip-driver/main/scripts/install-pico-mac-sender.sh
sudo bash install-pico-mac-sender.sh

Step 7: Install image-backup#

image-backup creates compressed backup images of Raspberry Pi SD cards that auto-expand on first boot. See https://forums.raspberrypi.com/viewtopic.php?t=332000 for details.

cd ~
git clone https://github.com/seamusdemora/RonR-RPi-image-utils.git
sudo install --mode=755 ~/RonR-RPi-image-utils/image-* /usr/local/sbin

Step 8: Clean Up Settings for Production#

Undo any temporary configuration so the image can be reused on multiple Pis with DHCP.

  1. Disable the static IP if you set one:

    sudo vim /boot/firmware/cmdline.txt
    # remove " ip=<your_static_ip_address>"
    
  2. Disable WiFi if you enabled it:

    sudo vim /boot/firmware/config.txt
    # add at the end:
    dtoverlay=disable-wifi
    dtoverlay=disable-bt
    

Step 9: Prepare the Backup Image for Distribution#

Set up a run-once service so copies of the image enable read-only mode on first boot:

echo '[Unit]
Description=Run script once on next boot
ConditionPathExists=/var/local/runonce.sh
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/bin/bash /var/local/runonce.sh

[Install]
WantedBy=multi-user.target
' | sudo tee /etc/systemd/system/runonce.service
sudo systemctl enable runonce.service

Create the runonce.sh script:

echo '#!/bin/bash
set -x

# Disable this script from running again
mv /var/local/runonce.sh /var/local/runonce.sh.done

# disable services that will report errors when in RO mode
systemctl mask dphys-swapfile.service
systemctl mask systemd-zram-setup@zram0.service

# enable read only overlay mode
raspi-config nonint do_overlayfs 0

# reboot to pick up the change
sync; reboot
' | sudo tee /var/local/runonce.sh

# Add packages required for read-only mode
sudo apt-get -y install cryptsetup cryptsetup-bin overlayroot

Step 10: Create a Backup Image of the microSD Card#

  1. Insert a USB stick into the Raspberry Pi.

  2. Mount the USB stick:

    sudo mkdir -p /media/local/usb
    sudo mount /dev/sda1 /media/local/usb
    
  3. Run image-backup:

    sudo image-backup
    # when prompted for output file, use something like:
    /media/local/usb/raspi-agent-server-0.3.0.img
    
  4. Sync and unmount:

    sync
    sudo umount /media/local/usb
    

Your image can now be used to commission additional Raspberry Pi agent servers as described in Commissioning a new Raspberry Pi as an Agent Server.