Monitor Ubuntu Servers in Home Assistant Using MQTT

Monitor Your Ubuntu Servers in Home Assistant Using MQTT

If you’re managing Linux or Ubuntu servers at home or in a lab, a simple, reliable way to view system health inside Home Assistant is a game changer. This post introduces my lightweight MQTT Agent for Ubuntu that integrates your servers via the Mosquitto broker—and includes the full install script for viewing and download.


🧠 What the MQTT Agent Does

The agent installs as a background service on your Ubuntu (Debian-based) machine and publishes system metrics to your Home Assistant MQTT broker. Home Assistant then auto-discovers the server as a device with sensors you can place on dashboards or use in automations.

Home Assistant Mosquitto MQTT add-on in the Add-on store
Mosquitto broker add-on in the Home Assistant Add-on store

Discovered Sensors

Once installed, these sensors are created for each server:

Sensor Description
Agent Online Confirms the agent is running and connected
CPU Usage Current CPU utilisation (%)
Disk Free Free space on the root drive
Disk Total Total size of the root drive
RAM Used % Memory utilisation (%)
Server IP Active IP address
Pending Updates Number of available OS updates (checked hourly)

The agent is lightweight and publishes over MQTT (port 1883 by default, or 8883 if you enable SSL on your broker).


🧩 Set Up MQTT in Home Assistant (Mosquitto)

  1. Install Mosquitto broker add-on
    Go to Settings > Add-ons > Add-on store, search for Mosquitto broker, then click Install.
  2. Create an MQTT user
    Settings > People > Users > Add User — for example:
    Display name: MQTT
    Username: MQTT
    Password: use something secure
    After creating the user, go back to the Mosquitto add-on and click Restart.
  3. (Optional) Enable SSL
    In the Mosquitto Configuration tab, upload your certificates if you want encrypted MQTT on port 8883.

That’s it—Home Assistant is now ready to receive metrics from your Ubuntu servers.


📜 Download the MQTT Agent Script

Here’s the exact installer script I use. You can download it directly, or copy it as-is from the viewer below.

⬇️ Download install-ha-mqtt-agent.sh

#!/usr/bin/env bash
# Version: 1.0.11
# Usage:
#   sudo bash install-ha-mqtt-agent.sh -install    # install/upgrade
#   sudo bash install-ha-mqtt-agent.sh -uninstall  # remove everything
set -euo pipefail

ACTION="${1:- -install}"

# ---- Config (edit if needed) ----
MQTT_HOST="HA URL Here" # ie ha.yourdomain.com
MQTT_PORT="1883"
MQTT_USER="MQTT User Here"
MQTT_PASS="MQTT User Passsword Here"

# Heartbeat & expiry (seconds)
HEARTBEAT_INTERVAL=30      # metrics timer
SENSOR_EXPIRE=120          # sensors stale timeout (cpu/ram/disk/updates/ip)

LOG_DIR="/var/log/mqtt-agent"
LOG_FILE="$LOG_DIR/agent.log"
MAX_LOG_BYTES=$((1024*1024))  # 1 MiB

DEVICE_ID="$(hostname -s || hostname)"
DEVICE_NAME="$DEVICE_ID"

ensure_logs() {
  mkdir -p "$LOG_DIR"
  touch "$LOG_FILE"
  # truncate if too big
  if [ -f "$LOG_FILE" ]; then
    size=$(stat -c%s "$LOG_FILE" 2>/dev/null || wc -c <"$LOG_FILE")
    if [ "${size:-0}" -gt "$MAX_LOG_BYTES" ]; then
      : > "$LOG_FILE"
    fi
  fi
}

write_common_lib() {
  install -d -m 0755 /usr/local/lib/ha-mqtt-agent
  cat > /usr/local/lib/ha-mqtt-agent/common.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

LOG_DIR="/var/log/mqtt-agent"
LOG_FILE="$LOG_DIR/agent.log"
MAX_LOG_BYTES=${LOG_MAX_BYTES:-1048576}

mkdir -p "$LOG_DIR"
touch "$LOG_FILE"
# truncate if too big
if [ -f "$LOG_FILE" ]; then
  size=$(stat -c%s "$LOG_FILE" 2>/dev/null || wc -c <"$LOG_FILE")
  if [ "${size:-0}" -gt "$MAX_LOG_BYTES" ]; then
    : > "$LOG_FILE"
  fi
fi

# Redirect all stdout/stderr to the log
exec >>"$LOG_FILE" 2>&1

log() {
  # usage: log "message"
  echo "$(date -Is) [$0] $*"
}
EOF
  chmod +x /usr/local/lib/ha-mqtt-agent/common.sh
}

install_all() {
  export DEBIAN_FRONTEND=noninteractive
  apt-get update
  apt-get install -y --no-install-recommends jq mosquitto-clients apt-show-versions coreutils gawk logrotate iproute2 util-linux

  ensure_logs
  install -d -m 0755 /usr/local/bin
  install -d -m 0755 /usr/local/lib/ha-mqtt-agent
  install -d -m 0755 /etc/ha-mqtt-agent
  install -d -m 0755 /run/ha-mqtt-agent

  # env file
  cat > /etc/ha-mqtt-agent/env <<EOF
MQTT_HOST="$MQTT_HOST"
MQTT_PORT="$MQTT_PORT"
MQTT_USER="$MQTT_USER"
MQTT_PASS="$MQTT_PASS"
HEARTBEAT_INTERVAL="$HEARTBEAT_INTERVAL"
SENSOR_EXPIRE="$SENSOR_EXPIRE"
# device id/name default to host at runtime
EOF

  # common lib (logging)
  write_common_lib

  # metrics (publishes heartbeat + metrics + cached updates + per-iface IPs every run)
  cat > /usr/local/bin/ha-mqtt-metrics.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
source /usr/local/lib/ha-mqtt-agent/common.sh
log "starting metrics script"
source /etc/ha-mqtt-agent/env

HOSTNAME_SHORT="$(hostname -s || hostname)"
DEVICE_ID="$HOSTNAME_SHORT"
DEVICE_NAME="$HOSTNAME_SHORT"
BASE="servers/$DEVICE_ID"
HEARTBEAT_TOPIC="$BASE/heartbeat"
STATE_TOPIC="$BASE/state"
UPDATES_TOPIC="$BASE/updates"
RUNDIR="/run/ha-mqtt-agent"; mkdir -p "$RUNDIR"
CACHE="$RUNDIR/updates.cache"

# CPU usage over ~0.5s
read -r cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
total1=$((user+nice+system+idle+iowait+irq+softirq+steal))
idle1=$idle
sleep 0.5
read -r cpu user nice system idle iowait irq softirq steal guest guest_nice < /proc/stat
total2=$((user+nice+system+idle+iowait+irq+softirq+steal))
idle2=$idle
totald=$((total2-total1))
idled=$((idle2-idle1))
cpu_used=$(( (1000*(totald-idled)/totald + 5)/10 ))

# RAM used %
mem_used_pct="$(free | awk '/Mem:/{printf("%.1f", $3*100/$2)}')"

# Disk for /
read -r total used free <<<"$(df -B1 / | awk 'NR==2{print $2, $3, $4}')"
disk_free_gb=$(awk -v f="$free" 'BEGIN {printf "%.1f", f/1024/1024/1024}')
disk_total_gb=$(awk -v t="$total" 'BEGIN {printf "%.1f", t/1024/1024/1024}')

payload="$(jq -n --arg host "$DEVICE_NAME" \
  --argjson cpu "$cpu_used" \
  --argjson ram "$mem_used_pct" \
  --argjson disk_free_gb "$disk_free_gb" \
  --argjson disk_total_gb "$disk_total_gb" \
  '{host:$host, cpu:$cpu, ram:$ram, disk_free_gb:$disk_free_gb, disk_total_gb:$disk_total_gb}')"

mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$STATE_TOPIC" -m "$payload" || log "ERROR publishing metrics"

# Per-interface IPv4s (first address per interface), only 'up' and global
# Publish to servers/<host>/ip/<iface>
while IFS= read -r line; do
  iface_raw="$(echo "$line" | awk '{print $2}')"
  iface="${iface_raw%%@*}"  # strip @ifindex
  ipaddr="$(echo "$line" | awk '{print $4}' | cut -d'/' -f1)"
  # sanitize iface name for topic (and trim trailing _)
  safe_iface="$(echo "$iface" | tr -c 'A-Za-z0-9_' '_' | sed 's/_\+$//')"
  [ -n "$ipaddr" ] && mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" \
    -t "$BASE/ip/$safe_iface" -m "$iface: $ipaddr" || true
done < <(ip -o -4 addr show scope global up | awk '!seen[$2]++')

# Re-publish cached updates (so sensor expires with heartbeat if agent dies)
if [ -f "$CACHE" ]; then
  cached="$(tr -d '[:space:]' < "$CACHE")"
  if [[ "$cached" =~ ^[0-9]+$ ]]; then
    mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$UPDATES_TOPIC" -m "$cached" || log "ERROR publishing cached updates"
    log "published cached updates: $cached"
  fi
fi

# Heartbeat (non-retained)
mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$HEARTBEAT_TOPIC" -m "online" || true
EOF
  chmod +x /usr/local/bin/ha-mqtt-metrics.sh

  # updates (hourly real count; single-instance lock; waits for apt locks; writes cache; non-retained publish)
  cat > /usr/local/bin/ha-mqtt-updates.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
source /usr/local/lib/ha-mqtt-agent/common.sh
log "starting updates script"
source /etc/ha-mqtt-agent/env

HOSTNAME_SHORT="$(hostname -s || hostname)"
DEVICE_ID="$HOSTNAME_SHORT"
BASE="servers/$DEVICE_ID"
UPDATES_TOPIC="$BASE/updates"
RUNDIR="/run/ha-mqtt-agent"; mkdir -p "$RUNDIR"
CACHE="$RUNDIR/updates.cache"
LOCK="$RUNDIR/updates.lock"

# ensure only one updates run at a time
exec 200>"$LOCK"
if ! flock -n 200; then
  log "another updates run is active, exiting"
  exit 0
fi

wait_for_apt_locks() {
  local tries=0
  local max_tries=40   # ~10 minutes at 15s
  local sleep_s=15
  while [ $tries -lt $max_tries ]; do
    local blocked=0
    for f in /var/lib/apt/lists/lock /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock; do
      if fuser "$f" >/dev/null 2>&1; then
        blocked=1
        log "apt lock on $f; waiting ${sleep_s}s (try $((tries+1))/$max_tries)"
      fi
    done
    [ $blocked -eq 0 ] && return 0
    tries=$((tries+1))
    sleep "$sleep_s"
  done
  log "apt appears locked for too long; proceeding anyway"
  return 0
}

export DEBIAN_FRONTEND=noninteractive

log "waiting for apt locks (if any)..."
wait_for_apt_locks

log "running apt-get update..."
if apt-get update -qq -o Acquire::Retries=3; then
  log "apt-get update complete"
else
  log "apt-get update failed (continuing to count upgrades)"
fi

count="$(apt-show-versions -u -b | sed '/^No .* upgrades/d' | wc -l | tr -d '[:space:]' || echo 0)"
[ -z "${count:-}" ] && count=0
echo "$count" > "$CACHE"
log "updates pending: $count (cached at $CACHE)"

mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$UPDATES_TOPIC" -m "$count" || log "ERROR publishing updates"
EOF
  chmod +x /usr/local/bin/ha-mqtt-updates.sh

  # discovery (uses heartbeat for availability + expire_after for ALL sensors including updates and IPs)
  cat > /usr/local/bin/ha-mqtt-discovery.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
source /usr/local/lib/ha-mqtt-agent/common.sh
log "starting discovery script"
source /etc/ha-mqtt-agent/env

HOSTNAME_SHORT="$(hostname -s || hostname)"
DEVICE_ID="$HOSTNAME_SHORT"
DEVICE_NAME="$HOSTNAME_SHORT"
HEARTBEAT_TOPIC="servers/$DEVICE_ID/heartbeat"
STATE_TOPIC="servers/$DEVICE_ID/state"

device_json="$(jq -n --arg id "$DEVICE_ID" --arg name "$DEVICE_NAME" '{identifiers:[$id],manufacturer:"DIY",model:"Linux Server",name:$name}')"

pub_cfg_sensor() {
  local object="$1"; shift
  local body="$1"; shift
  local topic="homeassistant/sensor/$DEVICE_ID/$object/config"
  local tries=0
  until mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -u "$MQTT_USER" -P "$MQTT_PASS" -t "$topic" -r -m "$body"; do
    tries=$((tries+1))
    log "WARN: publish $object discovery failed (attempt $tries)"
    if [ $tries -ge 5 ]; then
      log "ERROR: giving up on $object discovery after $tries attempts"
      return 0
    fi
    sleep 2
  done
  log "published discovery for $object"
}

# Agent Online (sensor with expire_after so it becomes Unavailable)
agent_online_cfg="$(jq -n \
  --arg name "$DEVICE_NAME Agent Online" \
  --arg uid "${DEVICE_ID}_agent_online" \
  --arg stat "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, avty_t:$stat, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, icon:"mdi:lan-connect", dev:$dev}')"

