NixOS on a CM3588

August 10, 2025

I started migrating my home lab's file server to a CM3588 module + NAS carrier. It's a neat little ARM board with 4 NVMe slots for SSDs. Off the beaten path so installing the One True Operating System (NixOS) takes effort.

Disclaimer: I have no idea what I'm doing. Following my instructions may destroy everything you love. Don't sue me.

Resources

Some useful resources found while troubleshooting:

Boot Process

The standard NixOS image won't boot as-is. RK3588's ROM expects bootloader firmware at specific offsets. The official U-Boot docs have instructions about compiling for Rockchip boards, but some legend already contributed it to nixpkgs.

Mic92 took that package and generated boot images. In short: take the upstream NixOS SD image, yoink the root filesystem, and repackage it with Rockchip firmware handling boot.

nix build 'github:Mic92/nixos-aarch64-images#cm3588NAS'

Flashing the build artifact should be enough to boot the device.

Note: HDMI never worked. No idea why. I installed everything over SSH.

SSH Access

The standard install environment brings up networking and SSH by default, but unless you know the default password, you need to mount the disk and add authorized keys.

After first boot (it runs a bit of setup), shut down and mount the device. Add public keys:

cd /mnt/etc/ssh/
mkdir authorized_keys.d
echo $MY_PUBLIC_KEYS > authorized_keys.d/root

Boot again and ssh root@<ip>.

Resizing the Partition

Normally these SD live installers auto-inflate the root partition to fill available space. Something went wrong here: the installer created an empty 4th partition and inflated that instead. Nix commands fail because the disk is full.

It's frustrating to fix. You have to adjust the partition while it's mounted. This can corrupt your filesystem, so take a moment to pray to your deities.

# Delete partition 4, resize partition 3 to fill available space
parted /dev/mmcblk1 rm 4
parted /dev/mmcblk1 resizepart 3 100%
# Expand ext4 to fill the new partition space
resize2fs /dev/mmcblk1p3

During install /nix/store was mounted read-only. A stern reboot fixed it.

Building/Installing

This is where the install process starts to look familiar.

mount /dev/mmcblk1p3 /mnt # This should be your root partition
nixos-generate-config --root /mnt

Edit the generated config. Don't forget SSH or you'll experience the joy of starting over.

{
# ...
networking.hostName = "nas-001";
environment.systemPackages = [ pkgs.vim ];
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
users.users.root.openssh.authorizedKeys.keys = [
"... public key here ..."
];
# Default output from `nixos-generate-config`.
# Delegates booting to the pre-flashed U-Boot slots.
boot.loader.generic-extlinux-compatible.enable = true;
boot.loader.grub.enable = false;
}

Yeet.

nixos-install --root /mnt

After that finishes and a root password is set, reboot and you're done! It's standard process from here.

Updating U-Boot

Since NixOS is only managing its own partition, the U-Boot artifacts are fixed in time. They won't update automatically. Not surprising, it's basically the same for Raspberry Pi firmware.

In theory you can just dd newer files into the same partitions/sector offsets. I found this crazy file where someone automated the firmware update.

Me? I plan on never touching this again unless something breaks.

U-Boot was a black box before I started on this path. Low-level OS stuff never captured my interest. I'm grateful to learn, but happy it's over.