Files
Varaverk/unRAID_Essentials/php_fpm_max_children.sh
T
Gmer4LfeandClaude Sonnet 4.6 0ae31b5fa6 feat: Tailscale resolution hardening, partnership offboard completion, Emby provisioning
common.sh:
- Add resolve_tailscale_ip() helper — tries `tailscale ip -4` first, falls back to
  parsing `tailscale status` output; handles hosts where MagicDNS short-name resolution
  is not active
- Add PARTNERSHIP_OWN_CONTAINERS alias in detect_hosts()
- Add aliasing for 4 Emby provisioning vars (PARTNERSHIP_PROVISION_EMBY_ADMIN,
  PARTNERSHIP_EMBY_ADMIN_USER, PARTNERSHIP_EMBY_ADMIN_PASS, PARTNERSHIP_EMBY_PORT)

Partnership/partnership_manager.sh:
- Replace 9 bare `tailscale ip -4` calls with resolve_tailscale_ip()
- Add read_remote_conf_var() and read_remote_conf_array() — SSH to mirror, source its
  own load_config.sh + detect_hosts(), return aliased variable; solves sparse-checkout
  problem where HOST1 cannot read master_host2.conf directly
- Add derive_short_name() — strips unraid- prefix, capitalises first char
- Add cleanup_partner_containers() — removes partner containers via FolderView3 folder
  if enabled, else falls back to FALLBACK_*_COVERS_*_TIER* arrays
- Add cleanup_owner_containers_on_mirror() — SSH to mirror, stops and removes containers
  matching *-${OWNER_SHORT} naming convention
- Add start_own_stack() and start_mirror_own_stack() — restart own containers locally
  or on mirror via SSH using PARTNERSHIP_OWN_CONTAINERS
- Add provision_emby_admin() — reads mirror credentials via read_remote_conf_var, checks
  for username collision, creates user + sets password + grants admin policy via Emby API
- Add revoke_emby_admin() — looks up mirror username on local Emby, deletes via REST API
- Wire offboard paths (both mirror-initiated and owner-initiated) to call container
  cleanup and stack restart; update --check finalisation paths accordingly
- Fix write_state_file in --onboard not gated on DRY_RUN (was writing ACTIVE state on
  dry runs)

master_host1.conf:
- Add HOST1_PARTNERSHIP_OWN_CONTAINERS array
- Add partnership Emby provisioning config (toggle + port + per-host credentials)

master_host2.conf:
- Add HOST2_PARTNERSHIP_OWN_CONTAINERS array
- Add HOST2_PARTNERSHIP_EMBY_ADMIN_USER and HOST2_PARTNERSHIP_EMBY_ADMIN_PASS

Tailscale fix applied to:
- Initial_run/ssh_setup.sh (2 callsites)
- unRAID_Essentials/rsync_stop.sh (1 callsite)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10 20:09:13 -04:00

206 lines
11 KiB
Bash
Executable File

