Create a disk image from a Raspberry Pi SD card

After setting up a Raspberry Pi with the desired software and configurations, create a disk image to replicate it on other devices.

Cloning an SD card using a Raspberry Pi

The TL;DR (Too Long; Didn't Read)

Learn how to make an exact copy of an SD card using a Raspberry Pi.


Why create a disk image?
Ensure that each new Raspberry Pi device has the exact same configuration and save time re-installing software on new Raspberry Pi devices.
Why use a Raspberry Pi to clone an SD card?
There are several different ways to clone an SD card that will be OS specific. This tutorial assumes developers following this tutorial have a Raspberry Pi, instead of writing out different steps for Unix, Mac, and Windows.
Cloned how?
The Raspberry Pi will make a copy of an SD card and save the file to a USB Key (see Prerequisites)

Prerequisites

  • SD Card
    With the installed software and configuration that you wish to clone
  • SD card reader
    To mount the source card to the Pi via USB
  • USB Key
    With at least 2x capacity of the source SD card to store the disk image

Prepare the Raspberry Pi   Step 1 of 3

Start the Raspberry Pi and connect the SD card and USB drive


Why use a USB Drive?
It is necessary to have enough storage to hold both the full image of the SD card, as well as the final shrunk and zipped file. Using a USB Drive will minimize the risk of running out of space during the cloning process, as most USB drives are larger than the SD cards used in Raspberry Pi devices. Using a USB Drive will also allow you to easily transfer the zipped image to another device, such as a laptop or desktop computer.
What's the source card?
This is the card that will be used to create the disk image, facilitating cloning.

Connect to the Raspberry Pi   Part 1

  1. Boot up the Raspberry Pi with the SD card containing the base Raspberry Pi OS. (not the card you would like to clone)

  2. Connect to the Raspberry Pi with SSH or a monitor and keyboard.

  3. Open a terminal on the Raspberry Pi.

Insert and identify the source SD card   Part 2

Using an SD card reader, insert the source SD card into one of the available USB ports on the Raspberry Pi.

  1. Insert the SD card into the SD card reader.
  2. Insert the SD card reader into an available USB port on the Raspberry Pi.
  3. Identify the location of the SD card with the command: sudo fdisk -l

The output will include a list of block devices, including the SD card. The SD card will be identified as a block device, such as /dev/sda, /dev/sdb, etc...

It will appear similar to the following:

  Disk /dev/sda: 7.36 GiB, 7901020160 bytes, 15431680 sectors
  Disk model: Storage Device

While there are two partions on the SD card, (eg: /dev/sda1 and /dev/sda2), the partition that will be cloned is the entire disk, not just one partition. As such, we are interested in the block device, not the partition.

The block device id will look similar to the following: /dev/sda, /dev/sdb, etc..., it does not have a number at the end.

Insert and mount the USB Drive   Part 3

Insert and mount a USB Drive to which the disk image will be written

  1. Insert the USB drive into an available USB port on the Raspberry Pi.
  2. Identify the USB drive with the command: sudo fdisk -l

    The USB drive will be identified as a Disk, such as /dev/sda, /dev/sdb, etc... with the Device partions listed below it, such as /dev/sdb1, /dev/sdb2, etc... It will appear similar to the following:

      Disk /dev/sdb: 7.36 GiB, 7901020160 bytes, 15431680 sectors
      Disk model: Storage Device
      ...
      Device     Boot Start      End  Sectors  Size Id Type
      /dev/sdb1        8064 15431679 15429632 14.4G  b HPFS/NTFS/exFAT
    It is the identifier /dev/sdb1 that will be used to mount the drive.

  3. Once you've identified the drive (ie: sda, sdb, etc...) from the command prompt on the Pi, mount the drive to a directory on the Raspberry Pi with the command: sudo mount /dev/sdb1 /mnt

    The /mnt directory is a common location to mount external drives. If you have a different location you would like to use, you can change this to a different directory. The directory name will be referenced in a later step.

Clone the source SD card   Step 2 of 3

Use the Raspberry Pi to clone the source SD card as a disk image written to the USB drive.


Why use dd?
It is not enough to copy all of the files from one SD card to another.

dd makes a bit-for-bit copy of the entire SD card, including the boot sector, partition table, and all of the data on the card, saving it all to a single file.
What is the status=progress argument?
Using dd can take a long time! The `status=progress` argument will display how many bytes have been written out during this process.

Clone the SD card

With the Raspberry Pi setup with the SD card connected and USB Drive mounted, it's now ready to clone the entire contents of the SD card to a single *.img file.

  1. From the command prompt on the Pi, change to the directory where the image is located on the USB drive with the command: cd /mnt

    If you mounted the SD card to a different directory, change to that directory instead.

  2. Use the dd application to start cloning the SD card with the command: sudo dd if=/dev/sda of=pi-clone.img bs=4M status=progress   15+ mins
  3. Once the dd process has completed, you can remove the source SD card if desired, as it's no longer needed for this process.

  Notes:

  • The if parameter, eg: /dev/sda, /dev/sdb, is the location of the SD card, identified in Step 1, Part 2.
  • The of parameter, pi-clone.img is the name of the file where the contents of the SD card will be written.
  • The output file will be the same size as the SD card, so make sure you have enough space on the USB drive to hold the entire image.

Shrink the image.   Step 3 of 3

Install and run `pishrink.sh` to compress the cloned img file.


What is PiShrink?
PiShrink is an open-source script that will compress a pi image
Why srhink the image?
A typical SD card will contain a lot of empty space. The dd program will copy all of this empty space even though it's not really needed. Shrinking the image will remove this empty space, making the image smaller and easier to transfer to other devices.

Install PiShrink Part 1

From the command prompt on the Pi, complete the following steps:

  1. Download the pishrink script from github with the command: wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
  2. Add execute permissions to the pishrink script with the command: sudo chmod +x pishrink.sh

  3. Move the script to a folder for executables found in the path with the command: sudo mv pishrink.sh /usr/local/bin

Shrink the pi image Part 2

This next step will overwrite the original image file with a new, smaller image file. If you'd like to keep the original pi-clone.img, make a copy of it before proceeding.

From the command prompt on the Pi, complete the following steps:

  1. Change to the directory where the image is located on the USB drive with the command: cd /mnt

    If you saved the image to a different directory, change to that directory instead.

  2. Shrink and gzip the image with the command: sudo pishrink.sh -vz pi-clone.img   30+ mins
  3. PiShrink v24.10.23 - https://github.com/Drewsif/PiShrink
    
    pishrink.sh: Gathering data
    pishrink.sh: Checking filesystem
    rootfs: 122290/445312 files (0.1% non-contiguous), 1018640/1808384 blocks
    resize2fs 1.47.0 (5-Feb-2023)
    pishrink.sh: Shrinking filesystem
    resize2fs 1.47.0 (5-Feb-2023)
    Resizing the filesystem on /dev/loop0 to 1463731 (4k) blocks.
    Begin pass 2 (max = 8046)
    Relocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Begin pass 3 (max = 56)
    Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    The filesystem on /dev/loop0 is now 1463731 (4k) blocks long.
    
    pishrink.sh: Zeroing any free space left
    PiShrink v24.10.23 - https://github.com/Drewsif/PiShrink
    
    pishrink.sh: Gathering data
    pishrink.sh: An existing /etc/rc.local was not found, autoexpand may fail...
    grep: /tmp/tmp.uGvlhvd09L/etc/rc.local: No such file or directory
    Creating new /etc/rc.local
    pishrink.sh: Checking filesystem
    rootfs: 122290/445312 files (0.1% non-contiguous), 1018640/1808384 blocks
    resize2fs 1.47.0 (5-Feb-2023)
    pishrink.sh: Shrinking filesystem
    resize2fs 1.47.0 (5-Feb-2023)
    Resizing the filesystem on /dev/loop0 to 1463731 (4k) blocks.
    Begin pass 2 (max = 8046)
    Relocating blocks             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    Begin pass 3 (max = 56)
    Scanning inode table          XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    The filesystem on /dev/loop0 is now 1463731 (4k) blocks long.
    
    pishrink.sh: Zeroing any free space leftpishrink.sh: Zeroed 1.8G
    pishrink.sh: Shrinking partition
    pishrink.sh: Truncating image
    pishrink.sh: Using gzip on the shrunk image
    pi-clone.img:	 78.9% -- replaced with pi-clone.img.gz
    pishrink.sh: Shrunk pi-clone.img.gz from 7.5G to 1.3G

  4. Once PiShrink has completed, safely unmount the USB drive with the command: sudo umount /mnt
  Notes:
  • The -v tells PiShrink to be verbose
  • The -z tells PiShrink to gzip the image
  • The first argument, pi-clone.img is the source image file
  • The second argument, pi-clone.img.gz is the destination image file that is zipped

Conclusion

That's it! You can now copy the pi-clone.img.gz file to your hard drive, upload it to a cloud storage service, or share it with others. It can be used to create a new SD card with Raspberry Pi Imager.

Tutorial prepared with by James Eberhardt.

You can reelyActive's open source efforts directly by contributing code & docs, collectively by sharing across your network, and commercially through our packages.

Where to next?

Continue exploring our open architecture and all its applications.