A 4-Line fstab Bind Mount Let Caddy Serve Private Home Files
Caddy couldn't read /home/tacavar/Desktop. One fstab line fixed it without chmod 777. This is the caddy bind mount pattern that let Tacavar serve private home files at hub.tacavar.com/videos without copying data or weakening permissions.
Caddy runs as uid 995 and /home/tacavar is chmod 750
On Tacavar's edge host, Caddy runs as uid 995. Not root, not the tacavar shell user. That is correct. But /home/tacavar is chmod 750, so only the owner can traverse it. Caddy cannot walk through /home/tacavar to reach /home/tacavar/Desktop. Linux checks execute/search permission on every path component, not just the final file. A file can be 644 and still unreadable to Caddy if an ancestor directory is 750. The usual fixes are bad. chmod 755 /home/tacavar makes your home world-readable. Running Caddy privileged widens the blast radius. Copying files creates stale state and a second source of truth. We needed a path-level permission boundary, not a ownership change. That is when linux fstab permissions stop being a sysadmin detail and become part of the serving architecture. caddy uid 995 is fixed in production, so the app has to adapt to that identity.
Why symlinks fail when Caddy walks the full path
A symlink from /var/www/videos to /home/tacavar/Desktop looks like the obvious answer. It is not. When Caddy resolves a request, it walks the full path. If /var/www/videos is a symlink, the kernel resolves it to the target and then checks traversal on /home/tacavar. Caddy still hits the 750 wall. The same is true for symlinked subdirectories. A symlink does not grant permission; it redirects the path, and the permission checks follow the redirected path. Enabling symlink following in Caddy does not fix parent traversal. The logs on Tacavar showed permission denied on /home/tacavar, not on the file. That made the problem clear: path resolution, not file mode. ACLs can work here. setfacl -m u:995:x /home/tacavar gives Caddy traverse permission. But ACLs drift, get lost on restores, and add another thing to audit. We wanted something declarative and reproducible.
The fstab bind mount from Desktop to /var/www/videos
The fix is a bind mount in /etc/fstab. It makes /home/tacavar/Desktop appear at /var/www/videos. Both paths point to the same inodes. Nothing is copied. The entry looks like this:
/home/tacavar/Desktop /var/www/videos none bind,nofail,x-systemd.requires=/home/tacavar 0 0
After mount, Caddy can traverse /var/www/videos because its ancestors are /var/www and /, not /home/tacavar. The private home directory stays private. The serving path stays under /var/www where Caddy already has read access. This caddy bind mount is not a copy, not a sync, and not a permission workaround. It is the kernel presenting the same directory at another path. If Hermes writes a new file to Desktop, it appears at /var/www/videos immediately. If you remove it from Desktop, it disappears from the route. One inode, one state.
Serving hub.tacavar.com/videos with zero file copies
Caddy's file server points at /var/www/videos. The route hub.tacavar.com/videos/ serves whatever is mounted there. No rsync job. No cron. No cache invalidation. No duplicate storage. On Tacavar, this turned a home-directory authoring surface into a clean edge-served media surface. Hermes writes generated clips into /home/tacavar/Desktop/videos, and Caddy uid 995 serves them from /var/www/videos. The path changes, the data does not. That matters for video files, where copies are expensive and delays are visible. It also matters for generated assets, logs, and build outputs that need a public URL but should not live in a public directory. The bind mount gives you a read path controlled by the kernel, not by an application-level copy step.
Permission boundaries without chmod or privileged Caddy
We did not chmod /home/tacavar. We did not add Caddy to the tacavar group. We did not run Caddy as root. The linux fstab permissions model remains intact. Only the tacavar user can traverse /home/tacavar. Caddy uid 995 gets access only through /var/www/videos. If Caddy is compromised, it can read the mounted directory, but it cannot list /home/tacavar or pivot into other home directories. That is a real boundary. Use nofail so a missing home mount does not break boot. Use x-systemd.requires=/home/tacavar so the bind mount waits for home. If you manage mounts with systemd units, add RequiresMountsFor=/home/tacavar. Unmount /var/www/videos and Caddy loses the route while the home directory stays private. That is the right failure mode for a private source path.
When to use bind mounts instead of copies or ACLs
Use a bind mount when the source changes frequently, you need zero-copy serving, and the service runs as a fixed unprivileged uid like caddy uid 995. Use it when the source has private ancestors that you refuse to open up. Use it when you control the host's fstab or systemd mount units. Avoid it when the source is on a remote filesystem with different semantics, when you need per-file access control, or when mount lifecycle is unmanaged. Copies are fine for immutable artifacts. ACLs are fine for a one-off grant, but they drift and hide intent. Bind mounts are the right tool for the Tacavar edge pattern: home directory for writing, /var/www for serving. The kernel enforces the separation without duplicating data or weakening linux fstab permissions. For more tacavar devops patterns, use the same model: keep private paths private, expose only the serving view.
Use Tacavar's edge file-serving pattern at tacavar.com/devops.