-
-
Notifications
You must be signed in to change notification settings - Fork 0
Pi Image Setup Guide
This page describes how I create the image file used on the Raspberry Pi. Regular users don't need this, but I've put this here for reference and because others might find this useful.
All steps are performed on a Linux machine with the Raspberry Pi SD card mounted via a card reader. The root partition is assumed to be mounted at /media/$USER/rootfs and the boot partition at /media/$USER/bootfs.
lsblkIdentify the device (e.g. /dev/sda) and note where the partitions are mounted, for example:
-
Root partition →
/media/$USER/rootfs -
Boot partition →
/media/$USER/bootfs
If the partitions are not mounted yet:
sudo mkdir -p /media/$USER/rootfs /media/$USER/bootfs
sudo mount /dev/sda2 /media/$USER/rootfs
sudo mount /dev/sda1 /media/$USER/bootfsThe user can add/edit this file to setup their WiFi without having to log into the Pi. A service will look for this file on boot and update the WiFi settings accordingly.
Create /media/$USER/bootfs/wifi.txt:
# Enter your WiFi credentials below, then save the file.
# This file will be deleted automatically on first boot for security.
SSID=YourNetworkName
PASSWORD=YourPassword
# Optional: set your country code (default: GB)
# COUNTRY=GBUse QEMU to emulate the Pi's ARM architecture on your desktop, allowing you to work inside the SD card image as if you were on the Pi itself.
# Install QEMU on your desktop
sudo apt install qemu-user-static binfmt-support
# Copy the QEMU ARM binary into the image so it can be used inside chroot
sudo cp /usr/bin/qemu-arm-static /media/$USER/rootfs/usr/bin/
# Mount required virtual filesystems
sudo mount --bind /dev /media/$USER/rootfs/dev
sudo mount --bind /proc /media/$USER/rootfs/proc
sudo mount --bind /sys /media/$USER/rootfs/sys
# Chroot in
sudo chroot /media/$USER/rootfsYou are now inside the Pi's filesystem. All following commands in sections 4, 5, and 6 run as if on the Pi itself.
Create /usr/local/bin/wifi-setup.sh:
cat > /usr/local/bin/wifi-setup.sh << 'EOF'
#!/bin/bash
set -e
WIFI_CONFIG="/boot/wifi.txt"
FLAG="/etc/wifi-configured"
# Only run once
if [ -f "$FLAG" ]; then
exit 0
fi
# Check config file exists
if [ ! -f "$WIFI_CONFIG" ]; then
echo "No wifi.txt found, skipping WiFi setup."
exit 1
fi
# Parse credentials
SSID=$(grep -E "^SSID=" "$WIFI_CONFIG" | cut -d= -f2-)
PASSWORD=$(grep -E "^PASSWORD=" "$WIFI_CONFIG" | cut -d= -f2-)
COUNTRY=$(grep -E "^COUNTRY=" "$WIFI_CONFIG" | cut -d= -f2-)
COUNTRY=${COUNTRY:-GB}
if [ -z "$SSID" ] || [ -z "$PASSWORD" ]; then
echo "SSID or PASSWORD missing in wifi.txt"
exit 1
fi
# Set country
raspi-config nonint do_wifi_country "$COUNTRY"
# Write wpa_supplicant config
wpa_passphrase "$SSID" "$PASSWORD" > /etc/wpa_supplicant/wpa_supplicant.conf
cat >> /etc/wpa_supplicant/wpa_supplicant.conf <<WPAEOF
country=$COUNTRY
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
WPAEOF
# Shred and remove the config file for security
shred -u "$WIFI_CONFIG"
# Mark as done
touch "$FLAG"
echo "WiFi configured for SSID: $SSID"
EOF
chmod +x /usr/local/bin/wifi-setup.shCreate /etc/systemd/system/wifi-setup.service:
cat > /etc/systemd/system/wifi-setup.service << 'EOF'
[Unit]
Description=First-boot WiFi configuration
Before=network.target
ConditionPathExists=!/etc/wifi-configured
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wifi-setup.sh
RemainAfterExit=yes
SuccessExitStatus=0 1
[Install]
WantedBy=multi-user.target
EOFCreate /etc/systemd/system/little-printer-zigbee-bridge.service:
cat > /etc/systemd/system/little-printer-zigbee-bridge.service << 'EOF'
[Unit]
Description=Little Printer Zigbee Bridge Script
After=network-online.target wifi-setup.service
Wants=network-online.target
Requires=wifi-setup.service
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/little-printer-zigbee-bridge
ExecStartPre=/bin/sh -c 'until ping -c1 1.1.1.1 > /dev/null 2>&1; do sleep 2; done'
ExecStart=/usr/bin/env python3 -m bridge.main --sirius
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOFOnly needed if the Pi has been booted before!
cat > /etc/systemd/system/regen-ssh-keys.service << 'EOF'
[Unit]
Description=Regenerate SSH host keys on first boot
Before=ssh.service
ConditionPathExists=!/etc/ssh/ssh_host_rsa_key
[Service]
Type=oneshot
ExecStart=/usr/bin/ssh-keygen -A
ExecStartPost=/bin/systemctl disable regen-ssh-keys.service
[Install]
WantedBy=multi-user.target
EOFsystemctl enable wifi-setup.service
systemctl enable little-printer-zigbee-bridge.service
systemctl enable regen-ssh-keys.service # only if Pi was booted before
systemctl enable systemd-networkd.service
systemctl enable systemd-networkd-wait-online.serviceVerify the services are linked:
ls /etc/systemd/system/multi-user.target.wants/# Fix DNS so apt can reach the internet
echo "nameserver 8.8.8.8" > /etc/resolv.conf
# Update and upgrade packages
apt update
apt upgrade
# To skip kernel/firmware updates (they won't take effect without a real boot anyway):
# apt upgrade --exclude=raspberrypi-kernel --exclude=raspberrypi-bootloader
# Install system dependency for PIL
apt install libopenjp2-7
# Install Python dependencies
apt install python3-pip
cd /home/pi/little-printer-zigbee-bridge
pip3 install -r bridge/requirements.txt --break-system-packages
# Exit the chroot
exitBack on your desktop:
sudo umount /media/$USER/rootfs/dev
sudo umount /media/$USER/rootfs/proc
sudo umount /media/$USER/rootfs/sys
sudo rm /media/$USER/rootfs/usr/bin/qemu-arm-staticThis is only needed if you've been logged in to the device.
sudo bash -c 'cat > /media/$USER/rootfs/etc/wpa_supplicant/wpa_supplicant.conf' <<EOF
country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
EOFRestore wifi.txt to the blank template (or confirm it only contains placeholder values - see step 2).
sudo rm -f /media/$USER/rootfs/etc/wifi-configuredThis ensures WiFi setup runs again on first boot for the new user.
sudo rm -f /media/$USER/rootfs/etc/ssh/ssh_host_*The regen-ssh-keys.service will generate fresh keys on first boot.
sudo rm -f /media/$USER/rootfs/root/.bash_history
sudo rm -f /media/$USER/rootfs/home/pi/.bash_historysudo rm -f /media/$USER/rootfs/etc/machine-id
sudo rm -f /media/$USER/rootfs/var/lib/dbus/machine-id
sudo touch /media/$USER/rootfs/etc/machine-idAn empty /etc/machine-id triggers a fresh ID to be generated on first boot.
sudo rm -rf /media/$USER/rootfs/var/log/journal/*
sudo rm -rf /media/$USER/rootfs/var/log/*.log
sudo rm -rf /media/$USER/rootfs/tmp/*
sudo rm -rf /media/$USER/rootfs/var/tmp/*sudo umount /media/$USER/rootfs
sudo umount /media/$USER/bootfsReplace /dev/sda with your actual device from lsblk:
sudo dd if=/dev/sda of=~/little-printer-zigbee-bridge.img bs=4M status=progressThis copies the full card. For a 16GB card it will produce a 16GB file - shrink it in the next step.
wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
chmod +x pishrink.sh
sudo ./pishrink.sh -z ~/little-printer-zigbee-bridge.imgThis creates little-printer-zigbee-bridge.img.gz, compressed and shrunk to the minimum size needed (from SD card size to about 800MB).
- Download
little-printer-zigbee-bridge.img.gzand flash it to an SD card using Raspberry Pi Imager or balenaEtcher - After flashing, open the boot partition of the SD card (visible on Windows, Mac, and Linux as a small FAT drive)
- Open
wifi.txtand fill in your WiFiSSIDandPASSWORD - Save the file, eject the SD card, and insert it into the Raspberry Pi
- Power on - the Pi will configure WiFi on first boot and start the bridge automatically
Service fails with "dependency" error
Check whether wifi-setup.service succeeded:
sudo journalctl -b | grep wifi-setupWiFi never comes up
Check systemd-networkd-wait-online:
sudo systemctl status systemd-networkd-wait-online.serviceScript starts before network is ready
The ExecStartPre ping loop should make the script wait until internet is reachable.