stvorl/pupsmon
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
pupsmon - Pseudo-UPS Monitor for Linux
=======================================
Overview
--------
pupsmon is a lightweight daemon that provides UPS-like power loss detection
without requiring a UPS with a USB/serial interface or vendor driver support.
The idea is simple: place a small always-on device (e.g. an old router or
switch) on direct mains power - not through the UPS. The monitored system
(which IS on UPS) periodically pings that device. When it stops responding,
mains power is assumed lost, and a configurable handler is executed
(e.g. a graceful shutdown).
This approach is useful when:
- You have a UPS with no supported communication interface
- You are running an embedded system, mini-PC, NAS, or Raspberry Pi
- You want zero-dependency power loss detection using only standard tools
Important limitation: unlike NUT/apcupsd, pupsmon has no control over the UPS
itself. It cannot instruct the UPS to do delayed cut of output power and
auto-restart when mains returns. After a shutdown, your system will stay off
until someone powers it on manually. Make sure you have a plan for that before deploying
(for example, IPMI unit or external iKVM)
How It Works
------------
1. pupsmon pings a designated "indicator host" on your LAN at a fixed interval.
2. If the host fails to respond for 'fail_threshold' consecutive checks,
power loss is declared and the handler command is executed.
3. If the host becomes reachable again for 'recover_threshold' consecutive
checks, a recovery is logged.
4. After the handler runs, pupsmon waits 300 seconds, then resets its state.
This allows a subsequent outage to be detected if the system is still
running - for example, when the handler sends a notification rather than
triggering a poweroff. If the system does shut down during those 300 seconds,
the wait is simply interrupted. A handler that fails to shut down the system
is an abnormal situation outside the scope of this script.
Requirements
------------
- bash
- ping (standard on all Linux systems)
- crudini (INI file parser - install with: apt install crudini)
Installation
------------
1. Clone the repository into /opt/pupsmon (recommended):
git clone <repo-url> /opt/pupsmon
cd /opt/pupsmon
2. Run the installer as root:
sudo ./install.sh
The installer will:
- Check for the crudini dependency
- Generate pupsmon.service from the template with the correct path
- Create a symlink in /etc/systemd/system/
- Copy pupsmon-example.ini to pupsmon.ini (if not already present)
- Set pupsmon.ini permissions to root:root 600
- Enable the systemd service
3. Edit the configuration file:
sudo nano /opt/pupsmon/pupsmon.ini
4. Start the service:
sudo systemctl start pupsmon
5. Check the logs:
journalctl -t pupsmon -f
Configuration (pupsmon.ini)
---------------------------
All settings are in the [general] section.
monitor_host IP address or hostname of the mains-powered indicator device.
This host must NOT be on UPS - it should lose power when
mains power fails.
IMPORTANT: set this before starting the service or do reboot.
The default value in pupsmon-example.ini (192.168.1.250) is a placeholder.
If that address happens to be unreachable on your network,
the handler will trigger in time and may shut the system down.
ping_count Number of ICMP requests per check. Usually 1 is sufficient.
interval Seconds between checks. Recommended range: 10–30.
fail_threshold Consecutive failed checks before triggering the handler.
Total detection time = fail_threshold x interval seconds.
Example: 12 x 10 = 120 seconds.
recover_threshold Consecutive successful checks required to log a recovery.
Example: 2 x 10 = 20 seconds of stable responses.
logging_tag Syslog tag for log entries. Filter with: journalctl -t <tag>
handler Command executed on power loss. Can be:
- Path to an executable script: /usr/local/bin/on_power_loss.sh
- Inline shell command:
bash -c '/opt/notify.sh && sleep 5 && poweroff'
- Simple command: poweroff
Removal
-------
To stop and uninstall the service (configuration is preserved):
sudo ./remove.sh
Security Notes
--------------
- pupsmon.ini is set to root:root 600 by the installer. Only root can read
or modify it. This matters because the handler field is executed as root.
- The handler is invoked via bash -c, not eval, to reduce injection risk.
- The service runs as root (required for poweroff and similar commands).
For notification-only use cases, consider adding a dedicated user.
Project Structure
-----------------
pupsmon.sh Main monitoring script
pupsmon-example.ini Annotated configuration template
pupsmon-template.service systemd unit template (@INSTALL_DIR@ is substituted
during install)
install.sh Installation script
remove.sh Removal script
License
-------
MIT