From 68405048577c1f3aeabea8ad9f1e5aa1f4961d98 Mon Sep 17 00:00:00 2001 From: James Lance Date: Fri, 13 Mar 2026 21:52:58 +0000 Subject: [PATCH 1/3] chore: add AI tooling configuration Co-Authored-By: Claude Opus 4.6 --- .claude/settings.local.json | 42 +++++++++++++++++++++++++++++++++++++ GEMINI.md | 1 + 2 files changed, 43 insertions(+) create mode 100644 .claude/settings.local.json create mode 120000 GEMINI.md diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..8704415 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,42 @@ +{ + "permissions": { + "allow": [ + "Bash(git -C /home/jalance/Projects/docker-services log --all --oneline)", + "Bash(git -C /home/jalance/Projects/docker-services log --pretty=format:\"%h %s\" -20)", + "Bash(docker compose pull:*)", + "Bash(docker compose:*)", + "Bash(docker logs:*)", + "Bash(docker exec:*)", + "Bash(curl:*)", + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git push)", + "Bash(docker pull:*)", + "Bash(docker ps:*)", + "Bash(git checkout:*)", + "Bash(git pull:*)", + "WebFetch(domain:doc.traefik.io)", + "WebSearch", + "Bash(du:*)", + "Bash(ls:*)", + "Bash(wc:*)", + "Bash(docker inspect:*)", + "Bash(git ls-tree:*)", + "Bash(.git/hooks/pre-commit)", + "Bash(git -C /home/jalance/Projects/docker-services status)", + "Bash(git -C /home/jalance/Projects/docker-services log --oneline -5)", + "Bash(git -C /home/jalance/Projects/docker-services diff docker-compose.yml)", + "Bash(git -C /home/jalance/Projects/docker-services log --oneline -3)", + "WebFetch(domain:github.com)", + "Bash(python3:*)", + "Bash(docker stats:*)", + "Bash(./scripts/validate-traefik.sh:*)", + "Bash(git -C /home/jalance/Projects/docker-services diff TODO progress.md)", + "WebFetch(domain:traefik.io)", + "Bash(git -C /home/jalance/Projects/docker-services log master..traefikv3 --oneline)", + "WebFetch(domain:docs.linuxserver.io)", + "WebFetch(domain:trash-guides.info)", + "Bash(read f:*)" + ] + } +} diff --git a/GEMINI.md b/GEMINI.md new file mode 120000 index 0000000..681311e --- /dev/null +++ b/GEMINI.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file From e19499fc9b516711b1e4fc44699c3de5ee669302 Mon Sep 17 00:00:00 2001 From: James Lance Date: Fri, 13 Mar 2026 21:53:01 +0000 Subject: [PATCH 2/3] docs: add TODO for migrating service configs from NFS to local storage SQLite-over-NFS is causing disk I/O errors in Sonarr and Radarr. This TODO outlines the plan to move all service configs to local NVME with rsync backup to Synology NAS. Co-Authored-By: Claude Opus 4.6 --- TODO-local-configs.md | 56 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 TODO-local-configs.md diff --git a/TODO-local-configs.md b/TODO-local-configs.md new file mode 100644 index 0000000..f58a80a --- /dev/null +++ b/TODO-local-configs.md @@ -0,0 +1,56 @@ +# Fix SQLite-over-NFS Crashes + +Sonarr and Radarr are experiencing recurring SQLite `disk I/O error` crashes because their +databases live on NFS. The fix is to move ALL service configs (~85GB) to local NVME storage +and rsync to Synology NAS every 4 hours. + +> Detailed plan: `.claude/plans/typed-wondering-hennessy.md` + +--- + +## Step 1: Create Feature Branch & Scripts + +- [ ] Create feature branch (e.g. `migrate-configs-to-local`) +- [ ] Create `scripts/migrate-nfs-to-local.sh` — one-time rsync from NFS to local +- [ ] Create `scripts/backup-configs.sh` — recurring rsync from local to NFS (every 4 hours via cron) + +## Step 2: Modify docker-compose.yml + +- [ ] Remove 16 NFS config volume definitions (lines 29-108) +- [ ] Remove dead `traefik_acme_config` NFS volume definition +- [ ] Keep media NFS volumes (video, audiobooks, music, photo, ebooks, downloads) +- [ ] Switch all 15 services from named volumes to `$LOCALDOCKERDIR` bind mounts + +## Step 3: Update env.example + +- [ ] Clarify `LOCALDOCKERDIR` = local config storage (e.g. `/usr/local/docker`) +- [ ] Clarify `DOCKERDIR` = NFS mount, now backup destination only (e.g. `/mnt/docker`) + +## Step 4: Migration Execution (requires downtime) + +- [ ] `docker compose down` +- [ ] Create local directories under `$LOCALDOCKERDIR` +- [ ] Set ownership: `chown -R $PUID:$PGID $LOCALDOCKERDIR/` +- [ ] Run migration script (rsync NFS → local, ~85 GB) +- [ ] Deploy updated docker-compose.yml +- [ ] Remove old Docker named volumes +- [ ] `docker compose up -d` +- [ ] Verify each service has data intact +- [ ] Install host cron job for backup script + +## Step 5: Update CLAUDE.md + +- [ ] Update Storage Strategy section +- [ ] Update Adding New Services section to use `$LOCALDOCKERDIR` bind mounts +- [ ] Document backup script and cron schedule + +## Verification + +- [ ] Each service's web UI loads with data intact +- [ ] `scripts/validate-traefik.sh` passes +- [ ] NFS backup directories updating after first cron run +- [ ] No SQLite I/O errors after 24-48 hours + +## Rollback + +If something goes wrong: revert docker-compose.yml to NFS volumes — original NFS data is untouched. From 6ac8ac656a62f7d6cfba5149e216156bf7f57561 Mon Sep 17 00:00:00 2001 From: James Lance Date: Fri, 13 Mar 2026 21:53:13 +0000 Subject: [PATCH 3/3] chore: remove unused docker-gc service Docker cleanup is now handled by task-scheduler's daily prune job. Co-Authored-By: Claude Opus 4.6 --- docker-gc/Dockerfile | 26 -------------------------- docker-gc/cleanup.sh | 26 -------------------------- 2 files changed, 52 deletions(-) delete mode 100644 docker-gc/Dockerfile delete mode 100644 docker-gc/cleanup.sh diff --git a/docker-gc/Dockerfile b/docker-gc/Dockerfile deleted file mode 100644 index 00a80a3..0000000 --- a/docker-gc/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -FROM docker:cli - -# Install dcron (Alpine's cron daemon) -RUN apk add --no-cache dcron - -# Copy cleanup script -COPY cleanup.sh /usr/local/bin/cleanup.sh -RUN chmod +x /usr/local/bin/cleanup.sh - -# Create crontab file - run daily at midnight -RUN echo "0 0 * * * /usr/local/bin/cleanup.sh >> /var/log/docker-cleanup.log 2>&1" > /etc/crontabs/root - -# Create log file -RUN touch /var/log/docker-cleanup.log - -# Create entrypoint script -RUN echo '#!/bin/sh' > /entrypoint.sh && \ - echo 'echo "Docker cleanup cron started. Runs daily at midnight."' >> /entrypoint.sh && \ - echo 'echo "DOCKER_HOST: $DOCKER_HOST"' >> /entrypoint.sh && \ - echo '# Run cleanup once on startup' >> /entrypoint.sh && \ - echo '/usr/local/bin/cleanup.sh' >> /entrypoint.sh && \ - echo '# Start cron in foreground' >> /entrypoint.sh && \ - echo 'crond -f -l 2' >> /entrypoint.sh && \ - chmod +x /entrypoint.sh - -ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker-gc/cleanup.sh b/docker-gc/cleanup.sh deleted file mode 100644 index 2ffa1f8..0000000 --- a/docker-gc/cleanup.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Docker cleanup script using native Docker prune commands - -echo "[$(date)] Starting Docker cleanup..." - -# Remove unused containers older than 7 days (604800 seconds) -echo "Pruning containers..." -docker container prune -f --filter "until=168h" - -# Remove unused images older than 7 days -echo "Pruning images..." -docker image prune -a -f --filter "until=168h" - -# Remove unused volumes -echo "Pruning volumes..." -docker volume prune -f - -# Remove unused networks -echo "Pruning networks..." -docker network prune -f - -# Show disk usage after cleanup -echo "Docker disk usage after cleanup:" -docker system df - -echo "[$(date)] Docker cleanup complete."