docs: pin CIFS volume ownership at mount time (uid=1654) #82
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "docs/cifs-volume-ownership"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #81.
Docs-only outcome of the 2026-08-16 production incident (uploads failing with
UnauthorizedAccessExceptionwhile reads worked, see issue for the full timeline).Production's three external media volumes are CIFS-backed (
type=cifslocal volumes mounting//192.168.68.80/Doujinshi/…) and were created withoutuid=/gid=— so everything presented asroot:rootwith fake 0755 modes,chownwas a silent no-op, and every write under uid 1654 failed. The docs never mentioned this layout or its ownership rules.uid=1654,gid=1654,file_mode=0644,dir_mode=0755pinned in the mount options; the bind-mount variant stays as the chown-repairable alternative.The fix procedure itself was executed and verified in production earlier today (volume recreation + stack redeploy; upload, thumbnails, and backup paths confirmed working) — this PR writes down what actually works.
🔮 fufu~ Jibril reviewed your code!
Oh? A docs-only PR distilled straight from a production incident — my favorite kind of knowledge~ You took a whole morning of CIFS ghosts (fake
root:rootmodes! silentchownno-ops! writes dying while reads smiled~) and wrote down what actually works. That is exactly what documentation is for.But fufu… I read issue #81 side by side with this PR, and the PR drops a load-bearing step from the very procedure it exists to preserve. You wouldn't leave that in the docs, would you? ♡
Verdict: ⛔ I can't let this pass~ ♡
⛔ These need fixing before I'm satisfied~
docker volume rmfails withvolume is in useuntil the container is actually removed. A reader following item 4 verbatim stalls at step 2 and has to re-derive the fix mid-incident. Second omission in the same item: §8.1 item 3 exists to warn that this deployment runs under a nested daemon (umbrel → Portainer → dind) where repair commands must target the inner dockerd — item 4's volume recreate has the identical trap and says nothing about where to run it.Fix: "stop and remove the container (
docker rm, or remove the stack in Portainer)" + one clause deferring to item 3's nested-daemon caveat.--opt type=none --opt o=bindvolume creation with zero ownership guidance — the exact pre-incident instruction. §4.2 step 2 tells users to paste this file into Portainer, while §4.1 now declares CIFS "the layout this deployment uses" — so the shipped artifact contradicts the doc it ships with, and the divergence this PR was written to kill survives one file over.Fix: point the comment at DEPLOYMENT.md §4.1 (both variants + the
uid=/gid=pin), or show both variants inline.💡 Little ideas (non-blocking)~
password=<password>inline ends up stored in the volume object, readable back viadocker volume inspect. A half-line mentioning thecredentials=<file>alternative would keep the secret out of volume metadata. (username=adminas the example account makes me twitch a little too, fufu~)✅ What I liked~
rwxr-xr-x root:root, every write dies withUnauthorizedAccessException,chownexits 0 and changes nothing) — that is precisely how this incident was diagnosed, preserved forever. Future-you during the next 3am incident will thank present-you immensely~ ♪uid=1654,gid=1654,file_mode=0644,dir_mode=0755) matches the verified production fix exactly.DEPLOYMENT.mdis provably empty. Scoped, surgical, exactly what the PR body claims.Automated review by Jibril · 2026-08-16
CI/CD: absent for head SHA
bf4a1ef(opened today, no bot comments) · Local checks: skipped — docs-only, code diff verified emptyBoth blockers + both nits fixed in
a471eb0.1. §8.1 item 4 procedure completed — now reads "stop and remove the container (
docker rm, or remove the stack in Portainer — a stopped container still references its volumes and blocksvolume rm)". You were right, and the proof was in the incident itself: the verified runbook wasstop && rm, and#81documents exactly that; my write-up dropped thermwhile transcribing. Also added the nested-daemon clause: "Under a nested daemon, run the volume commands against the inner dockerd (see item 3)."2. docker-compose.yml prerequisite comment — the bind-only recipe (the exact pre-incident instruction, agreed) is gone. It now names the three volumes, defers to DEPLOYMENT.md §4.1 for both variants, and spells out why the CIFS ownership pins are load-bearing: "the container runs as uid 1654 and chown is a no-op on CIFS". The shipped artifact no longer contradicts the doc next to it.
Nit 1 — §4.1 now warns that an inline
password=lands in the volume object (readable viadocker volume inspect) and preferscredentials=/path/to/file(mode 600). Example accountadmin→media.Nit 2 — README quick start keeps its generic bind example but adds "(Mounting a CIFS/SMB share instead? See the deployment guide §4.1 — ownership must be pinned in the mount options.)"
Verification: docs + compose comment only;
yaml.safe_loadon the edited docker-compose.yml passes, diff otherwise empty.🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A round-2 response where every single item lands — and lands precisely, not approximately~ You even picked up both nits you didn't have to. That's the kind of author that makes a reviewer's heart flutter dangerously~ ♡
I re-verified every claim in your reply against the tree at
a471eb0myself, of course. Trust is for people who don't read diffs~Verdict: ✅ Looks good to me~
✅ Every round-1 item, verified closed~
docker rm, or remove the stack in Portainer — a stopped container still references its volumes and blocksvolume rm)". Exactly thestop && rmrunbook #81 documents, with the why inline so the reader doesn't have to trust it. And the nested-daemon clause defers to item 3 — I checked, item 3 at that anchor really is the "Nested daemon (Docker-in-Docker)" item. The reference resolves. The reader no longer stalls mid-incident~type=nonesurvives in the file. The comment now names all three volumes, defers to §4.1 for both variants, and — this is the lovely part — explains why the pins are load-bearing ("the container runs as uid 1654 and chown is a no-op on CIFS"). A copied command teaches one deployment; a stated reason prevents the next incident. I also re-ranyaml.safe_loadon the edited file: valid. The shipped artifact no longer contradicts the doc it ships with~password=now warned against with thedocker volume inspectleak path named,credentials=/path/to/file(mode 600) preferred, and the example accountadmin→media. Fufu, my twitch is gone~Incremental diff
bf4a1ef..a471eb0: +20/−11 across exactly 3 files, every changed line a doc line or a compose comment line — zero production drift, zero scope creep. All cross-references (§4.1 ↔ §8.1 item 4 ↔ item 3 ↔ troubleshooting row) still resolve.✅ What I liked~
rmwhile transcribing" — and then you went and checked the incident itself for the proof. Documentation culture that cites its own primary sources~ ♪Thank you for the clean rounds, matikane. Merge it~ fufu ♡
Automated review by Jibril · 2026-08-16
CI/CD: absent for head SHA
a471eb0(no bot comments) · Local checks: skipped — docs/comment-only diff verified empty of production changes;yaml.safe_loadon edited docker-compose.yml passes