fix(deploy): MountFlags=shared on web service for fuse mount propagation

ProtectSystem=full + ReadWritePaths implicitly give the unit a private
mount namespace (systemd needs to remount /usr read-only). The default
namespace propagation is slave, so mounts the worker creates inside
never reach the host. The gameserver units (started via systemctl,
each with their own namespace) then inherit a host that lacks the
overlay, and their CHDIR into /var/lib/left4me/runtime/<name>/merged
fails.

Set MountFlags=shared so mount events propagate from the worker's
namespace back to the host, then onward to gameserver units at their
unshare time.

Verified on test box: nsenter -t <gunicorn-pid> -m mount showed the
fuse-overlayfs mount inside the worker but plain mount on the host
did not, while web unit had ProtectSystem=full + ReadWritePaths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mwiegand 2026-05-07 02:01:24 +02:00
parent 593611e194
commit 1968684c03
No known key found for this signature in database

View file

@ -17,14 +17,15 @@ Restart=on-failure
RestartSec=3 RestartSec=3
# NoNewPrivileges intentionally not set: the worker invokes fusermount3 # NoNewPrivileges intentionally not set: the worker invokes fusermount3
# (setuid-root) and sudo to run the systemctl wrapper. # (setuid-root) and sudo to run the systemctl wrapper.
# PrivateTmp intentionally not set: it creates a private mount # ProtectSystem=full + ReadWritePaths implicitly give this unit a
# namespace, which would hide per-instance fuse-overlayfs mounts from # private mount namespace. MountFlags=shared makes its mount events
# the host and the gameserver units. The mount must land in the host # propagate back to the host so per-instance fuse-overlayfs mounts are
# namespace so the systemd-managed gameserver service inherits it at # visible to the gameserver units (which inherit host mounts at their
# unshare time. Remaining hardening: dedicated user, ProtectSystem, # own unshare time). Without it, the per-instance mount only exists
# ReadWritePaths, narrow sudoers allowlist. # inside the worker's namespace and the gameserver units fail CHDIR.
ProtectSystem=full ProtectSystem=full
ReadWritePaths=/var/lib/left4me ReadWritePaths=/var/lib/left4me
MountFlags=shared
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target