cpu_cfg="$(jq -n \
  --arg name "$DEVICE_NAME CPU Usage" \
  --arg uid "${DEVICE_ID}_cpu" \
  --arg stat "$STATE_TOPIC" \
  --arg avail "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, val_tpl:"{{ value_json.cpu }}", unit_of_meas:"%", dev_cla:"power_factor", avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, dev:$dev}')"

ram_cfg="$(jq -n \
  --arg name "$DEVICE_NAME RAM Used %" \
  --arg uid "${DEVICE_ID}_ram" \
  --arg stat "$STATE_TOPIC" \
  --arg avail "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, val_tpl:"{{ value_json.ram }}", unit_of_meas:"%", dev_cla:"power_factor", avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, dev:$dev}')"

disk_free_cfg="$(jq -n \
  --arg name "$DEVICE_NAME Disk Free" \
  --arg uid "${DEVICE_ID}_disk_free" \
  --arg stat "$STATE_TOPIC" \
  --arg avail "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, val_tpl:"{{ value_json.disk_free_gb }}", unit_of_meas:"GB", stat_cla:"measurement", avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, dev:$dev}')"

disk_total_cfg="$(jq -n \
  --arg name "$DEVICE_NAME Disk Total" \
  --arg uid "${DEVICE_ID}_disk_total" \
  --arg stat "$STATE_TOPIC" \
  --arg avail "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, val_tpl:"{{ value_json.disk_total_gb }}", unit_of_meas:"GB", avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, dev:$dev}')"

