Skip to content

fix(deploy): /var/run tmpfs mode 0755 → 1777 so supervisord can write pidfile as UID 1000#581

Closed
enihcam wants to merge 2 commits into
HKUDS:devfrom
enihcam:fix/var-run-mode
Closed

fix(deploy): /var/run tmpfs mode 0755 → 1777 so supervisord can write pidfile as UID 1000#581
enihcam wants to merge 2 commits into
HKUDS:devfrom
enihcam:fix/var-run-mode

Conversation

@enihcam

@enihcam enihcam commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

One-line fix to compose.yaml: the deeptutor service's /var/run tmpfs entry is changed from mode=0755 to mode=1777. Same shape as /tmp, which has worked cleanly.

This eliminates a CRIT could not write pidfile /var/run/supervisord.pid line on every container start when the stack is run under rootless podman with userns_mode: keep-id and read_only: true.

Closes #580

Why

PR #577 made the image drop privileges to a fixed non-root deeptutor user (UID 1000) before exec gosu deeptutor supervisord in the entrypoint. With read_only: true and a tmpfs-backed /var/run at mode=0755 (owned by root), PID 1 (UID 1000) can no longer create the supervisord pidfile. The pidfile is best-effort — children still spawn and reach RUNNING state — but the CRIT line in podman compose logs -f deeptutor is noise that hides real failures.

PocketBase's /var/run (compose.yaml line 82) is intentionally left at mode=0755 — pocketbase does not run supervisord inside the container, so no pidfile is written there.

Reproduction

  1. Pull the merged images: podman pull ghcr.io/hkuds/deeptutor:latest && podman pull ghcr.io/muchobien/pocketbase:latest
  2. cp .env.example .env
  3. podman compose -f compose.yaml up -d
  4. Wait for deeptutor and pocketbase to reach healthy
  5. podman compose -f compose.yaml logs deeptutor | grep -i crit
  6. Observe: CRIT could not write pidfile /var/run/supervisord.pid

Fix

-      - /var/run:size=8m,mode=0755
+      # /var/run is sticky + world-writable so PID 1 (UID 1000, the
+      # non-root deeptutor user added in PR #577) can create
+      # supervisord's pidfile at /var/run/supervisord.pid without
+      # tripping a CRIT on every container start.
+      - /var/run:size=8m,mode=1777

/var/run is mode 1777 (sticky + world-writable). Sticky is unnecessary here (single user, single process) but matches the /tmp convention and is harmless.

Acceptance criteria

  • podman compose -f compose.yaml up -d brings the stack up on rootless podman with userns_mode: keep-id, read_only: true, and the documented tmpfs paths.
  • podman compose -f compose.yaml logs deeptutor | grep -i crit returns no pidfile lines.
  • podman exec deeptutor ls -la /var/run/supervisord.pid shows the file owned by deeptutor:deeptutor.
  • Both services reach healthy in the same time as before.
  • The full end-to-end probe set (backend root, frontend HTML, proxy.ts /api/v1/foo rewrite, PocketBase /api/health, useAuthStatus JSON, /api/v1/auth/status, direct + proxied WebSocket ping/pong) continues to pass.

Severity

Cosmetic / log-noise only. Children still spawn and the stack is fully functional — this is a papercut on the deployment story, not a blocker.

Related

Files changed

 compose.yaml | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

One commit, one file. No image rebuild needed — the fix is in the deployment config only.

nanw added 2 commits June 22, 2026 14:45
…e pidfile as UID 1000

Closes HKUDS#580

Under rootless podman with userns_mode: keep-id and read_only: true, the
container's PID 1 runs as the deeptutor user (UID 1000, added by PR HKUDS#577).
The compose.yaml mounted /var/run as a tmpfs with mode=0755, owned by root.
supervisord's pidfile at /var/run/supervisord.pid could not be written by
the non-root process, producing a CRIT on every container start:

  CRIT could not write pidfile /var/run/supervisord.pid

The pidfile is best-effort (children still spawn and reach RUNNING state),
but the log noise hides real failures.

Switch /var/run to mode=1777 (sticky + world-writable) so PID 1 can create
the pidfile. Same shape as /tmp, which has worked cleanly.

PocketBase's /var/run (compose.yaml line 82) is left at mode=0755 — it
does not run supervisord inside the container, so the pidfile is not
written there.

Refs: HKUDS#580 (related: HKUDS#576, HKUDS#577)
Move bind mount source from ./data to ${HOME}/.local/share/deeptutor
so the host location follows the XDG_DATA_HOME standard and is
independent of the working directory.

Per-user deployment — not coupled to the repo working tree.

Compose-divergence note: docker-compose.yml still uses ./data. The two
files serve different deployment modes (rootless per-user vs.
daemon-mode shared) and are intentionally divergent.

Migration: existing users with state under ./data will need to move it
to ~/.local/share/deeptutor manually. CONTAINERIZATION.md will be
updated in a follow-up to note the new default.

Refs: HKUDS#580, HKUDS#581
@pancacake

Copy link
Copy Markdown
Collaborator

Thanks for digging into this — but the root cause is already gone, so this fix is no longer needed.

The PR assumes PID 1 runs as UID 1000 via exec gosu deeptutor supervisord (from #577). A few hours after this PR was opened, that approach was reverted: supervisord now runs as root (PID 1), and only the backend/frontend children drop to deeptutor via per-program user= directives.

  • bac68364fix: run supervisord as root so services start under rootful Docker
  • 8ad39f70chore(docker): drop now-dead gosu/libcap2-bin infra

With root as PID 1, it can write /var/run/supervisord.pid even at mode=0755 (root owns the tmpfs), so the CRIT could not write pidfile from #580 no longer happens on current dev. The 0755 → 1777 change is now a no-op, and its new comment ("PID 1 (UID 1000)") would actually be wrong.

Separately, the second commit moves the data bind mount ./data → ${HOME}/.local/share/deeptutor. That's unrelated to #580, isn't mentioned in the Summary, and is a breaking change for existing users (manual data migration) with no doc update. If the XDG convention is worth doing, it deserves its own PR with a migration note in CONTAINERIZATION.md.

Closing as superseded by the root-supervisord fix. Appreciate the careful write-up regardless 🙏

@pancacake pancacake closed this Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants