Skip to content

Latest commit

 

History

16 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Workstation Setup

Nix-darwin flake that manages macOS system configuration, Homebrew apps, and user environment via Home Manager. Supports multiple machines from a single repo.

Prerequisites

New machine setup

1. Install Nix

curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

Open a new terminal after installation.

2. Clone and configure

git clone git@github.com:sgpbyrne/workstation-setup.git ~/dev/workstation-setup
cd ~/dev/workstation-setup
cp hosts-config.nix.template hosts-config.nix

Edit hosts-config.nix with your values:

  • hostname -- run scutil --get LocalHostName to find it
  • username -- your macOS username
  • gitName / gitEmail -- your git identity
  • clusters -- your AKS cluster details (see template for format)

Track the file for Nix flakes (required), then hide local changes from git:

git add hosts-config.nix
git update-index --skip-worktree hosts-config.nix

3. Fix SSL certs (corporate network only)

If your network uses a TLS-intercepting proxy, Nix fails with SSL errors. There are three distinct knobs, and all three must be set before the first build:

  1. The Nix daemon's own downloads (substituters) use ssl-cert-file in nix.conf.
  2. In-build fetchers (fetchgit/fetchurl) read NIX_SSL_CERT_FILE from the daemon's environment — a separate knob from ssl-cert-file.
  3. The macOS build sandbox blocks builds from reading the cert file at all.

The key insight: the proxy presents host certs signed by a single corporate root CA (here, untrust.loc). Trust that root once and every proxied host verifies. Trusting a per-host leaf (e.g. just cache.nixos.org) only fixes that one host and silently breaks any build that fetches from elsewhere.

a) Save the proxy ROOT CA to /etc/nix/proxy-cert.pem:

This is the file the activation script consumes on every rebuild. Grab the proxy's CA chain (everything past the per-host leaf) from any HTTPS host:

echo | /usr/bin/openssl s_client -showcerts -connect cache.nixos.org:443 </dev/null 2>/dev/null \
  | awk '/-----BEGIN CERTIFICATE-----/{n++} n>1' \
  | sudo tee /etc/nix/proxy-cert.pem >/dev/null
# (optional) also make it visible to other system tools
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /etc/nix/proxy-cert.pem

b) Point the daemon at a proxy-inclusive bundle (for in-build fetches):

# Build a stable bundle: standard CAs + the proxy root
cat /etc/nix/macos-keychain.crt /etc/nix/proxy-cert.pem | sudo tee /etc/nix/ca-bundle-proxy.crt >/dev/null

# Set the daemon's NIX_SSL_CERT_FILE via its launchd plist (SIP blocks `launchctl setenv`)
PLIST=/Library/LaunchDaemons/systems.determinate.nix-daemon.plist
sudo /usr/libexec/PlistBuddy -c "Add :EnvironmentVariables dict" "$PLIST" 2>/dev/null
sudo /usr/libexec/PlistBuddy -c "Add :EnvironmentVariables:NIX_SSL_CERT_FILE string /etc/nix/ca-bundle-proxy.crt" "$PLIST" \
  || sudo /usr/libexec/PlistBuddy -c "Set :EnvironmentVariables:NIX_SSL_CERT_FILE /etc/nix/ca-bundle-proxy.crt" "$PLIST"

c) Disable the macOS sandbox and reload the daemon:

echo 'sandbox = false' | sudo tee -a /etc/nix/nix.custom.conf
sudo launchctl bootout system "$PLIST" 2>/dev/null; sudo launchctl bootstrap system "$PLIST"

Verify a build now sees the cert (should print the path, not nothing):

nix-build --no-out-link --expr 'derivation {
  name = "ssl-probe"; system = builtins.currentSystem; builder = "/bin/sh";
  args = ["-c" "export -p; exit 1"];
  impureEnvVars = ["NIX_SSL_CERT_FILE"];
  outputHashMode = "flat"; outputHashAlgo = "sha256";
  outputHash = "0000000000000000000000000000000000000000000000000000000000000000";
}' 2>&1 | grep NIX_SSL_CERT_FILE

These steps are only needed once before the first build. After that, the activation script (hosts/common/default.nix) reads /etc/nix/proxy-cert.pem and re-asserts both the bundle and the daemon plist env on every rebuild — surviving Determinate regenerating its own cert bundle.

4. First build

darwin-rebuild doesn't exist yet, so bootstrap with:

nix run nix-darwin -- switch --flake ~/dev/workstation-setup#personal-mac

Replace personal-mac with your config name (the key in hosts-config.nix).

Open a new terminal after this completes to pick up the new shell config.

5. Set up Kubernetes (if applicable)

kube-init

This logs into Azure (if needed) and fetches credentials for all configured AKS clusters. Use kubectx to switch between them.

Day-to-day usage

Applying changes

rebuild

This alias runs darwin-rebuild switch and reloads the shell. It's available after the first build.

Pulling upstream changes

git-sync

This handles the skip-worktree dance for hosts-config.nix automatically -- stashes your local values, pulls, pops the stash, and re-applies skip-worktree.

Updating dependencies

nix flake update

Updates all flake inputs (nixpkgs, home-manager, nix-darwin, etc.) to latest. Review with git diff flake.lock before rebuilding.

Debugging

Add --show-trace for full error traces:

sudo darwin-rebuild switch --flake ~/dev/workstation-setup#personal-mac --show-trace

Common issues:

  • "Path not tracked by Git" - new files must be git added before Nix can see them. Nix flakes only see files tracked by git.
  • "attribute not found" - usually a typo in a module argument or a missing specialArgs value. Check that the function signature in the failing .nix file matches what's passed in flake.nix.
  • Homebrew zap removing apps - onActivation.cleanup = "zap" removes anything not declared. If an app disappears after rebuild, add it to the appropriate homebrew.nix.
  • SSL cert errors in Nix - on a corporate network, run the cert fix from step 3 above. nix flake update/substituters use ssl-cert-file; in-build fetches (a build cloning a git repo) instead need NIX_SSL_CERT_FILE set on the daemon's environment and sandbox = false. To see what a build actually gets, use the ssl-probe snippet in step 3.
  • SSL errors after a Determinate update - a daemon update can rewrite the launchd plist and drop the NIX_SSL_CERT_FILE env. Run rebuild (the activation script re-asserts it in the plist), then reload the daemon or reboot for it to take effect. A plain reboot alone is fine — the plist env and /etc/nix/ca-bundle-proxy.crt both persist.

Adding a new machine

  1. Create a host directory with default.nix and homebrew.nix:
mkdir hosts/<name>
# hosts/<name>/default.nix
{ ... }:
{
  imports = [
    ../common
    ./homebrew.nix
  ];
}
# hosts/<name>/homebrew.nix
{ ... }:
{
  homebrew = {
    casks = [];
    brews = [];
  };
}
  1. Add the host to hosts-config.nix.template (with placeholders) and your local hosts-config.nix (with real values).

  2. Add the configuration to flake.nix:

darwinConfigurations."<name>" = mkDarwin "<name>" hosts.<name>;
  1. Stage and build:
git add hosts/<name> hosts-config.nix.template flake.nix
nix run nix-darwin -- switch --flake ~/dev/workstation-setup#<name>

Adding apps

To all machines - add to hosts/common/homebrew.nix

To one machine - add to that host's homebrew.nix

CLI tools via Nix - add to the relevant file under home/programs/ (cli-tools.nix, devops.nix, etc.)

About

This repo contains the dev configuration for my macbook

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages