From c287fb0145c28f67da513d47811126fbfc0c72da Mon Sep 17 00:00:00 2001 From: Timothy Kim Date: Sat, 29 Aug 2026 20:38:35 -0400 Subject: [PATCH] add hannah smb user, fix music dir permissions --- CLAUDE.md | 1 + RUNBOOK.md | 12 +++++++----- scripts/restore-users.sh | 5 +++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 01a08eb..75fe295 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,6 +15,7 @@ Recovery steps are in `RUNBOOK.md`. Repo overview and workflows are in `README.m - **Cockpit (argento.timothykim.net)**: Runs directly on the host (not Docker) on port 9090 with self-signed TLS. The nginx conf inlines security headers instead of including security-headers.inc because Cockpit's internal iframes break with X-Frame-Options: DENY. Cockpit has a known bug where font files return 404 — this is not a proxy issue. - **Minecraft HTTP-only**: HTTPS causes WebSocket/CORS errors with the MCSManager daemon. No cert issued for this domain. - **SSL cert issuance chicken-and-egg**: On fresh recovery, certs don't exist so SSL confs can't load. The `.hold` pattern moves SSL confs aside, starts nginx with HTTP-only confs, issues certs, then restores SSL confs. +- **ZFS NFSv4 ACLs on threeteras/media**: `acltype=nfsv4`, `aclmode=restricted`, `aclinherit=passthrough`. `chmod` on anything under `/opt/argento/smb/media` fails with `Operation not permitted` (EPERM) even as root — that is the ACL refusing to be overwritten, not a bug. New dirs inherit the parent's ACL automatically, so setgid bits and `chmod` are unnecessary; don't put `force create mode` / `force directory mode` in smb.conf shares over this dataset either, since those make Samba call chmod. - **SELinux is enforcing**: Caused issues with samba (symlinks blocked, parent directory traversal blocked). Don't use symlinks for config files — use the sync-system.sh copy approach instead. - **Secrets in .env files**: All secrets (DB passwords, API keys, tokens) live in `.env` files under each app's `docker//` directory on the server. These are gitignored (`**/.env` in root `.gitignore`). The `.env` files are included in the USB backup. If the backup is lost, all secrets can be recreated from Bitwarden. The `system/msmtprc` in the repo has its password REDACTED -- the real one is only on the server. - **ZFS parent dataset mountpoints**: Pools have parent datasets (e.g., `nextcloud`, `threeteras`) that create mountpoints like `/mnt/nextcloud`. These are empty and expected — do not delete them. diff --git a/RUNBOOK.md b/RUNBOOK.md index f8b0a13..76e1195 100644 --- a/RUNBOOK.md +++ b/RUNBOOK.md @@ -130,9 +130,11 @@ done # Shared music dir. Lives inside the media dataset (so it rides the media # snapshot policy) but is exported as its own writable [music] share. -# setgid so files dropped in over SMB inherit sambagroup and stay readable -# by the Navidrome container. -install -d -o timothykim -g sambagroup -m 2775 /opt/argento/smb/media/Music +# No chmod: threeteras/media is acltype=nfsv4 aclmode=restricted, so chmod +# fails with EPERM. aclinherit=passthrough already copies the parent's ACL +# onto the new dir, which is what grants sambagroup write. +mkdir -p /opt/argento/smb/media/Music +chown timothykim:sambagroup /opt/argento/smb/media/Music # SELinux contexts for samba — fresh ZFS datasets get unlabeled_t and samba # refuses to serve them. Persistent rules (semanage) survive full relabels; @@ -153,7 +155,7 @@ so file ownership lands on the correct UIDs. /opt/argento/scripts/restore-users.sh ``` -This recreates timothykim, yireh, isaac, and the sambagroup group with +This recreates timothykim, yireh, isaac, hannah, and the sambagroup group with their original UIDs/GIDs, then restores the samba password hashes from `/mnt/backup/argento/system/samba-private/` if present (mirrored there by sync-system.sh, gitignored so the hashes aren't in version control). @@ -161,7 +163,7 @@ by sync-system.sh, gitignored so the hashes aren't in version control). If the samba passdb backup is missing, set passwords manually: ```bash -for u in timothykim yireh isaac; do +for u in timothykim yireh isaac hannah; do smbpasswd -a "$u" smbpasswd -e "$u" done diff --git a/scripts/restore-users.sh b/scripts/restore-users.sh index 1e719f4..e776d3b 100755 --- a/scripts/restore-users.sh +++ b/scripts/restore-users.sh @@ -25,6 +25,7 @@ USERS=( "timothykim:1000:1000:/bin/bash:home:wheel,video,docker,sambagroup" "yireh:1100:1100:/sbin/nologin:nohome:sambagroup" "isaac:1101:1101:/sbin/nologin:nohome:sambagroup" + "hannah:1102:1102:/sbin/nologin:nohome:sambagroup" ) # Abort if an existing entity's numeric ID doesn't match what we expect @@ -122,7 +123,7 @@ if ! mountpoint -q /mnt/backup; then echo "[!] /mnt/backup is not mounted — skipping samba passdb restore" echo " mount the USB backup drive (RUNBOOK step 5) and re-run if you want" echo " to restore preserved SMB passwords; otherwise set them manually:" - echo " for u in timothykim yireh isaac; do smbpasswd -a \"\$u\"; done" + echo " for u in timothykim yireh isaac hannah; do smbpasswd -a \"\$u\"; done" elif [ -f "$PASSDB_SRC/passdb.tdb" ]; then install -d -m 700 /var/lib/samba/private cp "$PASSDB_SRC"/*.tdb /var/lib/samba/private/ @@ -130,7 +131,7 @@ elif [ -f "$PASSDB_SRC/passdb.tdb" ]; then echo "[+] restored samba passdb from $PASSDB_SRC/" else echo "[!] no samba passdb backup found at $PASSDB_SRC/" - echo " run: for u in timothykim yireh isaac; do smbpasswd -a \"\$u\"; done" + echo " run: for u in timothykim yireh isaac hannah; do smbpasswd -a \"\$u\"; done" fi echo ""