updates_cfg="$(jq -n \
  --arg name "$DEVICE_NAME Updates Pending" \
  --arg uid "${DEVICE_ID}_updates" \
  --arg stat "servers/$DEVICE_ID/updates" \
  --arg avail "$HEARTBEAT_TOPIC" \
  --argjson dev "$device_json" \
  --argjson exp ${SENSOR_EXPIRE:-120} \
  '{name:$name, uniq_id:$uid, stat_t:$stat, unit_of_meas:"updates", icon:"mdi:package-up", avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, dev:$dev, entity_category:"diagnostic"}')"

pub_cfg_sensor "agent_online" "$agent_online_cfg"
pub_cfg_sensor "cpu" "$cpu_cfg"
pub_cfg_sensor "ram" "$ram_cfg"
pub_cfg_sensor "disk_free" "$disk_free_cfg"
pub_cfg_sensor "disk_total" "$disk_total_cfg"
pub_cfg_sensor "updates" "$updates_cfg"

# Per-interface IP sensors (discovered dynamically)
# We'll publish sensor for each active global IPv4 interface, name: "IP (<iface>)"
while IFS= read -r line; do
  iface_raw="$(echo "$line" | awk '{print $2}')"
  iface="${iface_raw%%@*}"  # strip @ifindex
  ipaddr="$(echo "$line" | awk '{print $4}' | cut -d'/' -f1)"
  [ -z "$ipaddr" ] && continue
  safe_iface="$(echo "$iface" | tr -c 'A-Za-z0-9_' '_' | sed 's/_\+$//')"
  name="$DEVICE_NAME IP ($iface)"
  uid="${DEVICE_ID}_ip_${safe_iface}"
  stat="servers/$DEVICE_ID/ip/$safe_iface"

  ip_cfg="$(jq -n \
    --arg name "$name" \
    --arg uid "$uid" \
    --arg stat "$stat" \
    --arg avail "$HEARTBEAT_TOPIC" \
    --argjson dev "$device_json" \
    --argjson exp ${SENSOR_EXPIRE:-120} \
    '{name:$name, uniq_id:$uid, stat_t:$stat, avty_t:$avail, pl_avail:"online", pl_not_avail:"offline", exp_aft:$exp, icon:"mdi:ip-network", dev:$dev, entity_category:"diagnostic"}')"

  pub_cfg_sensor "ip_${safe_iface}" "$ip_cfg"
