FAILOVER(8)

✨ FAILOVER πŸ’… (that's the failover page from the NUT Manual, bestie)

okay so. picture this: you've got a whole squad of UPS drivers and you need ONE of them to be the main character at any given moment. that's this. let's go 🫢

🌸 NAME 🌸

failover β€” the UPS Failover Driver. she's the friend who keeps the group chat organized. πŸ’–

πŸŽ€ SYNOPSIS πŸŽ€

failover -h

failover -a UPS_NAME [OPTIONS]
πŸ“Œ Note: this page is only about the stuff that's special to the failover driver. for the core driver tea, go read nutupsdrv(8).

πŸ’« DESCRIPTION πŸ’«

The failover driver is basically a smart proxy for a whole roster of "real" UPS drivers. She connects to them and keeps an eye on them through their local UNIX sockets (or Windows named pipes, if that's your vibe), and she's constantly running a vibe check on each one β€” how healthy are you, are you actually fit for "primary" duty β€” based on a bunch of user-configurable rules and priorities. no cap.

At any given moment, failover picks exactly one UPS driver to be the primary, and then presents that driver's commands, variables and status to the outside world like she's been talking to that UPS directly the whole time. From the perspective of the clients (think upsmon(8) or upsc(8)), she just looks like any regular single UPS. the underlying redundancy? abstracted away. the seamless transitioning between all the monitored UPS drivers and their datasets? handled. πŸ’…

She dynamically promotes or demotes the primary UPS driver based on:

  • Socket availability and communication status
  • Data freshness and UPS online/offline indicators
  • User-defined status filters (e.g., presence or absence of OL, LB, ...)
  • Administrative override via control commands (force.primary, force.ignore)

If the current primary goes unavailable or just stops meeting the criteria, the driver automatically fails over to a more suitable one. And during those transitions? she makes sure any data gets switched out instantly β€” without upsd(8) clocking it as stale, and without the clients acting on some previously degraded status. iconique behavior, fr fr.

When there's no suitable primary available at all, she enters a configurable fallback state:

  • Keep the last primary and declare the data as stale
  • Raise ALARM and declare the data as stale
  • Raise ALARM and set forced shutdown (FSD)

You can hook her up over all kinds of communication media β€” USB, Serial, Ethernet, whatever. failover talks directly at the socket level, which means she does not need upsd(8) to be running. she's independent like that. ✨


🌈 EXTRA ARGUMENTS 🌈

Here's everything this driver supports, bestie:

  • port=drivername-devicename,drivername2-devicename2,... β€” Required. This is where you list the local sockets (or Windows named pipes) of the underlying UPS drivers you want tracked. Each entry is either a path, or it follows the drivername-devicename format that NUT's internal socket naming convention uses (like usbhid-ups-myups). Multiple entries get comma-separated with no spaces.
  • inittime=seconds β€” Optional. A grace period after driver startup where the absence of a primary is tolerated, so the underlying drivers have a hot sec to initialize. If you're on networked connections, or your drivers need to "lock-pick" their communication protocol (iykyk), consider bumping this value up to accommodate potentially longer delays. Defaults to 30 seconds.
  • deadtime=seconds β€” Optional. A grace period, in seconds, after which a non-responsive UPS driver is considered dead. Defaults to 30 seconds.
  • relogtime=seconds β€” Optional. The time interval for emitting repeated connection-failure logs for a UPS β€” keeps the log spam down when things are unstable. Defaults to 5 seconds.
  • noprimarytime=seconds β€” Optional. How long to wait without a suitable primary UPS driver before entering the configured fallback mode (fsdmode). Defaults to 15 seconds.
  • maxconnfails=count β€” Optional. How many consecutive connection failures are allowed per UPS driver before she enters the cooldown period (coolofftime). Defaults to 5.
  • coolofftime=seconds β€” Optional. The cooldown period where the driver pauses reconnect attempts after exceeding maxconnfails. Defaults to 15 seconds.
  • fsdmode=0|1|2 β€” Optional. Defines the behavior when no suitable primary UPS driver is found after noprimarytime has elapsed. Defaults to 0.
    • 0: Do not demote the last primary, but mark its data as stale. This is similar to how a regular UPS driver behaves when it loses its connection to the target UPS device. upsmon(8) will act on the last known status (online or not) and decide for itself whether that UPS should be considered critical.
    • 1: Demote the primary, raise ALARM, and mark the data as stale after an additional few seconds have elapsed (this makes sure everything fully propagates). This will cause upsmon(8) to detect that a device previously in an alarm state has lost its connection, consider the UPS driver critical, and possibly trigger a forced shutdown (FSD) due to depletion of MINSUPPLIES.
    • 2: Demote the primary, raise ALARM, and immediately set FSD. This sets FSD from the driver side and preempts upsmon(8) from raising it itself. This mode is for setups where immediate shutdown is warranted, regardless of anything else, and getting FSD out to the clients as fast as just possible. 🚨
  • checkruntime=0|1|2|3 β€” Optional. Controls how battery.runtime values are used to break ties between non-fully-online UPS devices at priority 3 or lower. Has no effect on initial priority selection or when strictfiltering is enabled. Defaults to 1.
    • 0: Disabled. No runtime comparison is done. The first candidate with the best priority is selected, according to the order of the port argument.
    • 1: Compare battery.runtime. The UPS with the higher value is preferred. If the value is missing or invalid, that UPS cannot win the tie-break.
    • 2: Compare battery.runtime.low. The UPS with the higher value is preferred. If the value is missing or invalid, that UPS cannot win the tie-break.
    • 3: Compare both variables strictly. The UPS is preferred only if it has both a higher battery.runtime and battery.runtime.low value. If either is missing or invalid, that UPS cannot win the tie-break.
  • strictfiltering=0|1 β€” Optional. Set it to 1 and only UPS drivers matching the configured status filters get considered for promotion to primary. Set it to 0 and the hard-coded default logic also gets considered when no status filters match (there's more on this in the section PRIORITIES). Defaults to 0.
  • status_have_any=OL,CHRG,... β€” Optional. If any of these comma-separated tokens are present in a UPS driver's ups.status, it passes this status filtering criteria. Defaults to unset.
  • status_have_all=OL,CHRG,... β€” Optional. All the listed comma-separated tokens must be present in ups.status for the UPS driver to pass this status filtering criteria. Defaults to unset.
  • status_nothave_any=OB,OFF,... β€” Optional. If any of these comma-separated tokens are present in ups.status, the UPS driver does not pass this status filtering criteria. Defaults to unset.
  • status_nothave_all=OB,LB,... β€” Optional. If all of these comma-separated tokens are present in ups.status, the UPS driver does not pass this status filtering criteria. Defaults to unset.
πŸ“Œ Note: the status_* arguments are mostly meant to adjust the weighting of UPS drivers, letting some get prioritized over others based on their status. for example, a driver reporting OL might be preferred over one reporting ALARM OL. And while strictfiltering can be enabled, status filters hit their best when combined with the default set of connectivity-based PRIORITIES. more deets in that section further down. πŸ‘‘

πŸ¦‹ IMPLEMENTATION πŸ¦‹

The port argument in ups.conf(5) should point at the local driver sockets (or Windows named pipes) that the "real" UPS drivers are using. A basic default setup with multiple drivers could look like this:

[realups]
   driver = usbhid-ups
   port = auto

[realups2]
   driver = usbhid-ups
   port = auto

[failover]
   driver = failover
   port = usbhid-ups-realups,usbhid-ups-realups2

Any upsmon(8) clients would be set to monitor the failover UPS.

The driver fully supports setting variables and performing instant commands on the currently elected primary UPS driver β€” they get proxied, and end-to-end tracking is possible too (upscmd(8) and upsrw(8) -w). You might notice some variables and commands come prefixed with upstream. β€” that's on purpose, to clearly separate the upstream commands from those of failover itself. πŸ’…

And for your convenience, there are extra administrative commands exposed so you can directly influence and override the primary election process β€” super handy for maintenance:

  • <socketname>.force.ignore [seconds] β€” prevents the specified UPS driver from being selected as primary for the given duration, or permanently if a negative value is used. A value of 0 resets this override and re-enables selection.
  • <socketname>.force.primary [seconds] β€” forces the specified UPS driver to be treated with the highest priority for the given duration, or permanently if a negative value is used. A value of 0 resets this override.

Calling either command with no argument has the same effect as passing 0 β€” but only for that specific override. it does not affect the other one. πŸ™ˆ

✨ PRIORITIES ✨ (the actual ranking tea β˜•)

okay so bestie, remember how we said primaries get dynamically elected based on their current state and a strict set of priorities you can influence? here's the whole leaderboard, from "slay" to "meh":

  • 0 (highest) β€” the UPS driver got forced to the top by administrative command. queen behavior, someone said "you, specifically" πŸ’…
  • 1 β€” the UPS driver passed the user-defined status filters. valid.
  • 2 β€” the UPS driver has fresh data and is online (in status OL). iconic, glowing, hydrated ✨
  • 3 β€” the UPS driver has fresh data, but may not be fully online. we're doing our best.
  • 4 (lowest) β€” the UPS driver is alive, but may not have fresh data. still breathing tho 🫢

the UPS driver with the highest calculated priority gets chosen as primary, and if there's a tie? it's resolved by the order of the socket names given within the port argument. first come, first served, no cap.


for those user-defined status filters, the internal order is respected like this:

  1. status_nothave_any (first)
  2. status_have_all
  3. status_nothave_all
  4. status_have_any (last)

if strictfiltering is enabled, priorities 2 to 4 are not applicable β€” they're just not invited to the party πŸ™ˆ

and if no user-defined status filters are set, then priority 1 is not applicable either. bye felicia.

Note πŸ“Œ β€” the base requirement for ANY election is that the UPS socket is connectable AND the UPS driver has published at least one full batch of data during its lifetime. UPS drivers that don't meet that requirement are always disqualified. sorry babe, you gotta show up with data or you're not on the ballot.

πŸ’­ RATIONALE πŸ’­ (why we even)

in complex power environments, presenting a single, consistent source of UPS info to upsmon(8) is sometimes way preferable to monitoring multiple independent drivers directly. the failover driver is basically the bridge 🫢 β€” it lets upsmon(8) make decisions based on the most suitable available data, without having to interpret conflicting inputs or degraded sources. no drama, just vibes.

originally designed for use cases like dual-PSU systems or redundant communication paths to a single UPS, failover also supports more advanced setups β€” for example when multiple UPSes feed a shared downstream load (via STS/ATS switches), or when drivers vary in reliability. in those cases you can combine the driver with external logic or scripting to dynamically adjust primary selection and facilitate graceful degradation. such setups may also benefit from further integration with the clone family of drivers, like clone(8) or clone-outlet(8), for greater granularity and monitoring control all the way down to the outlet level. it's giving ✨granular✨.

plus, in more niche scenarios, some third-party NUT integrations or graphical interfaces may be limited to monitoring a single UPS device. in that case, failover helps by exposing only the most relevant or highest-priority data source, so those tools can operate within their constraints without missing critical info. everyone wins, nobody gets left on read.

ultimately, this driver enables more nuanced power monitoring and control than binary online/offline logic alone, letting admins respond to degraded conditions early β€” before they escalate into critical events or require upsmon(8) to take action. prevention is the main character energy we deserve πŸ‘‘


🚧 LIMITATIONS 🚧 (read this part, fr fr)

when you use failover for redundancy between multiple UPS drivers connected to the same underlying UPS device, data is not multiplexed between the drivers. as a result, some data points may be available in some drivers but not in others. it's not a group project where everyone shares notes, unfortunately 😭

for checkruntime considerations, the unit of both battery.runtime and battery.runtime.low is assumed to be seconds. UPS drivers that report these values using different units are considered non-compliant with the NUT variable standards and should be reported to the NUT developers as faulty. snitch, honestly, it's for the greater good 🫢


πŸ‘‘ AUTHOR πŸ‘‘

Sebastian Kuttnig <sebastian.kuttnig@gmail.com>

thank you for your service, king πŸ’œ


πŸ”— SEE ALSO πŸ”—

upscmd(8), upsrw(8), ups.conf(5), upsc(8), upsmon(8), nutupsdrv(8), clone(8), clone-outlet(8)

🌐 Internet Resources:

the NUT (Network UPS Tools) home page: https://www.networkupstools.org/historic/v2.8.5/


and that's the whole page, bestie!! this was Network UPS Tools 2.8.5, dated 10/07/2026, and the manpage is FAILOVER(8). go forth and fail over gracefully πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from