The Complete Computing Environment

Morph for managing NixOS

LifeTechEmacsTopicsArcology

Morph is a tool for managing existing NixOS hosts - basically a fancy wrapper around nix-build, nix copy, nix-env, nix/store…/bin/switch-to-configuration, scp and more. Morph supports updating multiple hosts in a row, and with support for health checks makes it fairly safe to do so.

Interestingly, it seems like I can just use my NixOps laptop profile…? stealin' it! that's nice.

Deploying My Laptops

My laptops are installed through my NixOS Automatic Partitioning Installer and carry My NixOS configuration for laptops, the "endpoint configuration".

let
  endpointCfg = ../roles/endpoint;
  # nixpkgsPin = (import ../versions.nix {}).nixpkgs;
  # pkgs = import (builtins.fetchTarball nixpkgsPin) {};
  pkgs = import <nixpkgs> {};
in {
  network.pkgs = pkgs;
  network.description = "my laptops";
  network.enableRollback = true;

  meadow-crush = {config, pkgs, ...}:
    {
      imports = [ endpointCfg ../hosts/meadow-crush ];
      deployment.targetHost = "meadow-crush";
      deployment.targetUser = "root";
      system.stateVersion = "22.05";
    };

  virtuous-cassette = {config, pkgs, ...}:
    {
      imports = [ endpointCfg ../hosts/virtuous-cassette ];
      deployment.targetHost = "virtuous-cassette";
      system.stateVersion = "22.05";
    };
}

Meadow Crush

hosts/meadow-crush/default.nix replaces the generated.nix, basically, for my GPD Pocket:

{
  imports = [ ./hardware-configuration.nix ../../nixos/gpd-pocket.nix ];

  networking.hostName = "meadow-crush";
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  services.tailscale.authKey = "tskey-kqvV5P3CNTRL-K3bdvSJcUreG8nrGcDKXCh";

  # networking.wireguard.interfaces.wg0 = {
  #   privateKeyFile = "/etc/wireguard-key/meadow-crush.key";
  #   ips = ["10.10.10.4/32"];
  # };

  networking.hostId = "c9ec7cad"; # required for zfs use
  boot.initrd.luks.devices = {
    "swap" = { name = "swap"; device = "/dev/mmcblk0p2"; preLVM = true; };
    "root" = { name = "root"; device = "/dev/mmcblk0p3"; preLVM = true; };
  };

  fileSystems."/mnt/music" =
    { device = "/dev/disk/by-label/muzak";
      fsType = "ext4";
      noCheck = true;
    };
}

I pull file:nixlib/hosts/meadow-crush/hardware-configuration.nix with nixops:

nixops scp --from meadow-crush /etc/nixos/hardware-configuration.nix nixlib/hosts/meadow-crush/hardware-configuration.nix

I put my Wireguard configuration on the device (for now) using nixops scp

nixops ssh meadow-crush mkdir -p /etc/wireguard-key/ && \
nixops scp --to meadow-crush wireguard/meadow-crush.key /etc/wireguard-key/meadow-crush.key && \
nixops ssh meadow-crush chown 400 /etc/wireguard-key/meadow-crush.key

I need to make sure this stays in sync with my JustDoIt script!

Virtuous Cassette

Virtuous Cassette is my Framework Laptop.

hosts/tres-ebow/default.nix replaces the generated.nix, basically, for my GPD Pocket:

{
  imports = [ ./hardware-configuration.nix ];

  networking.hostName = "virtuous-cassette";
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # networking.wg-quick.interfaces.wg0 = {
  #   privateKeyFile = "/etc/wireguard-key/virtuous-cassette.key";
  #   address = ["10.10.10.13/32" "2620:fc:c000:0:1000::d/128"];
  # };
  # networking.wg-quick.interfaces.wg1 = {
  #   privateKeyFile = "/etc/wireguard-key/virtuous-cassette.key";
  #   address = ["10.10.10.13/32" "2620:fc:c000:0:1000::d/128"];
  # };
  services.tailscale.authKey = "tskey-kMJ8ZX2CNTRL-tDGQZ1dZQLZ9hnuGRgKXS";

  networking.hostId = "754ccef7"; # required for zfs use
  boot.initrd.luks.devices = {
    "swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
    "root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
  };
}

NEXT implement nixos encrypted secrets and make these safe! maybe hosts.toml for a lot of this too…

Deploying My NixOS Set Top Box

let
  settopCfg = ../roles/settop;
  # nixpkgsPin = (import ../versions.nix {}).nixpkgs;
  # pkgs = import (builtins.fetchTarball nixpkgsPin) {};
  pkgs = import <nixpkgs> {};
