mirror of
https://github.com/zephrynis/nix-flake.git
synced 2026-08-17 21:45:53 +00:00
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:
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
88
README.md
Normal file
88
README.md
Normal 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
40
flake.nix
Normal 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
47
home/zephrynis.nix
Normal 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
|
||||
];
|
||||
}
|
||||
39
hosts/nixos-pc/default.nix
Normal file
39
hosts/nixos-pc/default.nix
Normal 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";
|
||||
}
|
||||
26
hosts/nixos-pc/hardware-configuration.nix
Normal file
26
hosts/nixos-pc/hardware-configuration.nix
Normal 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
47
modules/core.nix
Normal 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
31
modules/desktop.nix
Normal 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
19
modules/gaming.nix
Normal 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
30
modules/nvidia.nix
Normal 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user