#!/bin/bash # ============================================================================================== # ========================== HOST1 CONFIGURATION — unRAID-Gmer4Lfe ============================ # ============================================================================================== # HOST1-specific variables — credentials, container names, share paths, failover lists. # Sourced after master.conf — values here extend shared profile arrays and add HOST1-specific # identity, credentials, and container configuration. # # Sparse checkout (git) ensures HOST2 never receives this file. # HOST2 never sees HOST1 credentials — clean separation at the file level. # # DO NOT put shared config here — thresholds, toggles, profiles belong in master.conf. # DO NOT put HOST2 variables here — they belong in master_host2.conf. # # ── INDEX ───────────────────────────────────────────────────────────────────────────────────── # # ── IDENTITY & CONNECTIVITY ──────────────────────────────────────────────────────────────── # IDENTITY hostname, SSH key # EMBY container name, URL, API key # NOTIFICATIONS Discord webhook # PARTNERSHIP auth containers, backup paths # # ── RSYNC ────────────────────────────────────────────────────────────────────────────────── # DAILY SYNC SHARES media shares HOST1 owns and pushes to HOST2 # WEEKLY SYNC SHARES appdata shares synced weekly (Sunday 2:30am) # CRITICAL SYNC SHARES appdata shares synced every 15 minutes # BACKUP VERIFY shares for checksum verification against remote # HOST1 RSYNC PROFILE host1-appdata profile for HOST1-specific appdata syncs # # ── DOCKER ───────────────────────────────────────────────────────────────────────────────── # DOCKER DAILY RESTART containers restarted daily # DOCKER WEEKLY RESTART containers restarted weekly # DOCKER WATCHDOG memory limits, health URLs, required containers, ignore list # DOCKER NETWORK CONNECT networks and containers for docker_network_connect.sh # # ── FALLBACK ─────────────────────────────────────────────────────────────────────────────── # DDNS DDNS containers managed by HOST1 # INTERNET LOSS containers stopped when internet is lost # FALLBACK TIERS what HOST1 runs for HOST2 per tier # TIER DELAYS how long HOST1 must be down before each tier activates on HOST2 # RSYNC WRITEBACK HOST1 appdata synced back on handback # # ── MEDIA ────────────────────────────────────────────────────────────────────────────────── # MEDIA PERMISSIONS share list for media_shares_permissions.sh # MEDIA CLEANER folder lists for media_cleaner.sh # # ── MONITORS ─────────────────────────────────────────────────────────────────────────────── # CERTIFICATE MONITOR domains checked for SSL expiry # SMART HEALTH drives to skip in SMART monitoring # ZFS REPORT pools to exclude from ZFS health report # # ── TRANSCODES ───────────────────────────────────────────────────────────────────────────── # TRANSCODES ramdisk size, thresholds, SSD path, server array # # ── ARR STACK ────────────────────────────────────────────────────────────────────────────── # DOWNLOADERS slskd, SABnzbd, qBittorrent credentials and URLs # LIDARR URL, API key, path map # SONARR URL, API key, path map # RADARR URL, API key, path map # ARR RECOVERY per-arr recovery toggles # # ============================================================================================== # ============================================================================================== # ── IDENTITY & CONNECTIVITY ─────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ Identity ━━━ # HOST1 hostname lives in master.conf (not a credential — safe for all servers). # SSH key used for all server-to-server operations — rsync, failover container commands. # Must be in /root/.ssh/ and authorised in HOST2's /root/.ssh/authorized_keys. HOST1_SSH_KEY="/root/.ssh/gmer4lfe_rsync_automation" # ━━━ Emby ━━━ # Referenced by transcode_manager.sh, emby_session_report.sh, emby_database_repair.sh, # weekly_sync_maintenance.sh, and HOST1_TRANSCODE_SERVERS below. # API key: Emby Dashboard → API Keys → + New Key HOST1_EMBY_CONTAINER="Emby" HOST1_EMBY_URL="http://localhost:8096" HOST1_EMBY_API_KEY="0c27448d93a7431f9ac63569f7655829" # ━━━ Notifications ━━━ # Discord webhook — leave blank to disable. # Per-host so HOST1 and HOST2 can post to different channels or only one server notifies. HOST1_DISCORD_WEBHOOK="" # ━━━ Partnership ━━━ # HOST1 is always the owner (source of truth) unless --transfer has been run. # See README-Partnership.md and master.conf PARTNERSHIP section for full lifecycle docs. # Auth containers reconfigured on onboard/offboard. # Format: "ContainerName|WebUIPort" # On onboard → WebUI pointed at owner's Tailscale IP (mirror clicks NPM, gets owner's auth) # On offboard → WebUI pointed back at localhost HOST1_PARTNERSHIP_AUTH_WEBUIS=( "NginxProxyManager|81" "Lldap-Gmer4Lfe|17170" "Authelia|9091" "Authelia-Secondary|9092" ) # XML templates (from this server's templates-user/) pushed to mirror during onboard. # These become the mirror's active auth stack, backed by the rsync-synced appdata. # Update filename if Lldap is renamed to drop the host suffix. HOST1_PARTNERSHIP_AUTH_STACK=( # Dependencies first — Mariadb/Redis must be healthy before Authelia starts "my-Mariadb-Authelia.xml" "my-Mariadb-Authelia-Secondary.xml" "my-Redis-Authelia.xml" "my-Redis-Authelia-Secondary.xml" # Auth apps — deployed after their deps are confirmed healthy "my-Authelia.xml" "my-Authelia-Secondary.xml" "my-NginxProxyManager.xml" "my-Lldap-Gmer4Lfe.xml" ) # XML templates pushed to mirror for the arr stack during onboard. # Deps (e.g. databases) first if any — same ordering rule as auth stack. HOST1_PARTNERSHIP_ARR_STACK=( # "my-Sonarr.xml" # "my-Radarr.xml" # "my-Lidarr.xml" # "my-Prowlarr.xml" # "my-Bazarr.xml" ) # Paths HOST2 should collect during the grace window after offboard. # Notified on offboard — no auto-deletion, HOST2 must collect manually within PARTNERSHIP_GRACE_HOURS. HOST1_PARTNERSHIP_MIRROR_BACKUPS=( # "/mnt/user/appdata-Fallback/Jayred365-Emby" ) # Containers parked on this server when partnership is active. # Stopped on onboard (owner deploys its stack instead), restarted on offboard. HOST1_PARTNERSHIP_OWN_CONTAINERS=( # "Emby" # "NginxProxyManager" ) # Emby admin provisioning — toggle is owner-only, credentials are per-host. # Owner enables/disables the feature. Each host sets the account they want on the shared Emby. # On onboard: owner reads mirror's HOST*_PARTNERSHIP_EMBY_ADMIN_* and creates that account. # On offboard: account is deleted. Username collision → onboard exits with error. HOST1_PARTNERSHIP_PROVISION_EMBY_ADMIN=false # owner controls whether Emby is shared HOST1_PARTNERSHIP_EMBY_PORT=8096 HOST1_PARTNERSHIP_EMBY_ADMIN_USER="" # this server's desired Emby username HOST1_PARTNERSHIP_EMBY_ADMIN_PASS="" # this server's desired Emby password # ============================================================================================== # ── RSYNC ───────────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ Daily Sync Shares ━━━ # Shares HOST1 pushes to all other nodes every night (1am via daily_sync_maintenance.sh). # Mesh model: every node pushes every media share — no ownership, no mirrors. # arr_sync ensures all arr libraries converge (union). rsync spreads files (additive, no --delete). # arr_cleanup removes true orphans based on local arr state. # Any node can download content to any share — it propagates to all nodes on the next cycle. # Nextcloud is intentionally one-directional (HOST1→HOST2 offsite backup — not arr-managed). # Uses DEFAULT_RSYNC_OPTS from master.conf — no profile needed. # For shares needing container stops or custom options — add a profile in master.conf. HOST1_DAILY_SYNC_SHARES=( /mnt/user/Books /mnt/user/Intros /mnt/user/Kids_Movies /mnt/user/Kids_Tv_Shows /mnt/user/Movies /mnt/user/Music /mnt/user/Music_Videos /mnt/user/Nextcloud /mnt/user/stand-up_comedy /mnt/user/Sports /mnt/user/Tv_Shows /mnt/user/Anime_Shows-Old /mnt/user/Anime_Movies-Old /mnt/user/Anime_Movies /mnt/user/Anime_Shows ) # Personal encrypted shares — synced for offsite backup, independent of media shares. # ZFS encrypted at dataset level — remote receives encrypted blocks, cannot read content. # See README-Rsync_Setup.md for ZFS encryption setup before uncommenting. HOST1_PERSONAL_SHARES=( # /mnt/user/HOST1-Personal # uncomment after creating encrypted dataset ) # ━━━ Weekly Sync Shares ━━━ # Appdata shares synced during the weekly maintenance window (Sunday 2:30am). # Containers stopped both sides before sync — full clean state guaranteed. # Profiles drive container stops, excludes, and options — configured in master.conf RSYNC section. # Order matters — Emby first (larger transfer), then Critical-Data (auth stack). HOST1_WEEKLY_SYNC_SHARES=( "/mnt/user/Media_Server/Emby" # emby profile — full clean mirror "/mnt/user/appdata-Fallback/Critical-Data" # critical-data profile — auth stack ) # ━━━ Intermediate Sync Shares ━━━ # Shares synced every 4 hours by intermediate_sync_maintenance.sh. # Uses DEFAULT_RSYNC_OPTS (no --delete) — for sub-daily propagation of metadata or watch state. # Full media share sync stays in the daily window. Leave empty to skip mid-day rsync entirely. HOST1_INTERMEDIATE_SYNC_SHARES=( # Add shares here to enable mid-day rsync # Example: "/mnt/user/Emby_Metadata" ) # ━━━ Critical Sync Shares ━━━ # Appdata shares synced every 15 minutes by critical_sync_maintenance.sh. # Format: "/path/to/share" or "/path/to/share|profile-name" # Order matters — Critical-Data first (auth stack), then Emby dirty sync. HOST1_CRITICAL_SYNC_SHARES=( "/mnt/user/appdata-Fallback/Critical-Data|critical-fallback" # auth dirty sync — stays running "/mnt/user/Media_Server/Emby|emby-fallback" # Emby dirty sync — stays running ) # ━━━ Backup Verify ━━━ # Shares verified by backup_verify.sh — random file checksum comparison against remote. # Leave empty to use HOST1_DAILY_SYNC_SHARES automatically. # Sample size and minimum file size defined in master.conf. HOST1_BACKUP_VERIFY_SHARES=( # leave empty to use HOST1_DAILY_SYNC_SHARES automatically ) # ━━━ HOST1 Rsync Profile — host1-appdata ━━━ # HOST1-specific appdata sync profile — extends the shared PROFILE_* arrays in master.conf. # Use for appdata unique to HOST1 (Organizrv2, VaultWarden, UptimeKuma etc.) # Shared appdata (auth stack, Emby) use dedicated profiles defined in master.conf. # Run manually: bash Rsync/rsync.sh /mnt/user/appdata-Fallback/HOST1-Appdata --profile=host1-appdata PROFILE_RSYNC_OPTS[host1-appdata]="-av --info=progress2 --bwlimit=${PROFILE_BW_LIMIT[host1-appdata]:-8000}" PROFILE_BW_LIMIT[host1-appdata]=8000 PROFILE_RETRY_COUNT[host1-appdata]=3 PROFILE_SLEEP[host1-appdata]=300 PROFILE_CRITICAL_CONTAINER_NAMES[host1-appdata]="Organizrv2-Gmer4Lfe UptimeKuma-Gmer4Lfe VaultWarden-Gmer4Lfe" PROFILE_DELAYED_CONTAINERS[host1-appdata]="" PROFILE_CONTAINER_DELAY[host1-appdata]=5 PROFILE_EXCLUDE_DIRS[host1-appdata]="logs *.tmp" # ============================================================================================== # ── DOCKER ──────────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ Docker Daily Restart ━━━ # Containers restarted every day via DAILY_MAINTENANCE_SCRIPTS. # Dispatcharr degrades over time without restart — daily is intentional, not just housekeeping. # Order matters — auth stack first, then media services. HOST1_DAILY_RESTART_CONTAINERS=( "NginxProxyManager" "Lldap-Gmer4Lfe" "Authelia" "Authelia-Secondary" "Dispatcharr-Iptv-Users" "Dispatcharr" # Live TV scheduler — degrades without daily restart "Dispatcharr-Basic" "ErsatzTV-Emby" "Slskd" # Soulseek connection drops after extended uptime; restart refreshes share index ) # ━━━ Docker Weekly Restart ━━━ # Less critical services restarted weekly via WEEKLY_MAINTENANCE_SCRIPTS (Sunday 2:30am). # Containers already stopped for weekly sync — restart adds zero extra downtime. HOST1_WEEKLY_RESTART_CONTAINERS=( "NextCloud" "Organizrv2-Gmer4Lfe" "AdGuard-Home" "Immich-Gmer4Lfe" ) # ━━━ Docker Watchdog ━━━ # Per-HOST1 container configuration for docker_watchdog.sh. # Shared thresholds and toggles live in master.conf. # Memory hard limits in MB — immediate restart if exceeded. # Set at "container is clearly broken" not "container is busy". # 20GB=20480 18GB=18432 16GB=16384 12GB=12288 8GB=8192 4GB=4096 2GB=2048 1GB=1024 declare -A HOST1_WATCHDOG_CONTAINERS=( ["Emby"]=18432 # 18GB — large library + active transcodes ["LidaTube"]=6144 # 6GB — memory leak over time ["Tdarr"]=6144 # 6GB — encoding is memory intensive ["Code-Server"]=1024 # 1GB — should never need more ) # HTTP health check URLs — checked every cycle, strike system before restart. # Only add containers with a meaningful web interface to check. declare -A HOST1_WATCHDOG_CONTAINER_URLS=( ["Emby"]="http://localhost:8096" ) # Required containers — must always be running on HOST1. # Strike system before restart — repeated failures go on skip list, auto-clears on recovery. # Listed in dependency order — dependencies before dependents. HOST1_WATCHDOG_REQUIRED_CONTAINERS=( "NginxProxyManager" "Lldap-Gmer4Lfe" "Mariadb-Authelia" "Mariadb-Authelia-Secondary" "Redis-Authelia" "Redis-Authelia-Secondary" "Authelia" "Authelia-Secondary" ) # Containers to skip in Tier 2 global scan — legitimately stopped or frequently restarting. # Watchdog leaves these alone entirely — no restart attempts, no crash loop tracking. HOST1_WATCHDOG_SCAN_IGNORE=( "DashGate" "PIA-WG-Config-Generator" "Aperture" "Aperture-Kids" "pgvector-18-Apeture-Kids" "Pgvector18-Aperture" ) # Dependency ordering — skip restarting a container if its dependency is also down. # Prevents watchdog from restarting Authelia before Mariadb is back up. # SPACE-SEPARATED STRINGS — converted to array at runtime. declare -A HOST1_WATCHDOG_DEPENDENCIES=( ["Authelia"]="Mariadb-Authelia Redis-Authelia" ["Authelia-Secondary"]="Mariadb-Authelia Redis-Authelia-Secondary" ["NextCloud"]="Postgres-NextCloud" ) # ━━━ Docker Network Connect ━━━ # Containers connected to custom networks at array start by docker_network_connect.sh. # Networks created if they don't exist — idempotent, safe to re-run. HOST1_NETWORK_CONNECT_CONTAINERS=( "memcached" "Npm-CrowdSec" ) HOST1_NETWORK_CONNECT_NETWORKS=( "high-availability" ) # ============================================================================================== # ── FALLBACK ────────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ DDNS ━━━ # DDNS containers HOST1 manages — started/stopped by fallback.sh per DDNS absolute rules: # Internet loss → stop immediately # Failover → HOST2 starts HOST1's DDNS as Tier 1 (before any other containers) # Handback → stop HOST1's DDNS on HOST2 → rsync → start containers → start local DDNS last HOST1_DDNS_CONTAINERS=( "Gmer4Lfe.com" ) # ━━━ Internet Loss ━━━ # Containers stopped immediately on HOST1 when internet connection is lost. # Prevents external-facing services from operating without connectivity. FALLBACK_HOST1_STOP_ON_NO_NET=( "Gmer4Lfe.com" ) # ━━━ Fallback Tiers — HOST1 Runs for HOST2 ━━━ # Containers HOST1 starts when HOST2 goes down. # Tier 1 is always immediate — vital services cannot wait. # Higher tiers activate after HOST2_TIER*_DELAY minutes (set in master_host2.conf). FALLBACK_HOST1_COVERS_HOST2_TIER1=( "Gmer4Lfe.us" "VaultWarden-Jayred365" ) FALLBACK_HOST1_COVERS_HOST2_TIER2=( # "container-placeholder" ) FALLBACK_HOST1_COVERS_HOST2_TIER3=( # "container-placeholder" ) FALLBACK_HOST1_COVERS_HOST2_TIER4=( # "container-placeholder" ) # ━━━ Tier Delays — HOST1's Containers on HOST2 ━━━ # How long HOST1 must be down before each tier activates on HOST2 — in minutes. # Tier 1 is always immediate — no delay var needed. HOST1_TIER2_DELAY=240 # 4 hours — NextCloud, Immich HOST1_TIER3_DELAY=720 # 12 hours — secondary services HOST1_TIER4_DELAY=1440 # 24 hours — arrs + downloaders # ━━━ Rsync Writeback — HOST1 Appdata Back on Handback ━━━ # Syncs HOST1 appdata BACK to HOST1 when it comes back online after a failover. # Containers stopped before writeback — clean source, no competing writes. # # HOST1_TIER1_WRITEBACK_DELAY: short outages skip Tier 1 writeback — primary state # is more reliable than dirty sync data for brief outages. HOST1_TIER1_WRITEBACK_DELAY=60 # skip Emby writeback if outage under 1hr # Tier 4 automatically syncs HOST1_DAILY_SYNC_SHARES — only list paths NOT in that array. FALLBACK_HOST1_WRITEBACK_TIER1=( "/mnt/user/Media_Server/Emby" # watch states built up during outage ) FALLBACK_HOST1_WRITEBACK_TIER2=( "/mnt/user/appdata-Fallback/Important-Data" # NextCloud + Postgres — files added during outage ) FALLBACK_HOST1_WRITEBACK_TIER3=( # "location-placeholder" ) FALLBACK_HOST1_WRITEBACK_TIER4=( "/mnt/user/appdata-Fallback/Arrs_Stack" # arr databases — downloads queued during outage ) # ============================================================================================== # ── MEDIA ───────────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ Media Permissions ━━━ # Shares that media_shares_permissions.sh applies PERMISSIONS_MODE and PERMISSIONS_OWNER to. # Runs first in DAILY_MAINTENANCE_SCRIPTS — arr cleanup depends on correct ownership. HOST1_MEDIA_PERMISSION_SHARES=( /mnt/user/Anime_Movies /mnt/user/Anime_Movies-Old /mnt/user/Anime_Shows /mnt/user/Anime_Shows-Old /mnt/user/appcache /mnt/user/Books /mnt/user/Downloads /mnt/user/Games /mnt/user/Intros /mnt/user/Kids_Movies /mnt/user/Kids_Tv_Shows /mnt/user/Movie_Recordings /mnt/user/Movies /mnt/user/Music /mnt/user/Music_Videos /mnt/user/Photo /mnt/user/Sports /mnt/user/stand-up_comedy /mnt/user/Temp_Storage /mnt/user/Tv_Recordings /mnt/user/Tv_Shows /mnt/user/YouTube ) # ━━━ Media Cleaner ━━━ # Folder lists for media_cleaner.sh — two profiles: anime and media. # File patterns shared across all servers — defined in master.conf. # Called via DAILY_MAINTENANCE_SCRIPTS. Run manually: Media/media_cleaner.sh anime|media HOST1_ANIME_CLEAN_FOLDERS=( /mnt/user/Anime_Movies /mnt/user/Anime_Movies-Old /mnt/user/Anime_Shows /mnt/user/Anime_Shows-Old ) HOST1_MEDIA_CLEAN_FOLDERS=( /mnt/user/Kids_Movies /mnt/user/Kids_Tv_Shows /mnt/user/Movies /mnt/user/Music /mnt/user/Sports /mnt/user/stand-up_comedy /mnt/user/Tv_Shows ) # ============================================================================================== # ── MONITORS ────────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # ━━━ Certificate Monitor ━━━ # Domains checked via direct openssl connection — not relying on NPM's certificate state. # Checks the actual certificate served, not what NPM thinks it has. # Thresholds (CERT_WARN_DAYS, CERT_CRIT_DAYS) defined in master.conf. HOST1_CERT_MONITOR_DOMAINS=( "Gmer4Lfe.com" "Gmer4Lfe.us" ) # ━━━ SMART Health ━━━ # Drives skipped in SMART attribute monitoring — hardware is server-specific. # Thresholds read from dynamix.cfg at runtime — fallbacks in master.conf. HOST1_SMART_IGNORE_DRIVES=( "sda" # boot USB — SMART not meaningful on flash drives ) # ━━━ ZFS Report ━━━ # Pools excluded from the weekly ZFS health report — reduces noise from single-disk array pools. # These are individual array disks formatted as ZFS — converting to XFS over time via unBalance. # Pool health thresholds defined in master.conf. HOST1_ZFS_REPORT_IGNORE_POOLS=( "disk5" "disk6" "disk8" "disk9" "disk10" ) # ============================================================================================== # ── TRANSCODES ──────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # Ramdisk size ceiling — tmpfs only uses RAM actually needed, not the full size upfront. # Real-world: 9 streams peaked at ~5.5GB — 8G gives comfortable headroom on 128GB RAM. HOST1_RAMDISK_SIZE="8G" # Usage thresholds — coupled to HOST1_RAMDISK_SIZE, adjust all three together if size changes. # Hysteresis gap (6.8 - 5.5 = 1.3GB) prevents flip-flop between ramdisk and SSD. HOST1_RAMDISK_WARN_GB=6.8 # flip to SSD when ramdisk usage reaches this HOST1_RAMDISK_LOW_GB=5.5 # flip back to ramdisk when usage drops to this # SSD fallback path — where transcodes land when ramdisk exceeds HOST1_RAMDISK_WARN_GB. # Must be on cache pool — array disks too slow for active transcode writes. HOST1_TRANSCODE_SSD="/mnt/cache/Temp_Storage/Emby/Transcodes/" # Media servers sharing the ramdisk transcode space on HOST1. # Format: "ContainerName|URL|APIKey|Type" — Type: emby | jellyfin | plex # Entries with placeholder API keys are skipped automatically. # ⚠️ Tdarr does NOT belong here — keep Tdarr on SSD, not ramdisk. HOST1_TRANSCODE_SERVERS=( "${HOST1_EMBY_CONTAINER}|${HOST1_EMBY_URL}|${HOST1_EMBY_API_KEY}|emby" ) # ============================================================================================== # ── ARR STACK ───────────────────────────────────────────────────────────────────────────────── # ============================================================================================== # Used by arr cleanup scripts and arrs_failed_stalled_recovery.sh. # detect_hosts() selects HOST1 vars when running on HOST1. # # PATH MAPS — container path → host path translation. # Arr stores file paths using container-internal paths — scripts need host paths to scan. # Add one entry per root folder in arr Settings → Media Management → Root Folders. # ━━━ Downloaders ━━━ # Used by downloaders_reset.sh — runs every 15min via CRITICAL_MAINTENANCE_SCRIPTS. # Clears stuck states, purges old history, prepares each client for a clean cycle. # slskd — clears stuck searches, dead transfers, purges expired failed imports. # SLSKD_FAILED_IMPORTS_DIR: where Soularr moves albums Lidarr rejected. HOST1_SLSKD_URL="http://localhost:8980" HOST1_SLSKD_API_KEY="4bF9kL2mNpQrT7vWxYz1A3dEgHjKoRsU" HOST1_SLSKD_FAILED_IMPORTS_DIR="/mnt/user/Temp_Storage/Slskd/completed/failed_imports" # SABnzbd HOST1_SABNZBD_URL="http://localhost:8180" HOST1_SABNZBD_API_KEY="8bfefe41d83b4d50883e32859b55ca9a" # qBittorrent — deleteFiles=false removes torrent from qBit but leaves files on disk. # Radarr/Sonarr manage actual files independently. HOST1_QBIT_URL="http://localhost:8080" HOST1_QBIT_USERNAME="root" HOST1_QBIT_PASSWORD="Stay0utD!ck" # ━━━ Lidarr — HOST1 only ━━━ # HOST2 does not run Lidarr — HOST1_LIDARR_RECOVERY flag handles the exit cleanly. HOST1_LIDARR_URL="http://localhost:8686" HOST1_LIDARR_API_KEY="b2977e71ef074bc0a0529d9fcce3b2dc" HOST1_LIDARR_MUSIC_ROOT="/mnt/user/Music-New" HOST1_FANART_API_KEY="Yd7147a43b692df0b364b94dc47efb81" HOST1_LASTFM_API_KEY="be6dc169c33ae263e690c30d18b7491d" declare -A HOST1_LIDARR_PATH_MAP=( ["/ext-music"]="/mnt/user/Music-New" ) # ━━━ Sonarr ━━━ HOST1_SONARR_URL="http://localhost:8989" HOST1_SONARR_API_KEY="130decd3db5b4c25afad64864cd03f9f" HOST1_SONARR_TV_ROOT="/mnt/user/Tv_Shows" # Note: stand-up_comedy in both Sonarr + Radarr — TV specials and movie specials, one folder declare -A HOST1_SONARR_PATH_MAP=( ["/tv"]="/mnt/user/Tv_Shows" ["/ext-standup-comedy"]="/mnt/user/stand-up_comedy" ["/kids tv"]="/mnt/user/Kids_Tv_Shows" ["/ext-anime-shows"]="/mnt/user/Anime_Shows-Old" ) # ━━━ Radarr ━━━ HOST1_RADARR_URL="http://localhost:7878" HOST1_RADARR_API_KEY="d43a3ec6cf1549edb4af0cc63f98b2a9" HOST1_TMDB_API_KEY="3dac5e2e49b5540472d2eafec4f01260" HOST1_RADARR_MOVIES_ROOT="/mnt/user/Movies" # Note: stand-up_comedy in both Radarr + Sonarr — movie specials and TV specials, one folder declare -A HOST1_RADARR_PATH_MAP=( ["/movies"]="/mnt/user/Movies" ["/kids movies"]="/mnt/user/Kids_Movies" ["/ext-stand-up-comedy"]="/mnt/user/stand-up_comedy" ["/anime-movies"]="/mnt/user/Anime_Movies-Old" ) # ━━━ Arr Recovery Toggles ━━━ # false = skip that arr on this host — exits cleanly without error HOST1_SONARR_RECOVERY=true HOST1_RADARR_RECOVERY=true HOST1_LIDARR_RECOVERY=true # HOST1 only — exits cleanly on HOST2 # ============================================================================================== # ── SYSTEM WATCHDOG ─────────────────────────────────────────────────────────────────────────── # ============================================================================================== # Per-host check toggles and NIC config for system_watchdog.sh. # Aliased by detect_hosts() — script uses unprefixed SYS_WATCHDOG_* names. # HOST1: TR1950X 128GB — full media server, active transcoding, ZFS cache pools. # # Three-tier response — all critical checks enabled by default on HOST1: # Tier 1 (bypass strikes, reboot now): docker daemon, rootfs full, kernel oops, FD, /boot # Tier 2 (bypass strikes with OOM): RAM critical + OOM kills in cycle # Tier 3 (standard strike system): everything else # # RAM tiers, OOM limits, and reboot loop settings in master.conf System Watchdog section. # ━━━ Primary NIC ━━━ # Network interface for NIC state check — verify with: ip link show | grep "^[0-9]" # Common values: eth0, bond0, br0, eno1 HOST1_SYS_WATCHDOG_NIC="eth0" # ━━━ Tier 1 — Critical Checks ━━━ # These bypass the strike system — a single hit triggers immediate reboot. # Disabling any of these is not recommended — they protect against acute system failure. # Docker daemon unresponsive → try restart, reboot if restart fails. # Without a working daemon docker_watchdog.sh is blind and containers cannot be managed. HOST1_SYS_WATCHDOG_CHECK_DOCKER_DAEMON=true # rootfs at critical threshold (ROOTFS_CRITICAL_PCT=99) → reboot immediately. # At 99% rootfs writes fail silently — logs stop, Docker errors out, SSH may stop working. # Standard 95% threshold still uses strike system — only 99%+ is critical tier. HOST1_SYS_WATCHDOG_CHECK_ROOTFS=true # Kernel BUG/Oops in dmesg delta since last cycle → reboot immediately. # A kernel oops means the kernel ran with a corrupted state — stability is not guaranteed. HOST1_SYS_WATCHDOG_CHECK_KERNEL_OOPS=true # File descriptor exhaustion at FD_CRITICAL_PCT (95%) → reboot immediately. # At 95% FD: new connections fail, Docker can't spawn processes, SSH drops. HOST1_SYS_WATCHDOG_CHECK_FD=true # /boot read-only detected → reboot immediately. # Unexpected read-only /boot means state files and config writes are silently failing. # Fallback state, watchdog reboot log, and lock files all go stale silently. HOST1_SYS_WATCHDOG_CHECK_BOOT=true # ━━━ Tier 2 — Urgent OOM Check ━━━ # Bypass strikes when RAM is critically low AND OOM kill rate confirms active crisis. # Both must be enabled for Tier 2 bypass to function — disable either to always use strikes. # Track kernel OOM kills each cycle via /proc/vmstat oom_kill delta. # Also provides diagnostic context in reboot messages (which processes were killed). HOST1_SYS_WATCHDOG_CHECK_OOM=true # Free RAM check — required for both Tier 2 bypass and RAM tier logic. # Tiers: MEM_WARN_GB(10) → notify | MEM_SHUTDOWN_GB(6) → stop containers | MEM_GB(4) → strikes HOST1_SYS_WATCHDOG_CHECK_RAM=true # ━━━ Tier 3 — Standard Checks (strike system) ━━━ # Each check must fail SYS_WATCHDOG_STRIKE_LIMIT consecutive cycles before action is taken. # Single spikes are ignored — sustained problems trigger reboot. # /var/log filesystem usage above SYS_WATCHDOG_LOG_PCT. # Log spam (Docker log storms, syslog loops) fills rootfs — indicates something broken. HOST1_SYS_WATCHDOG_CHECK_LOG=true # ZFS ARC memory pinned above SYS_WATCHDOG_ARC_PINNED_PCT after cache drop. # Enabled on HOST1 — ZFS cache pools actively used. Disable on hosts without ZFS. HOST1_SYS_WATCHDOG_CHECK_ARC=true # CPU temperature above SYS_WATCHDOG_CPU_TEMP_MAX (95°C). # Sustained high temp causes kernel throttling or panic. Requires lm-sensors. HOST1_SYS_WATCHDOG_CHECK_CPU_TEMP=true # Load average above SYS_WATCHDOG_LOAD_MULTIPLIER × core count. # DISABLED on HOST1 — Tdarr and Emby cause legitimate sustained load spikes during encoding. # Enable on idle servers or adjust SYS_WATCHDOG_LOAD_MULTIPLIER if load is always high. HOST1_SYS_WATCHDOG_CHECK_LOAD=false # Zombie process count above SYS_WATCHDOG_ZOMBIE_LIMIT (50). # Large zombie counts indicate serious process management failure — something is stuck. HOST1_SYS_WATCHDOG_CHECK_ZOMBIES=true # Check docker_watchdog.sh persistent skip list — required containers on skip list. # Cross-watchdog coordination: if docker_watchdog gave up, system_watchdog escalates. # ENABLED — HOST1 fully built and operational, skip list is meaningful. HOST1_SYS_WATCHDOG_CHECK_CONTAINERS=true # /tmp filesystem usage above SYS_WATCHDOG_TMP_PCT with auto-clear attempt. # Script tries to clear aged /tmp files first — only strikes if clear fails. # Lock files, rsync temp files, and Docker ops use /tmp — 100% means lock failures. HOST1_SYS_WATCHDOG_CHECK_TMP=true # Array disk error count delta in /proc/mdstat — accumulating errors = disk failing now. # Triggers on SYS_WATCHDOG_MDSTAT_ERROR_LIMIT new errors in one cycle. HOST1_SYS_WATCHDOG_CHECK_MDSTAT=true # Primary NIC operstate — detects NIC going down (physical or driver failure). # Uses HOST1_SYS_WATCHDOG_NIC above. Strike system — brief flaps don't trigger reboot. HOST1_SYS_WATCHDOG_CHECK_NETWORK=true # sshd running check — attempts restart before escalating. # sshd down = no remote access. Script tries rc.sshd start, notifies, strikes on failure. HOST1_SYS_WATCHDOG_CHECK_SSHD=true # Runaway process detection — single process above SYS_WATCHDOG_RUNAWAY_CPU_PCT sustained. # DISABLED — Tdarr encoding and Emby transcoding legitimately peg CPU for extended periods. # Enable only if HOST1 has no CPU-intensive workloads. HOST1_SYS_WATCHDOG_CHECK_RUNAWAY=false # ============================================================================================== # ── RESOURCE MANAGER ────────────────────────────────────────────────────────────────────────── # ============================================================================================== # Containers to manage under pressure — see master.conf RW_CRITICAL_CONTAINERS for exclusions. # docker pause at medium pressure (RAM < RW_RAM_MEDIUM_GB or load > medium threshold) # Suspended in-place — instant to pause/unpause, no state lost, no restart delay. HOST1_RW_PAUSE_CONTAINERS=( "Huntarr" # arr search automation — safe to suspend "Cleanuparr" # download cleanup — safe to suspend "Healarr" # arr health checks — safe to suspend "Soularr" # Slskd automation — background only "ChannelTube" # YouTube archiver — background only "Pinchflat" # YouTube archiver — background only ) # docker stop at hard pressure (RAM < RW_RAM_HARD_GB) # Full stop — these are optional/heavy services that free significant RAM when stopped. # resource_watchdog.sh restarts them when pressure fully clears (RAM >= RW_RAM_RECOVER_GB). HOST1_RW_STOP_CONTAINERS=( "LocalAI" # GPU/CPU heavy — largest RAM consumer when idle "7DaysToDie" # game server — optional "V-Rising" # game server — optional "Code-Server" # IDE — not needed during pressure events ) # ============================================================================================== # ──────────────────────── End Of HOST1 Variables ────────────────────────────────────────────── # ==============================================================================================