Create a custom Raspberry Pi OS image
Resize the Root Partition
The base OS image is designed to be as small as possible. The OS Lite partition sizes are shown in Figure 3b. This image will barely fit on a 2GB SD card. Analyzing the device reveals that the card does not have much free space. In the stock Pi OS Lite distro, it consumes 92 percent of the root volume.
Remember the concept here: You create a custom image that is as small as possible to save download bandwidth and burn time. Then, at boot time, you expand the root partition to the full size of the host SD card. Simple and elegant.
Because automatic resizing of the /rootfs
partition is disabled, you do not have much space to add your preferred software packages. You must have enough space on the /rootfs
partition to accommodate your customizations.
My resize_root_part.sh
Bash script (Listing 1) default setting is to increase the size of the root partition by 256MB (512,000 sectors):
Listing 1
resize_root_part.sh
#! /bin/bash # ------------------------------------------------------------------- # resize_root_part.sh # # Script to resize root partition of a Pi OS image. # Copyright 2021 Michael G. Spohn # License: Attribution-ShareAlike 4.0 International # (CC BY-SA 4.0) # https://creativecommons.org/licenses/by-sa/4.0/legalcode # # Use this script at your own risk! No warranty of any kind provided. # # Contact information: # mspohn@topmail.com # # Version 1.0 - 2021-06-26 # ------------------------------------------------------------------- # Size, in sectors, of additional space to add to root partition. # Modify this value to suit your needs. # Value should be divisible by 512. ADD_SECTOR_COUNT=512000 echo "------------------------------------" echo " Script to resize / partition." echo " Written by M. Spohn" echo " Version 1.0" echo " 2021-03-11" echo " Use this script at your own risk." echo " --------> No warranty <------------" echo " mspohn@topmail.com" echo "------------------------------------" echo echo "Current / partition info:" ROOT_PART_DEV=$(findmnt / -o source -n) echo -e "\t/ partition is on: " $ROOT_PART_DEV ROOT_PART_NAME=$(echo "$ROOT_PART_DEV" | cut -d "/" -f 3) echo -e "\t/ partion name: " $ROOT_PART_NAME ROOT_DEV_NAME=$(echo /sys/block/*/"${ROOT_PART_NAME}" | cut -d "/" -f 4) #echo -e "\t/ device name: " $ROOT_DEV_NAME ROOT_DEV="/dev/${ROOT_DEV_NAME}" #echo -e "\t/ device: " $ROOT_DEV ROOT_PART_NUM=$(cat "/sys/block/${ROOT_DEV_NAME}/${ROOT_PART_NAME}/partition") echo -e "\t/ partion number: " $ROOT_PART_NUM PARTITION_TABLE=$(parted -m "$ROOT_DEV" unit s print | tr -d 's') LAST_PART_NUM=$(echo "$PARTITION_TABLE" | tail -n 1 | cut -d ":" -f 1) ROOT_PART_LINE=$(echo "$PARTITION_TABLE" | grep -e "^${ROOT_PART_NUM}:") ROOT_PART_START=$(echo "$ROOT_PART_LINE" | cut -d ":" -f 2) echo -e "\t/ partition start sector: " $ROOT_PART_START ROOT_PART_END=$(echo "$ROOT_PART_LINE" | cut -d ":" -f 3) echo -e "\t/ partition end sector: " $ROOT_PART_END ROOT_DEV_SIZE=$(cat "/sys/block/${ROOT_DEV_NAME}/size") ORI_PART_SIZE=$(( $ROOT_PART_END - $ROOT_PART_START + 1 )) echo -e "\t/ partion size in sectors: $ORI_PART_SIZE" TARGET_END=$(($ROOT_PART_END + $ADD_SECTOR_COUNT)) # echo "TARGET_END: " $TARGET_END # Sanity checks. if [ "$ROOT_PART_END" -gt "$TARGET_END" ]; then echo "Root partition runs past the end of device." return 1 fi if [ "$TARGET_END" -gt "$ROOT_DEV_SIZE" ]; then echo "Not enough room on root partition to add $ADD_SECTOR_SCOUNT sectors." return 1 fi echo echo "Adding $ADD_SECTOR_COUNT sectors to / partition table entry..." # Use parted to change the partition table. echo "Changing root partion size..." if ! parted -m "$ROOT_DEV" u s resizepart "$ROOT_PART_NUM" "$TARGET_END"; then echo "Root partition resize failed." return 1 fi # Use resize2fs to physically change partition size. echo "Physically changing / partion layout..." resize2fs $ROOT_PART_DEV if [ $? -ne 0 ]; then echo "Error resizing root partion." return 1 fi echo echo "/ partition resize complete." echo ORI_ROOT_SIZE_BYTES=$(($ORI_PART_SIZE * 512)) NEW_ROOT_SIZE_SECTORS=$(($ORI_PART_SIZE + $ADD_SECTOR_COUNT)) NEW_ROOT_SIZE_BYTES=$(($NEW_ROOT_SIZE_SECTORS * 512)) echo "/ partition size change:" echo -e "\tOld / partition size: $ORI_PART_SIZE (sectors), $ORI_ROOT_SIZE_BYTES (bytes)." echo -e "\tNew / partition size: $NEW_ROOT_SIZE_SECTORS (sectors), $NEW_ROOT_SIZE_BYTES (bytes)."


