Initial NixOS flake: Hyprland (end-4 illogical-impulse), NVIDIA, gaming, dev tools

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C5ydBQk68JYw8HXzUDLAyV
This commit is contained in:
2026-07-18 15:41:54 +01:00
commit d14196dcde
10 changed files with 368 additions and 0 deletions

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

88
README.md Normal file
View File

@@ -0,0 +1,88 @@
# nixos-pc
NixOS flake for the desktop PC: Hyprland with [end-4's illogical-impulse](https://github.com/end-4/dots-hyprland) via [soymou/illogical-flake](https://github.com/soymou/illogical-flake), NVIDIA RTX 3080, Steam/gaming, dev tools.
- Host: `nixos-pc` · User: `zephrynis` · Channel: nixos-unstable
- Boot: systemd-boot on this install's **own ESP** on the 1TB WD SSD; **rEFInd** (on the 2TB NVMe's ESP) remains the top-level OS picker and auto-detects it.
```
hosts/nixos-pc/ host wiring, bootloader, user, hardware config
modules/ core, desktop (hyprland/sddm/fonts), nvidia, gaming
home/zephrynis.nix illogical-impulse + git/direnv/vscode/CLI tools
```
Rebuild after changes: `sudo nixos-rebuild switch --flake .#nixos-pc`
Update inputs (one at a time is safer): `nix flake update <input>`
---
## Install procedure
Target: ~250GB shrunk from the work-Windows partition on the **1TB WD SA500 SATA SSD**. The work Windows on that disk and everything on the 2TB NVMe (other Windows, Arch, rEFInd's ESP) must not be touched.
### 1. Prep (from the work Windows)
1. Back up anything important. If BitLocker is enabled on C:, **export the recovery key** and suspend BitLocker before repartitioning.
2. Disable Fast Startup: `powercfg /h off` (admin) — otherwise NTFS is left dirty.
3. Shrink C: by ~256000 MB: Disk Management → right-click C: → Shrink Volume. If it won't shrink enough (unmovable files): temporarily disable pagefile + System Restore on C:, reboot, retry, re-enable after.
4. Push this repo somewhere reachable from the ISO (GitHub) or copy to a USB stick. **Flakes only evaluate git-tracked files** — commit everything.
5. BIOS: disable Secure Boot (stock NixOS bootloader is unsigned). F11 = one-time boot menu.
### 2. Partition & install (NixOS ISO, UEFI mode)
```sh
ls /sys/firmware/efi # must exist (UEFI mode)
lsblk -o NAME,SIZE,FSTYPE,LABEL,MODEL # identify disks
```
The 1TB WD (WDS100T1R0A) is likely `/dev/sda`. **Do not touch any NTFS partition, and nothing on the NVMe.** In the ~250G free space (parted `unit GiB`, `print free` to see exact bounds):
```sh
parted /dev/sda -- mkpart ESP fat32 <freeStart> <freeStart+1GiB>
parted /dev/sda -- set <N> esp on
parted /dev/sda -- mkpart root ext4 <freeStart+1GiB> 100%
mkfs.fat -F 32 -n NIXBOOT /dev/sdaX # the new 1GiB partition
mkfs.ext4 -L nixos /dev/sdaY # the new large partition
mount /dev/disk/by-label/nixos /mnt
mkdir -p /mnt/boot
mount -o umask=0077 /dev/disk/by-label/NIXBOOT /mnt/boot
```
Get the flake and the real hardware config:
```sh
git clone <this-repo-url> /mnt/etc/nixos # or copy from USB
nixos-generate-config --root /mnt
mv /mnt/etc/nixos/hardware-configuration.nix /mnt/etc/nixos/hosts/nixos-pc/hardware-configuration.nix
rm /mnt/etc/nixos/configuration.nix
git -C /mnt/etc/nixos add -A
```
Install (needs network — ethernet just works, else `nmtui`):
```sh
nixos-install --flake /mnt/etc/nixos#nixos-pc # sets root password at the end
nixos-enter --root /mnt -c 'passwd zephrynis'
reboot
```
### 3. After first boot
1. rEFInd should show a new NixOS/systemd-boot entry (it scans all ESPs). Windows and Arch entries must still work.
2. If the firmware now boots straight into systemd-boot instead of rEFInd, fix the order from NixOS: `efibootmgr` to list, `sudo efibootmgr -o XXXX,YYYY,...` with rEFInd first.
3. Optional rEFInd polish (edit `refind.conf` on the NVMe ESP): a `menuentry` stanza for a custom NixOS name/icon, and `dont_scan_files`/`dont_scan_dirs` to hide duplicate auto-detected kernel entries from the NIXBOOT ESP.
4. Checks: `nvidia-smi`; `cat /sys/module/nvidia_drm/parameters/modeset``Y`; Hyprland session in SDDM; quickshell bar appears (Super for launcher); Steam runs a Proton title.
- If the `qs` (quickshell) binary is missing, add `inputs.illogical-flake.inputs.quickshell.packages.x86_64-linux.default` to `home.packages` and rebuild.
- Cursor invisible/glitchy: enable Hyprland `cursor:no_hardware_cursors = true`, or the commented `WLR_NO_HARDWARE_CURSORS` fallback in `modules/nvidia.nix`.
### Follow-up (someday): separate rEFInd entries for the two Windows installs
Both Windows currently share one Windows Boot Manager/BCD on the NVMe ESP, so rEFInd shows a single Windows entry with a second picker behind it. The new ESP on the 1TB SSD makes splitting easy:
1. From the **work Windows**, assign the NIXBOOT ESP a letter (e.g. `S:` via `diskpart``assign`), then:
`bcdboot C:\Windows /s S: /f UEFI`
This creates an independent Windows Boot Manager + BCD on the 1TB SSD's ESP that boots only the work OS. 1GiB is plenty for both this and NixOS's kernels.
2. rEFInd then shows two distinct Windows Boot Manager entries (one per ESP).
3. Remove the work OS's entry from the old shared BCD (`msconfig` → Boot tab, or `bcdedit /delete <id>`) so each menu boots exactly one Windows.

40
flake.nix Normal file
View File

@@ -0,0 +1,40 @@
{
description = "nixos-pc NixOS + Hyprland (end-4 illogical-impulse)";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
# end-4 dots-hyprland (illogical-impulse) home-manager port
illogical-flake = {
url = "github:soymou/illogical-flake";
inputs.nixpkgs.follows = "nixpkgs";
# To pin or fork the end-4 dotfiles themselves, override the port's
# `dotfiles` input (this is the only source-override mechanism):
# inputs.dotfiles.url = "git+https://github.com/end-4/dots-hyprland?submodules=1&rev=<sha>";
};
};
outputs = { nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.nixos-pc = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; };
modules = [
./hosts/nixos-pc
home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.extraSpecialArgs = { inherit inputs; };
home-manager.backupFileExtension = "hm-bak";
home-manager.users.zephrynis = import ./home/zephrynis.nix;
}
];
};
};
}

