My Free Photo Backup, Part 2: How I Broke It With One
This is the follow-up to "Why I Still Use a Pixel 5 in 2026: The Ultimate Storage Hack". Back then I explained the idea. This post is what happened when I actually built it — including the night I turned 26,000 family photos into blank files, and exactly how I fixed it so it never happens again.
If you just want the safe setup and don't care about my mistake, jump to The Fix. But honestly, the mistake is the whole lesson.
Quick recap: what I am actually building
The goal has not changed. I want my family's photos backed up to Google Photos for RM 0.00, using the old Pixel 5's unlimited "Storage Saver" backup. My home server is only the middle man. The flow looks like this:
Family phones ──▶ Immich (home server) ──▶ Syncthing ──▶ Pixel 5 ──▶ Google Photos
│ │
keeps thumbnails unlimited backup
+ a checksum record (Storage Saver)
│
deletes the big original
AFTER the Pixel has it
The important part is that last step. My server has a small disk. Once a photo is safely on the Pixel and backed up to Google, I want to delete the full-size original on the server to reclaim space — but keep enough information in Immich that the same photo is never re-imported and duplicated.
That "delete the original but not really" step is where I shot myself in the foot.
The mistake: truncate -s 0
My first cleanup script was clever, and wrong. To "empty" a file without deleting it, I used:
truncate -s 0 photo.jpg
This sets the file to 0 bytes but keeps the filename. In my head, this was perfect: Immich still sees the filename, so it won't re-download, and I get my disk space back. I ran it across the whole library.
A few days later I opened Google Photos on the Pixel and my stomach dropped. Hundreds of photos were pure blank white files. No image. No data. And Google was refusing to back them up because there was nothing to back up.
I had not saved space. I had quietly overwritten my good backups with nothing.
Why it broke (this is the key insight)
Syncthing does not think in terms of "the user deleted the content." It watches files for changes. When I truncated a file to 0 bytes, Syncthing saw that as a modification — "oh, this file changed, better sync the new version to the Pixel." So it dutifully pushed the empty 0-byte version over the top of the perfectly good photo already sitting on the phone.
So the exact thing meant to protect my backup was destroying it. A truncate on the server = a blank file on the Pixel = a failed Google backup. Lesson learned the hard way.
The Fix: three rules that make it safe
The rebuilt setup follows three rules. If you copy nothing else from this post, copy these.
Rule 1 — Never truncate. Actually delete.
A real rm is a delete, not a modify. Syncthing treats those completely differently, which leads to Rule 2.
Rule 2 — Tell Syncthing to ignore my deletes
Syncthing has a per-folder setting called Ignore Deletes. With it turned on, when I delete a file on the server, that deletion is not propagated to the Pixel. The Pixel keeps its copy; the server frees its space. Exactly what I wanted all along.
In the Syncthing web UI: Edit Folder → Advanced → tick "Ignore Deletes". (In the config it appears as ignoreDelete.) On the Pixel side, set the folder to Receive Only and turn on Trash Can file versioning as a second safety net.
Rule 3 — Only delete a file after the Pixel confirms it has that exact file
This is the rule that would have saved me. Before deleting any original, my script asks Syncthing, per file: "does the Pixel actually have this one yet?" Only if the answer is yes (and the file is at least 7 days old, so Google Photos has had time to pull it off the phone) does it get deleted.
But won't Immich just re-download the photo again?
No — and this is the part people worry about. Immich prevents duplicates using a checksum (a unique fingerprint of each file) stored in its database, not by looking at whether the big original file is still on disk.
When I delete the full-size original, I keep:
- the database record (filename + checksum), so Immich knows it already has this photo;
- the thumbnail, so the photo still shows up in the timeline.
If the same family photo ever tries to upload again, Immich matches the checksum and says "already have it" — no duplicate. So my library stays clean even though the heavy originals are gone. Best of both worlds.
The cleanup script (the safe version)
I run a manual script when the server disk gets full. It refuses to delete anything unless all three conditions are met. Here is the core logic, cleaned up so you can adapt it:
# For each original file in the library:
# 1. Skip if it is already empty (nothing to reclaim).
# 2. Ask Syncthing if the Pixel has THIS file:
# GET /rest/db/file?folder=<id>&file=<path>
# Only continue if the Pixel appears in ".availability".
# 3. Skip if the file is younger than 7 days (grace period).
# 4. Only then: delete it (real rm).
# The script also REFUSES to run unless "Ignore Deletes" is on,
# so a delete can never propagate to the phone.
It always runs as a dry run first and prints what it would delete. Nothing is removed until I add --apply. After the disaster, I never trust a cleanup script that deletes on the first run.
The golden lesson: "idle" does not mean "backed up"
Here is the trap that nearly caught me a second time. I opened Syncthing on my server, saw the folder said "Up to Date / 0 files needed / idle", and assumed everything was safely on the Pixel. It was not.
When I checked the completion toward the Pixel specifically, it was only 37%. The Pixel still needed 36 GB of photos it had never received.
Why did the server say "idle"? Because the Pixel was offline. The server had nothing to send right now, so it sat there looking finished — but "nothing to send to a phone that isn't listening" is very different from "the phone has everything."
Always check completion toward the receiving device, not just the sending side's status. A server that says "idle" with the phone unplugged is telling you nothing.
This is exactly why Rule 3 (per-file confirmation) matters. Even with the folder looking "done", my script correctly deleted zero files, because it checks each file against the Pixel individually — and the Pixel simply didn't have them yet.
Where I'm heading next: an external SSD on the Pixel
Running 24/7 backups means constant writing to the Pixel's internal storage, and flash memory wears out with writes. So the next upgrade is to mount an external SSD to the Pixel 5 (it's rooted) and point the backup at that, sparing the phone's internal chip. I'll document that build — hardware, formatting, and the mount script — in Part 3.
Related troubleshooting note: I also wrote how Claude Code helped me investigate a stuck Immich upload and safely check folders here: Claude Code + Immich: Fixing a 5GB Stuck Upload on My Home Server.
Final thoughts
The idea from Part 1 works. But the difference between "a clever idea" and "a backup I trust with my family's memories" was learning two things the hard way:
- Truncating a file is a modification, not a deletion — and sync tools will happily copy that emptiness onto your good backups.
- "Idle" is not "safe." Verify per file, on the receiving device, before you delete anything.
Get those two right, add a grace period, and you have a photo pipeline that quietly keeps your server small and your Google Photos full — still at RM 0.00. Just please, learn the truncate lesson from my blank photos instead of your own.
Questions or want the full scripts? Drop a comment.
Related photo backup posts
If you want the full context of this free photo backup setup, these are the related posts:
Comments