#!/bin/bash # Setup NUT client on a Proxmox slave node. # Usage: # ./setup-nut-slave.sh [UPS_NAME] [NUT_USER] [NUT_PASS] # # Example: # ./setup-nut-slave.sh 192.168.1.10 cyberpower remote remotepass # # MASTER_IP = IP of the NUT master (the host with the USB UPS) # UPS_NAME = NUT UPS name defined on the master (default: cyberpower) # NUT_USER = user defined in /etc/nut/upsd.users on master (default: remote) # NUT_PASS = that user's password (default: remotepass) set -euo pipefail MASTER_IP="${1:-}" UPS_NAME="${2:-cyberpower}" NUT_USER="${3:-remote}" NUT_PASS="${4:-remotepass}" NUT_CONF="/etc/nut/nut.conf" UPSMON_CONF="/etc/nut/upsmon.conf" if [[ -z "${MASTER_IP}" ]]; then echo "Usage: $0 [UPS_NAME] [NUT_USER] [NUT_PASS]" exit 1 fi if [[ "$(id -u)" -ne 0 ]]; then echo "This script must be run as root." exit 1 fi echo "=== NUT slave setup on Proxmox node ===" echo "Master IP : ${MASTER_IP}" echo "UPS name : ${UPS_NAME}" echo "NUT user : ${NUT_USER}" install_nut_client() { echo echo ">>> Installing NUT client..." apt-get update -y apt-get install -y nut-client } configure_nut_mode() { echo echo ">>> Configuring NUT mode (netclient) in ${NUT_CONF}..." if [[ -f "${NUT_CONF}" ]]; then cp "${NUT_CONF}" "${NUT_CONF}.bak.$(date +%s)" echo "Backup created: ${NUT_CONF}.bak.*" fi cat > "${NUT_CONF}" <>> Configuring upsmon in ${UPSMON_CONF}..." if [[ -f "${UPSMON_CONF}" ]]; then cp "${UPSMON_CONF}" "${UPSMON_CONF}.bak.$(date +%s)" echo "Backup created: ${UPSMON_CONF}.bak.*" fi cat > "${UPSMON_CONF}" <>> Enabling and restarting nut-client..." systemctl enable nut-client || true systemctl restart nut-client echo ">>> nut-client status:" systemctl --no-pager status nut-client || true } test_connectivity() { echo echo "=== TEST: NUT connectivity from this slave ===" echo echo "1) Testing raw UPS status from master with 'upsc'..." if command -v upsc >/dev/null 2>&1; then if upsc "${UPS_NAME}@${MASTER_IP}" ups.status 2>/dev/null; then echo "OK: Successfully queried UPS status from master." else echo "ERROR: Could not query UPS status from master." echo " - Check firewall between this node and ${MASTER_IP}:3493" echo " - Check that master has LISTEN 0.0.0.0 3493 in /etc/nut/upsd.conf" echo " - Check MONITOR user/password and UPS name." fi else echo "Command 'upsc' not found (should be installed with nut-client)." fi echo echo "2) Testing upsmon status locally..." if command -v upsmon >/dev/null 2>&1; then if upsmon -c status 2>/dev/null; then echo "OK: upsmon is running and sees the UPS." else echo "WARNING: upsmon status failed. Check /etc/nut/upsmon.conf and nut-client service." fi else echo "Command 'upsmon' not found." fi echo echo "3) OPTIONAL: Simulate a forced shutdown (fsd) test" echo " This will cause this node to initiate a real shutdown if everything is wired correctly." echo " ONLY do this if you're prepared for the node to go down." read -r -p "Run 'upsmon -c fsd' now on THIS NODE? [y/N]: " ans case "${ans}" in y|Y) echo ">>> Running 'upsmon -c fsd' (this may trigger a shutdown)..." upsmon -c fsd || echo "upsmon fsd command failed." ;; *) echo "Skipped FSD test." ;; esac } main() { install_nut_client configure_nut_mode configure_upsmon enable_services test_connectivity echo echo "=== Done. This Proxmox node is now configured as a NUT SLAVE. ===" echo "When the master detects LOWBATT, it will signal this node to shut down via upsmon." echo "Backups of original configs (if any) are in:" echo " - ${NUT_CONF}.bak.*" echo " - ${UPSMON_CONF}.bak.*" } main