Skip to content

stvorl/pupsmon

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

About

Monitor power outages on Linux by pinging a mains-powered device - triggers graceful shutdown when mains fails. Works with any UPS, no driver required.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages