diff --git a/README.md b/README.md index 6df4cb9..6348c5f 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,18 @@ My personal NixOS system configuration. | File | Contents | |---|---| | `configuration.nix` | Imports only | -| `modules/system.nix` | Boot, networking, locale, audio, hardening | -| `modules/drivers.nix` | GPU, tablet, I2C, RTL-SDR | -| `modules/desktop.nix` | Plasma, theming | -| `modules/users.nix` | Account, shell, Steam | -| `modules/apps.nix` | Installed packages | -| `modules/scripts.nix` | Custom scripts in `modules/scripts/` | +| `modules/boot.nix` | Limine, kernel, zram/swap | +| `modules/networking.nix` | NetworkManager, firewall, DNS-over-TLS, MAC randomization | +| `modules/locale.nix` | Timezone, locale, console keymap | +| `modules/nix-settings.nix` | Nix features, GC, unfree | +| `modules/security.nix` | sysctl hardening, sudo, firejail, GnuPG, polkit | +| `modules/hardware.nix` | GPU, tablet, Bluetooth, I2C, RTL-SDR, OpenRGB, printing | +| `modules/audio.nix` | PipeWire | +| `modules/desktop.nix` | Plasma, SDDM, fonts, theming | +| `modules/users.nix` | Account, shell, Steam, Flatpak | +| `modules/apps.nix` | Installed packages, nix-ld | | `modules/default-apps.nix` | MIME associations | +| `modules/scripts.nix` | Custom scripts in `modules/scripts/` | --- diff --git a/configuration.nix b/configuration.nix index f639910..abdbb21 100644 --- a/configuration.nix +++ b/configuration.nix @@ -3,13 +3,24 @@ { imports = [ ./hardware-configuration.nix - ./modules/system.nix - ./modules/drivers.nix + + # Core system + ./modules/boot.nix + ./modules/networking.nix + ./modules/locale.nix + ./modules/nix-settings.nix + ./modules/security.nix + + # Hardware + ./modules/hardware.nix + ./modules/audio.nix + + # Desktop & user ./modules/desktop.nix ./modules/users.nix ./modules/apps.nix - ./modules/scripts.nix ./modules/default-apps.nix + ./modules/scripts.nix ]; # Do not change this value. Read documentation before updating. diff --git a/modules/apps.nix b/modules/apps.nix index b677f3b..24fcb0b 100644 --- a/modules/apps.nix +++ b/modules/apps.nix @@ -70,6 +70,7 @@ in gcc python3 openjdk25 + go claude-code ]; @@ -100,5 +101,17 @@ in qt5.qtwayland qt6.qtwayland qemu + file + ]; + + # Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker. + programs.nix-ld.enable = true; + programs.nix-ld.libraries = with pkgs; [ + glib gtk3 gdk-pixbuf pango cairo atk + dbus dbus-glib fontconfig freetype + libx11 libxext libxrender libxtst + libxi libxcomposite libxdamage libxfixes + libxrandr libxcursor libxcb libxkbcommon + alsa-lib mesa zlib stdenv.cc.cc ]; } diff --git a/modules/audio.nix b/modules/audio.nix new file mode 100644 index 0000000..9b8434f --- /dev/null +++ b/modules/audio.nix @@ -0,0 +1,12 @@ +{ config, pkgs, ... }: + +{ + security.rtkit.enable = true; + services.pulseaudio.enable = false; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; +} diff --git a/modules/boot.nix b/modules/boot.nix new file mode 100644 index 0000000..e156000 --- /dev/null +++ b/modules/boot.nix @@ -0,0 +1,39 @@ +{ config, lib, pkgs, ... }: + +{ + boot.loader.efi.canTouchEfiVariables = true; + boot.loader.limine = { + enable = true; + maxGenerations = 5; + + # Gruvbox, to match the icon theme. + style = { + wallpapers = [ ]; # Solid background; a path here would be used instead + interface = { + branding = "NixOS"; + brandingColor = "fabd2f"; + helpColor = "928374"; + helpColorBright = "d79921"; + }; + graphicalTerminal = { + foreground = "ebdbb2"; + background = "00282828"; + brightForeground = "fbf1c7"; + palette = "282828;cc241d;98971a;d79921;458588;b16286;689d6a;a89984"; + brightPalette = "928374;fb4934;b8bb26;fabd2f;83a598;d3869b;8ec07c;ebdbb2"; + margin = 32; + }; + }; + }; + + boot.kernelPackages = pkgs.linuxPackages; + boot.supportedFilesystems = [ "fuse" ]; + programs.fuse.userAllowOther = true; + + # zram instead of disk swap: nothing sensitive is written to disk in + # plaintext. systemd's gpt-auto-generator would otherwise re-activate the + # old swap partition regardless of swapDevices, hence the kernel param. + zramSwap.enable = true; + swapDevices = lib.mkForce [ ]; + boot.kernelParams = [ "systemd.gpt_auto=0" "acpi_enforce_resources=lax" ]; +} diff --git a/modules/desktop.nix b/modules/desktop.nix index 171f9d7..86a237c 100644 --- a/modules/desktop.nix +++ b/modules/desktop.nix @@ -14,8 +14,6 @@ wayland.enable = true; }; - security.polkit.enable = true; - services.xserver.xkb = { layout = "pl"; variant = ""; @@ -34,4 +32,18 @@ pkgs.gruvbox-plus-icons pkgs.bibata-cursors ]; + + fonts.packages = with pkgs; [ + corefonts + dejavu_fonts + noto-fonts + noto-fonts-cjk-sans + noto-fonts-color-emoji + nerd-fonts.fira-code + nerd-fonts.jetbrains-mono + nerd-fonts.hack + inter + liberation_ttf + roboto + ]; } diff --git a/modules/drivers.nix b/modules/hardware.nix similarity index 61% rename from modules/drivers.nix rename to modules/hardware.nix index 16c8c24..63332b5 100644 --- a/modules/drivers.nix +++ b/modules/hardware.nix @@ -6,10 +6,34 @@ enable32Bit = true; }; + services.xserver.videoDrivers = [ "nvidia" ]; + + hardware.nvidia = { + modesetting.enable = true; + open = true; + nvidiaSettings = true; + package = config.boot.kernelPackages.nvidiaPackages.stable; + }; + hardware.opentabletdriver.enable = true; hardware.uinput.enable = true; boot.kernelModules = [ "uinput" ]; + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + settings = { + General = { + Experimental = true; # Battery level of connected devices + FastConnectable = true; # Faster reconnects, more power draw + }; + Policy = { + AutoEnable = true; + }; + }; + }; + services.blueman.enable = true; + boot.extraModprobeConfig = '' # DualSense/PS4 pads pair over Bluetooth then drop instantly; broken # ERTM in many adapters. Disabling it is the standard fix. @@ -23,12 +47,15 @@ # For ddcutil — no laptop backlight here, only external DisplayPort. hardware.i2c.enable = true; - services.xserver.videoDrivers = [ "nvidia" ]; - - hardware.nvidia = { - modesetting.enable = true; - open = true; - nvidiaSettings = true; - package = config.boot.kernelPackages.nvidiaPackages.stable; + services.hardware.openrgb = { + enable = true; + motherboard = "amd"; }; + + services.udev.extraRules = '' + # OpenRGB + SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" + ''; + + services.printing.enable = true; } diff --git a/modules/locale.nix b/modules/locale.nix new file mode 100644 index 0000000..5cb596e --- /dev/null +++ b/modules/locale.nix @@ -0,0 +1,19 @@ +{ config, pkgs, ... }: + +{ + time.timeZone = "Europe/Warsaw"; + i18n.defaultLocale = "pl_PL.UTF-8"; + i18n.extraLocaleSettings = { + LC_ADDRESS = "pl_PL.UTF-8"; + LC_IDENTIFICATION = "pl_PL.UTF-8"; + LC_MEASUREMENT = "pl_PL.UTF-8"; + LC_MONETARY = "pl_PL.UTF-8"; + LC_NAME = "pl_PL.UTF-8"; + LC_NUMERIC = "pl_PL.UTF-8"; + LC_PAPER = "pl_PL.UTF-8"; + LC_TELEPHONE = "pl_PL.UTF-8"; + LC_TIME = "pl_PL.UTF-8"; + }; + + console.keyMap = "pl2"; +} diff --git a/modules/networking.nix b/modules/networking.nix new file mode 100644 index 0000000..69dcd7e --- /dev/null +++ b/modules/networking.nix @@ -0,0 +1,38 @@ +{ config, pkgs, ... }: + +{ + networking.hostName = "nixos"; + networking.networkmanager.enable = true; + + networking.firewall = { + enable = true; + allowPing = true; + allowedTCPPortRanges = [ { from = 1714; to = 1764; } ]; + allowedUDPPortRanges = [ { from = 1714; to = 1764; } ]; + allowedTCPPorts = [ 80 443 ]; + }; + + # DNS-over-TLS via systemd-resolved; NetworkManager defers to it rather + # than writing its own /etc/resolv.conf. + networking.nameservers = [ "1.1.1.1#cloudflare-dns.com" "9.9.9.9#dns.quad9.net" ]; + services.resolved = { + enable = true; + settings.Resolve = { + DNSSEC = "allow-downgrade"; + DNSOverTLS = "true"; + }; + }; + networking.networkmanager.dns = "systemd-resolved"; + + # Ethernet stays "stable" (pseudonymous but consistent) so static DHCP + # reservations on the router keep working; Wi-Fi is fully random. + networking.networkmanager.wifi.macAddress = "random"; + networking.networkmanager.wifi.scanRandMacAddress = true; + networking.networkmanager.ethernet.macAddress = "stable"; + + # Disable NetworkManager's periodic captive-portal probe. + networking.networkmanager.settings.connectivity = { + uri = ""; + interval = 0; + }; +} diff --git a/modules/nix-settings.nix b/modules/nix-settings.nix new file mode 100644 index 0000000..4c04710 --- /dev/null +++ b/modules/nix-settings.nix @@ -0,0 +1,14 @@ +{ config, pkgs, ... }: + +{ + nixpkgs.config.allowUnfree = true; + + nix.settings.experimental-features = [ "nix-command" "flakes" ]; + nix.settings.auto-optimise-store = true; + + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; +} diff --git a/modules/security.nix b/modules/security.nix new file mode 100644 index 0000000..d2621bc --- /dev/null +++ b/modules/security.nix @@ -0,0 +1,38 @@ +{ config, pkgs, ... }: + +{ + security.polkit.enable = true; + + security.sudo.extraConfig = '' + Defaults pwfeedback + ''; + + programs.firejail.enable = true; + + programs.gnupg.agent = { + enable = true; + enableSSHSupport = true; + pinentryPackage = pkgs.pinentry-rofi; + }; + + boot.kernel.sysctl = { + "kernel.kptr_restrict" = 2; + "kernel.dmesg_restrict" = 1; + "net.ipv4.conf.all.rp_filter" = 1; + "net.ipv4.conf.default.rp_filter" = 1; + "net.ipv4.conf.all.accept_redirects" = false; + "net.ipv4.conf.default.accept_redirects" = false; + "net.ipv6.conf.all.accept_redirects" = false; + "net.ipv6.conf.default.accept_redirects" = false; + "net.ipv4.conf.all.send_redirects" = false; + "net.ipv4.conf.default.send_redirects" = false; + # Only bites ad-hoc `gdb -p ` on a non-child process. + "kernel.yama.ptrace_scope" = 1; + "net.ipv4.tcp_timestamps" = 0; + }; + + systemd.coredump.enable = false; + security.protectKernelImage = true; + + services.geoclue2.enable = false; +} diff --git a/modules/system.nix b/modules/system.nix deleted file mode 100644 index 0d3e9b4..0000000 --- a/modules/system.nix +++ /dev/null @@ -1,200 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - boot.loader.efi.canTouchEfiVariables = true; - boot.loader.limine = { - enable = true; - maxGenerations = 5; - - # Gruvbox, to match the icon theme. - style = { - wallpapers = [ ]; # Solid background; a path here would be used instead - interface = { - branding = "NixOS"; - brandingColor = "fabd2f"; - helpColor = "928374"; - helpColorBright = "d79921"; - }; - graphicalTerminal = { - foreground = "ebdbb2"; - background = "00282828"; - brightForeground = "fbf1c7"; - palette = "282828;cc241d;98971a;d79921;458588;b16286;689d6a;a89984"; - brightPalette = "928374;fb4934;b8bb26;fabd2f;83a598;d3869b;8ec07c;ebdbb2"; - margin = 32; - }; - }; - }; - boot.kernelPackages = pkgs.linuxPackages; - boot.supportedFilesystems = [ "fuse" ]; - networking.hostName = "nixos"; - networking.networkmanager.enable = true; - - networking.firewall = { - enable = true; - allowPing = true; - allowedTCPPortRanges = [ { from = 1714; to = 1764; } ]; - allowedUDPPortRanges = [ { from = 1714; to = 1764; } ]; - allowedTCPPorts = [ 80 443 ]; - }; - - time.timeZone = "Europe/Warsaw"; - i18n.defaultLocale = "pl_PL.UTF-8"; - i18n.extraLocaleSettings = { - LC_ADDRESS = "pl_PL.UTF-8"; - LC_IDENTIFICATION = "pl_PL.UTF-8"; - LC_MEASUREMENT = "pl_PL.UTF-8"; - LC_MONETARY = "pl_PL.UTF-8"; - LC_NAME = "pl_PL.UTF-8"; - LC_NUMERIC = "pl_PL.UTF-8"; - LC_PAPER = "pl_PL.UTF-8"; - LC_TELEPHONE = "pl_PL.UTF-8"; - LC_TIME = "pl_PL.UTF-8"; - }; - - nix.settings.auto-optimise-store = true; - nix.gc = { - automatic = true; - dates = "weekly"; - options = "--delete-older-than 7d"; - }; - - console.keyMap = "pl2"; - - security.rtkit.enable = true; - services.pulseaudio.enable = false; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - }; - - hardware.bluetooth = { - enable = true; - powerOnBoot = true; - settings = { - General = { - Experimental = true; # Battery level of connected devices - FastConnectable = true; # Faster reconnects, more power draw - }; - Policy = { - AutoEnable = true; - }; - }; - }; - - services.udev.extraRules = '' - # OpenRGB - SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660" - ''; - - services.blueman.enable = true; - - programs.firejail = { - enable = true; - }; - - programs.fuse.userAllowOther = true; - - programs.gnupg.agent = { - enable = true; - enableSSHSupport = true; - pinentryPackage = pkgs.pinentry-rofi; - }; - - security.sudo.extraConfig = '' - Defaults pwfeedback - ''; - - services.printing.enable = true; - - nixpkgs.config.allowUnfree = true; - - fonts.packages = with pkgs; [ - corefonts - dejavu_fonts - noto-fonts - noto-fonts-cjk-sans - noto-fonts-color-emoji - nerd-fonts.fira-code - nerd-fonts.jetbrains-mono - nerd-fonts.hack - inter - liberation_ttf - roboto - ]; - - # Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker. - programs.nix-ld.enable = true; - programs.nix-ld.libraries = with pkgs; [ - glib gtk3 gdk-pixbuf pango cairo atk - dbus dbus-glib fontconfig freetype - libx11 libxext libxrender libxtst - libxi libxcomposite libxdamage libxfixes - libxrandr libxcursor libxcb libxkbcommon - alsa-lib mesa zlib stdenv.cc.cc - ]; - environment.systemPackages = [ pkgs.file ]; - - nix.settings.experimental-features = [ "nix-command" "flakes" ]; - - # --- Hardening --- - - # zram instead of disk swap: nothing sensitive is written to disk in - # plaintext. systemd's gpt-auto-generator would otherwise re-activate the - # old swap partition regardless of swapDevices, hence the kernel param. - zramSwap.enable = true; - swapDevices = lib.mkForce [ ]; - boot.kernelParams = [ "systemd.gpt_auto=0" "acpi_enforce_resources=lax" ]; - - boot.kernel.sysctl = { - "kernel.kptr_restrict" = 2; - "kernel.dmesg_restrict" = 1; - "net.ipv4.conf.all.rp_filter" = 1; - "net.ipv4.conf.default.rp_filter" = 1; - "net.ipv4.conf.all.accept_redirects" = false; - "net.ipv4.conf.default.accept_redirects" = false; - "net.ipv6.conf.all.accept_redirects" = false; - "net.ipv6.conf.default.accept_redirects" = false; - "net.ipv4.conf.all.send_redirects" = false; - "net.ipv4.conf.default.send_redirects" = false; - # Only bites ad-hoc `gdb -p ` on a non-child process. - "kernel.yama.ptrace_scope" = 1; - "net.ipv4.tcp_timestamps" = 0; - }; - - systemd.coredump.enable = false; - security.protectKernelImage = true; - - systemd.tmpfiles.rules = [ - "L+ /var/lib/flatpak/exports/share/applications - - - - /var/lib/flatpak/app/com.usebottles.bottles/current/active/export/share/applications" - ]; - - networking.nameservers = [ "1.1.1.1#cloudflare-dns.com" "9.9.9.9#dns.quad9.net" ]; - services.resolved = { - enable = true; - settings.Resolve = { - DNSSEC = "allow-downgrade"; - DNSOverTLS = "true"; - }; - }; - networking.networkmanager.dns = "systemd-resolved"; - - # Ethernet stays "stable" (pseudonymous but consistent) so static DHCP - # reservations on the router keep working; Wi-Fi is fully random. - networking.networkmanager.wifi.macAddress = "random"; - networking.networkmanager.wifi.scanRandMacAddress = true; - networking.networkmanager.ethernet.macAddress = "stable"; - - # Disable NetworkManager's periodic captive-portal probe. - networking.networkmanager.settings.connectivity = { - uri = ""; - interval = 0; - }; - services.hardware.openrgb = { - enable = true; - motherboard = "amd"; - }; - services.geoclue2.enable = false; -} diff --git a/modules/users.nix b/modules/users.nix index b8532df..121d6f5 100644 --- a/modules/users.nix +++ b/modules/users.nix @@ -18,4 +18,10 @@ }; services.flatpak.enable = true; + + # Flatpak's exported .desktop files aren't on XDG_DATA_DIRS by default, + # so Bottles would otherwise not show up in the launcher. + systemd.tmpfiles.rules = [ + "L+ /var/lib/flatpak/exports/share/applications - - - - /var/lib/flatpak/app/com.usebottles.bottles/current/active/export/share/applications" + ]; }