I ordered a second UPS because thanks to PeaNUT, I saw that my current UPS is only providing 20 minutes of uptime. Unfortunately, as of this post, PeaNUT will only read one UPS’ metrics from Network UPS Tools per PeaNUT instance, so I’m going to start scraping the metrics into Prometheus and displaying them with Grafana. Here’s how I did it.

Prerequisites

Setup

Configure the NUT exporter for Prometheus

I decided to use the hon95/prometheus-nut-exporter container to proxy metrics from NUT to Prometheus.

Here’s a docker-compose.yaml file for starting nut-upsd and the prometheus nut exporter. For simplicity, I’m not including how to make it accessible via https. If you do want to secure the exporter with SSL, I documented how to use nginx-proxy-manager as an SSL reverse proxy here.

version: '3.9'
services:
  # Details on nuts-upsd configuration are at https://unixorn.github.io/post/homelab/homelab-nut-upsd
  nut-upsd:
    image: instantlinux/nut-upsd
    container_name: nut
    environment:
      - API_PASSWORD=${API_PASSWORD:-'aPasswordForAPIaccess'}
      - TZ=${TZ:-America/Denver}
      # Driver found with this tool https://networkupstools.org/stable-hcl.html
      - DRIVER=usbhid-ups
    devices:
      # Device numbers are subject to change, so map in the whole bus so nuts-upsd can find your UPS
      - /dev/bus/usb:/dev/bus/usb
    ports:
      - "3493:3493"
    restart: unless-stopped

  prometheus-nut-exporter:
    image: hon95/prometheus-nut-exporter:stable
    container_name: prometheus-nut-exporter
    environment:
      - HTTP_PATH=/nut
      - TZ=${TZ:-America/Denver}
      # Defaults
      #- RUST_LOG=info
      #- HTTP_PORT=9995
      #- HTTP_PATH=/nut
      #- LOG_REQUESTS_CONSOLE=false
      #- PRINT_METRICS_AND_EXIT=false
    ports:
      - "9995:9995"
    # Don't start until nut-upsd is running so we don't serve garbage data
    # to prometheus when it scrapes us
    depends_on:
      - nut-upsd
    restart: unless-stopped

Run docker-compose up -d and you should be able to go to http://yourserver.example.com:9995/nut?target=nut-upsd:3493 and see output similar to this:

# TYPE nut_exporter_info info
# UNIT nut_exporter_info
# HELP nut_exporter_info Metadata about the exporter.
nut_exporter_info{version="1.2.1"} 1
# TYPE nut_server_info info
# UNIT nut_server_info
# HELP nut_server_info Metadata about the NUT server.
nut_server_info{version="2.8.1"} 1
# TYPE nut_ups_info info
# UNIT nut_ups_info
# HELP nut_ups_info Metadata about the UPS.
nut_ups_info{ups="ups",description="UPS",device_type="ups",manufacturer="CPS",model="CP800AVRa",battery_type="PbAcid",driver="usbhid-ups",driver_version="2.8.1",driver_version_internal="0.52",driver_version_data="CyberPower HID 0.8",usb_vendor_id="0764",usb_product_id="0501",type="ups",nut_version="2.8.1"} 1
# TYPE nut_info info
# A lot more information snipped for brevity

The example URL assumes you’re running nut-upsd out of the same docker-compose.yaml file you’re using to run the exporter. If not, replace nut-upsd in the link with an ip or dns name so it looks like http://yourserver.example.com:9995/nut?target=nut-upsd.example.com:3493

Add NUT scrape configuration to Prometheus

Here’s the nut scrape job I’m using, with my hostnames stripped. More detailed configuration instructions available at github.com/hon95/prometheus-nut-exporter site.

global:
    scrape_interval: 15s
    scrape_timeout: 10s

scrape_configs:
  - job_name: "nut"
    scrape_interval: 30s
    static_configs:
      # Insert NUT server address here
      - targets: ["nut-upsd:3493"]
    metrics_path: /nut
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        # Insert NUT exporter address here
        replacement: your.exporter.server.example.com:9995

Add a nut dashboard to Grafana

Finally, add a dashboard to your grafana instance to display your nut metrics. I’m using the one here - the ID is 14371 if you want to directly import it to grafana.

Here’s what the resulting dashboard looks like in Grafana for one of my UPSes.

nut-grafana-dashboard