immich-duplicate-finder: diagnosed crashloop, redeployed as a proper stack
Why: Damien noticed the immich-duplicate-finder container was stuck in a restart loop in Portainer (had been for a while, never actually used). Wanted to know what was wrong and turn it into something usable for himself and for the partner/friends with Immich accounts.
1. Root cause of the crashloop
The container's working directory is /immich_duplicate_finder and its entrypoint is streamlit run app.py. app.py (and the rest of the app's source) is baked into the image at that path. But the running container had a Docker volume named immich_model-cache bind-mounted on top of /immich_duplicate_finder — and that volume contained Immich's own ML model cache (clip/, facial-recognition/, ocr/ dirs). The mount shadowed the source code, Streamlit couldn't find app.py, exited 2, and Docker restarted the container forever.
The original deploy was a one-off docker run (no compose labels, no Portainer stack), most likely copied from a snippet that mistakenly reused Immich's ML cache volume name expecting it to be the app's own cache.
2. Redeploy
Removed the broken container, then deployed via Portainer API (bypassing the 2.42.0 UI phantom-error bug) as a clean stack — no volume, since the image is self-contained and the app talks to Immich over HTTP:
services:
immich-duplicate-finder:
image: eulemitkeule/immich-duplicate-finder:latest
container_name: immich-duplicate-finder
restart: unless-stopped
ports:
- 8501:8501
Stack id 44 in Portainer. Streamlit responds with HTTP 200 on http://192.168.1.136:8501/.
3. Multi-user reality
The app reads the Immich server URL and API key from text inputs in its sidebar (not env vars), and persists them to a local settings.db (SQLite). There is no login, no per-user session isolation in the saved-settings sense. Practically:
- Each person's Immich API key only ever lets the app see their photos — that part is naturally safe.
- But the saved URL/key fields are shared. Whoever clicks Save last writes over the previous defaults.
- The duplicate-analysis output (
processed_assets.db,duplicates.db) is also shared — the last analysis someone ran is what others will see until they re-run with their own key.
Damien's stated plan: run it manually for each user as needed, just swap the URL+key in the sidebar between sessions. No persistence configured on this deploy — if the container restarts, the sidebar fields reset and any cached analysis is gone. Trade-off accepted in exchange for keeping the deploy simple (the alternative is bind-mounting individual SQLite files, which is fiddly and would only save a re-paste step).
4. Open question for next session
Sonarr (port 8989), Radarr (port 7878), and rdt-client (port 6500) are currently LAN-only. If external access is wanted, each needs an NPM proxy host plus a decision about auth (these are admin UIs — should not be naked on the internet). Worth deciding before adding proxy entries: LAN-only forever, LAN + tailscale/wireguard, or NPM with HTTP Basic in front. Deliberately not wiring any of this up tonight.
5. Retired same day — incompatible with Immich 2.x
Smoke test failed immediately: clicking "Find photos duplicate" returned 404 Not Found for https://photos.skyhouse.dev/api/asset/. Investigation showed the app targets the Immich 1.x API (GET /api/asset/), but this server runs Immich 2.7.5, where asset listing moved to POST /api/search/metadata with an entirely different request/response shape (the thumbnail and download endpoints changed too). That's a full immichApi.py refactor, not a path rename, and the upstream project hasn't kept pace.
Decision: retired the tool. Deleted Portainer stack 44 and the container. Immich 2.x has built-in duplicate detection (Administration → Jobs → Duplicate Detection, reviewed under Utilities → Duplicates), which is the path forward. The immich_model-cache volume was left intact — it belongs to immich_machine_learning, not this tool.