setting up a headless raspbian boot image

2020-12-12 · 2 min read

Objective #

  1. Custom SD card boot image for Raspberry Pi Zero W.
  2. RPi should boot headless, connect to configured WiFi, run ssh.

Better Alternative? #

I only discovered this after successfully generating my own image, but it seems more convenient: (https://github.com/kenfallon/fix-ssh-on-pi, http://www.lpenz.org/articles/ansiblerpi/index.html). It just mounts a stock Raspbian image and directly modifies the wpa_supplicant.conf and other configuration, instead of building a fresh image from scratch, which takes like 45 minutes...

EDIT: It looks like rpi-imager has basic image customization available? #

TODO #

  • enable kernel I2C, SPI, and PWM controllers in /boot/config.txt

Installation #

(Windows, macOS) Install Docker Desktop #

See: https://www.docker.com/products/docker-desktop

Clone pi-gen: #

$ git clone --depth=1 git@github.com:RPi-Distro/pi-gen.git

Add pi-gen/config #

IMG_NAME=raspbian_headless
LOCALE_DEFAULT=en_US.UTF-8
TARGET_HOSTNAME=<..>
TIMEZONE_DEFAULT=America/Los_Angeles
FIRST_USER_NAME=phlip9
FIRST_USER_PASS=<..>
DISABLE_FIRST_BOOT_USER_RENAME=1
WPA_ESSID="<..>"
WPA_PASSWORD="<..>"
WPA_COUNTRY=US
ENABLE_SSH=1
PUBKEY_ONLY_SSH=1
PUBKEY_SSH_FIRST_USER="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGrOw2yrUxOYB9ItWrZW4e/AmatL5GH58jTnI/HNoXZz philiphayes9@gmail.com"
STAGE_LIST="stage0 stage1 stage2"

This config sets up all the locale shit and all, but most importantly, enables wifi on boot and pubkey-only ssh, so we can ssh into the running board without needing to hookup a keyboard / monitor.

NOTE: The Raspberry Pi Zero W DOES NOT support 5GHz wifi.

(Linux/x86_64) Install qemu-user-static #

This lets us run arm binaries on an x86_64 machine via qemu.

$ sudo apt install qemu-user-static

Context:

Linux is able execute binaries from other architectures, meaning that it should be possible to make use of pi-gen on an x86_64 system, even though it will be running ARM binaries. This requires support from the binfmt_misc kernel module.

If this is not set up correctly, you will see something like this error in the next step:

W: Failure trying to run: chroot "/pi-gen/work/test/stage0/rootfs" /bin/true
and/or
chroot: failed to run command '/bin/true': Exec format error

Build the image #

$ ./build-docker.sh

This should spit out our fresh image in ./deploy/:

~/dev/pi-gen$ ls -lh deploy/
total 528M
-rw-r--r-- 1 phlip9 phlip9  74K Nov 26 15:56 2022-11-26-raspbian_headless-lite.info
-rw-r--r-- 1 phlip9 phlip9 6.2K Nov 26 15:58 build.log
-rw-r--r-- 1 phlip9 phlip9 528M Nov 26 15:57 image_2022-11-26-raspbian_headless-lite.zip
drwxr-xr-x 2 phlip9 phlip9 4.0K Nov 26 15:58 raspbian_headless-lite

If the build hangs/fails for some inscrutable reason (happened the first time), just ^CTRL-C and try again with:

$ CONTINUE=1 ./build-docker.sh

(WSL) I tried their suggestion of using apt-cache to improve rebuild times, but that didn't work :'(

Mount SD card #

Download Raspberry Pi Imager #

https://www.raspberrypi.org/software/

Open Raspberry Pi Imager #

Select the "deploy/*.zip" file as the image to write and then image the mounted SD card. #

Unmount the SD card, put it into the Pi, plug in the Pi, wait ~2 min to boot, and test: #

$ ssh raspberrypi.local

phlip9@raspberrypi:~ $ exit