#!/bin/bash
# ==============================================================================================
# ============================= PHP-FPM Max Children ===========================================
# ==============================================================================================
# Persistently sets PHP-FPM pm.max_children on unRAID to prevent WebGUI slowdowns.
# Run once at array start via ARRAY_START_SCRIPTS in master.conf.
# Idempotent — completely silent when value is already correct.
#
# ── WHY THIS EXISTS ───────────────────────────────────────────────────────────────────────────
# unRAID's WebGUI runs through PHP-FPM. The default pm.max_children is very low (4-8).
# Under load — multiple users, Docker operations, heavy dashboard usage — all PHP workers
# saturate and new requests queue. The WebGUI becomes slow or unresponsive.
#
# pm.max_children controls how many PHP worker processes can run simultaneously.
# Raising it allows the WebGUI to handle more concurrent requests without queuing.
# Too high: wastes RAM. Too low: WebGUI slowdowns.
# PHP_MAX_CHILDREN=250 is appropriate for 128GB — ~2MB per worker = ~500MB total.
#
# ── WHY IDEMPOTENT ────────────────────────────────────────────────────────────────────────────
# This runs at every array start. If the value is already correct there is nothing to do —
# no config write, no PHP-FPM restart. Restarting PHP-FPM unnecessarily disrupts active
# WebGUI sessions and is annoying on every boot.
#
# ── APPLY SEQUENCE ────────────────────────────────────────────────────────────────────────────
# 1. Read current pm.max_children from PHP_CONF
# 2. If already at target → exit silently (idempotent)
# 3. Verify sed pattern matches before writing
# 4. Apply sed replacement
# 5. Restart PHP-FPM via rc.php-fpm
# 6. Verify PHP-FPM process running after restart
# 7. Verify config file reflects target value
#
# ── SAFEGUARDS ────────────────────────────────────────────────────────────────────────────────
# Root check — writing to system config requires root
# acquire_lock — prevents concurrent runs at array start
# Idempotent check — only restarts PHP-FPM when value actually changes
# Pattern match check — verifies sed found pm.max_children before writing
# Process verify — confirms PHP-FPM running after restart
# Config verify — reads back config to confirm value applied
# validate_unraid — notify validated before use
# Silent on correct — runs every boot, no noise when already set ✅
#
# ── CONFIGURATION (master.conf) ───────────────────────────────────────────────────────────────
# PHP_MAX_CHILDREN — target pm.max_children value (default 250)
# PHP_CONF — path to PHP-FPM www.conf (default /etc/php83/php-fpm.d/www.conf)
#
# ── USAGE ─────────────────────────────────────────────────────────────────────────────────────
# php_fpm_max_children.sh — normal run (idempotent)
# php_fpm_max_children.sh --dry-run — show what would change
# php_fpm_max_children.sh --status — show current vs target and process state
# php_fpm_max_children.sh --log — verbose output
# ==============================================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../load_config.sh"
parse_args "$@"
# ==============================================================================================
# ━━━ Setup ━━━
# ==============================================================================================
if [[ "$EUID" -ne 0 ]]; then
error "Must be run as root — writing system config requires root"
exit 1
fi
validate_unraid_cmd \
"/usr/local/emhttp/plugins/dynamix/scripts/notify" \
"" "" \
"unRAID notify script" || warn "unRAID notify script not found — native notifications disabled"
validate_int PHP_MAX_CHILDREN "$PHP_MAX_CHILDREN"
require_var PHP_CONF
acquire_lock
detect_hosts
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes will be made"
# ==============================================================================================
# ━━━ Status ━━━
# ==============================================================================================
if [[ "$SHOW_STATUS" == true ]]; then
echo ""
echo "━━━━━ $ICON_SUMMARY PHP-FPM STATUS ━━━━━"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_GEAR Config file: $PHP_CONF"
echo "$ICON_PHP Target: pm.max_children = $PHP_MAX_CHILDREN"
echo ""
if [[ -f "$PHP_CONF" ]]; then
CURRENT_VAL=$(grep -E "^pm\.max_children" "$PHP_CONF" 2>/dev/null | \
awk '{print $NF}')
if [[ "${CURRENT_VAL:-0}" -eq "$PHP_MAX_CHILDREN" ]]; then
echo " $ICON_SUCCESS Current: pm.max_children = $CURRENT_VAL (correct ✅)"
else
echo " $ICON_WARN Current: pm.max_children = ${CURRENT_VAL:-not set} (would update)"
fi
else
echo " $ICON_ERROR Config file not found: $PHP_CONF"
fi
echo ""
if pgrep -f "php-fpm" >/dev/null 2>&1; then
FPM_COUNT=$(pgrep -fc "php-fpm" 2>/dev/null || echo "?")
echo " $ICON_SUCCESS PHP-FPM: running ($FPM_COUNT worker(s))"
else
echo " $ICON_ERROR PHP-FPM: NOT running"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━"
exit 0
fi
# ==============================================================================================
# ━━━ PHP-FPM Config ━━━
# ==============================================================================================
START=$(date +%s)
if [[ ! -f "$PHP_CONF" ]]; then
error "PHP config file not found: $PHP_CONF"
notify "PHP-FPM config not found on $(hostname) ($MY_ID) — $PHP_CONF missing" \
"PHP-FPM" "warning"
exit 1
fi
# ── Idempotent check ─────────────────────────────────────────────────────────────────────────
CURRENT_VAL=$(grep -E "^pm\.max_children" "$PHP_CONF" 2>/dev/null | awk '{print $NF}')
if [[ "${CURRENT_VAL:-0}" -eq "$PHP_MAX_CHILDREN" ]]; then
log "pm.max_children already $PHP_MAX_CHILDREN — no changes needed"
exit 0
fi
warn "pm.max_children: ${CURRENT_VAL:-not set}$PHP_MAX_CHILDREN"
# ── Verify pattern exists before writing ─────────────────────────────────────────────────────
if ! grep -qE "^pm\.max_children" "$PHP_CONF" 2>/dev/null; then
error "pm.max_children not found in $PHP_CONF — cannot apply"
error "Add 'pm.max_children = $PHP_MAX_CHILDREN' to $PHP_CONF manually"
notify "PHP-FPM pm.max_children not found in config on $(hostname) ($MY_ID)" \
"PHP-FPM" "warning"
exit 1
fi
if [[ "$DRY_RUN" == true ]]; then
warn "DRY RUN — would set pm.max_children = $PHP_MAX_CHILDREN in $PHP_CONF"
warn "DRY RUN — would restart PHP-FPM"
exit 0
fi
# ── Apply setting ─────────────────────────────────────────────────────────────────────────────
log "Applying pm.max_children = $PHP_MAX_CHILDREN..."
if ! sed -i "s/^pm\.max_children.*/pm.max_children = $PHP_MAX_CHILDREN/" "$PHP_CONF"; then
error "Failed to update $PHP_CONF"
notify "PHP-FPM config update failed on $(hostname) ($MY_ID)" \
"PHP-FPM" "warning"
exit 1
fi
log "Config updated"
# ── Restart PHP-FPM ──────────────────────────────────────────────────────────────────────────
log "Restarting PHP-FPM..."
if ! /etc/rc.d/rc.php-fpm restart >/dev/null 2>&1; then
error "PHP-FPM restart command failed"
notify "PHP-FPM restart failed on $(hostname) ($MY_ID)" \
"PHP-FPM" "warning"
exit 1
fi
sleep 3 # Allow PHP-FPM workers to initialise
# ── Verify process running ────────────────────────────────────────────────────────────────────
if ! pgrep -f "php-fpm" >/dev/null 2>&1; then
error "PHP-FPM not running after restart — WebGUI may be broken"
notify "PHP-FPM failed to start after config update on $(hostname) ($MY_ID)" \
"PHP-FPM" "warning"
exit 1
fi
# ── Verify config reflects target ────────────────────────────────────────────────────────────
APPLIED_VAL=$(grep -E "^pm\.max_children" "$PHP_CONF" 2>/dev/null | awk '{print $NF}')
if [[ "${APPLIED_VAL:-0}" -ne "$PHP_MAX_CHILDREN" ]]; then
warn "Config reads pm.max_children = ${APPLIED_VAL:-unknown} — expected $PHP_MAX_CHILDREN"
warn "Check $PHP_CONF manually"
else
log "Verified: pm.max_children = $APPLIED_VAL ✅"
fi
END=$(date +%s)
# ==============================================================================================
# ━━━ Summary ━━━
# ==============================================================================================
echo ""
echo "━━━━━ $ICON_SUMMARY PHP-FPM SUMMARY ━━━━━"
echo "$ICON_HOST Identity: $MY_ID ($LOCAL_SERVER_NAME)"
echo "$ICON_GEAR Config file: $PHP_CONF"
echo "$ICON_PHP Applied: pm.max_children = $PHP_MAX_CHILDREN"
echo "$ICON_TIME Duration: $(format_duration $(( END - START )))"
echo ""
log "$ICON_DONE Status: done ✅"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
exit 0