How to Use a Real Hard Drive on a Raspberry Pi

With my recent success of setting up an m.2 drive on a Raspberry Pi, I thought I’d repurpose an old 3.5″ SATA drive. I jumped on and found a GeeekPi SATA Expansion Board X825. You screw the hard drive to one side of it and mount the Raspberry Pi to the other.

There’s a USB3 bridge to connect the USB ports of the two cards.

Then attach a jumper wire from the expansion board to +5v on the GPIO to power the Raspberry. Reading the specs, I decided to go ahead and purchase the 4A power supply as well, since the Raspberry would never be able to provide enough juice to the mechanical hard drive.

Boot It UP!

Prepare an SD card to boot from and apply power to the expansion board (not the USB-C on the Raspberry). Push the power button and the Raspberry springs to life. Once you get organized, changing passwords and timezones, do a lsblk and check for the hard drive:

root@nas:~# lsblk
sda 8:0 0 3.7T 0 disk
└─sda1 8:1 0 3.7T 0 part
mmcblk0 179:0 0 14.9G 0 disk
├─mmcblk0p1 179:1 0 256M 0 part /boot
└─mmcblk0p2 179:2 0 14.6G 0 part /

It works! Now, what we need to do is partition the drive. We’ll create a 256M partition for /boot and we’ll create a second partition for the root file system comprised of the rest of the drive.

root@nas:~# parted
GNU Parted 3.2 Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands. (parted) mklabel gpt
(parted) mkpart
Partition name? []? boot
File system type? [ext2]?fat32
Start? 1 End? 256M
(parted) mkpart
Partition name? []? root
File system type? [ext2]? ext4
Start? 256M
End? 100%
(parted) p
Model: ASMT 2115 (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt
Disk Flags:
Number Start End Size File system Name Flags
1 4194kB 273MB 268MB fat32 Microsoft basic data msftdata
2 273MB 4001GB 4001GB ext4 Linux filesystem
(parted) q

Move Your Data

Next, we need to create file systems on the two partitions:

root@NAS:~# mkfs /dev/sdb1
mke2fs 1.44.5 (15-Dec-2018)
Creating filesystem with 248832 1k blocks and 62248 inodes
Filesystem UUID: 01df2433-a986-4358-b9a2-9062de0101c1
Superblock backups stored on blocks:
8193, 24577, 40961, 57345, 73729, 204801, 221185
Allocating group tables: done
Writing inode tables: done
Writing superblocks and filesystem accounting information: done
root@NAS:~# mkfs /dev/sdb2

Next, let’s rsync everything from /boot to our new boot partition on /dev/sda1. Then we’ll unmount and remount sda2 and copy all of / :

root@NAS:~# mount /dev/sda1 /mnt
root@NAS:~# rsync -avx /boot /mnt
root@NAS:~# umount /mnt
root@NAS:~# mount /dev/sda2 /mnt
root@NAS:~# rsync -avx / /mnt

(I’ve only shown the commands, not the standard output.)

Next, we’ll need to edit /boot/cmdline.txt ON THE HARD DRIVE, not on the SD card, so that when the system boots from /dev/sda1, it can find the root file system on /dev/sda2. Of course, you COULD just specify the location of the file system with those names, but no promises that everything will work if you ever put another peripheral in one of the other USB ports! Copy the PARTUUID for /dev/sda2 and paste it into /boot/cmdline.txt, replacing the UUID for the SD card:

root@NAS:~# blkid
/dev/sda1: LABEL_FATBOOT="boot" LABEL="boot" UUID="4AD7-B4D5" TYPE="vfat" PARTLABEL="Microsoft basic data" PARTUUID="c70c87e1-9461-4d4a-bca4-7ae79526fc11"
/dev/sda2: LABEL="rootfs" UUID="2887d26c-6ae7-449d-9701-c5a4018755b0" TYPE="ext4" PARTLABEL="Linux filesystem" PARTUUID="05b3b063-c450-4f96-b498-0acfdcc5b2c4"
root@NAS:/# mount /dev/sda1 /mnt
root@NAS:/# cd mnt
root@NAS:/mnt# vi cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=05b3b063-c450-4f96-b498-0acfdcc5b2c4 rootfstype=ext4 elevator=deadline rootwait

We’re also going to have to edit /etc/fstab. This determines what file systems are mounted and available on the system. /dev/sda1 is just /boot. /dev/sda2 is /, that is, the rest of the file system. So mount /

mount /dev/sda2 /mnt

and then edit the new working fstab in /mnt/etc/fstab. We’re going to use those same UUIDs in fstab:

proc /proc proc defaults 0 0
PARTUUID=c70c87e1-9461-4d4a-bca4-7ae79526fc11 /boot vfat defaults 0 2
PARTUUID=05b3b063-c450-4f96-b498-0acfdcc5b2c4 / ext4 defaults,noatime 0 1

Save your work. At this point, we should be ready to roll. The Raspberry Pi 4 will try to boot from SD. If there’s nothing in the SD card slot, it will go out to the USB ports, looking for a boot partition. If it finds one, it will use it. Since we just edited the cmdline in that partition, the boot process will ALSO find the / (root) file system and load up the operating system! Ready? Shutdown the Raspberry. Pull the power. Pull the SD card. Apply power. (Cross your fingers.) And wait a little longer than you’re used to. And if things go as planned, you should get a login prompt!

Winner, Winner, Chicken Dinner!

root@NAS:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 3.6T 1.3G 3.5T 1% /
devtmpfs 1.8G 0 1.8G 0% /dev
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 1.9G 8.5M 1.9G 1% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/sda1 253M 54M 199M 22% /boot
tmpfs 383M 0 383M 0% /run/user/0

Yep! Check the size of that / partition! Lots of room! AND NO SD card to crash and foul things up! Definitely a win-win!

One thought on “How to Use a Real Hard Drive on a Raspberry Pi”

  1. Thanks John!
    Exactly what I was looking for (but for a a SSD disk). I did not finish yet, but I will have a few differences with your setup :
    1) I created 2 more partitions: a swap partition, and a “data” one (/export in my case), from where I will bind-mount /tmp, /var, and /home, leaving root partition mostly read-only.
    2) For rsync, I prefer to preserve hard links, for instance “rsync -avHx src dest”.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.