done < <(ip -o -4 addr show scope global up | awk '!seen[$2]++')
EOF
  chmod +x /usr/local/bin/ha-mqtt-discovery.sh

  # systemd units (ensure /run/ha-mqtt-agent exists automatically; and preserve it after stop)
  cat > /etc/systemd/system/ha-mqtt-metrics.service <<'EOF'
[Unit]
Description=Publish Linux metrics to MQTT (HA)
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ha-mqtt-metrics.sh
EnvironmentFile=/etc/ha-mqtt-agent/env
RuntimeDirectory=ha-mqtt-agent
RuntimeDirectoryMode=0755
RuntimeDirectoryPreserve=yes
EOF

  cat > /etc/systemd/system/ha-mqtt-metrics.timer <<EOF
[Unit]
Description=Run HA MQTT metrics every ${HEARTBEAT_INTERVAL}s

[Timer]
OnBootSec=20s
OnUnitActiveSec=${HEARTBEAT_INTERVAL}s
Unit=ha-mqtt-metrics.service

[Install]
WantedBy=timers.target
EOF

  cat > /etc/systemd/system/ha-mqtt-updates.service <<'EOF'
[Unit]
Description=Publish updates count to MQTT (HA)
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ha-mqtt-updates.sh
EnvironmentFile=/etc/ha-mqtt-agent/env
RuntimeDirectory=ha-mqtt-agent
RuntimeDirectoryMode=0755
RuntimeDirectoryPreserve=yes
EOF

  cat > /etc/systemd/system/ha-mqtt-updates.timer <<'EOF'
[Unit]
Description=Run updates publisher hourly

[Timer]
OnBootSec=2m
OnUnitActiveSec=1h
Unit=ha-mqtt-updates.service

[Install]
WantedBy=timers.target
EOF

  cat > /etc/systemd/system/ha-mqtt-discovery.service <<'EOF'
[Unit]
Description=Publish Home Assistant MQTT Discovery configs
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ha-mqtt-discovery.sh
EnvironmentFile=/etc/ha-mqtt-agent/env

[Install]
WantedBy=multi-user.target
EOF

  # logrotate
  cat > /etc/logrotate.d/mqtt-agent <<'EOF'