47
home/zephrynis.nix Normal file
View File

@@ -0,0 +1,47 @@
{ inputs, pkgs, ... }:
{
imports = [ inputs.illogical-flake.homeManagerModules.default ];
home.username = "zephrynis";
home.homeDirectory = "/home/zephrynis";
# Matches the release era of system.stateVersion; never change afterwards.
home.stateVersion = "25.11";
programs.illogical-impulse = {
enable = true;
# All default to true — listed for discoverability
dotfiles = {
fish.enable = true;
kitty.enable = true;
starship.enable = true;
};
# hyprland.plugins = [ ]; # listOf package, loaded via hyprland's plugin mechanism
};
programs.git = {
enable = true;
userName = "zephrynis";
userEmail = "zephrynis.yt@gmail.com";
};
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
programs.vscode.enable = true;
home.packages = with pkgs; [
ripgrep
fd
fzf
jq
btop
eza
bat
tree
nixfmt-rfc-style
nil # Nix LSP
];
}

View File

@@ -0,0 +1,39 @@
{ pkgs, ... }:
{
imports = [
./hardware-configuration.nix
../../modules/core.nix
../../modules/desktop.nix
../../modules/nvidia.nix
../../modules/gaming.nix
];
networking.hostName = "nixos-pc";
# systemd-boot lives on this install's OWN ESP (on the 1TB WD SSD) and only
# serves NixOS generations. rEFInd on the NVMe ESP stays the top-level OS
# picker and auto-detects this as a new entry — do not add Windows/Arch
# entries here.
boot.loader = {
systemd-boot = {
enable = true;
configurationLimit = 10;
};
efi.canTouchEfiVariables = true;
};
users.users.zephrynis = {
isNormalUser = true;
description = "zephrynis";
extraGroups = [ "wheel" "networkmanager" "video" "input" ];
shell = pkgs.fish; # end-4 dots are fish-centric
};
programs.fish.enable = true;
time.timeZone = "Europe/London";
i18n.defaultLocale = "en_GB.UTF-8";
# Set to the NixOS release of the ISO used at install time; never change afterwards.
system.stateVersion = "25.11";
}

View File

@@ -0,0 +1,26 @@
# PLACEHOLDER — on install day, overwrite this file with the one produced by
# nixos-generate-config --root /mnt
# (it lands in /mnt/etc/nixos/hardware-configuration.nix), then `git add` it —
# flakes only evaluate tracked files. The generated file adds the correct
# boot.initrd.availableKernelModules for this machine.
#
# The labels below match the mkfs commands in README.md (mkfs.ext4 -L nixos,
# mkfs.fat -n NIXBOOT), so this stub is bootable even before replacement.
{ ... }:
{
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-label/NIXBOOT";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};
swapDevices = [ ]; # 128GB RAM — no swap
hardware.cpu.intel.updateMicrocode = true;
}

47
modules/core.nix Normal file
View File

@@ -0,0 +1,47 @@
{ pkgs, ... }:
{
nix.settings = {
experimental-features = [ "nix-command" "flakes" ];
auto-optimise-store = true;
trusted-users = [ "root" "@wheel" ];
};
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 14d";
};
nixpkgs.config.allowUnfree = true;
networking.networkmanager.enable = true; # required by illogical-flake
hardware.bluetooth = {
enable = true;
powerOnBoot = true;
};
services.pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
};
security.rtkit.enable = true;
services.fstrim.enable = true;
# Read the Windows/data partitions when needed
boot.supportedFilesystems = [ "ntfs" ];
environment.systemPackages = with pkgs; [
wget
curl
file
unzip
p7zip
pciutils
usbutils
efibootmgr # check/fix boot order so rEFInd stays first
];
}

31
modules/desktop.nix Normal file
View File

@@ -0,0 +1,31 @@
{ pkgs, ... }:
{
# System-side requirements of illogical-flake (the HM module does the rest)
programs.hyprland.enable = true;
services.geoclue2.enable = true; # QtPositioning — weather / night light widgets
services.displayManager.sddm = {
enable = true;
wayland.enable = true;
};
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; # file pickers etc.
security.polkit.enable = true;
programs.dconf.enable = true;
services.gvfs.enable = true;
services.udisks2.enable = true;
services.upower.enable = true;
fonts.packages = with pkgs; [
# named by the illogical-flake README
rubik
nerd-fonts.ubuntu
nerd-fonts.jetbrains-mono
material-symbols
noto-fonts
noto-fonts-cjk-sans
noto-fonts-color-emoji
];
}

19
modules/gaming.nix Normal file
View File

@@ -0,0 +1,19 @@
{ pkgs, ... }:
{
programs.steam = {
enable = true;
remotePlay.openFirewall = true;
gamescopeSession.enable = true; # "Steam (gamescope)" session in SDDM
extraCompatPackages = [ pkgs.proton-ge-bin ];
};
programs.gamemode.enable = true;
programs.gamescope.enable = true;
# programs.gamescope.capSysNice = true; # left off — known to break gamescope under Steam
environment.systemPackages = with pkgs; [
mangohud
protonup-qt
];
}

30
modules/nvidia.nix Normal file
View File

@@ -0,0 +1,30 @@
{ config, ... }:
{
services.xserver.videoDrivers = [ "nvidia" ];
hardware.graphics = {
enable = true;
enable32Bit = true; # Steam/Proton
};
hardware.nvidia = {
modesetting.enable = true; # nvidia-drm.modeset=1 — mandatory for Wayland
open = true; # RTX 3080 (Ampere): NVIDIA-recommended on driver >= 560
nvidiaSettings = true;
powerManagement.enable = true; # preserves VRAM across suspend — avoids Wayland resume corruption
powerManagement.finegrained = false; # desktop GPU
package = config.boot.kernelPackages.nvidiaPackages.stable;
};
boot.kernelParams = [ "nvidia_drm.fbdev=1" ];
environment.sessionVariables = {
LIBVA_DRIVER_NAME = "nvidia";
NVD_BACKEND = "direct";
ELECTRON_OZONE_PLATFORM_HINT = "auto";
# Fallbacks — only if symptoms appear (should be unnecessary with driver 560+ / explicit sync):
# WLR_NO_HARDWARE_CURSORS = "1"; # invisible/glitchy cursor
# __GLX_VENDOR_LIBRARY_NAME = "nvidia"; # Xwayland picks wrong GL vendor
};
}