Skip to content

Instantly share code, notes, and snippets.

@gcochard
Last active August 18, 2022 22:19
Show Gist options
  • Save gcochard/78f1aed9c5d3bfb5ef50ea0fdd326bf3 to your computer and use it in GitHub Desktop.
Save gcochard/78f1aed9c5d3bfb5ef50ea0fdd326bf3 to your computer and use it in GitHub Desktop.
prometheus node_exporter and NUT setup raspi-os
#!/bin/bash
set -euo pipefail
# first elevate to root
if [[ $EUID != 0 ]]; then
sudo "$0" "$@"
exit $?
fi
mkdir -p /etc/systemd/system/systemd-udevd.service.d
tee /etc/systemd/system/systemd-udevd.service.d/mountflags.conf <<EOF
[Service]
PrivateMounts=no
EOF
mkdir -p /var/run/usbmount
ln -s /media/usb0 /var/run/usbmount/WD_easystore_25FB_1
#!/bin/bash
set -euo pipefail
# first elevate to root
if [[ $EUID != 0 ]]; then
sudo "$0" "$@"
exit $?
fi
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
#!/bin/bash
# first elevate to root
if [[ $EUID != 0 ]]; then
sudo "$0" "$@"
exit $?
fi
arch=$(uname -m)
version=$(curl -I https://github.com/prometheus/node_exporter/releases/latest -s | egrep ^location | awk -F'v' '{ print $NF}' | tr -d "\r\n")
target=$(
case $arch in
("aarch64") echo "arm64" ;;
("armv8") echo "armv7" ;;
("armv7l") echo "armv7" ;;
("armv6l") echo "armv6" ;;
(*) echo $arch ;;
esac)
wget https://github.com/prometheus/node_exporter/releases/download/v${version}/node_exporter-${version}.linux-${target}.tar.gz
tar xzvf node_exporter-${version}.linux-${target}.tar.gz
useradd -rs /bin/false node_exporter
mv node_exporter-${version}.linux-${target}/node_exporter /usr/local/bin/
rm -rf node_exporter-${version}.linux-${target}/
tee /etc/systemd/system/node_exporter.service <<EOF
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl start node_exporter
systemctl enable node_exporter
#!/bin/bash
set -euo pipefail
# first elevate to root
if [[ $EUID != 0 ]]; then
sudo "$0" "$@"
exit $?
fi
apt -y install nut nut-cgi fcgiwrap msmtp
tee /etc/nut/hosts.conf <<EOF
# Network UPS Tools: example hosts.conf
#
# This file is used to control the CGI programs. If you have not
# installed them, you may safely ignore or delete this file.
#
# -----------------------------------------------------------------------
#
# upsstats will use the list of MONITOR entries when displaying the
# default template (upsstats.html). The "FOREACHUPS" directive in the
# template will use this file to find systems running upsd.
#
# upsstats and upsimage also use this file to determine if a host may be
# monitored. This keeps evil people from using your system to annoy
# others with unintended queries.
#
# upsset presents a list of systems that may be viewed and controlled
# using this file.
#
# -----------------------------------------------------------------------
#
# Usage: list systems running upsd that you want to monitor
#
# MONITOR <system> "<host description>"
MONITOR cyberpower@closetpi.lan "Closetpi - CyberPower SL750U LV Cabinet"
MONITOR CP685AVR@mediapi.lan "Mediapi - CP685AVR"
EOF
tee /etc/nut/notifycmd.sh <<'EOF'
#!/bin/bash
EMAIL='greg.cochard@gmail.com'
printf "Subject: NUT ALERT\nFrom: nut@cochard.io\nTo: $EMAIL\n\nUPS: $UPSNAME\r\nAlert Type: $NOTIFYTYPE" | msmtp $EMAIL
EOF
chmod +x /etc/nut/notifycmd.sh
tee /etc/nut/nut.conf <<EOF
MODE=standalone
EOF
tee /etc/nut/ups.conf <<EOF
# Set maxretry to 3 by default, this should mitigate race with slow devices:
maxretry = 3
[CP685AVR]
driver = usbhid-ups
port = auto
vendorid = 0764
pollinterval = 15
EOF
tee /etc/nut/upsd.conf <<EOF
MAXAGE 25
LISTEN 0.0.0.0 3493
EOF
tee /etc/nut/upsd.users <<EOF
[admin]
password = admin
action = SET
instcmds = ALL
upsmon master
EOF
tee /etc/nut/upsmon.conf <<EOF
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
POLLFREQ 5
POLLFREQALERT 5
HOSTSYNC 15
DEADTIME 15
POWERDOWNFLAG /etc/killpower
RBWARNTIME 43200
NOCOMMWARNTIME 300
FINALDELAY 5
MONITOR CP685AVR@localhost 1 admin admin master
NOTIFYCMD /etc/nut/notifycmd.sh
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC
NOTIFYFLAG FSD SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK SYSLOG+WALL+EXEC
NOTIFYFLAG COMMBAD SYSLOG+WALL+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT SYSLOG+WALL+EXEC
NOTIFYFLAG NOCOMM SYSLOG+WALL+EXEC
NOTIFYFLAG NOPARENT SYSLOG+WALL+EXEC
DEADTIME 25
EOF
tee /etc/nut/upssched.conf <<EOF
CMDSCRIPT /bin/upssched-cmd
EOF
tee /etc/nut/upsset.conf <<EOF
I_HAVE_SECURED_MY_CGI_DIRECTORY
EOF
tee /etc/nut/upsstats-single.html <<'EOF'
<!-- upsstats template file -->
<!--
This is upsstats-single.html, a template for monitoring a single
host. This mode is selected by adding "host=<host>" to the
upsstats.cgi URL.
Such URLs are generated automatically when using the HOSTLINK
command.
See upsstats.html(5) for more information on template files.
-->
<!-- change this to TEMPF if you don't like Celsius. -->
@TEMPC@
@UPSSTATSPATH upsstats.cgi@
@UPSIMAGEPATH upsimage.cgi@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
@REFRESH@
<title>@HOSTDESC@ : @VAR ups.model@ on @HOST@</title>
<!-- LINK REL="stylesheet" TYPE="text/css" HREF="http://localhost/nut/nut.css" / -->
</head>
<body BGCOLOR="#808080" TEXT="#00FC00" LINK="#0000EE" VLINK="#551A8B">
<table BORDER="1" ALIGN="CENTER" CELLSPACING="0" CELLPADDING="10" BGCOLOR="#000000">
<tr>
<th COLSPAN="20">Network UPS Tools upsstats @VERSION@ - @HOSTDESC@ - @VAR ups.model@ on @HOST@</th>
</tr>
<tr>
<th>@DATE %a %b %d %X %Z %Y@</th>
@IFSUPP ambient.temperature@
<th>Ambient</th>
@ELSE@
@IFSUPP ambient.humidity@
<th>Ambient</th>
@ENDIF@
<th>Battery</th>
<th>Input</th>
<th>Output</th>
<th>Load</th>
</tr>
<tr>
<td BGCOLOR="#000000" VALIGN="TOP">
<table BORDER="0"> <!-- table 2 -->
<tr>
<th ALIGN="RIGHT">UPS Model:</th>
<td>@VAR ups.model@</td>
</tr>
<tr>
<th ALIGN="RIGHT">Status:</th>
<td>@STATUS@</td>
</tr>
@IFSUPP battery.runtime@
<tr>
<th ALIGN="RIGHT">Runtime:</th>
<td>@RUNTIME@</td>
</tr>
@ENDIF@
@IFSUPP ups.temperature@
<tr>
<th ALIGN="RIGHT">UPS temp:</th>
<td>@UPSTEMP@ @DEGREES@</td>
</tr>
@ENDIF@
@IFSUPP battery.voltage@
<tr>
<th ALIGN="RIGHT">Battery: </th>
<td>@VAR battery.voltage@ V@IFSUPP battery.current@, @VAR battery.current@ A</td>
@ENDIF@
<tr>
<th VALIGN="TOP" ALIGN="RIGHT">Input: </th>
<td>
@IFSUPP input.L2-L3.voltage@
@VAR input.L1-L2.voltage@ V<br>
@VAR input.L2-L3.voltage@ V<br>
@VAR input.L3-L1.voltage@ V<br>
</td>
</tr>
@ELSE@
@IFSUPP input.L2-N.voltage@
@VAR input.L1-N.voltage@ V<br>
@VAR input.L2-N.voltage@ V<br>
@VAR input.L3-N.voltage@ V<br>
</td>
</tr>
@ELSE@
@IFSUPP input.voltage@
@VAR input.voltage@ V<br>
</td>
</tr>
@ENDIF@
@IFSUPP input.L2.current@
<tr>
<th>
<td>
@VAR input.L1.current@ A<br>
@VAR input.L2.current@ A<br>
@VAR input.L3.current@ A<br>
</td>
</tr>
@ELSE@
@IFSUPP input.current@
<tr>
<th>
<td>
@VAR input.current@ A
</td>
</tr>
@ENDIF@
@IFSUPP input.frequency@
<tr>
<th>
<td>
@VAR input.frequency@ Hz
</td>
</tr>
@ENDIF@
<tr>
<th VALIGN="TOP" ALIGN="RIGHT">Output: </th>
<td>
@IFSUPP output.L2-L3.voltage@
@VAR output.L1-L2.voltage@ V<br>
@VAR output.L2-L3.voltage@ V<br>
@VAR output.L3-L1.voltage@ V<br>
</td>
</tr>
@ELSE@
@IFSUPP output.L2-N.voltage@
@VAR output.L1-N.voltage@ V<br>
@VAR output.L2-N.voltage@ V<br>
@VAR output.L3-N.voltage@ V<br>
</td>
</tr>
@ELSE@
@IFSUPP output.voltage@
@VAR output.voltage@ V
</td>
</tr>
@ENDIF@
@IFSUPP output.L2.current@
<tr>
<th>
<td>
@VAR output.L1.current@ A<br>
@VAR output.L2.current@ A<br>
@VAR output.L3.current@ A<br>
</td>
</tr>
@ELSE@
@IFSUPP output.current@
<tr>
<th>
<td>
@VAR output.current@ A
</td>
</tr>
@ENDIF@
@IFSUPP output.frequency@
<tr>
<th>
<td>
@VAR output.frequency@ Hz
</td>
</tr>
@ENDIF@
</table> <!-- table 2 -->
</td>
@IFSUPP ambient.temperature@
@IFSUPP ambient.humidity@
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
<td ALIGN="CENTER">Temperature<br>@IMG ambient.temperature tempmin=0 tempmax=50 width=90@</td>
<td ALIGN="CENTER">Humidity<br>@IMG ambient.humidity width=90@</td>
</tr></table>
</td>
@ELSE@
@IFSUPP ambient.temperature@
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
<td ALIGN="CENTER">Temperature<br>@IMG ambient.temperature tempmin=0 tempmax=50@</td>
</tr></table>
</td>
@ELSE@
@IFSUPP ambient.humidity@
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
<td ALIGN="CENTER">Humidity<br>@IMG ambient.humidity@</td>
</tr></table>
</td>
@ENDIF@
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
@IFSUPP battery.charge@
@IFSUPP battery.voltage@
<td ALIGN="CENTER">Charge<br>@IMG battery.charge width=90@</td>
<td ALIGN="CENTER">Voltage<br>@IMG battery.voltage width=90@</td>
@ELSE@
@IFSUPP battery.charge@
<td ALIGN="CENTER">Charge<br>@IMG battery.charge@</td>
@ELSE@
<td ALIGN="CENTER">Voltage<br>@IMG battery.voltage@</td>
@ENDIF@
</tr></table>
</td>
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
@IFSUPP input.L2-L3.voltage@
<td ALIGN="CENTER">L1-L2<br>@IMG input.L1-L2.voltage width=68@</td>
<td ALIGN="CENTER">L2-L3<br>@IMG input.L2-L3.voltage width=68@</td>
<td ALIGN="CENTER">L3-L1<br>@IMG input.L3-L1.voltage width=68@</td>
@ELSE@
@IFSUPP input.L2-N.voltage@
<td ALIGN="CENTER">L1-N<br>@IMG input.L1-N.voltage width=68@</td>
<td ALIGN="CENTER">L2-N<br>@IMG input.L2-N.voltage width=68@</td>
<td ALIGN="CENTER">L3-N<br>@IMG input.L3-N.voltage width=68@</td>
@ELSE@
<td ALIGN="CENTER"><br>@IMG input.voltage@</td>
@ENDIF@
</tr></table>
</td>
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
@IFSUPP output.L2-L3.voltage@
<td ALIGN="CENTER">L1-L2<br>@IMG output.L1-L2.voltage width=68@</td>
<td ALIGN="CENTER">L2-L3<br>@IMG output.L2-L3.voltage width=68@</td>
<td ALIGN="CENTER">L3-L1<br>@IMG output.L3-L1.voltage width=68@</td>
@ELSE@
@IFSUPP output.L2-N.voltage@
<td ALIGN="CENTER">L1-N<br>@IMG output.L1-N.voltage width=68@</td>
<td ALIGN="CENTER">L2-N<br>@IMG output.L2-N.voltage width=68@</td>
<td ALIGN="CENTER">L3-N<br>@IMG output.L3-N.voltage width=68@</td>
@ELSE@
<td ALIGN="CENTER"><br>@IMG output.voltage@</td>
@ENDIF@
</tr></table>
</td>
<td ALIGN="CENTER" VALIGN="TOP" BGCOLOR="#000000">
<table BORDER="0"><tr>
@IFSUPP output.L2.power.percent@
<td ALIGN="CENTER">L1<br>@IMG output.L1.power.percent width=68@</td>
<td ALIGN="CENTER">L2<br>@IMG output.L2.power.percent width=68@</td>
<td ALIGN="CENTER">L3<br>@IMG output.L3.power.percent width=68@</td>
@ELSE@
@IFSUPP output.L2.realpower.percent@
<td ALIGN="CENTER">L1<br>@IMG output.L1.realpower.percent width=68@</td>
<td ALIGN="CENTER">L2<br>@IMG output.L2.realpower.percent width=68@</td>
<td ALIGN="CENTER">L3<br>@IMG output.L3.realpower.percent width=68@</td>
@ELSE@
<td ALIGN="CENTER"><br>@IMG ups.load@</td>
@ENDIF@
</tr></table>
</td>
</tr>
</table>
</body>
</html>
EOF
tee /etc/nut/upsstats.html <<'EOF'
<!-- upsstats template file -->
<!--
This (upsstats.html) is the default template file which is used
when upsstats.cgi is loaded with no arguments.
It usually contains a FOREACHUPS block to iterate through every
UPS in the hosts.conf.
See upsstats.html(5) for more information on template files.
-->
<!-- change this to TEMPF if you don't like Celsius. -->
@TEMPC@
@UPSSTATSPATH upsstats.cgi@
@UPSIMAGEPATH upsimage.cgi@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
@REFRESH@
<title>
Network UPS Tools upsstats
@VERSION@
: UPS Status
</title>
<!-- link rel="stylesheet" type="text/css" href="nut.css" / -->
@REFRESH@
</head>
<body BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000EE" VLINK="#551A8B">
<table BGCOLOR="#50A0A0" ALIGN="CENTER">
<tr><td>
<table CELLPADDING="5">
<tr>
<th COLSPAN="10" BGCOLOR="#60B0B0">
<font SIZE="+2">Network UPS Tools upsstats
@VERSION@
</font>
<br>
@DATE %a %b %d %X %Z %Y@
</th>
</tr>
<tr BGCOLOR="#60B0B0">
<th COLSPAN="1">System</th>
<th COLSPAN="1">Model</th>
<th COLSPAN="1">Status</th>
<th COLSPAN="1">Battery</th>
<th COLSPAN="1">Input (VAC)</th>
<th COLSPAN="1">Output (VAC)</th>
<th COLSPAN="1">Load (%)</th>
<th COLSPAN="1">UPS<br>Temp</th>
<th COLSPAN="1">Battery<br>Runtime</th>
<th COLSPAN="1">Data<br>Tree</th>
</tr>
@FOREACHUPS@
<tr ALIGN=CENTER>
<td BGCOLOR="#00FFFF">
@HOSTLINK@
</td>
<td BGCOLOR="#00FFFF">
@VAR ups.model@
</td>
<td BGCOLOR="@STATUSCOLOR@">
@STATUS@
</td>
<td BGCOLOR="#00FF00">
@IFSUPP battery.charge@
@VAR battery.charge@
%
@ENDIF@
</td>
@IFSUPP input.L2-L3.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L1-L2.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L2-L3.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L3-L1.voltage@
<td BGCOLOR="#00FF00">
@ELSE@
@IFSUPP input.L2-N.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L1-N.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L2-N.voltage@
@IFBETWEEN input.transfer.low input.transfer.high input.L3-N.voltage@
<td BGCOLOR="#00FF00">
@ELSE@
@IFBETWEEN input.transfer.low input.transfer.high input.voltage@
<td BGCOLOR="#00FF00">
@ELSE@
<td BGCOLOR="#FF0000">
@ENDIF@
@IFSUPP input.L2-L3.voltage@
@VAR input.L1-L2.voltage@
@VAR input.L2-L3.voltage@
@VAR input.L3-L1.voltage@
@ELSE@
@IFSUPP input.L2-N.voltage@
@VAR input.L1-N.voltage@
@VAR input.L2-N.voltage@
@VAR input.L3-N.voltage@
@ELSE@
@IFSUPP input.voltage@
@VAR input.voltage@
@ENDIF@
</td>
<td BGCOLOR="#00FF00">
@IFSUPP output.L2-L3.voltage@
@VAR output.L1-L2.voltage@
@VAR output.L2-L3.voltage@
@VAR output.L3-L1.voltage@
@ELSE@
@IFSUPP output.L2-N.voltage@
@VAR output.L1-N.voltage@
@VAR output.L2-N.voltage@
@VAR output.L3-N.voltage@
@ELSE@
@IFSUPP output.voltage@
@VAR output.voltage@
@ENDIF@
</td>
<td BGCOLOR="#00FF00">
@IFSUPP output.L2.power.percent@
@VAR output.L1.power.percent@
@VAR output.L2.power.percent@
@VAR output.L3.power.percent@
@ELSE@
@IFSUPP output.L2.realpower.percent@
@VAR output.L1.realpower.percent@
@VAR output.L2.realpower.percent@
@VAR output.L3.realpower.percent@
@ELSE@
@IFSUPP ups.load@
@VAR ups.load@
%
@ENDIF@
</td>
<td BGCOLOR="#00FF00">
@IFSUPP ups.temperature@
@UPSTEMP@
@DEGREES@
@ELSE@
@IFSUPP battery.temperature@
@BATTTEMP@
@DEGREES@
@ENDIF@
</td>
<td BGCOLOR="#00FF00">
@IFSUPP battery.runtime@
@RUNTIME@
@ENDIF@
</td>
<td BGCOLOR="#00FF00">
@TREELINK@
</td>
</tr>
@ENDFOR@
</table>
</td></tr>
</table>
</body></html>
EOF
tee /etc/nginx/sites-available/nut <<'EOF'
server {
location /nut {
alias /usr/share/nut/www/;
try_files $uri $uri/ /index.html;
}
location /cgi-bin/ {
gzip off;
root /usr/lib;
include fastcgi_params;
fastcgi_pass unix:/var/run/fcgiwrap.socket;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
EOF
tee /etc/msmtprc <<EOF
defaults
auth on
tls on
tls_certcheck on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
acount default
host smtp.gmail.com
protocol smtp
port 587
from nut@cochard.io
user greg@cochard.io
password ********
EOF
chmod 644 /etc/nut/hosts.conf
chmod 644 /etc/nut/*.html
chown www-data:www-data /usr/lib/cgi-bin/nut/*.cgi
systemctl restart fcgiwrap.service
systemctl restart fcgiwrap.socket
systemctl restart nginx
#!/bin/bash
set -euo pipefail
# first elevate to root
if [[ $EUID != 0 ]]; then
sudo "$0" "$@"
exit $?
fi
echo deb https://downloads.plex.tv/repo/deb public main > /etc/apt/sources.list.d/plexmediaserver.list
curl https://downloads.plex.tv/plex-keys/PlexSign.key | apt-key add -
apt update
apt -y install plexmediaserver
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment