From 575c4ac185fb9db017d61f07cedd7cf911d56db1 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 15:50:10 +0000 Subject: [PATCH] Fix anki-sync-server container failing to start: data/ ownership MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit afrima/anki-sync-server is built on gcr.io/distroless/static-debian12: nonroot — the process always runs as that image's fixed nonroot UID/GID (65532), never as ACTUAL_USER, and distroless ships no shell so nothing inside the container can chown its own data dir at startup. The installer's final chown gave the whole instance directory to ACTUAL_USER, including ./data, which the container then can't write to — it fails outright the moment it tries to create anything under /data (e.g. a new user's collection), not just at sync time. Confirmed live. Fix: re-chown ./data to 65532:65532 specifically, applied *after* the existing ACTUAL_USER chown (not before — that call recurses over the whole instance dir and would just clobber it). docker-compose.yml/.env/ README.md stay owned by ACTUAL_USER as before. The same fix is applied in the "update" path so an already-broken existing install self-heals on the next non-destructive update, without touching its port, Caddy config, or accounts. Verified live: fresh install now leaves data/ owned by 65532:65532 while the rest of the instance dir stays ACTUAL_USER; simulating a pre-fix broken install (data/ owned by root) and running "update" correctly repairs it. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_014DyceEVVeQ33EeS6C1PDv5 --- services/anki-sync-server.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/services/anki-sync-server.sh b/services/anki-sync-server.sh index 29b726d..c73fdba 100644 --- a/services/anki-sync-server.sh +++ b/services/anki-sync-server.sh @@ -440,6 +440,16 @@ install_anki-sync-server() { case "$MODE" in update) log_info "Refreshing the Anki Sync Server image only — existing accounts, port, and Caddy setup are left as-is." + # The image is a Google distroless "nonroot" build (fixed UID/GID + # 65532, no shell — it can't chown anything itself at startup), so + # ./data has to already be writable by that exact UID or the + # container fails to start. Versions of this installer before this + # fix chowned it to ACTUAL_USER instead, which the container can't + # write to — re-asserting the correct ownership here repairs any + # install made under that bug, non-destructively (it's the + # installer's own bug being corrected, not a config choice, so it + # belongs in the non-destructive update path). + chown -R 65532:65532 "$ANKI_DIR/data" 2>/dev/null ( cd "$ANKI_DIR" && docker compose pull && docker compose up -d ) \ && log_success "Anki Sync Server image refreshed" \ || log_warning "Refresh failed — check: docker compose -f $ANKI_DIR/docker-compose.yml logs" @@ -568,6 +578,19 @@ ANKI_ENV chown -R "$ACTUAL_USER:$ACTUAL_USER" "$ANKI_DIR" + # afrima/anki-sync-server is built on gcr.io/distroless/static-debian12:nonroot + # — the process always runs as that image's fixed "nonroot" UID/GID (65532), + # never as ACTUAL_USER, and distroless has no shell so nothing inside the + # container can chown its own data dir at startup. Applied AFTER the + # ACTUAL_USER chown above (not before — that call would just clobber it, + # since it recurses over the whole $ANKI_DIR including data/) so ./data ends + # up owned by 65532 specifically while docker-compose.yml/.env/README.md + # (which the sysadmin edits, not the container) stay owned by ACTUAL_USER. + # Confirmed live: getting this wrong is exactly what makes the container + # fail to come up with a permissions error the moment it tries to create + # anything under /data (e.g. a new user's collection). + chown -R 65532:65532 "$ANKI_DIR/data" + echo "" log_success "Anki Sync Server${INSTANCE_SUFFIX:+ ($INSTANCE_SUFFIX)} configured at $ANKI_DIR (port $WEB_PORT)" echo ""