Create a Custom RaspberryPi OS Image
In this tutorial, we will see a method to create a custom RaspberryPi OS image, in which we can pre-install our own packages and configurations.
The steps are detailed step-by-step, but for automation via a script, you can find an example here.
Preparing the Base Image
First, you need to download a RaspberryPi OS image from the official page.
Then, decompress it:
unxz -k -d raspios.img.xz -c > "raspios.img"Preparing the Filesystem
It may be necessary to enlarge the root partition of the image to be able to install new packages. We start by adding zeros to the end of the image (here, 512 MB):
dd if=/dev/zero bs=1M count=512 >> "raspios.img"and we resize the root partition accordingly:
sudo parted "raspios.img" resizepart 2 100%Now, we need to modify the filesystem of this partition to occupy all the available space. We get the partition information:
parted -s "raspios.img" unit B printwe get something like:
Model: (file)
Disk raspios.img: 2558525440B
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
Number Start End Size Type File system Flags
1 8388608B 545259519B 536870912B primary fat32 lba
2 545259520B 2558525439B 2013265920B primary ext4The information we are interested in is the start of the root partition (ext4), so: 545259520B. Below, be sure to remove the trailing B. We use this information to create a loop device:
sudo losetup --show -f -o 545259520 raspios.imgand note the path of the created device, here: /dev/loop0.
It is recommended to check the filesystem integrity:
sudo e2fsck -p -f /dev/loop0We resize the filesystem to the size of the partition:
sudo resize2fs /dev/loop0there should be a message confirming that the resizing was successful.
Mounting the Filesystems
We will now mount the boot partition and the root partition.
First, we need to create the loop device for the boot partition, just as we did for the root partition. We need to get the start of the partition given by the parted command we used earlier, in our case 8388608B. We remove the trailing B, and create the loop device:
sudo losetup --show -f -o 8388608 raspios.imgand note the path of the created device, here: /dev/loop1.
We can now mount our partitions:
mkdir boot root
sudo mount /dev/loop1 boot
sudo mount /dev/loop0 root
sudo mkdir -p root/boot
sudo mount --bind boot root/bootPreparing the chroot
We need to mount the special directories in the root filesystem:
sudo mount --bind /dev root/dev
sudo mount --bind /sys root/sys
sudo mount --bind /proc root/procalso, we copy the DNS server information for domain name resolution:
sudo cp /etc/resolv.conf root/etc/resolv.confModifying the Filesystem via chroot
We can now do:
sudo chroot root /bin/bashFrom there, you can install packages in the image:
sudo apt update
sudo apt install ...or modify the system configuration.
Finalizing the Image Creation
To exit the chroot, press CTRL + D. Then, remove the resources that are no longer needed and unmount the special filesystems:
sudo rm -f root/etc/resolv.conf
sudo umount root/dev
sudo umount root/sys
sudo umount root/proc
sudo umount root/boot
sudo umount root
sudo umount bootDestroy the loop devices:
sudo losetup -d /dev/loop0
sudo losetup -d /dev/loop1Finally, compress the image:
xz -k -c raspios.img > raspios_custom.img.xz