Automatically suspend selfmade NAS when disks are idle
I’ve recently had the urge to have a NAS as my central data storage. For typical home workloads (for me anyway) the home network speeds are good enough and having my data in a central space means I don’t have to worry about hard-drive failure in my laptop and desktop PC. Setting up regular backups is also a lot easier.
Instead of buying a NAS I decided to recycle one of my old machines and build my own. While this saves money, it also means I’m missing features I would usually get out-of-the-box.
I’ve installed a fresh headless copy of Debian 10 and got to work.
My NAS doesn’t need to run 24/7, it just needs to be available 24/7. What do I mean by this? I don’t use my computer non-stop all day. During the times of day where I don’t use the files on my NAS, be it because I’m sleeping or just browsing the web, the drives can be spun down and the NAS itself can go to sleep. However, it needs to wake up and be available once I decide I need access to the files.
Automatically spin down drives
Debian 10 comes pre-installed with hdparm. It allows you to see the current state of a drive and set certain parameters, one of which is the amount of idle time before the drive spins down.
root@nas:~$ hdparm -S 120 /dev/sdb
/dev/sdb:
setting standby to 120 (10 minutes)
Setting the standby time you want requires a bit of math. A value of 0 prevents the drive from ever going into standby. Values between 1 and 240 are multiplied by 5 seconds and values between 241 and 251 increase in 30 minute steps (241 = 30min, 242 = 60min,…).
These settings are not permanent, which is why I’ve written a script to set them.
#!/bin/bash
for DRIVE in \
"/dev/sdb" \
"/dev/sdc"
do
hdparm -S 120 $DRIVE
done
Automatically suspend when all drives are spun down
Now that the drives automatically spin down when they’re not in use we can work on letting the whole system go to sleep. The easiest way (that I’ve found) is setting up a cronjob with another script.
#!/bin/bash
for DRIVE in \
"/dev/sdb" \
"/dev/sdc"
do
if [ -z "$(hdparm -C $DRIVE | grep standby)" ]; then
# $DRIVE is not in standby
exit 0
fi
done
systemctl suspend
If any of the drives is not in standby the script exits early. If all drives are in standby the script sends the NAS to sleep.
All that is left to do is to set up the cronjob to run the script every 5 minutes.
*/5 * * * * /usr/local/bin/suspend_on_inactivity > /dev/null 2>&1
Make it work after sleeping
For this to work you have to activate “Wake On Lan” in your BIOS / UEFI.
When the NAS receives the WOL packet it wakes up and returns to the state it was in when going to sleep. However, the settings for our drives are not recovered, which means we need to run our script again.
Debian 10 uses systemd, which means that we can create a new service that runs every time the NAS boots up. The following is all we need.
[Unit]
Description=Sets hdparm sleep timers
After=suspend.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/set_hdparm
[Install]
WantedBy=multi-user.target suspend.target
All that is left to do is to enable and start the newly created service.
systemctl enable hdparm.service
systemctl start hdparm.service