A robust, universal, and configurable Bash script that safely shuts down a Linux-based system by monitoring a remote NUT (Network UPS Tools) server. It's designed to be a reliable replacement for inflexible or buggy built-in UPS clients. It now includes an optional "Hub Mode" for centrally managing the configuration of multiple clients from a single API endpoint.
Many appliance-like operating systems, such as Synology DSM, Proxmox VE, or TrueNAS, offer built-in UPS support. However, this support can be surprisingly brittle, especially in custom setups (like using a non-Synology device as a NUT server for a Synology client).
This project was born out of frustration with a common failure mode: upon receiving a "Low Battery" signal, the system would start a shutdown procedure but hang indefinitely, becoming unresponsive. This is often caused by a flawed "Standby Mode" or "Safe Mode" implementation that fails to complete. A system in this hung state requires a hard power cycle to recover, which is a critical issue for remote or unattended servers.
This script bypasses the native, problematic shutdown logic entirely. Instead of relying on the host OS's UPS integration, it uses a simple and direct approach:
- It runs periodically via cron.
- It directly queries the NUT server using the REST API
/upsc
endpoint. - If a critical
On Battery, Low Battery
state is detected, it initiates a configurable countdown. - If power is restored during the countdown, the shutdown is cleanly cancelled.
- If the countdown completes, it executes the universally reliable
/sbin/shutdown -h now
command.
This method provides predictable, robust, and platform-agnostic protection against data loss during a power failure.
- Reliable Shutdown: Uses the low-level
shutdown
command, avoiding complex and fragile "standby" modes. - Centralized Configuration (Hub Mode): Optionally, the script can fetch its configuration (
SHUTDOWN_DELAY_MINUTES
) from a central REST API endpoint. This is perfect for managing multiple client machines from a single location. - Configurable Delay: Set a grace period (in minutes) before shutdown, giving short power outages a chance to resolve.
- Smart Cancellation: Automatically cancels the pending shutdown if mains power is restored.
- Resilient Fallback: If the central API hub is unreachable, the script automatically falls back to using its last known good configuration from the local
ups.env
file, ensuring uninterrupted protection. - Universal Compatibility: Works on virtually any Linux-based system with Bash, curl and jq (Synology DSM, Proxmox, Debian, Ubuntu, etc.).
- Lightweight & Stateless: Has minimal dependencies and uses a simple flag file for state management, requiring no complex daemons.
- Easy to Configure: All settings are managed in a simple, external
ups.env
file for standalone mode, with an override for hub mode. - Automated Updates: Includes an optional update script to pull the latest version from the official repository.
- Active Status Reporting: In Hub Mode, the script reports its status (
online
,shutdown_pending
) back to theUPS_Server_Docker
API on every run. This provides a live, accurate view of the client's health in the central dashboard.
This project is the perfect companion to the UPS_Server_Docker application. The new Hub Mode feature is specifically designed to work with the REST API provided by UPS_Server_Docker
.
The script's logic runs every minute and follows these steps:
- Load Configuration: The script requires
API_SERVER_URI
andAPI_TOKEN
to be defined inups.env
. It attempts to fetch its configuration from the central API. If successful, it uses the fetched settings and caches them back toups.env
. If the API is unreachable, the script falls back to the local configuration in theups.env
file. - Check UPS Status: The script queries the
/upsc
API endpoint to get the UPS status from the configured UPS server. - Detect Low Battery: If the status is
OB LB
(On Battery, Low Battery), the script checks for the existence of a flag file (/tmp/ups_shutdown_pending.flag
).- If the flag doesn't exist, it's the first sign of trouble. The script writes the current timestamp into the flag file and logs that the countdown has begun.
- If the flag exists, the script calculates the time elapsed since the timestamp in the file. If the elapsed time exceeds the configured delay, it executes
shutdown -h now
.
- Detect Power Restoration: If the status is
OL
(On Line) and the flag file exists, the script knows a shutdown was pending. It logs the cancellation and simply deletes the flag file, effectively resetting the state.
Follow these steps to set up the monitor on a new system.
Ensure the following packages are installed on your system:
bash
(usually installed by default)cron
or another task schedulercurl
(for hub mode and the update script)jq
(required for hub mode to parse API responses)- a configured UPS Server with REST API (see: UPS_Server_Docker)
git
for cloning the project from GitHub
First, place the script files in a persistent location on your server.
For most Linux systems (Proxmox, Debian, etc.), a good choice is /opt/ups-monitor
:
# Example using git
git clone https://github.com/MarekWo/UPS_monitor.git /opt/ups-monitor
cd /opt/ups-monitor
For Synology DSM Users:
The Synology operating system does not have an /opt
directory. The best practice is to place scripts on a data volume to ensure they survive system updates. The recommended location is a dedicated scripts
folder on volume1
.
# Create the directory on your data volume
sudo mkdir -p /volume1/scripts/ups-monitor
# Clone the repository into the new directory
git clone https://github.com/MarekWo/UPS_monitor.git /volume1/scripts/ups-monitor
cd /volume1/scripts/ups-monitor
Create your local configuration file by copying the provided example. This file will be ignored by git, so your settings are safe.
cp ups.env.example ups.env
Now, edit the newly created ups.env
with your specific settings:
# ups.env
# --- Required API Configuration ---
# This feature is designed to work with the UPS_Server_Docker project.
# The address of your central UPS Hub API server.
API_SERVER_URI="http://<UPS_SERVER_IP>:5000"
# The secret token to authenticate with the API Hub.
# The API_TOKEN value MUST exactly match the API_TOKEN set in the server's power_manager.conf file.
API_TOKEN="your_secret_api_token_here"
# --- Fallback Configuration ---
# Used if the API Hub is unreachable or does not provide configuration.
# The delay in minutes before shutdown after a low battery is detected.
SHUTDOWN_DELAY_MINUTES=5
Make the main script and the update script executable.
chmod +x ups_monitor.sh
chmod +x update.sh
The script needs to run every minute to be effective. You must schedule it to run as the root
user, as the shutdown
command requires root privileges.
For most Linux systems: Open the root user's crontab for editing:
sudo crontab -e
Add the following line, making sure the path is correct for your installation, then save and exit:
# Run the UPS monitor script every minute
* * * * * /opt/ups-monitor/ups_monitor.sh
For Synology DSM Users:
- Go to
Control Panel
>Task Scheduler
. - Click
Create
>Scheduled Task
>User-defined script
. - In the General tab:
- Task:
UPS Monitor
- User:
root
- Task:
- In the Schedule tab:
- Run on the following days:
Daily
- Frequency:
Every 1 minute
- Run on the following days:
- In the Task Settings tab, enter the full path to the script in the
Run command
box:bash /volume1/scripts/ups-monitor/ups_monitor.sh
- Click
OK
to save the task.
To update the script to the latest version from your repository, simply run the update.sh
script.
# Navigate to your script directory and run the updater
# (e.g., /opt/ups-monitor or /volume1/scripts/ups-monitor)
cd /path/to/your/script/directory
./update.sh
You can also automate this by adding a second cron job (or another Task Scheduler entry on Synology) to run the updater daily, for example, at 3:00 AM.
After setup, you can test the script's functionality:
- Run it manually: Execute
/path/to/your/script/ups_monitor.sh
and check for any errors. - Check the logs:
- For systemd-based systems (Debian, Proxmox):
journalctl -f | grep UPS_Shutdown_Script
- For Synology DSM: Open the
Log Center
application or check the log file directly withtail -f /var/log/messages | grep UPS_Shutdown_Script
- For systemd-based systems (Debian, Proxmox):
- Simulate a power failure: Change the state of your (dummy) NUT server to
OB LB
and watch the logs. The script should log that the countdown has started. - Simulate power restoration: Before the delay is over, change the NUT server state back to
OL
. The script should log that the shutdown has been cancelled.
This is a community-driven project. If you have an idea for an improvement or find a bug, please feel free to fork the repository, make your changes, and submit a pull request. You can also open an issue to start a discussion.
IMPORTANT: Starting with version 4.3.0, this project has undergone significant changes to improve reliability and simplify deployment.
- API-Only Operation: The Linux script now exclusively uses REST API calls instead of the
upsc
command - Mandatory API Configuration:
API_SERVER_URI
andAPI_TOKEN
are now required inups.env
- No More NUT Client Dependency: The
nut-client
package is no longer required on client machines
-
Run the update.sh script:
# Navigate to your script directory and run the updater cd /path/to/your/script/directory # for example /opt/ups-monitor ./update.sh
-
Update Your Configuration File:
# Add these required fields to your ups.env file: API_SERVER_URI="http://your-ups-server:5000" API_TOKEN="your_api_token_here"
-
Remove NUT Client (Optional):
# On Debian/Ubuntu systems: sudo apt remove nut-client # On other systems, consult your package manager documentation
-
Test the New Version: Run the script manually to ensure it connects to your UPS server API:
./ups_monitor.sh
-
Verify Logs: Check your system logs to confirm the script is working correctly with API calls.
- β Simplified Installation: No need to install and configure NUT client tools
- β Better Error Handling: More detailed error messages for API connectivity issues
- β Unified Approach: Linux and Windows versions now use identical logic
- β
Reduced Dependencies: Only requires
curl
andjq
(already needed for Hub Mode)
This project is licensed under the MIT License. See the LICENSE file for details.