# ━━━━━ SYSTEM ESSENTIALS — Manual ━━━━━ Configuration reference, operational procedures, and troubleshooting for system-level scripts. Read the ARRAY_START_SCRIPTS order section before adding or reordering scripts at array start. > **Platform-specific scripts** (`webgui_watchdog.sh`, `php_fpm_max_children.sh`, > `mover_stop.sh`, `user_scripts_stop.sh`) and their configuration live in > `Plugin/unraid/System_Essentials/`. Watchdog configuration (`stability_watchdog.sh`, > `resource_watchdog.sh`, `docker_watchdog.sh`, `System/storage_watchdog.sh`) lives > in `Watchdogs/Manual-Watchdogs.md`. --- ## ━━━ CONTENTS ━━━ - [ARRAY_START_SCRIPTS / ARRAY_STOP_SCRIPTS Order](#array_start_scripts--array_stop_scripts-order) - [conf_sync.sh](#conf_syncsh) - [conf_cache_save.sh](#conf_cache_savesh) - [conf_cache_restore.sh](#conf_cache_restoresh) - [inotify_tuning.sh](#inotify_tuningsh) - [docker_syslog_filter.sh](#docker_syslog_filtersh) - [clear_logs.sh](#clear_logssh) - [rsync_stop.sh](#rsync_stopsh) - [server_reboot.sh](#server_rebootsh) - [Full Configuration Reference](#full-configuration-reference) - [Troubleshooting](#troubleshooting) --- ## Output Tiers All scripts use a two-tier output model: `echo` lines are always visible; `log` lines only appear when `--log` is passed. **One-shot scripts** (`conf_sync.sh`, `conf_cache_save.sh`, `conf_cache_restore.sh`, `clear_logs.sh`, `docker_syslog_filter.sh`, `inotify_tuning.sh`, `rsync_stop.sh`, `server_reboot.sh`): without `--log`, section headers, per-step results, and the final summary are visible. Per-item detail suppressed. --- ## ARRAY_START_SCRIPTS / ARRAY_STOP_SCRIPTS Order > **Order matters.** Scripts that set up conditions other scripts depend on must run > first. Getting the order wrong causes subtle failures. ```bash # master.conf (current order — from ARRAY_START_SCRIPTS) ARRAY_START_SCRIPTS=( "Plugin/unraid/System_Essentials/unraid_api_key_renew.sh" # plugin API key — ephemeral registry "System_Essentials/conf_sync.sh" # 1st cross-server op — pull partner confs into RAM cache "System_Essentials/conf_cache_restore.sh" # fill gaps if partner was down at boot "Transcodes/ramdisk_setup.sh" # ramdisk before Emby starts "System_Essentials/docker_syslog_filter.sh" # before veth interfaces are created "Plugin/unraid/System_Essentials/php_fpm_max_children.sh" # WebGUI tuning "System_Essentials/inotify_tuning.sh" # before docker_network_connect and continuous scripts "Docker_Essentials/docker_network_connect.sh" # ensure networks + container connections "Tools/claude_startup.sh" # persist Claude data to appdata; re-symlink on boot "Media/start_webhook_listener.sh" # arr upgrade webhook — continuous "Fallback/fallback.sh" # mutual failover — continuous ) ARRAY_STOP_SCRIPTS=( "System_Essentials/conf_cache_save.sh" # FIRST: snapshot RAM cache while fresh "Plugin/unraid/System_Essentials/user_scripts_stop.sh" "Fallback/fallback.sh --stop" "System_Essentials/rsync_stop.sh --rsync-only" "Plugin/unraid/System_Essentials/mover_stop.sh" "Docker_Essentials/docker_container_stop.sh" ) ``` Why conf_sync before conf_cache_restore: the sync runs first to get the freshest possible partner conf. The restore only fills in for confs that the sync couldn't fetch — it is a fallback, not the primary path. Why docker_syslog_filter before inotify: the filter must be in place before any container creates veth interfaces. inotify must be set before docker_network_connect and the continuous scripts (start_webhook_listener, fallback), which are the first steps that actually touch containers. Why conf_cache_save is FIRST in ARRAY_STOP_SCRIPTS: the RAM cache at `/tmp/.cache/vv/d/` is wiped on reboot. Saving it must happen before anything else shuts down or changes state. --- ## conf_sync.sh ### Modes ``` conf_sync.sh Full sync: pull from all partners + push to all partners conf_sync.sh --push-only Push own conf to all partners (fast — for conf-save hook) conf_sync.sh --pull-only Pull partner confs only (intermediate orchestrator) conf_sync.sh --dry-run Show what would happen, no changes conf_sync.sh --log Verbose output ``` ### What It Syncs - **Pull**: reads the partner's `Configurations/${partner_id}.conf` from their disk via SCP → writes to local `/tmp/.cache/vv/d/${partner_id}.conf` - **Push**: sends own `Configurations/${my_id}.conf` to partner's `/tmp/.cache/vv/d/${my_id}.conf` via SCP - **Own conf in local cache**: copies own conf to `/tmp/.cache/vv/d/${my_id}.conf` on full sync (so the cache has a complete snapshot of all confs) Only partner confs are sourced from cache — `load_config.sh` always reads own conf from disk to avoid sourcing a stale cached copy. ### Remote SCRIPTS_DIR Resolution The pull path reads the partner's `/boot/config/plugins/varaverk/varaverk.cfg` to find their actual `SCRIPTS_DIR` before building the SCP path. This handles the case where the partner is in appdata storage mode and their conf is at `/mnt/user/appdata/Varaverk/Configurations/` rather than the internal path. ### PARTNERSHIP_ENABLED Gate conf_sync.sh calls `require_partnership` — if `PARTNERSHIP_ENABLED=false`, it exits silently with 0. The conf cache will be empty for partner confs while partnership is disabled. ### If Conf Pull Fails at Boot If the partner is unreachable, `conf_sync.sh` logs a warning and exits 1. `conf_cache_restore.sh` then runs (next in ARRAY_START_SCRIPTS) and loads the persistent backup from `$PERSISTENT_CONF_CACHE` if available. A notification fires if any partner fails — check partner reachability via Tailscale. --- ## conf_cache_save.sh ### What It Does At array stop, copies all partner confs from `/tmp/.cache/vv/d/` to `$PERSISTENT_CONF_CACHE`. Own conf is skipped (always on disk). The backup survives the reboot and is used by `conf_cache_restore.sh` at next array start if the sync can't reach the partner. `conf_cache_watchdog.sh` (in `Watchdogs/System/`) refreshes this backup every 15 minutes while the partner is offline — keeping it current even during extended outages. ### PARTNERSHIP_ENABLED Gate Exits silently when `PARTNERSHIP_ENABLED=false`. No backup is written. ### Usage ```bash conf_cache_save.sh # save partner confs from RAM cache (called at array stop) conf_cache_save.sh --dry-run # show what would be saved conf_cache_save.sh --log # verbose output ``` --- ## conf_cache_restore.sh ### What It Does At array start (after `conf_sync.sh`), checks which partner confs are missing from `/tmp/.cache/vv/d/`. For each missing conf, loads it from `$PERSISTENT_CONF_CACHE` if a backup exists there. Always removes the persistent backup when done — whether used or not. On a normal reboot where the partner was reachable, the sync already populated the cache and the backup is cleaned up without being used. ### PARTNERSHIP_ENABLED Gate Exits silently when `PARTNERSHIP_ENABLED=false`. ### Usage ```bash conf_cache_restore.sh # restore missing confs from backup (called at array start) conf_cache_restore.sh --dry-run # show what would be restored conf_cache_restore.sh --log # verbose output ``` --- ## inotify_tuning.sh ### What It Sets ```bash INOTIFY_MAX_INSTANCES=1024 # max inotify fd objects per user (default: 128) INOTIFY_MAX_WATCHES=1048576 # max watches shared across all users (default: 8192) INOTIFY_MAX_QUEUED_EVENTS=32768 # max buffered events (default: 16384) ``` Verify current values: ```bash inotify_tuning.sh --status # Shows current vs target for each limit, active instance count, top consumers ``` ### If Code-Server Shows "Unable to Watch for File Changes" ```bash # 1. Verify limits are set: sysctl fs.inotify.max_user_watches # Expected: 1048576 # 2. Check total usage across all containers: find /proc/*/fd -lname 'anon_inode:inotify' 2>/dev/null | wc -l # 3. If limits are set but Code-Server still shows the error: docker restart Code-Server # Running containers inherit limits at launch. Restart picks up the new values. # 4. If limits are NOT set (inotify_tuning.sh hasn't run yet): inotify_tuning.sh --log ``` --- ## docker_syslog_filter.sh ### What It Creates ``` /etc/rsyslog.d/ignore-docker-veth.conf: if ($msg contains "veth" or $msg contains "docker0") then { stop } ``` This drops any syslog message containing "veth" or "docker0" before it reaches any output target, including the log file. ### Verify ```bash docker_syslog_filter.sh --status # Shows filter file content and rsyslog process state # Manual verify: cat /etc/rsyslog.d/ignore-docker-veth.conf pgrep -x rsyslogd && echo "rsyslog running" || echo "rsyslog NOT running" # Test the filter is active (should produce no syslog output): logger "test veth message" grep "test veth" /var/log/syslog 2>/dev/null || echo "filtered correctly" ``` ### If Syslog Still Has Veth Noise ```bash # 1. Verify filter file exists with correct content: docker_syslog_filter.sh --status # 2. If content differs — re-apply: docker_syslog_filter.sh --log # 3. Verify rsyslog is using the conf.d directory: grep -r "IncludeConfig" /etc/rsyslog.conf # Expected: IncludeConfig /etc/rsyslog.d/*.conf (or similar) ``` --- ## clear_logs.sh ### Thresholds ```bash LOG_MIN_SIZE_MB=10 # skip system log if under this — keep recent history LOG_DOCKER_MAX_MB=100 # clear Docker container log only if over this LOG_FILES=( "/var/log/syslog" "/var/log/messages" "/var/log/dmesg" ) ``` ### Why Truncation Not Deletion unRAID writes logs to tmpfs (`/var/log`). Truncation (`: > file`) keeps the file descriptor open and valid while emptying content — syslogd continues writing to the same fd without interruption. Deleting the file would orphan the file descriptor and syslog would stop writing until restarted. ### Identifying Large Docker Logs ```bash clear_logs.sh --status # Shows top 10 Docker logs by size, current size vs threshold # Find the biggest log manually: du -sh /var/lib/docker/containers/*/*.log 2>/dev/null | sort -rh | head -5 ``` --- ## rsync_stop.sh ### Auto-Detection Logic rsync_stop.sh detects whether an orchestrator script (daily/weekly/critical sync) is the parent of the running rsync process by scanning lock files in `$LOCK_DIR`. **Default behavior (orchestrator detected):** Kills only the rsync subprocess. The orchestrator sees rsync died, moves to the next share or exits cleanly. The orchestrator is NOT killed — it can still clean up. **Default behavior (no orchestrator):** Kills rsync directly (standalone rsync.sh run). **--full-stop:** Kills the orchestrator first, then kills rsync. Nothing continues after this. Use when everything needs to stop immediately. ### Container Recovery After killing rsync, the script checks all containers in `PROFILE_CRITICAL_CONTAINER_NAMES` for any that were stopped by the interrupted rsync session and restarts them. Remote containers are left for docker_watchdog.sh to recover. Skip container recovery with `--rsync-only` — used when called by array_stopping.sh (which handles container stop separately via docker_container_stop.sh). ### Usage ```bash rsync_stop.sh # smart stop (auto-detect orchestrator) rsync_stop.sh --full-stop # kill orchestrator + rsync rsync_stop.sh --rsync-only # kill rsync, skip container recovery rsync_stop.sh --status # show local and remote rsync state rsync_stop.sh --dry-run # preview without changes rsync_stop.sh --full-stop --dry-run # preview full stop ``` --- ## server_reboot.sh ### Full Shutdown Sequence ``` 1. Pre-flight checks (warn only — do not block): - rsync running? → warn, suggest rsync_stop.sh first - mover running? → warn, suggest mover_stop.sh first - Emby sessions? → warn (active streams will be interrupted) 2. Wall message to all logged-in terminal users 3. unRAID dashboard notification 4. Wait REBOOT_SLEEP seconds (default: 30) 5. Graceful VM shutdown: virsh shutdown (ACPI signal — clean shutdown) Wait REBOOT_VM_WAIT seconds (default: 30) for VMs to respond 6. /etc/rc.d/rc.libvirt stop (VM Manager) 7. Orchestrators/array_stopping.sh — safe ordered array stop: - conf_cache_save.sh snapshot partner conf RAM cache - user_scripts_stop.sh stop background User Scripts - fallback.sh --stop graceful fallback teardown - rsync_stop.sh --rsync-only kill active rsync transfers - mover_stop.sh stop mover - docker_container_stop.sh stop all containers gracefully 8. sync (flush filesystem buffers to disk) 9. /sbin/reboot ``` ### Configuration ```bash REBOOT_SLEEP=30 # seconds between warning and shutdown sequence REBOOT_VM_WAIT=30 # seconds to wait for VMs to shut down gracefully ``` ### Recommended Pre-Reboot Sequence For a clean reboot when services are active: ```bash rsync_stop.sh # stop any active rsync (smart mode) server_reboot.sh --status # check what's still running server_reboot.sh --reason="planned maintenance" ``` ### Usage ```bash server_reboot.sh # reboot with 30s warning server_reboot.sh --dry-run # walk through without rebooting server_reboot.sh --status # show what would be affected server_reboot.sh --reason="disk work" # include reason in notification ``` --- ## Full Configuration Reference ```bash # master.conf # ── Conf Sync ────────────────────────────────────────────────────────────────── CONF_SYNC_ENABLED=true # toggle: false disables conf_sync.sh entirely # ── inotify Tuning ───────────────────────────────────────────────────────────── INOTIFY_MAX_INSTANCES=1024 INOTIFY_MAX_WATCHES=1048576 INOTIFY_MAX_QUEUED_EVENTS=32768 INOTIFY_WARN_PCT=80 # warn (in reports) if instances exceed this % of limit # ── Syslog Filter ────────────────────────────────────────────────────────────── FILTER_FILE="/etc/rsyslog.d/ignore-docker-veth.conf" # ── Log Cleaner ──────────────────────────────────────────────────────────────── LOG_FILES=("/var/log/syslog" "/var/log/messages" "/var/log/dmesg") LOG_MIN_SIZE_MB=10 LOG_DOCKER_MAX_MB=100 # ── Server Reboot ────────────────────────────────────────────────────────────── REBOOT_SLEEP=30 REBOOT_VM_WAIT=30 # ── State Paths (auto-adapt to storage mode) ─────────────────────────────────── # STATE_DIR and PERSISTENT_CONF_CACHE are derived from SCRIPTS_DIR in master.conf. # They adapt to internal (/boot/config/plugins/varaverk) or appdata storage mode # (/mnt/user/appdata/Varaverk) automatically — do not hardcode paths. STATE_DIR="${SCRIPTS_DIR}/State_Files" PERSISTENT_CONF_CACHE="${SCRIPTS_DIR}/.cache/vv/d" ``` --- ## Troubleshooting ### Partner Conf Not In RAM Cache After Boot ```bash # Check what's in the RAM cache: ls -la /tmp/.cache/vv/d/ # Check what's in the persistent backup: ls -la "$PERSISTENT_CONF_CACHE/" # set SCRIPTS_DIR first or use full path # Re-run conf sync manually: /boot/config/plugins/varaverk/System_Essentials/conf_sync.sh --log # If partner is reachable but pull failed, check SSH key: ssh -i /path/to/ssh_key root@ "echo ok" ``` ### Persistent Backup Is Stale or Empty ```bash # conf_cache_watchdog.sh refreshes the backup while partner is offline. # Check watchdog state: cat "$STATE_DIR/conf_cache_watchdog_state.db" # Force a manual backup from current RAM cache: /boot/config/plugins/varaverk/System_Essentials/conf_cache_save.sh --log ``` ### rsync_stop Killed the Wrong Thing If --full-stop killed an orchestrator you didn't intend to kill: ```bash # Next time use default mode (no --full-stop) to kill only rsync subprocess. # To verify what would be killed before running: rsync_stop.sh --status # shows running rsync and detected orchestrators rsync_stop.sh --dry-run # shows smart mode decision rsync_stop.sh --full-stop --dry-run # shows full-stop decision ``` ### inotify Exhaustion After Boot ```bash # Verify limits are applied: sysctl fs.inotify.max_user_watches # expect 1048576 sysctl fs.inotify.max_user_instances # expect 1024 # If not set — run manually: inotify_tuning.sh --log # Check current usage: inotify_tuning.sh --status ``` ### Syslog Still Noisy After Array Start ```bash # Check filter is in place: docker_syslog_filter.sh --status # Re-apply if needed: docker_syslog_filter.sh --log # Restart rsyslog to pick up the filter: /etc/rc.d/rc.rsyslogd restart ```