From Panic to Pixels: Migrating My NAS and Recovering an Immich Library the Hard Way⌗

I recently upgraded my homelab storage to a new NAS, and like any good plan, it worked perfectly… right up until it didn’t.

What started as a straightforward data migration turned into a deep dive into Docker, PostgreSQL, and how modern apps actually store data. In the end, I recovered everything—but not before learning a few lessons the hard way.


The Goal⌗

  • Move ~6.5TB of data from an old Ubuntu-based NAS

  • Stand up a new Unraid system (UGreen DXP4800 Plus)

  • Migrate services like Plex and Immich cleanly

Simple enough… in theory.


Step 1: Moving the Data⌗

I used rsync over SSH to transfer everything:

rsync -avh --progress /old/media/ /mnt/user/media/

After fixing a bad Ethernet cable (don’t underestimate layer 1), I was getting ~100MB/s, and the transfer completed without issues.


Step 2: Rebuilding the Stack⌗

On the new NAS:

  • Installed Unraid

  • Set up shares (media, appdata)

  • Deployed Immich using Docker Compose

Everything came up clean. Containers were running. UI loaded.

Then I opened Immich…

👉 “Create Admin Account”


Step 3: The “Oh No” Moment⌗

No photos. No albums. Nothing.

But I knew the data was there.

That’s when I learned a critical truth:

Apps like Immich don’t just read files—they rely heavily on a database.


Step 4: Understanding Immich Storage⌗

Immich doesn’t store photos in a human-readable way. Instead, it uses:

  • Hashed directories

  • UUID-based storage

  • Metadata stored entirely in PostgreSQL

So while my files existed, they were effectively meaningless without the database.


Step 5: Hunting Down the Database⌗

I initially copied what I thought was the database directory, but something felt off.

Eventually, I found the real one:

/home/miles/immich-app/postgres

From there, I:

  1. Stopped the Immich stack

  2. Wiped the new Postgres data directory

  3. Copied the old database over with rsync

  4. Fixed permissions (chown -R 999:999)

  5. Restarted the stack


Step 6: More Problems (Because of Course)⌗

After restoring the DB:

  • Containers started rebooting

  • Postgres authentication kept failing

Turns out:

  • The database had its own internal password

  • My .env file didn’t match it

I had to reset the password inside Postgres to align everything.


Step 7: The Unexpected Hero⌗

After all that… Immich still showed a “Restore Database” option.

I clicked it (against my better judgment 😄)

👉 And it worked.

Immich had been quietly creating nightly backups of the database, and I was able to restore from one of those.


Step 8: Everything Comes Back⌗

Suddenly:

  • Timeline populated

  • Albums restored

  • Metadata intact

  • Face recognition data preserved

Total recovery.


Lessons Learned⌗

1. Files ≠ Data⌗

Modern apps rely on databases. Without them, your files may be useless.

2. Always Migrate Database + Storage Together⌗

If you move one without the other, things break in weird ways.

3. Check the Actual Data Paths⌗

Configs don’t always match reality. Verify where things really live.

4. Permissions Matter⌗

Docker + Linux permissions can silently break everything.

5. Backups Are Everything⌗

Immich’s built-in DB backups saved me. Period.


What I’d Do Differently⌗

  • Backup the database explicitly before migrating

  • Validate the DB path before copying

  • Test restore before wiping the old system


Final Thoughts⌗

What started as a routine NAS upgrade turned into a full-on recovery exercise. But in the process, I gained a much deeper understanding of how my stack actually works.

And more importantly…

👉 I didn’t lose a single photo.


If you’re running services like Immich, Plex, or anything database-driven:

Don’t just back up your files—back up your data.