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 Bash script (Listing 1) default setting is to increase the size of the root partition by 256MB (512,000 sectors):

Listing 1

#! /bin/bash
# -------------------------------------------------------------------
# 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)
# Use this script at your own risk! No warranty of any kind provided.
# Contact information:
# 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.
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 ""
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
#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_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")
echo -e "\t/ partion size in sectors: $ORI_PART_SIZE"
# Sanity checks.
if [ "$ROOT_PART_END" -gt "$TARGET_END" ]; then
    echo "Root partition runs past the end of device."
    return 1
if [ "$TARGET_END" -gt "$ROOT_DEV_SIZE" ]; then
    echo "Not enough room on root partition to add $ADD_SECTOR_SCOUNT sectors."
    return 1
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
# 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
echo "/ partition resize complete."
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 ./

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
Figure 4: Output from

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 the raspi-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/

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):

Figure 5: Restoration of resize2fs_once.
$ sudo wget -O /etc/init.d/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.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Disk Partitioning

    Partitioning prepares your disk to receive an operating system. We help you navigate this unfamiliar landscape safely.

  • Top 10 Knoppix Rescue Tricks

    The Knoppix Live Linux distro is packed with powerful tools for fixing broken systems. We ask Knoppix creator Klaus Knopper for his favorite Knoppix rescue tricks.

  • Command Line: Partitioning

    Despite the popularity of LVM, traditional partitioning is still preferred by some admins. We provide some tips to consider before choosing a partitioning scheme for your setup.

  • Parted Magic

    It's really annoying when a disk suddenly dies on you or a typo in a command deletes important data. The free Parted Magic Live distro offers help.

  • Ask Klaus!

    Klaus Knopper is the creator of Knoppix and co-founder of the LinuxTag expo. He currently works as a teacher, programmer, and consultant. If you have a configuration problem, or if you just want to learn more about how Linux works, send your questions to:

comments powered by Disqus