You can modify this by changing the value of the ADD_SECTOR_COUNT
variable at the top of the script.
Make sure the number of bytes you increase the partition by is divisible by 512 so the partition ends on a sector boundary. Now, copy the script to your Pi and run it as root:
$ sudo ./resize_root_part.sh
It only takes a few seconds to run. You can see a sample of the output of the script in Figure 4. Now when you look at the SD card size with fdisk
$ sudo fdisk -l

you can see that partition 2 is larger (Figure 3c).
After making disk geometry changes with sudo reboot
, it is always a good idea to reboot.
Install and Customize Software
Once logged in after rebooting, configure your Pi as desired with raspi-config
. The first thing I do is configure WiFi and enable SSH, which allows me to connect remotely to the Pi from my laptop. You also can enable a camera and the I2C serial interface, set localization options, and take care of any other settings you require, after which you should exit raspi-config
and reboot. At this point, do not perform a system update or upgrade. An upgrade will download numerous software updates and increase the size of your image.
Now, log back in to your Pi and install your favorite tools and utilities that you want on your custom image. A few of the tools I install include:
git
p7zip-full
mc
(Midnight Commander)python3-pip
i2c-tools
cmake
ripgrep
Configure any of your other favorite tweaks, such as custom .rc
files, environment variables, and so on. Now is a good time to use pip
to install your favorite Python modules.
Restore Auto-Resize on First Boot
The final step to complete before you burn a new master image is to restore the ability to automatically resize the root partition, which involves three steps:
- Edit
cmdline.txt
and add the text to call theraspi-config
init script. - Put a copy of the
resize2fs_once
file in the/etc/init.d
folder. - Register
resize2fs
as an init service.
The cmdline.txt
file is in the /boot
folder, and you must be root to edit it. Open the file in an editor and add the following text to the end of line 1:
quiet init=/usr/lib/raspi-config/init_resize.sh
Remember, this file can only have one line in it, so do not add a newline before saving the file.
Next, you need to restore the resize2fs_once
file to /etc/init.d
in one of two ways. If your Pi is connected to the Internet, you can enter the three commands (Figure 5):

$ sudo wget -O /etc/init.d/resize2fs_once https://raw.githubusercontent.com/RPi-Distro/pi-gen/master/stage2/01-sys-tweaks/files/resize2fs_once $ sudo chmod +x /etc/init.d/resize2fs_once $ sudo systemctl enable resize2fs_once
This is a quick and easy way to go, but it does have drawbacks. First, you must be connected to the Internet to get it to work. Second, you do not know if or when the file changes, and you do not know the reputation of the source.
An alternative is to copy the resize2fs_once
file from a current Raspberry Pi OS distro to your Pi. If you do copy a known good file to /etc/init.d
, you still have to perform the last two commands above.
Before creating a custom master image, shut down the Pi and take out the SD card.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)