plain: one x86_64 target, no host branching
Drops the mbp (Asahi) target and everything that existed only to serve
two machines at once:
- apple-silicon input, firmware/ (87M of Mac Wi-Fi/BT blobs), hosts/mbp/
- the mkHost helper and the common-vs-host-module split, merged into one
`pc` module
- the osConfig.networking.hostName conditional that generated
hypr/monitors.conf per host -- the monitor layout, workspace placement
and panel float rule are now stated once, inline in hyprland.conf
- the aarch64 nixbuild.net builder and the aarch64 devShell
- Mac-only hyprland bits: the apple-spi-keyboard device block and the
touchpad input block
hosts/pc/hardware-configuration.nix moves to the repo root: with one
machine there is no host to namespace it under. The flake output stays
named `pc` so it matches networking.hostName, which means plain
`nixos-rebuild switch --flake ~/nixos` resolves it with no #target.
eww goes too. It only ever drew a battery popup (SUPER+R), and a battery
readout on a desktop with no battery is nothing.
Also fixes the services.logind.suspendKey/hibernateKey/lidSwitch rename
that eval has been warning about; the rendered logind.conf keeps the same
three Handle*=ignore directives.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e2085e0e86
commit
64a399597a
14 changed files with 103 additions and 409 deletions
62
README.md
62
README.md
|
|
@ -1,64 +1,48 @@
|
|||
# nixos
|
||||
|
||||
One flake, two machines. Hyprland + greetd autologin, Zen+Tridactyl, neovim, zsh+starship.
|
||||
|
||||
| host | arch | build |
|
||||
|------|------|-------|
|
||||
| `mbp` | aarch64 | MacBook M1 Pro (Asahi) |
|
||||
| `pc` | x86_64 | any UEFI x86 |
|
||||
One flake, one machine: x86_64 UEFI desktop. Hyprland + greetd autologin,
|
||||
Zen+Tridactyl, neovim, zsh+starship.
|
||||
|
||||
```
|
||||
flake.nix all config (common + home modules, both hosts)
|
||||
config/ raw configs: hypr eww fuzzel nvim
|
||||
hosts/*/hardware-configuration.nix mbp: regenerate on Mac · pc: generic, as-is
|
||||
firmware/ Mac Wi-Fi/BT blobs — git-add at install. KEEP REPO PRIVATE.
|
||||
flake.nix all config (the `pc` system module + the `home` module)
|
||||
hardware-configuration.nix generic x86_64 UEFI profile — mounts by label, as-is
|
||||
config/ raw configs: hypr fuzzel nvim
|
||||
```
|
||||
|
||||
Set `time.timeZone` in `common`. Rename a host = change the `nixosConfigurations.<name>` key + its `networking.hostName`.
|
||||
Set `time.timeZone` in the `pc` module. Monitors, workspace placement and
|
||||
keybinds live in `config/hypr/hyprland.conf`.
|
||||
|
||||
## Apply
|
||||
|
||||
The flake output is named after the hostname, so no `#target` is needed:
|
||||
|
||||
```sh
|
||||
sudo nixos-rebuild switch --flake ~/nixos#mbp # or #pc
|
||||
nix flake update && sudo nixos-rebuild switch --flake ~/nixos#mbp # update
|
||||
sudo nixos-rebuild switch --flake ~/nixos
|
||||
nix flake update && sudo nixos-rebuild switch --flake ~/nixos # update
|
||||
```
|
||||
Roll back = pick an older generation at boot.
|
||||
|
||||
## Install: MacBook (Asahi)
|
||||
## Install
|
||||
|
||||
Full/latest guide: <https://github.com/nix-community/nixos-apple-silicon/blob/main/docs/uefi-standalone.md>. **Back up — a bad partition can brick the Mac.**
|
||||
No hardware generation needed — `hardware-configuration.nix` is generic and
|
||||
mounts by the labels below. Boot the NixOS ISO, `sudo -i`:
|
||||
|
||||
1. macOS Terminal: `curl https://alx.sh | sh` → `r` resize (≥20 GB free) → `f` install **UEFI environment only**, name `NixOS` → recovery: permissive security. Reboots to U-Boot; power off.
|
||||
2. Installer USB (on a Linux+Nix box): `nix build github:nix-community/nixos-apple-silicon#installer-bootstrap -o installer` then `dd` the ISO to USB.
|
||||
3. Boot USB → `sudo su`:
|
||||
```sh
|
||||
sgdisk /dev/nvme0n1 -n 0:0 -s && sgdisk /dev/nvme0n1 -p # note new 8300 part, e.g. p5
|
||||
mkfs.ext4 -L nixos /dev/nvme0n1p5
|
||||
mount /dev/disk/by-label/nixos /mnt && mkdir -p /mnt/boot
|
||||
mount /dev/disk/by-partuuid/$(cat /proc/device-tree/chosen/asahi,efi-system-partition) /mnt/boot
|
||||
nixos-generate-config --root /mnt
|
||||
git clone <private-remote> /mnt/root/nixos && cd /mnt/root/nixos
|
||||
cp /mnt/etc/nixos/hardware-configuration.nix hosts/mbp/
|
||||
mkdir -p firmware && cp /mnt/boot/asahi/{all_firmware.tar.gz,kernelcache*} firmware/
|
||||
git add -f hosts/mbp/hardware-configuration.nix firmware/*
|
||||
nixos-install --flake .#mbp && reboot
|
||||
```
|
||||
|
||||
## Install: x86
|
||||
|
||||
No hardware generation — `hosts/pc/hardware-configuration.nix` is generic (mounts by label). Boot the NixOS ISO, `sudo -i`:
|
||||
```sh
|
||||
parted /dev/nvme0n1 -- mklabel gpt \
|
||||
mkpart ESP fat32 1MiB 512MiB set 1 esp on \
|
||||
mkpart primary 512MiB 100%
|
||||
mkfs.fat -F32 -n BOOT /dev/nvme0n1p1
|
||||
mkfs.ext4 -L nixos /dev/nvme0n1p2
|
||||
mount /dev/disk/by-label/nixos /mnt && mkdir -p /mnt/boot && mount /dev/disk/by-label/BOOT /mnt/boot
|
||||
mkfs.fat -F32 -n NIXBOOT /dev/nvme0n1p1
|
||||
mkfs.ext4 -L NIXROOT /dev/nvme0n1p2
|
||||
mount /dev/disk/by-label/NIXROOT /mnt && mkdir -p /mnt/boot
|
||||
mount /dev/disk/by-label/NIXBOOT /mnt/boot
|
||||
git clone <private-remote> /mnt/root/nixos && cd /mnt/root/nixos
|
||||
nixos-install --flake .#pc && reboot
|
||||
```
|
||||
Exotic storage controller won't boot? Add its module to `availableKernelModules` in `hosts/pc/hardware-configuration.nix` (`nixos-generate-config --show-hardware-config` lists it).
|
||||
Exotic storage controller won't boot? Add its module to
|
||||
`availableKernelModules` in `hardware-configuration.nix`
|
||||
(`nixos-generate-config --show-hardware-config` lists it).
|
||||
|
||||
## After first boot
|
||||
|
||||
`passwd` (ships `initialPassword = "changeme"`). If you land on a tty instead of Hyprland, change greetd's `uwsm start hyprland` → `Hyprland` in `common`.
|
||||
`passwd` (ships `initialPassword = "changeme"`). If you land on a tty instead
|
||||
of Hyprland, change greetd's `uwsm start hyprland` → `Hyprland`.
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
* {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
.battery-popup {
|
||||
background-color: #16181a;
|
||||
padding: 6px 10px;
|
||||
}
|
||||
|
||||
.battery-popup-text {
|
||||
font-family: monospace;
|
||||
font-size: 14px;
|
||||
color: #ddd;
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
(defpoll battery-percent :interval "10s" "scripts/battery-capacity")
|
||||
(defpoll battery-status :interval "10s" "scripts/battery-status")
|
||||
|
||||
(defwidget battery-popup []
|
||||
(box :class "battery-popup"
|
||||
:halign "center"
|
||||
:valign "center"
|
||||
(label :class "battery-popup-text"
|
||||
:text "${battery-percent}% ${battery-status}")))
|
||||
|
||||
(defwindow battery-popup
|
||||
:monitor 0
|
||||
:geometry (geometry :anchor "center")
|
||||
:stacking "overlay"
|
||||
:exclusive false
|
||||
:focusable false
|
||||
(battery-popup))
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Print the charge % of the first real battery. Portable across machines
|
||||
# (macsmc-battery on Asahi, BAT0/BAT1 on x86).
|
||||
for d in /sys/class/power_supply/*; do
|
||||
[ "$(cat "$d/type" 2>/dev/null)" = "Battery" ] || continue
|
||||
cat "$d/capacity" 2>/dev/null && exit 0
|
||||
done
|
||||
echo "?"
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
#!/bin/sh
|
||||
# Print the charging status of the first real battery. Portable across machines.
|
||||
for d in /sys/class/power_supply/*; do
|
||||
[ "$(cat "$d/type" 2>/dev/null)" = "Battery" ] || continue
|
||||
cat "$d/status" 2>/dev/null && exit 0
|
||||
done
|
||||
echo "Unknown"
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
# -- Monitors & input defaults --
|
||||
# Monitor layout is host-specific; written by the flake per host.
|
||||
source = ~/.config/hypr/monitors.conf
|
||||
# -- Monitors --
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LRFR, 2560x1440@60, 0x0, 1.0
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LPNY, 2560x1440@60, 2560x0, 1.0
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LRDD, 2560x1440@60, 5120x0, 1.0
|
||||
|
||||
device {
|
||||
name = apple-spi-keyboard
|
||||
kb_options = caps:ctrl_modifier,grp:win_space_toggle
|
||||
}
|
||||
# Each screen's home workspace; SUPER+ALT+h/l can still move it.
|
||||
workspace = 1, monitor:desc:Lenovo Group Limited P27q-20 V909LRFR, default:true
|
||||
workspace = 2, monitor:desc:Lenovo Group Limited P27q-20 V909LPNY, default:true
|
||||
workspace = 3, monitor:desc:Lenovo Group Limited P27q-20 V909LRDD, default:true
|
||||
|
||||
# -- Input --
|
||||
# TrackPoint (Corne nipple): hold middle button + move to scroll, joystick-style
|
||||
device {
|
||||
name = corne-tp
|
||||
|
|
@ -23,13 +25,6 @@ input {
|
|||
repeat_delay = 300
|
||||
accel_profile = custom
|
||||
scroll_points = 0.5 1.0 1.5 2.0 2.5
|
||||
touchpad {
|
||||
natural_scroll = true
|
||||
scroll_factor = 0.9
|
||||
tap-to-click = false
|
||||
clickfinger_behavior = true # 2-finger click = right-click, 3-finger = middle (Mac-like)
|
||||
disable_while_typing = true
|
||||
}
|
||||
}
|
||||
|
||||
general {
|
||||
|
|
@ -77,14 +72,11 @@ exec-once = uwsm finalize
|
|||
# also unlocks the keyring (see security.pam.services.hyprlock in flake.nix).
|
||||
exec-once = hyprlock
|
||||
exec-once = swaybg -c '#16181a'
|
||||
exec-once = GDK_BACKEND=wayland eww daemon
|
||||
exec-once = systemctl --user start hyprpolkitagent
|
||||
|
||||
# -- Core --
|
||||
bind = SUPER, Return, exec, kitty
|
||||
bind = SUPER, D, exec, fuzzel
|
||||
bind = SUPER, R, exec, eww open battery-popup
|
||||
bindr = SUPER, R, exec, eww close battery-popup
|
||||
bind = SUPER, Q, killactive
|
||||
bind = SUPER, F, fullscreen, 1
|
||||
bind = SUPER SHIFT, Space, togglefloating
|
||||
|
|
@ -97,9 +89,10 @@ bind = SUPER, A, exec, caffeine
|
|||
# Each gets its own app_id so the rule below floats only these and not every
|
||||
# terminal. Quit with the TUI's own `q`; no toggle wrapper.
|
||||
#
|
||||
# The float/size rule is in monitors.conf, generated per host: Hyprland 0.56
|
||||
# `size` takes ONLY absolute pixels -- percentages are silently ignored (they
|
||||
# parse fine and then do nothing), so the value depends on the resolution.
|
||||
# Hyprland 0.56 `size` takes ONLY absolute pixels -- percentages are silently
|
||||
# ignored (they parse fine and then do nothing), so this is 70% of 2560x1440.
|
||||
windowrule = match:class ^(panel-wifi|panel-bt)$, float on, size 1792 1440, center on
|
||||
|
||||
bind = SUPER, W, exec, kitty --class panel-wifi impala
|
||||
bind = SUPER, E, exec, kitty --class panel-bt bluetui
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
# Asahi peripheral firmware (vendored)
|
||||
|
||||
`hardware.asahi.peripheralFirmwareDirectory` points here. A **pure** flake
|
||||
cannot read `/boot/vendorfw`, so the Wi-Fi/Bluetooth firmware must live inside
|
||||
the repo tree and be git-tracked.
|
||||
|
||||
Since nixos-apple-silicon 66d8dd2 the module expects the pre-extracted
|
||||
`firmware.cpio` (placed on the ESP by the Asahi installer) instead of
|
||||
`all_firmware.tar.gz` + `kernelcache.*`.
|
||||
|
||||
## During install, on the Mac:
|
||||
|
||||
```sh
|
||||
cp /boot/vendorfw/firmware.cpio ~/.dotfiles/firmware/
|
||||
git -C ~/.dotfiles add -f firmware/firmware.cpio
|
||||
```
|
||||
|
||||
(They're `.gitignore`-exempt via `-f` if needed — but the flake only sees
|
||||
**tracked** files, so they must be added.)
|
||||
|
||||
## ⚠ Keep this repository PRIVATE
|
||||
|
||||
This firmware is **non-free and non-redistributable**. Do not push it to a
|
||||
public remote.
|
||||
|
||||
Until you copy these files in, `nixos-rebuild`/`nixos-install` will fail at the
|
||||
firmware-extraction step — that's expected, same as the placeholder
|
||||
`hardware-configuration.nix`.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
37
flake.lock
37
flake.lock
|
|
@ -1,26 +1,5 @@
|
|||
{
|
||||
"nodes": {
|
||||
"apple-silicon": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1785426242,
|
||||
"narHash": "sha256-QHAP8KsJQmI+dpNS/wfWAtEBQ0Zby+B0Ty+qZIO/U2w=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-apple-silicon",
|
||||
"rev": "66d8dd2c27f99bd5420c99938b60695aac1785c4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-apple-silicon",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"firefox-addons": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
|
@ -43,21 +22,6 @@
|
|||
"type": "gitlab"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"locked": {
|
||||
"lastModified": 1761640442,
|
||||
"narHash": "sha256-AtrEP6Jmdvrqiv4x2xa5mrtaIp3OEe8uBYCDZDS+hu8=",
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"rev": "4a56054d8ffc173222d09dad23adf4ba946c8884",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
|
|
@ -113,7 +77,6 @@
|
|||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"apple-silicon": "apple-silicon",
|
||||
"firefox-addons": "firefox-addons",
|
||||
"home-manager": "home-manager",
|
||||
"linear-tui-src": "linear-tui-src",
|
||||
|
|
|
|||
262
flake.nix
262
flake.nix
|
|
@ -1,14 +1,9 @@
|
|||
{
|
||||
description = "mads — NixOS for Apple Silicon (mbp) and x86 (pc), one flake";
|
||||
description = "mads — NixOS on x86_64, one flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
||||
apple-silicon = {
|
||||
url = "github:nix-community/nixos-apple-silicon";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
|
@ -34,7 +29,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, apple-silicon, home-manager, firefox-addons, zen-browser, linear-tui-src, ... }:
|
||||
outputs = { self, nixpkgs, home-manager, firefox-addons, zen-browser, linear-tui-src, ... }:
|
||||
let
|
||||
# linear-tui, built from the pinned source input above. Upstream ships no
|
||||
# flake and it is not in nixpkgs, but it has a committed Cargo.lock, so
|
||||
|
|
@ -55,48 +50,17 @@
|
|||
meta.mainProgram = "linear-tui";
|
||||
};
|
||||
|
||||
# ───────────────────── shared home-manager user ─────────────────────
|
||||
home = { pkgs, osConfig, ... }: {
|
||||
# ───────────────────────── home-manager user ─────────────────────────
|
||||
home = { pkgs, ... }: {
|
||||
imports = [ zen-browser.homeModules.beta ];
|
||||
home.stateVersion = "25.11";
|
||||
|
||||
programs.eww = {
|
||||
enable = true;
|
||||
package = pkgs.eww;
|
||||
};
|
||||
|
||||
# Raw configs that stay files (no good native module).
|
||||
# `hypr` is recursive so we can drop a host-specific monitors.conf in
|
||||
# alongside the shared files (hyprland.conf `source`s it).
|
||||
xdg.configFile = {
|
||||
"hypr" = { source = ./config/hypr; recursive = true; };
|
||||
"hypr/monitors.conf".text =
|
||||
if osConfig.networking.hostName == "mbp"
|
||||
then ''
|
||||
monitor = , preferred, auto, 2.0
|
||||
|
||||
# Floating TUI panels: 70% wide, full height. Absolute px because
|
||||
# Hyprland 0.56 ignores percentages in `size`. 1728x1080 logical.
|
||||
windowrule = match:class ^(panel-wifi|panel-bt)$, float on, size 1210 1080, center on
|
||||
''
|
||||
else ''
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LRFR, 2560x1440@60, 0x0, 1.0
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LPNY, 2560x1440@60, 2560x0, 1.0
|
||||
monitor = desc:Lenovo Group Limited P27q-20 V909LRDD, 2560x1440@60, 5120x0, 1.0
|
||||
|
||||
# Each screen's home workspace; SUPER+ALT+h/l can still move it.
|
||||
workspace = 1, monitor:desc:Lenovo Group Limited P27q-20 V909LRFR, default:true
|
||||
workspace = 2, monitor:desc:Lenovo Group Limited P27q-20 V909LPNY, default:true
|
||||
workspace = 3, monitor:desc:Lenovo Group Limited P27q-20 V909LRDD, default:true
|
||||
|
||||
# Same panels, sized for 2560x1440 logical.
|
||||
windowrule = match:class ^(panel-wifi|panel-bt)$, float on, size 1792 1440, center on
|
||||
'';
|
||||
"eww".source = ./config/eww;
|
||||
"hypr".source = ./config/hypr;
|
||||
"fuzzel".source = ./config/fuzzel;
|
||||
};
|
||||
|
||||
|
||||
# Launcher hygiene. These .desktop entries ship with packages we do want,
|
||||
# but they are noise in fuzzel. A NoDisplay entry in XDG_DATA_HOME
|
||||
# shadows the package's own copy, which is the only way to hide one
|
||||
|
|
@ -125,7 +89,7 @@
|
|||
# Notification daemon. Nothing owned org.freedesktop.Notifications before
|
||||
# this, so notify-send failed outright: hyprshot's "Screenshot saved"
|
||||
# toasts went nowhere, and kitty logged a DBus ServiceUnknown error on
|
||||
# every launch. Colours match the cyberdream kitty theme above.
|
||||
# every launch. Colours match the cyberdream kitty theme below.
|
||||
services.mako = {
|
||||
enable = true;
|
||||
settings = {
|
||||
|
|
@ -222,7 +186,7 @@
|
|||
];
|
||||
};
|
||||
|
||||
# Zen browser + Tridactyl, extensions pinned (works on aarch64 + x86).
|
||||
# Zen browser + Tridactyl, extensions pinned.
|
||||
programs.zen-browser = {
|
||||
enable = true;
|
||||
setAsDefaultBrowser = true;
|
||||
|
|
@ -263,8 +227,6 @@
|
|||
};
|
||||
programs.starship.enable = true;
|
||||
|
||||
|
||||
|
||||
# SSH auth via the 1Password agent — private keys stay in the vault,
|
||||
# never on disk or in the Nix store.
|
||||
programs.ssh = {
|
||||
|
|
@ -294,8 +256,11 @@
|
|||
home.packages = with pkgs; [ ripgrep fd tridactyl-native lazygit rustc cargo clippy rustfmt rust-analyzer claude-code gcc bluetui impala postgresql fastfetch (linearTui pkgs) ];
|
||||
};
|
||||
|
||||
# ───────────────────── shared system (both hosts) ─────────────────────
|
||||
common = { pkgs, ... }: {
|
||||
# ──────────────────────────── the machine ────────────────────────────
|
||||
pc = { config, pkgs, ... }: {
|
||||
networking.hostName = "pc";
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
# Trusted so client-side nix config takes effect — substituters and
|
||||
# remote builders are trusted settings, silently ignored for anyone
|
||||
|
|
@ -315,9 +280,7 @@
|
|||
# the only form the calling process cannot read.
|
||||
nix.settings.netrc-file = "/etc/nix/netrc";
|
||||
|
||||
# x86_64 derivations build off this machine rather than under local
|
||||
# qemu emulation, and aarch64 ones go out too when the local
|
||||
# machine is busy.
|
||||
# Big builds go out to other machines rather than tying this one up.
|
||||
#
|
||||
# The host keys are pinned system-wide because the ssh'ing party is
|
||||
# the root daemon, which has no known_hosts and never gets a tty to
|
||||
|
|
@ -342,8 +305,8 @@
|
|||
maxJobs = 16;
|
||||
supportedFeatures = [ "big-parallel" "kvm" "nixos-test" ];
|
||||
}
|
||||
# nixbuild.net, for both architectures. Listed after `builder` so
|
||||
# the machine we already pay for is preferred.
|
||||
# nixbuild.net. Listed after `builder` so the machine we already pay
|
||||
# for is preferred.
|
||||
#
|
||||
# Every feature it supports is advertised, not just the two in the
|
||||
# quickstart: nix only sends a derivation to a builder claiming
|
||||
|
|
@ -358,15 +321,6 @@
|
|||
maxJobs = 100;
|
||||
supportedFeatures = [ "benchmark" "big-parallel" "ca-derivations" "kvm" "nixos-test" ];
|
||||
}
|
||||
{
|
||||
hostName = "eu.nixbuild.net";
|
||||
sshUser = "root";
|
||||
sshKey = "/home/mads/.ssh/id_ed25519";
|
||||
protocol = "ssh-ng";
|
||||
system = "aarch64-linux";
|
||||
maxJobs = 100;
|
||||
supportedFeatures = [ "benchmark" "big-parallel" "ca-derivations" "kvm" "nixos-test" ];
|
||||
}
|
||||
];
|
||||
|
||||
# iwd owns Wi-Fi (driven from impala, which is iwd-only); networkd does
|
||||
|
|
@ -377,6 +331,19 @@
|
|||
networking.useNetworkd = true; # DHCP on any ethernet/wifi by default
|
||||
systemd.network.wait-online.anyInterface = true; # one link up is enough
|
||||
|
||||
# GigE camera link: static, never a route out. The segment also
|
||||
# carries AAU's IPv6 RAs, and taking them made v6 traffic default
|
||||
# out this port into a dead end.
|
||||
networking.interfaces.enp7s0 = {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [ { address = "192.168.12.1"; prefixLength = 24; } ];
|
||||
};
|
||||
systemd.network.networks."40-enp7s0" = {
|
||||
networkConfig.IPv6AcceptRA = false;
|
||||
networkConfig.ConfigureWithoutCarrier = true; # camera may be off
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
};
|
||||
|
||||
# iwd only reads /var/lib/iwd. C = copy once, so a password added to
|
||||
# the file later (or via impala) is never overwritten.
|
||||
systemd.tmpfiles.rules = [
|
||||
|
|
@ -454,12 +421,25 @@
|
|||
};
|
||||
};
|
||||
|
||||
# Desktop: never suspend or hibernate, even if something asks.
|
||||
systemd.sleep.settings.Sleep = {
|
||||
AllowSuspend = "no";
|
||||
AllowHibernation = "no";
|
||||
AllowHybridSleep = "no";
|
||||
AllowSuspendThenHibernate = "no";
|
||||
};
|
||||
# Ignore the keys that would normally trigger sleep.
|
||||
services.logind.settings.Login = {
|
||||
HandleSuspendKey = "ignore";
|
||||
HandleHibernateKey = "ignore";
|
||||
HandleLidSwitch = "ignore";
|
||||
};
|
||||
|
||||
xdg.portal = {
|
||||
enable = true;
|
||||
extraPortals = [ pkgs.xdg-desktop-portal-hyprland ];
|
||||
};
|
||||
|
||||
|
||||
# greetd autologins mads straight into Hyprland (via uwsm).
|
||||
services.greetd = {
|
||||
enable = true;
|
||||
|
|
@ -469,6 +449,19 @@
|
|||
};
|
||||
};
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true; # normal x86 UEFI
|
||||
|
||||
# NVIDIA (RTX 20-series or newer → open kernel module).
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics.enable = true; # OpenGL/Vulkan userspace (was hardware.opengl)
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true; # required for Wayland/Hyprland
|
||||
open = true; # open kernel module (Turing+)
|
||||
nvidiaSettings = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.stable;
|
||||
};
|
||||
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
hardware.bluetooth.enable = true;
|
||||
|
|
@ -536,151 +529,20 @@
|
|||
home-manager.users.mads = home;
|
||||
};
|
||||
|
||||
mkHost = { system, modules }: nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
modules = [
|
||||
home-manager.nixosModules.home-manager
|
||||
common
|
||||
({ pkgs, ... }: {
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
})
|
||||
] ++ modules;
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
nixosConfigurations = {
|
||||
# ── Apple Silicon MacBook (Asahi) ──
|
||||
mbp = mkHost {
|
||||
system = "aarch64-linux";
|
||||
modules = [
|
||||
apple-silicon.nixosModules.apple-silicon-support
|
||||
./hosts/mbp/hardware-configuration.nix # generated on the Mac
|
||||
({ ... }: {
|
||||
networking.hostName = "mbp";
|
||||
|
||||
# Wi-Fi/BT firmware, vendored (a pure flake can't read /boot/asahi).
|
||||
hardware.asahi.peripheralFirmwareDirectory = ./firmware;
|
||||
hardware.asahi.enable = true;
|
||||
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.systemd-boot.configurationLimit = 3; # 500M ESP is small
|
||||
boot.extraModprobeConfig = "options hid_apple fnmode=1";
|
||||
boot.blacklistedKernelModules = [ "pcspkr" ];
|
||||
|
||||
# Root is btrfs (p8). A scrub re-reads every block and verifies its
|
||||
# checksum, which is the only way bit rot on this SSD surfaces before
|
||||
# something tries to read the damaged file. Metadata is DUP, so a bad
|
||||
# metadata block gets repaired from its copy automatically.
|
||||
services.btrfs.autoScrub = {
|
||||
enable = true;
|
||||
interval = "monthly";
|
||||
fileSystems = [ "/" ];
|
||||
};
|
||||
|
||||
# 15G of RAM and no swap at all: a `nixos-rebuild` forks ~60 nix
|
||||
# evaluators, and stacked on a browser and a few editor sessions
|
||||
# that was enough to exhaust it. The kernel then OOM-killed a
|
||||
# process inside wayland-wm@hyprland.service, and systemd's default
|
||||
# OOMPolicy=stop tore the whole graphical session down with it.
|
||||
#
|
||||
# zram rather than a swapfile, because root is compress=zstd and a
|
||||
# btrfs swapfile needs its own nodatacow, uncompressed subvolume.
|
||||
zramSwap = {
|
||||
enable = true;
|
||||
memoryPercent = 50; # 7.6G of backing store, ~a third of that in real RAM
|
||||
};
|
||||
|
||||
# Swapping to RAM is cheap, so let the kernel compress anon pages
|
||||
# rather than evict page cache. At the OOM above, cache had already
|
||||
# been squeezed to 40M while 13G sat in anon and nothing was
|
||||
# reclaimable — the default swappiness of 60 gets that backwards here.
|
||||
boot.kernel.sysctl = {
|
||||
"vm.swappiness" = 180;
|
||||
"vm.page-cluster" = 0; # zram has no seek penalty, so no readahead
|
||||
};
|
||||
|
||||
# Build x86_64 derivations (packing-station iso/deploys) via qemu.
|
||||
boot.binfmt.emulatedSystems = [ "x86_64-linux" ];
|
||||
|
||||
# Resolve .local names, so the packing stations can be reached and
|
||||
# deployed to by hostname instead of by address.
|
||||
services.avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
};
|
||||
services.resolved.settings.Resolve.MulticastDNS = false; # avahi owns mDNS
|
||||
|
||||
# Asahi kernel + Mesa cache, and the Raspberry Pi vendor
|
||||
# kernel/firmware cache (else both compile from source).
|
||||
nix.settings = {
|
||||
extra-substituters = [
|
||||
"https://nixos-apple-silicon.cachix.org"
|
||||
"https://nixos-raspberrypi.cachix.org"
|
||||
];
|
||||
extra-trusted-public-keys = [
|
||||
"nixos-apple-silicon.cachix.org-1:8psDu5SA5dAD7qA0zMy5UT292TxeEPzIz8VVEr2Js20="
|
||||
"nixos-raspberrypi.cachix.org-1:4iMO9LXa8BqhU+Rpg6LQKiGa2lsNh/j2oiYLNOQ5sPI="
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
# ── Arbitrary x86_64 PC ──
|
||||
pc = mkHost {
|
||||
nixosConfigurations.pc = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
./hosts/pc/hardware-configuration.nix # generated on the PC
|
||||
({ config, ... }: {
|
||||
networking.hostName = "pc";
|
||||
|
||||
# GigE camera link: static, never a route out. The segment also
|
||||
# carries AAU's IPv6 RAs, and taking them made v6 traffic default
|
||||
# out this port into a dead end.
|
||||
networking.interfaces.enp7s0 = {
|
||||
useDHCP = false;
|
||||
ipv4.addresses = [ { address = "192.168.12.1"; prefixLength = 24; } ];
|
||||
};
|
||||
systemd.network.networks."40-enp7s0" = {
|
||||
networkConfig.IPv6AcceptRA = false;
|
||||
networkConfig.ConfigureWithoutCarrier = true; # camera may be off
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
};
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true; # normal x86 UEFI
|
||||
|
||||
# Desktop: never suspend or hibernate, even if something asks.
|
||||
systemd.sleep.settings.Sleep = {
|
||||
AllowSuspend = "no";
|
||||
AllowHibernation = "no";
|
||||
AllowHybridSleep = "no";
|
||||
AllowSuspendThenHibernate = "no";
|
||||
};
|
||||
# Ignore the keys that would normally trigger sleep.
|
||||
services.logind.suspendKey = "ignore";
|
||||
services.logind.hibernateKey = "ignore";
|
||||
services.logind.lidSwitch = "ignore";
|
||||
|
||||
# NVIDIA (RTX 20-series or newer → open kernel module).
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
hardware.graphics.enable = true; # OpenGL/Vulkan userspace (was hardware.opengl)
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true; # required for Wayland/Hyprland
|
||||
open = true; # open kernel module (Turing+)
|
||||
nvidiaSettings = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.stable;
|
||||
};
|
||||
})
|
||||
home-manager.nixosModules.home-manager
|
||||
./hardware-configuration.nix
|
||||
pc
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# `nix develop` on either arch.
|
||||
devShells = nixpkgs.lib.genAttrs [ "aarch64-linux" "x86_64-linux" ] (system: {
|
||||
default = nixpkgs.legacyPackages.${system}.mkShell {
|
||||
packages = [ nixpkgs.legacyPackages.${system}.nodejs ];
|
||||
devShells.x86_64-linux.default =
|
||||
nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
||||
packages = [ nixpkgs.legacyPackages.x86_64-linux.nodejs ];
|
||||
};
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "usb_storage" "sdhci_pci" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# Root lives on nvme0n1p8 (btrfs, subvol @) — the 256G reclaimed from
|
||||
# the shrunk macOS container. The old ext4 p5 is kept as a rollback until
|
||||
# it is added to this pool as a second device.
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/c828c1a0-ce7b-4e27-b8e4-bce032bb30bf";
|
||||
fsType = "btrfs";
|
||||
options = [ "subvol=@" "compress=zstd" "noatime" ];
|
||||
};
|
||||
|
||||
fileSystems."/boot" =
|
||||
{ device = "/dev/disk/by-uuid/0BB8-A960";
|
||||
fsType = "vfat";
|
||||
options = [ "fmask=0022" "dmask=0022" ];
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||
}
|
||||
Loading…
Reference in a new issue