NixOS Shenanigans

I had known of Nix (and NixOS subsequently) for quite some time, as friends raved over it. Despite that, it was only until recent that I learned about the capabilities of the Nix package manager! I have no clue what prevented me from attempting to using it, but it's wonderful. Nix has a premise that all builds are reproducible, sandboxed, properly installed, and easily changeable. Similar to things such as Gentoo you can modify how packages are built, add your own (even using the term "overlays" as one might with portage!) and so forth. I cannot tell you I'm an expert, but I know enough to be dangerous.

Knowing this: I have a machine named calypso (an old 2011 Mac Mini) that I treasure heavily, and primarily use for backups of my other devices. The poor thing has suffered from my continual desire to learn various operating systems. Despite this all, it has always found a way to be a device for Time Machine!

It has run:

We will now take a second for me to apologize to the poor Mac mini. It has suffered greatly due to how indecisive I can be[1]. Regardless, we love it and treasure it so. It has survived this long, and it will suffer with NixOS as well!

I immediately went to download a NixOS ISO, dd'd it to a USB, booted and prayed. Everything went wonderfully, and I was greeted with an extremely helpful manual to get things set up. One simple nixos-generate-config was enough to determine available partitions, interfaces on the machine, and so forth.

Perfect - we can get right to work! All that's needed configure the majority of everything NixOS is directly editing /etc/nixos/configuration.nix. The perks of a declarative OS!

We're greeted with something similar to the following:

# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;

These appear to be called "options", and have quite a nice database to search through! I made a few changes I typically make on new machines (time.timeZone = "Etc/UTC", services.openssh.passwordAuthentication = false) and carry on.

Lastly, we configure my user:

# Configure users
users.users = {
  spotlight = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
    shell = pkgs.zsh;
    openssh.authorizedKeys.keys = [ "blah blah blah" ];
  };
};

(As keys change occasionally, I omit them here.)

And just like that, we're ready to install. For a perfect first install, it takes just one line: nixos-install --no-root-passwd

and.. we're in! I cannot tell you how happy I am. I ssh in and life is good.

Unfortunately, this is Apple - everything is Broadcom. We need wireless drivers for our BCM4331! This poor thing seems to hurt every OS possible, except for macOS. Most BSDs just flat out give out on it, and its Windows drivers are not particularly stable.

No worries at all, Nix has us covered in typical Linux fashion:

nixpkgs.config.allowUnfree = true;
networking.enableB43Firmware = true;
boot.kernelModules = ["wl"];
boot.extraModulePackages = [ config.boot.kernelPackages.broadcom_sta ];

networking.interfaces.wlp3s0.useDHCP = true;

And just like that, we've declaratively fixed all wireless woes. Configuring an AP is just as easy. We could hardcode the password, but I decided to use wpa_supplicant to get its raw value instead to avoid easy copying:

networking.wireless = {
  enable = true;
  networks = {
    FoxNet = {
      pskRaw = "redacted";
    };
  };
};

No more hassle, life is good. One nixos-rebuild switch, one reboot, and we have everything configured.

Right, so.. we've set everything up! How can we use NixOS with Time Machine? Quite easily, it turns out!

We'll create a system user named time-machine to house our data, and a group for it by the same name.

users.users.time-machine = {
  isSystemUser = true;
  group = "time-machine";
  home = "/var/lib/time-machine";
}

users.groups.time-machine = {};

Then, we simply enable Samba and provide a few simple options. Here, I define a share named "Time Machine" out of /var/lib/time-machine, owned by time-machine.

services.samba = {
  shares = {
    "Time Machine" = {
      path = "/var/lib/time-machine";
      "valid users" = "time-machine";
      public = "no";
      writeable = "yes";
      "force user" = "time-machine";
      "fruit:aapl" = "yes";
      "fruit:time machine" = "yes";
      # We're an iPhone 3GS. Don't question it.
      "fruit:model" = "N88AP";
      "vfs objects" = "catia fruit streams_xattr";
      };
    };
  };
};

And.. that's that. One nixos-rebuild switch later, and life is good. Well, we most likely want Avahi to provide Bonjour advertisements about us being a Time Machine device, right? We can do it so easily it's not even funny. I was amazed.

services.avahi = {
  enable = true;
  publish = {
    enable = true;
    userServices = true;
  };
};

That's it. I needed to smbpasswd -a time-machine to allow my Mac to sign in and back up, and we have it: Time Machine in System Preferences. The

I genuinely have not felt this happy about configuring a system in quite some time. I have very little configuration other than this. You're welcome to view my end configuration on this GitHub gist.

That's all I have. I could tell you that I have more plans, but I shouldn't touch what works.. at least, for a while. Eventually I would like to explore putting NixOS on other servers where I can utilize very little configuration and have rapid replication!

Thank you for reading :)


[0]: When I say "I also post content often on my blog" on joscomputing.space, please ignore the word "often". It was a typo. The error is regretted.

[1]: When we all fall asleep, where did my data go?