Cloning/Migrating SSD/HDD on MacOS

Recently, I bought a new 2TB SSD for the Umbrel and wanted to clone all the data from the old SSD, mostly to avoid a new sync of the entire Bitcoin blockchain.

I couldn’t find any easy-to-follow tutorials, so this is what I did to migrate all the data to the new SSD using the macOS operating system for this task.

  1. Made sure I have backups for all wallets
  2. ssh umbrel@umbrel.local
  3. sudo shutdown -h now
  4. Turned off Raspberry Pi
  5. Connected both the old and new SSD disks to my macOS machine.
  6. Found names of both disks with the diskutil list command (example: /dev/disk4)
  7. Ran the disk duplication command: sudo dd if=source of=destination bs=64k
  8. In another terminal window, ran caffeinate -im to prevent the machine from going into sleep mode
  9. After ~12 hours, cloning was completed.
  10. Attached new SSD to the Raspberry Pi
  11. Done!

Note: Replace source and destination in the dd command with the actual device paths of your old and new SSDs, respectively.

If your new SSD is larger in size, also do this:

  1. ssh umbrel@umbrel.local
  2. sudo apt install cloud-init -y to get the growpart module
  3. df -h to find your drive (mine was /dev/sda1)
  4. sudo growpart /dev/sda 1
  5. sudo resize2fs /dev/sda1
  6. sudo reboot
4 Likes

This is great, the only thing i’d like to add here is the dd command could use status=progress

1 Like

Thanks for the tutorial.

The command can be enhanced like this:
sudo dd if=source of=destination bs=256k status=progress conv=fsync

bs=256k → Larger blocks reduce the number of read/write operations, making the process faster.

status=progress → Displays how many bytes have been copied, at what speed, and how long the command has been running.

conv=fsync → Ensures all data is written to disk before the process completes.

2 Likes

These instructions worked great to clone my 1TB Umbrel SSD to a new 2TB SSD on macOS. Thank you so much for providing this info!

Here are full steps that worked for me, verified, explained & enhanced with GPT-5 Thinking.

Umbrel: clone 1 TB → 2 TB on macOS

:warning: The destination disk will be overwritten. Triple-check identifiers by size.
:warning: Don’t boot the Pi with both old and new SSDs at the same time (duplicate UUIDs).

0) Clean shutdown of Umbrel (Raspberry Pi)

ssh umbrel@umbrel.local
sudo shutdown -h now

Wait until the Pi powers off. Unplug the old 1 TB SSD from the Pi.


1) Connect both SSDs to your Mac

  • Plug in old 1 TB (source) and new 2 TB (destination).

Identify just the externals:

diskutil list external

Example mapping (adjust to your output):

❯ diskutil list external
/dev/disk4 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk4
   1:       Microsoft Basic Data T7                      2.0 TB     disk4s1

/dev/disk5 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk5
   1:           Linux Filesystem                         1.0 TB     disk5s1
  • /dev/disk5old 1 TBSOURCE → use /dev/rdisk5

  • /dev/disk4new 2 TBDEST → use /dev/rdisk4

Tip: Re-run diskutil list external if you unplug/replug; numbers can change.


2) Unmount the whole disks (do NOT eject)

diskutil unmountDisk /dev/disk4
diskutil unmountDisk /dev/disk5

Unmounting frees the devices for raw cloning; “eject” would remove them from the system.


3) Keep the Mac awake

Run this in new Terminal tab/window.

caffeinate -dimsu

Leave this running while cloning. You’ll stop it later with Ctrl-C (Step 7).

  • -d prevent display sleep

  • -i prevent idle sleep

  • -m prevent disk sleep

  • -s prevent system sleep

  • -u simulate user activity

Alternatively, use an app like Amphetamine.


4) Check which dd you have installed

GNU with live progress vs. stock BSD

