Skip to content
atori.tech

Update notifications

Difficulty: Easy Tested v0.18.5.3

Monero, P2Pool and XMRig aren't installed through apt, so unattended-upgrades never updates them. This guide adds a small script that checks once a day whether a newer version is out, and whether the ban list changed. It shows the result when you log in:

MoneroBox: updates available
  monerod      0.18.5.3 -> 0.18.6.0   (guide 2.1, Upgrade)
  Ban list     changed upstream: Monero Research Lab spy node ban list version 3, 2026-11-02   (bonus: Monero ban list)

When everything is current, it shows nothing.

It only notifies

The script never downloads or installs a new version. You still upgrade by hand, following each guide's Upgrade section, so you verify every release yourself.

What it checks

Software Compared with Only if installed
monerod (2.1) Latest release on GitHub Yes
P2Pool (3.1) Latest release on GitHub Yes
XMRig (3.2) Latest release on GitHub Yes
monero-lws (Light wallet server) Highest release tag on GitHub Yes
Ban list (Monero ban list) The published file, byte for byte Yes

Everything installed with apt, including Tor and the system itself, is already covered by Ubuntu's own login message ("X updates can be applied") and by unattended-upgrades from 1.5.

Privacy

Every lookup goes through Tor. GitHub never sees your IP address, so nobody can link your home connection to the list of Monero software you run. The script only reads public pages: it sends no data about your node.

Requirements

Install the script

sudo nano /usr/local/bin/monerobox-update-check

Paste the whole script:

#!/usr/bin/env bash
# MoneroBox: check for new versions of the guide's software and the ban list.
# Writes a short report that the login message shows. All lookups go through
# Tor, so GitHub never learns your IP address or which software you run.
#
# Environment (all optional):
#   MONEROBOX_PROXY     proxy for lookups (default: socks5h://127.0.0.1:9050;
#                        set it to an empty value to connect directly)
#   MONEROBOX_BAN_LIST  your copy of the ban list (default: /data/monero/ban_list.txt)
#   STATE_DIRECTORY      where the report goes (set by systemd)

set -uo pipefail

