Migrate a Plex Media Server database from a Synology NAS onto an NVIDIA Shield, while your media library stays on the NAS (mounted over SMB). The Shield becomes the server (HW transcode, <10 W, always-on); the NAS goes back to being just a file server.
You keep everything: all libraries, watch history, collections, and your custom artwork — and the server keeps the NAS's machine identity, so every Plex client reconnects seamlessly with no re-pairing.
Companion project: once you're up and running, keep the server fast and safe with plex-maintenance-toolkit — recommended Plex settings for a NAS-mounted library, a mount-checked trash emptier, and nightly-maintenance notifications.
Status: validated end-to-end on a DS918+ → Shield Pro (2019, Android 11) migration — the real-world failures encountered along the way shaped each guard in this tool.
That's the obvious approach and it's a trap. This tool exists because of what goes wrong:
- rsync chokes on Plex's
Metadata/tree — hundreds of thousands of tiny files send rsync's incremental recursion into a stall. We use a singletarstream instead. - The system
sqlite3can't touch Plex's database — Plex uses ICU collation; only Plex's ownPlex SQLitebinary can run the path remap without corrupting indexes. - A flaky USB drive silently corrupts everything — a drive that drops off the bus mid-write trashes the exFAT metadata. The tool health-checks the drive first and refuses to proceed if it isn't reliable.
- Skipping the clean eject corrupts the copy — pulling an exFAT drive that wasn't
sync'd + unmounted sets the dirty bit (the Shield then hangs on a filesystem check) and risks unflushed data. The tool's final step is a flush + clean eject, and the DB is proven on-disk withPRAGMA integrity_check.
NAS (source) USB (transport) Shield (destination)
┌──────────────────────┐ cp + tar ┌────────────────┐ move ┌────────────────────┐
│ Plex DB + Metadata │ ───────────► │ Android/data/ │ ──────► │ Plex starts off USB│
│ /volume1/Media (34TB)│ │ .../Databases │ │ media via SMB mount│
└──────────────────────┘ └────────────────┘ └────────────────────┘
stays on NAS ◄───────────────── SMB ────────────────────── /storage/IDISKSTATION
The media never moves. Only Plex's application data (DB + artwork, a few GB) is copied to the USB the Shield boots from. The DB's media paths are rewritten /volume1/Media → /storage/IDISKSTATION/Media so every title Direct Plays immediately, no rescan.
- Synology NAS with the Plex Media Server package (provides
Plex SQLite) and exFAT Access. - An NVIDIA Shield running the Plex Media Server (SMB) app, with ADB-over-WiFi enabled.
- A healthy USB drive (formatted exFAT). Format it on a Mac/PC, then health-test it (
./migrate.sh healthdoes a write+readback md5 — a cheap drive that drops off the bus mid-write will silently corrupt your data).- macOS:
diskutil eraseDisk ExFAT PLEX MBR /dev/diskN - Plex stores tens of thousands of tiny files. macOS defaults to a large 128 KB exFAT cluster, which roughly doubles on-disk usage and slows the copy. For a dedicated drive, prefer a smaller cluster:
sudo newfs_exfat -c 32768 -v PLEX /dev/rdiskNs1(32 KB), or format on Windows/Linux with a small allocation unit.
- macOS:
- A workstation with
adb+curlfor the post-boot verification.
-
Configure. Copy
config/migrate.conf→config/migrate.conf.localand edit the paths/IPs for your setup. -
On the NAS, with the USB plugged in:
./migrate.sh health # prove the drive is reliable first ./migrate.sh run # stop NAS Plex → copy DB+art → remap → integrity_check → eject
Or run the phases individually (
preflight,stop,copy-db,copy-art,remap,eject). -
Move the USB to the Shield and power it on. Plex starts from the USB.
-
On your workstation, verify the migration actually worked:
./verify-shield.sh # identity + libraries + history + Direct Play path resolution -
Rollback at any time — the NAS Plex data is untouched:
./migrate.sh rollback # restart the NAS Plex package
migrate.sh # NAS-side orchestrator (subcommands)
shield-control.sh # Shield-side control over ADB — DETERMINISTIC, no screenshots
verify-shield.sh # workstation-side post-boot acceptance check (ADB + Plex API)
tools/exfat-set-serial.py # change a USB's exFAT volume serial in place (see below)
config/migrate.conf # all environment-specific values
lib/common.sh # logging / formatting helpers
shield-control.sh controls the Shield with precise, repeatable adb commands —
never screenshots or blind dpad navigation (which break across Plex versions).
Commands: release-usb (unmount so you can remove the USB while the Shield stays
awake), wait-up, launch, datadir (prints which dir Plex resolved — the fast
way to catch a serial mismatch), verify, and up (the whole post-boot sequence).
Note: poweroff uses reboot -p, which drops the Shield into deep standby where
ADB cannot wake it — powering the Shield back on is a manual (remote) step.
Plex addresses a removable drive by its exFAT volume serial (e.g.
/storage/FC5A-A76C/...). If you migrate the data onto a different USB drive,
Plex keeps looking for the old serial, can't find its data, and falls back to
first-run setup — with no way to re-point it (the setting lives past the first-run
wall). Fix it by making the new drive report the old serial:
diskutil unmount /dev/diskNs1
sudo python3 tools/exfat-set-serial.py /dev/rdiskNs1 OLD-SERIAL # dry-run
sudo python3 tools/exfat-set-serial.py /dev/rdiskNs1 OLD-SERIAL --commit # writeIt rewrites only the 4-byte volume serial + the exFAT boot checksum (main and
mirrored backup) — no file data is touched. It self-validates its checksum against
the drive's existing one before writing, and refuses on mismatch. Find the old
serial in Plex's log: Kepler Server: [Storage] Application support dir is <path>
(or shield-control.sh datadir).
- The NAS Plex data directory is only read, never modified — rollback is just restarting the package.
- Every destructive or irreversible step pauses for confirmation (
--yesto skip in automation). - Don't decommission the NAS Plex until
verify-shield.shpasses and you've watched a few days of playback.
MIT — see LICENSE.