Adaptive Kind

How to boot a Raspberry Pi from a local SSD drive

Published on by

I've used a Raspberry Pi 4 in an Argon ONE M.2 case for a while. It allows me to attach an M.2 SATA SSD to my Pi, improving boot times and performance considerably. Let's go through how we can get the Pi booting from a SSD device.

Raspberry Pi with SSD

Preparing Pi OS on a USB memory stick

I like to be able to SSH straight onto a new install with SSH keys, so let's first prepare a SSH key on our local machine with ssh-keygen which we'll bake into the install image.

ssh-keygen -t ed25519 -C "lab@adaptivekind.com" -f ~/.ssh/id_lab

Copy into the clipboard ready to add it to the image configuration in the steps below.

cat ~/.ssh/id_lab.pub | pbcopy

On your local machine, insert the USB drive, open up the Raspberry Pi Imager, select Raspberry Pi Device "Raspberry Pi 4", operating system "Raspberry Pi OS Lite (64-bit)" (under the Raspberry Pi OS (Other) section), select USB drive to write to and click next. I opt for Pi OS Lite for this image since this Pi acts as server and I don't need any desktop windows access. If you can access the microSD slot more readily, you may wish to install the initial image on the microSD.

Raspberry Pi customise OS

Configure the image to make connecting quicker once you boot up. Edit settings, set the host name to, e.g., angus and set an admin username and password. Configure WiFi connection at this point if desired. If you connect over wired Ethernet you can skip the WiFi connection. Under the services tab, enable SSH, select allow public-key authentication only, copy in the SSH key from our clipboard and click save.

Raspberry Pi enable SSH

Click "YES" to apply customisation settings and click "YES" to acknowledge that this will erase existing data on USB drive and write the image to the USB drive. Note that the Raspberry Pi imager will remember this customisations settings on your local machine for next time so repeating these steps are easier.

Once completed you can remove the USB drive from your local machine ready for spinning up on your Pi.

Boot up and initial log in

The microSD on the Argon ONE case is only accessible if I unscrew the case, which is why I prefer to prepare an install image on a USB thumb drive that I can mount with more ease. The SSD drive on the Argon ONE connects via a USB loop back dongle which plugs into one of the USB ports on the Raspberry Pi board. I can remove this USB dongle temporarily when I want to boot from a USB memory stick which is easier than unscrewing the case.

Raspberry Pi in Argon ONE case

On this initial boot I attach the USB memory stick with the new image to the Pi, and remove the SSD USB dongle so that the system boots from my new image instead of any boot image on the SSD drive. If you've gone for installing the image on a microSD you can configure the Raspberry Pi boot sequence so it boots from microSD first and then USB so that the system boots from the microSD first and once moved to the SSD drive you can remove the microSD card so that the system boots from the SSD drive.

Turn on the Raspberry Pi and let the Raspberry Pi boot up and initialise. This should just take a couple of minutes. Once the Raspberry Pi has started SSH onto to the Pi. You may need to register the SSH key locally, e.g. with the ssh-add command.

ssh-add ~/.ssh/id_lab
ssh admin@angus

Once logged in, if haven't done so already, you can connect the SSD drive. In my case this is a matter of putting the SSD USB dongle back in.

Partition the SSD drive

I've got a 240GB SSD drive connected. I would like to limit the space for the boot and root partition to leave space for other partitions that I can use for other data mounts. Separating data from the root partition helps with data management through upgrades and other customisations such as setting up an encrypted file system.

Let's go for 480MiB for the boot partition and then 48GB, 20% of the drive, for the root partition. We can create these partitions with the parted command. Also follow the similar structure to that created by the Raspberry Pi Imager on the USB stick or microSD card. We can see this structure by running parted print against the USB memory stick device.

$ sudo parted /dev/sda print
Model: SanDisk Extreme (scsi)
Disk /dev/sda: 62.7GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:

Number  Start   End     Size    Type     File system  Flags
 1      4194kB  541MB   537MB   primary  fat32        lba
 2      541MB   62.7GB  62.2GB  primary  ext4

We'll drop into an interactive sudo shell for the next commands with

sudo -i

and then partition the drives

parted /dev/sdb mklabel msdos
parted /dev/sdb mkpart primary fat32 0% 1048559s
parted /dev/sdb mkpart primary ext4 1048560s 20%

I choose 1048559s boundary for optimal alignment for my drive whilst minimising the size of the boot partition. See GNU Parted: Solving the dreaded "The resulting partition is not properly aligned for best performance" for tips on getting the best alignment. Check that the partition has optimal alignment for the start and end locations you picked.