/var/log/mqtt-agent/agent.log {
  size 1M
  rotate 3
  missingok
  notifempty
  compress
  delaycompress
  copytruncate
  create 0640 root adm
}
EOF

  systemctl daemon-reload
  systemctl enable --now ha-mqtt-discovery.service
  systemctl enable --now ha-mqtt-metrics.timer
  systemctl enable --now ha-mqtt-updates.timer

  # Seed sensors immediately
  /usr/local/bin/ha-mqtt-metrics.sh || true
  /usr/local/bin/ha-mqtt-updates.sh || true

  echo "Installation complete.
Device: $DEVICE_NAME
Broker: $MQTT_HOST:$MQTT_PORT
Metrics every ${HEARTBEAT_INTERVAL}s; sensors expire after ${SENSOR_EXPIRE}s if no data.
RuntimeDirectory preserved across job exits to avoid /run deletions mid-run.
Updates handle apt locks and prevent overlapping runs.
Logs: $LOG_FILE (rotated at ~1MiB)"
}

uninstall_all() {
  set +e
  systemctl disable --now ha-mqtt-metrics.timer ha-mqtt-updates.timer ha-mqtt-discovery.service 2>/dev/null
  systemctl stop ha-mqtt-metrics.service ha-mqtt-updates.service 2>/dev/null
  systemctl daemon-reload

  rm -f /etc/systemd/system/ha-mqtt-metrics.service
  rm -f /etc/systemd/system/ha-mqtt-metrics.timer
  rm -f /etc/systemd/system/ha-mqtt-updates.service
  rm -f /etc/systemd/system/ha-mqtt-updates.timer
  rm -f /etc/systemd/system/ha-mqtt-discovery.service

  rm -f /usr/local/bin/ha-mqtt-metrics.sh
  rm -f /usr/local/bin/ha-mqtt-updates.sh
  rm -f /usr/local/bin/ha-mqtt-discovery.sh

  rm -rf /usr/local/lib/ha-mqtt-agent
  rm -rf /etc/ha-mqtt-agent
  rm -f /etc/logrotate.d/mqtt-agent
  rm -rf /var/log/mqtt-agent
  rm -rf /run/ha-mqtt-agent

  systemctl daemon-reload
  echo "Uninstall complete."
}

case "$ACTION" in
  -install|--install|install)
    install_all
    ;;
  -uninstall|--uninstall|uninstall)
    uninstall_all
    ;;
  *)
    echo "Usage: $0 [-install|--install|install] | [-uninstall|--uninstall|uninstall]"
    exit 2
    ;;
esac

🖥️ Installing the MQTT Agent on Ubuntu

  1. Copy install-ha-mqtt-agent.sh to your server.
  2. Run the installer:
sudo bash install-ha-mqtt-agent.sh -install

When the installer completes, your server should appear in:

Home Assistant → Settings → Devices & Services → MQTT

If it doesn’t, confirm that port 1883 (or 8883 for SSL) is open between your server and Home Assistant.

For troubleshooting, check:

sudo systemctl status mqtt-agent
sudo tail -f /var/log/mqtt-agent/mqtt-agent.log

To remove the agent:

sudo bash install-ha-mqtt-agent.sh -uninstall

🧾 Example Data

Example Home Assistant dashboard with MQTT agent sensors: CPU, RAM, Disk, IP, updates

Typical MQTT Agent sensors on a Home Assistant dashboard

🚀 Future Plans

  • Additional metrics: uptime, network throughput, temperatures
  • Interactive installer prompts for SSL/TLS

💡 Final Thoughts

The Ubuntu MQTT Agent is a quick win for anyone who wants real-time server telemetry inside Home Assistant. It’s minimal, secure, and easy to automate against—perfect for homelabs and small server fleets.

Author: Jack Went
Website: jackwent.co.uk
Tags: Home Assistant, MQTT, Ubuntu, Linux, Monitoring, Mosquitto, Automation