in {
  network.pkgs = pkgs;
  network.description = "my settop";
  network.enableRollback = true;

  tres-ebow = {config, pkgs, ...}:
    {
      imports = [ settopCfg ../hosts/tres-ebow ];
      deployment.targetHost = "10.0.0.167";
    };
}

Tres Ebow

Tres Ebow is my Thinkpad Yoga gen 3 – a decent 2-in-1 with very un-Lenovo serviceability, and due to ordering error and soldered RAM, only 4 GiB of RAM. awkward. it'll be a fine kodi box.

{
  imports = [ ./hardware-configuration.nix ];

  networking.hostName = "tres-ebow";
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # networking.wg-quick.interfaces.wg0 = {
  #   privateKeyFile = "/etc/wireguard-key/tres-ebow.key";
  #   address = ["10.10.10.2/32" "2620:fc:c000:0:1000::b/128"];
  # };
  # networking.wg-quick.interfaces.wg1 = {
  #   privateKeyFile = "/etc/wireguard-key/tres-ebow.key";
  #   address = ["10.10.10.2/32" "2620:fc:c000:0:1000::b/128"];
  # };
  services.tailscale.authKey = "tskey-kGxjxy1CNTRL-ZoepgcGatEA78ezQKX5VVb";

  networking.hostId = "c9ec7cad"; # required for zfs use
  boot.initrd.luks.devices = {
    "swap" = { name = "swap"; device = "/dev/nvme0n1p2"; preLVM = true; };
    "root" = { name = "root"; device = "/dev/nvme0n1p3"; preLVM = true; };
  };
}

I pull file:nixlib/hosts/tres-ebow/hardware-configuration.nix with nixops:

nixops scp --from tres-ebow /etc/nixos/hardware-configuration.nix nixlib/hosts/tres-ebow/hardware-configuration.nix

I put my Wireguard configuration on the device (for now) using nixops scp

nixops ssh tres-ebow mkdir -p /etc/wireguard-key/ && \
nixops scp --to tres-ebow wireguard/tres-ebow.key /etc/wireguard-key/tres-ebow.key && \
nixops ssh tres-ebow chown 400 /etc/wireguard-key/tres-ebow.key

I need to make sure this stays in sync with my JustDoIt script!

Deploying The Wobserver

let
  serverCfg = ../roles/server;
  pkgs = import <nixpkgs> {};
in {
  network.pkgs = pkgs;
  network.description = "my wobserver";
  network.enableRollback = true;

  terra-firma = {config, pkgs, ...}:
    {
      imports = [ serverCfg ../hosts/terra-firma ];
      deployment.targetHost = "terra-firma";
      system.stateVersion = "22.11";
    };
}

Terra Firma

Terra Firma is my Wobserver hosted by Wobscale Technologies in Seattle, WA.

{
  imports = [ ./hardware-configuration.nix ];

  networking.hostName = "terra-firma";
  boot.loader.grub.enable = true;
  # boot.loader.grub.device = "/dev/sde";
  boot.loader.grub.device = "/dev/sdf";

  networking.hostId = "628c9fc3"; # required for zfs use
  services.tailscale.authKey = "tskey-auth-kc6ULA7CNTRL-DwkDu5vJo2RrekxqbUHNxQP4LmMDnRjS3";
}
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ "ehci_pci" "ata_piix" "uhci_hcd" "xhci_pci" "usb_storage" "usbhid" "sd_mod" ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "terra-firma/root";
      fsType = "zfs";
    };

  fileSystems."/home" =
    { device = "tank/home";
      fsType = "zfs";
    };

  fileSystems."/media" =
    { device = "tank/media";
      fsType = "zfs";
    };

  fileSystems."/srv" =
    { device = "tank/srv";
      fsType = "zfs";
    };

  fileSystems."/nix" =
    { device = "terra-firma/nix";
      fsType = "zfs";
    };

  fileSystems."/boot" =
    { device = "/dev/disk/by-uuid/2C1E-582F";
      fsType = "vfat";
    };

  swapDevices =
    [ { device = "/dev/disk/by-uuid/1ee46640-6164-4882-a59d-aa260c7780a2"; }
    ];


  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
  # (the default) this is the recommended approach. When using systemd-networkd it's
  # still possible to use this option, but it's recommended to use it in conjunction
  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
  networking.useDHCP = lib.mkDefault true;
  # networking.interfaces.eno1.useDHCP = lib.mkDefault true;
  # networking.interfaces.eno2.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
  hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}