parted /dev/sdb align-check opt 1
parted /dev/sdb align-check opt 2

Make the file systems on each partition, matching the file systems on your memory stick or MicroSD card.

mkfs -t vfat -F 32 /dev/sdb1
mkfs.ext4 /dev/sdb2

Clone the OS from USB stick to SSD

You are now ready to clone the OS from the USB stick. You can use rpi-clone to clone the OS from the USB stick onto the SSD. Bill Wilson initially created billw2/rpi-clone in 2013 and Jeff Geerling took up the baton in February 2024 by creating an updated fork. geerlingguy/rpi-clone hosts the latest version of this.

Install rpi-clone and clone to the /dev/sdb device, i.e. the SSD drive. You will still need to be in the interactive sudo shell.

sudo -i
curl https://raw.githubusercontent.com/geerlingguy/rpi-clone/master/install | bash
rpi-clone sdb

This first asks for confirmation of what is about to happen:

Booted disk: sda 62.7GB                    Destination disk: sdb 240.1GB
---------------------------------------------------------------------------
Part               Size    FS     Label           Part   Size    FS     Label
1 /boot/firmware   512.0M  fat32  --              1      479.5M  fat32  --
2 root              57.9G  ext4   rootfs          2       44.2G  ext4   --
---------------------------------------------------------------------------
== SYNC sda file systems to sdb ==
/boot/firmware        (63.5M used)   : SYNC to sdb1 (479.5M size)
/                     (1.9G used)    : SYNC to sdb2 (44.2G size)
---------------------------------------------------------------------------
Run setup script       : no.
Verbose mode           : no.
-----------------------:

Ok to proceed with the clone?  (yes/no):

Enter "yes" to proceed. It may take a few minutes to complete the clone. You should see a log of what happened, e.g.

Syncing file systems (can take a long time)
Syncing mounted partitions:
  Mounting /dev/sdb2 on /mnt/clone
mount: (hint) your fstab has been modified, but systemd still uses
       the old version; use 'systemctl daemon-reload' to reload.
  => rsync // /mnt/clone with-root-excludes ...
  Mounting /dev/sdb1 on /mnt/clone/boot/firmware
mount: (hint) your fstab has been modified, but systemd still uses
       the old version; use 'systemctl daemon-reload' to reload.
  => rsync /boot/firmware/ /mnt/clone/boot/firmware  ...

Editing /mnt/clone/boot/firmware/cmdline.txt PARTUUID to use 8bcefdd4
Editing /mnt/clone/etc/fstab PARTUUID to use 8bcefdd4
===============================
Done with clone to /dev/sdb
   Start - 18:38:10    End - 18:39:13    Elapsed Time - 1:03

Cloned partitions are mounted on /mnt/clone for inspection or customizing.

Hit Enter when ready to unmount the /dev/sdb partitions ...

Once completed, click "Enter" to unmount the cloned drive and shutdown.

shutdown now

Remove the USB thumb drive and start up the Pi again to boot from the SSD device. If all goes OK, then you can SSH back into the Pi with the same credentials as before.

ssh admin@angus

Performance gain

You can quickly check the IO performance gain with some writes and reads with the dd command.

dd if=/dev/zero of=./speed-test.dat bs=20M count=50 oflag=direct ; \
dd if=./speed-test.dat of=/dev/zero bs=20M count=50 oflag=dsync

Which shows, for me, a 10 fold IO performance gain on the SSD device over the USB memory stick.

Type Read Write
USB memory stick 36 MB/s 26 MB/s
SSD 380 MB/s 229 MB/s

Cheat sheet

In summary, we can set up a Raspberry Pi to boot off SSD as follows.

  1. Prepare a customised image on removable drive
  2. Attach removable drive and starting up
  3. SSH in to machine
  4. Attach SSD device
  5. Prepare partitions (or skip if happy with rpi-clone defaults)
  6. Create file systems (or skip if happy with rpi-clone defaults)
  7. Run rpi-clone
  8. Remove removable drive and restart
sudo -i
# Prepare partitions
parted /dev/sdb mklabel msdos
parted /dev/sdb mkpart primary fat32 0% 1048559s
parted /dev/sdb mkpart primary ext4 1048560s 20%
# Create filesystems
mkfs -t vfat -F 32 /dev/sdb1
mkfs.ext4 /dev/sdb2
# Run rpi-clone
curl https://raw.githubusercontent.com/geerlingguy/rpi-clone/master/install | bash
rpi-clone sdb
shutdown now