
NAS monitoring: watching disks, services and logs at a glance
Why monitor your NAS
On a machine running 24/7, disks age, services crash silently, and Docker logs pile up unread — until a disk starts showing wear or a container restarts in a loop with nobody noticing.
Four tools cover the need, each with a precise role and no overlap, all in Docker on an isolated monitoring_net network, with configs in /mnt/data/apps/monitoring/<service>/:
- Scrutiny (port 9998): SMART disk health
- Uptime Kuma (port 3001): service availability
- Dozzle (port 9999): live Docker logs
- Homepage (port 3010): unified dashboard
Scrutiny: disk health
The critical tool. Scrutiny collects SMART data from every disk and displays it with historical trends. The metrics that matter:
- Temperature: an overheating disk wears out faster
- Reallocated Sectors: reallocated sectors signal physical degradation
- Current Pending Sectors: sectors awaiting reallocation, an imminent problem
- Read/Write errors: rising error counts announce a failure
Scrutiny has two parts: a collector that polls the disks periodically and a web UI for results. The Docker config is unusual, since it needs direct disk access:
# docker-compose.yml (monitoring excerpt)
services:
scrutiny:
image: ghcr.io/analogj/scrutiny:master-omnibus
container_name: scrutiny
restart: unless-stopped
ports:
- '9998:8080'
volumes:
- /mnt/data/apps/monitoring/scrutiny/config:/opt/scrutiny/config
- /mnt/data/apps/monitoring/scrutiny/influxdb:/opt/scrutiny/influxdb
- /run/udev:/run/udev:ro
devices:
- /dev/sda
- /dev/sdb
- /dev/sdc
- /dev/sdd
cap_add:
- SYS_RAWIO
networks:
- monitoring_net
cap_add: SYS_RAWIO is mandatory: without it, the collector can't query disks over SMART. Mounting /run/udev read-only allows disk identification.
Uptime Kuma: service availability
Uptime Kuma covers HTTP, HTTPS, TCP, Ping and DNS. Every NAS service gets its own monitor.
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
ports:
- '3001:3001'
volumes:
- /mnt/data/apps/monitoring/uptime-kuma/data:/app/data
networks:
- monitoring_net
What's watched: HTTP checks on Jellyfin, Immich, Home Assistant, Sonarr, Radarr; TCP checks on Samba (445), SSH (22), NFS (2049); and pings on the NAS itself, the router and the switches.
Beyond outright failures, the latency graphs are valuable: gradual degradation often reveals a disk, network or RAM problem before the service actually goes down.
Notifications go out via email, Telegram, Discord, Slack, Gotify or ntfy. You can also create public or internal status pages to share service state.
Dozzle: logs in real time
When a container misbehaves, the first thing to check is its logs. Dozzle streams them in a web UI, with no SSH and no docker logs.
dozzle:
image: amir20/dozzle:latest
container_name: dozzle
restart: unless-stopped
ports:
- '9999:8080'
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- monitoring_net
Dozzle is deliberately minimal: no database, no persistence, no background collection. It reads the Docker socket and displays, which keeps it at a few MB of RAM. Day to day: search and filtering within a container's logs, a multi-container view to correlate events, auto-scroll with pause when you scroll back, and regex filtering.
Mounting the socket ro is enough: Dozzle reads, it doesn't control containers.
Homepage: the unified dashboard
With around twenty services, remembering ports gets tedious. Homepage provides a YAML-configurable dashboard.
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
restart: unless-stopped
ports:
- '3010:3000'
volumes:
- /mnt/data/apps/monitoring/homepage/config:/app/config
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- monitoring_net
An excerpt from services.yaml:
# /mnt/data/apps/monitoring/homepage/config/services.yaml
- Media:
- Jellyfin:
href: http://192.168.1.50:8096
icon: jellyfin.svg
description: Media server
widget:
type: jellyfin
url: http://192.168.1.50:8096
key: '{{HOMEPAGE_VAR_JELLYFIN_KEY}}'
- Immich:
href: http://192.168.1.50:2283
icon: immich.svg
description: Photos and videos
- Downloads:
- qBittorrent:
href: http://192.168.1.50:8080
icon: qbittorrent.svg
description: BitTorrent client
widget:
type: qbittorrent
url: http://192.168.1.50:8080
username: admin
password: '{{HOMEPAGE_VAR_QBIT_PASSWORD}}'
- Sonarr:
href: http://192.168.1.50:8989
icon: sonarr.svg
description: TV show management
- Monitoring:
- Scrutiny:
href: http://192.168.1.50:9998
icon: scrutiny.svg
description: Disk health
- Uptime Kuma:
href: http://192.168.1.50:3001
icon: uptime-kuma.svg
description: Service availability
Widgets enrich the dashboard: Jellyfin shows active sessions, qBittorrent shows ongoing downloads.
The isolated Docker network
networks:
monitoring_net:
name: monitoring_net
driver: bridge
Isolation buys two things: the monitoring containers talk to each other without going through published ports, and separation from the other stacks (media, downloads, home automation) stays clean.
Cockpit: the system complement
Alongside, Cockpit (port 9090) installed natively on Debian covers what the Docker tools can't see: CPU, RAM, swap, disk space, systemd services, web terminal.
sudo apt install cockpit
Cockpit for the host system, the four Docker tools for services and disks.
Verdict
Monitoring isn't a luxury on a NAS, it's insurance: Scrutiny flags an abnormal temperature before it turns critical, Uptime Kuma warns within seconds when a service goes down, Dozzle saves considerable debugging time, and Homepage acts as the single entry point. Four lightweight tools deployed in minutes through Docker Compose.
Related articles