PROXY=${MONEROBOX_PROXY-socks5h://127.0.0.1:9050}
BAN_LIST=${MONEROBOX_BAN_LIST:-/data/monero/ban_list.txt}
BAN_LIST_URL=https://raw.githubusercontent.com/Boog900/monero-ban-list/main/ban_list.txt
STATE_DIR=${STATE_DIRECTORY:-/var/lib/monerobox-updates}
REPORT=$STATE_DIR/status

export GIT_TERMINAL_PROMPT=0 HOME=$STATE_DIR

updates=()
errors=()

# curl and git, both through the proxy when one is set
fetch() {
  curl -fs --max-time 90 --retry 2 ${PROXY:+--proxy "$PROXY"} "$@"
}
git_remote() {
  git ${PROXY:+-c http.proxy="$PROXY"} ls-remote --tags --refs "$@"
}

# "v4.18" -> "4.18.0", "v0.18.5.3-release" -> "0.18.5.3"
normalize() {
  local v=${1#v}
  v=${v%%[-+ ]*}
  [[ $v =~ ^[0-9]+\.[0-9]+$ ]] && v=$v.0
  printf '%s' "$v"
}

# True when $2 is a newer version than $1
is_newer() {
  [[ $1 != "$2" && $(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1) == "$2" ]]
}

# Latest release tag, read from GitHub's /releases/latest redirect (no API, no rate limit)
latest_release() {
  local url
  url=$(fetch -o /dev/null -w '%{redirect_url}' "https://github.com/$1/releases/latest") || return 1
  [[ $url == */tag/* ]] || return 1
  printf '%s' "${url##*/tag/}"
}

# Highest vX.Y.Z tag, for projects that tag releases without publishing them
latest_tag() {
  git_remote "https://github.com/$1.git" 2>/dev/null \
    | sed -n 's#.*refs/tags/##p' \
    | grep -E '^v?[0-9]+\.[0-9]+(\.[0-9]+)?$' \
    | sort -V | tail -n1
}

# check NAME COMMAND REPO SOURCE GUIDE
#   COMMAND prints the installed version; SOURCE is "release" or "tag"
check() {
  local name=$1 cmd=$2 repo=$3 source=$4 guide=$5 installed latest
  command -v "${cmd%% *}" >/dev/null 2>&1 || return 0   # not installed here: skip
  installed=$($cmd 2>/dev/null | grep -oE 'v?[0-9]+\.[0-9]+(\.[0-9]+)*' | head -n1)
  if [[ -z $installed ]]; then
    errors+=("$name: couldn't read the installed version")
    return
  fi
  if [[ $source == release ]]; then
    latest=$(latest_release "$repo")
  elif command -v git >/dev/null 2>&1; then
    latest=$(latest_tag "$repo")
  else
    errors+=("$name: git isn't installed (sudo apt install git)")
    return
  fi
  if [[ -z $latest ]]; then
    errors+=("$name: couldn't reach github.com/$repo (is Tor running?)")
    return
  fi
  if is_newer "$(normalize "$installed")" "$(normalize "$latest")"; then
    updates+=("$(printf '%-12s %s -> %s   (%s)' "$name" "$(normalize "$installed")" "$(normalize "$latest")" "$guide")")
  fi
}

check monerod    "monerod --version"            monero-project/monero release "guide 2.1, Upgrade"
check P2Pool     "p2pool --version"             SChernykh/p2pool      release "guide 3.1, Upgrade"
check XMRig      "xmrig --version"              xmrig/xmrig           release "guide 3.2, Upgrade"
check monero-lws "monero-lws-daemon --version"  vtnerd/monero-lws     tag     "bonus: Light wallet server"

mkdir -p "$STATE_DIR"

# Ban list: compare your copy with the published one, byte for byte
if [[ -r $BAN_LIST ]]; then
  remote=$(mktemp "$STATE_DIR/.ban_list.XXXXXX")
  if fetch -o "$remote" "$BAN_LIST_URL"; then
    if ! cmp -s "$BAN_LIST" "$remote"; then
      header=$(sed -n '1s/^# *//p' "$remote")
      updates+=("$(printf '%-12s changed upstream%s   (bonus: Monero ban list)' "Ban list" "${header:+: $header}")")
    fi
  else
    errors+=("Ban list: couldn't download it (is Tor running?)")
  fi
  rm -f "$remote"
fi

# Write the report atomically, so a login never sees half of it
tmp=$(mktemp "$STATE_DIR/.status.XXXXXX")
{
  if ((${#updates[@]})); then
    echo "MoneroBox: updates available"
    printf '  %s\n' "${updates[@]}"
  fi
  if ((${#errors[@]})); then
    echo "MoneroBox: some update checks failed"
    printf '  %s\n' "${errors[@]}"
  fi
} > "$tmp"
chmod 644 "$tmp"
mv -f "$tmp" "$REPORT"

if [[ -s $REPORT ]]; then cat "$REPORT"; else echo "MoneroBox: everything is up to date"; fi

Make it executable:

sudo chmod 755 /usr/local/bin/monerobox-update-check

Run it daily

A systemd timer runs the check once a day, and 15 minutes after each boot. The service runs as a temporary, unprivileged user that systemd creates for each run. It can read your installed programs and the ban list, and write only its own report.

sudo nano /etc/systemd/system/monerobox-update-check.service
# MoneroBox: daily check for new versions
# /etc/systemd/system/monerobox-update-check.service

[Unit]
Description=MoneroBox update check
Wants=network-online.target
After=network-online.target tor.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/monerobox-update-check
DynamicUser=yes
# Read access to /data/monero/ban_list.txt
SupplementaryGroups=monero
StateDirectory=monerobox-updates

# Hardening
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
NoNewPrivileges=yes
sudo nano /etc/systemd/system/monerobox-update-check.timer
# MoneroBox: schedule for the update check
# /etc/systemd/system/monerobox-update-check.timer

[Unit]
Description=Daily MoneroBox update check

[Timer]
OnBootSec=15min
OnCalendar=daily
RandomizedDelaySec=2h
Persistent=true

[Install]
WantedBy=timers.target

RandomizedDelaySec spreads the check over two hours, so it doesn't happen at the same time every day.

sudo systemctl daemon-reload
sudo systemctl enable --now monerobox-update-check.timer

Show it at login

Ubuntu builds its login message from the scripts in /etc/update-motd.d/. Add one that prints the latest report:

sudo nano /etc/update-motd.d/95-monerobox-updates
#!/bin/sh
# MoneroBox: show the result of the last update check at login
report=/var/lib/monerobox-updates/status
[ -f "$report" ] || exit 0
# An empty report means everything is up to date: print nothing
if [ -s "$report" ]; then
  echo
  cat "$report"
fi
# Warn when the daily check has stopped running
age=$(( $(date +%s) - $(stat -c %Y "$report") ))
if [ "$age" -gt 259200 ]; then
  [ -s "$report" ] || echo
  echo "MoneroBox: the last update check ran $(( age / 86400 )) days ago. Check: systemctl status monerobox-update-check.timer"
fi
sudo chmod 755 /etc/update-motd.d/95-monerobox-updates

Validation

Run the check once by hand, and read its output:

sudo systemctl start monerobox-update-check
sudo journalctl -u monerobox-update-check -n 10 --no-pager
monerobox-update-check[4321]: MoneroBox: everything is up to date
systemd[1]: monerobox-update-check.service: Deactivated successfully.

Check that the timer is scheduled:

systemctl list-timers monerobox-update-check.timer
NEXT                         LEFT     LAST                         PASSED  UNIT                          ACTIVATES
Sat 2026-10-17 01:12:40 UTC  15h left Fri 2026-10-16 09:30:02 UTC  3min ago monerobox-update-check.timer monerobox-update-check.service

Log out and in again. When an update is available, it appears at the end of the login message.

Troubleshooting

couldn't reach github.com/… (is Tor running?)
  • systemctl is-active tor@default must print active. Tor needs a minute after a reboot; the next check retries anyway.
  • Test Tor by hand: curl --socks5-hostname 127.0.0.1:9050 -sI https://github.com | head -1 should print an HTTP status line.
  • GitHub occasionally refuses connections from Tor exit relays. If one check fails, the next one usually works.
couldn't read the installed version

The program is installed, but its --version output looks different than expected, for example after a big upstream change. Run the command from the table by hand (for example p2pool --version) and open an issue with the output.

The login message doesn't show the report
  • The report only has content when there's something to say. Check it directly: sudo cat /var/lib/monerobox-updates/status.
  • Check that the motd script is executable: ls -l /etc/update-motd.d/95-monerobox-updates.

Uninstall

sudo systemctl disable --now monerobox-update-check.timer
sudo rm /etc/systemd/system/monerobox-update-check.{service,timer}
sudo rm /usr/local/bin/monerobox-update-check /etc/update-motd.d/95-monerobox-updates
sudo systemctl daemon-reload
sudo rm -rf /var/lib/private/monerobox-updates /var/lib/monerobox-updates