monotux.tech

Disable disk spindown on NixOS

NixOS systemd

I have two disks in my homelab NAS that would spin down when idle, which puts unnecessary strain on the drives as they are typically woken up again a few minutes later. Disabling this is not very hard, and this pattern is usable for other cases where you want systemd to run multiple instances of something. While all examples below uses NixOS syntax, it’s all just standard systemd components at play.

I initially tried asking a LLM on how to do it and was just provided with a broken, impossible solution so I thought I might as well write this up if someone else needs something similar.

Table of Contents

Overview

We will create a new systemd target, which specifies what units it requires, and these units will be instance units that runs a bash script that will run a simple bash script that disables disk spindown using hdparm.

┌─────────┐     ┌─────────────────────────┐     ┌──────────────────────────────┐
│         │     │                         │     │                              │
│ systemd ├────►│ disable-spindown.target ├────►│ disable-spindown@sda.service │
│         │     │                         │     │                              │
└─────────┘     └────────────┬────────────┘     └──────────────────────────────┘
                             │                  ┌──────────────────────────────┐
                             │                  │                              │
                             └─────────────────►│ disable-spindown@sdb.service │
                                                │                              │
                                                └──────────────────────────────┘

(mermaid-ascii.art is great, but I should really make my hugo build my mermaid charts automagically)

Script

The actual script is really simple – it just runs hdparm on a given disk. Below I’ve wrapped it in some nix but it should be simple to understand:

{ lib, pkgs, ... }:
let
  disableSpindownScript = pkgs.writeShellScript "disable-spindown.sh" ''
    ${pkgs.hdparm}/bin/hdparm -B 255 -S 0 /dev/$1
  '';

  disableSpindownDisks = [
    "sda"
    "sdb"
  ];
in
{
  # the rest of the file goes here...
}

I’ve also added a list of disks to disable spindown for, which we’ll use later on.

systemd bits

First we create a systemd.target(5) which depends on our instance units, which will run said units on boot. Then we create a systemd.service(5) unit which will run the script per disk. Each disk will get it’s own disable-spindown@sda.service, disable-spindown@sdb.service et c

systemd.targets."disable-spindown" = {
  wantedBy = [ "multi-user.target" ];
  wants = map (i: "disable-spindown@${i}.service") disableSpindownDisks;
};

systemd.services."disable-spindown@" = {
  description = "Disable spindown for disk";
  wantedBy = [ "multi-users.target" ];
  serviceConfig = {
    Type = "oneshot";
    ExecStart = "${disableSpindownScript} %i";
  };
};

Just update disableSpindownDisks to change which disks to disable spindown for, and a new unit will spin up on boot (and after rebuilding if it’s a new disk added).

Conclusion

This pattern can probably be abstracted and reused, but I will probably just copy/paste it where needed as it’s just a few lines. While it might seem overkill for running a bash oneliner (and yes, it is for this case!) the pattern is simple and reusable for other, similar situations.