which gdd
which dd
dd --version   # GNU dd prints a version; BSD dd will complain about --version

  • If which gdd prints something like /opt/homebrew/bin/gdd, you have GNU dd → you’ll get live progress.

  • If not installed, you can add it: brew install coreutils (command is gdd), or skip to step 5-alt)

Example output

/opt/homebrew/bin/gdd
/bin/dd
dd: unknown operand --version

5) Clone using gdd (GNU dd) — with live progress

sudo gdd if=/dev/rdisk5 of=/dev/rdisk4 bs=4M status=progress conv=fsync

Flags

  • if=/dev/rdisk5input file: the raw source device (old 1 TB).

  • of=/dev/rdisk4output file: the raw destination device (new 2 TB).

  • rdisk* vs disk*rdisk is the raw device; it bypasses extra buffering for faster I/O on macOS.

  • bs=4Mblock size 4 MiB: reduces syscall overhead and usually maxes out USB-SSD throughput.

  • status=progresslive progress (bytes copied, speed, elapsed). GNU gdd feature only.

  • conv=fsyncflushes all write buffers at the end, ensuring data is physically on disk when the command exits.

Example output

Mine took 1hr 34min

❯ sudo gdd if=/dev/rdisk5 of=/dev/rdisk4 bs=4M status=progress conv=fsync

245903654912 bytes (246 GB, 229 GiB) copied, 890 s, 276 MB/s

Optional resilience
slower; only if you suspect read errors on the old SSD:

sudo gdd if=/dev/rdisk5 of=/dev/rdisk4 bs=1M status=progress conv=noerror,sync,fsync

  • noerror → don’t stop on read errors; continue.

  • sync → zero-pad unreadable blocks so offsets stay aligned.

  • This protects against a flaky source but costs throughput.

5-alt) Clone using stock macOS dd (BSD) — no live progress

sudo dd if=/dev/rdisk5 of=/dev/rdisk4 bs=4m conv=fsync

  • Progress: press Ctrl-T in that Terminal to print a status snapshot (BSD feature).

  • Note: bs=4m is lowercase m with BSD dd.


6) When the clone finishes

Eject both disks:

diskutil eject /dev/disk4
diskutil eject /dev/disk5

STOP CAFFEINATE: go to the window where it’s running and press Ctrl-C (or just close that window). This returns your Mac to normal sleep behavior.


7) Move the new 2 TB SSD to the Pi and boot

  • Plug only the new 2 TB SSD into the Pi.

  • Power on the Pi. Don’t connect the old SSD at the same time.


8) Expand the partition to use the full 2 TB (on the Pi)

Install the tool that provides growpart:

sudo apt update
sudo apt install -y cloud-guest-utils

Why install this?
The clone copied a 1 TB partition layout onto a 2 TB disk. You now need to:

  1. Grow the partition boundary to fill the disk (growpart).

  2. Resize the filesystem (ext4) to use that bigger partition (resize2fs).

Identify the disk/partition:

lsblk -f
# Typically you'll see the SSD as /dev/sda with the main ext4 partition /dev/sda1

Grow the partition, then the filesystem:

sudo growpart /dev/sda 1
sudo resize2fs /dev/sda1

  • growpart /dev/sda 1 – “stretch” partition 1 on /dev/sda to fill the remaining unallocated space.

  • resize2fs /dev/sda1 – expand the ext4 filesystem inside that partition to the new size.

Verify and reboot:

df -h
sudo reboot

  • df -h should now show ~2 TB available for your Umbrel data.

Sanity checklist

  • Pi boots normally with just the new SSD.

  • df -h shows the main partition near 2 TB size.

  • Umbrel services behave the same as before.


Quick safety notes

  • Re-check diskutil list external every time you reconnect drives; identifiers can change.

  • unmountDisk (Step 2) is required so the raw devices aren’t in use; don’t skip it.

  • gdd is optional but recommended for a real progress bar; stock dd works fine with Ctrl-T.