Harden NixOS config defaults and setup guidance #4
28
README.md
@@ -52,18 +52,18 @@ mkdir -p hosts/<hostname>
|
|||||||
cp /etc/nixos/hardware-configuration.nix hosts/<hostname>/
|
cp /etc/nixos/hardware-configuration.nix hosts/<hostname>/
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Replace Placeholders
|
### 2. Review Configuration Defaults
|
||||||
|
|
||||||
Edit the following files and replace these placeholders:
|
Defaults are set in `flake.nix` and used across modules. Update them there:
|
||||||
|
|
||||||
| Placeholder | Example Value | Files |
|
| Setting | Example Value | File |
|
||||||
|-------------|---------------|-------|
|
|---------|---------------|------|
|
||||||
| `<hostname>` | `desktop` | `flake.nix`, `modules/common.nix` |
|
| `hostname` | `desktop` | `flake.nix` |
|
||||||
| `<username>` | `john` | `modules/common.nix`, `modules/dev.nix`, `modules/gaming.nix` |
|
| `username` | `john` | `flake.nix` |
|
||||||
| `<timezone>` | `America/New_York` | `modules/common.nix` |
|
| `time.timeZone` | `America/New_York` | `modules/common.nix` |
|
||||||
| `<locale>` | `en_US.UTF-8` | `modules/common.nix` |
|
| `i18n.defaultLocale` | `en_US.UTF-8` | `modules/common.nix` |
|
||||||
|
|
||||||
Also rename the `hosts/hostname/` directory to match your actual hostname, and ensure the same hostname is used for all `<hostname>` placeholders (including in `flake.nix`).
|
Update the `hostname` value in `flake.nix` to match your machine. Then rename the default `hosts/atlas/` directory to the same value (e.g., `hosts/desktop/`). The flake uses it to locate `hosts/<hostname>/hardware-configuration.nix`.
|
||||||
|
|
||||||
### 3. Stage Files in Git
|
### 3. Stage Files in Git
|
||||||
|
|
||||||
@@ -136,10 +136,12 @@ sudo nixos-rebuild boot --profile-name gaming --flake .#gaming
|
|||||||
|
|
||||||
### Change Password
|
### Change Password
|
||||||
|
|
||||||
Generate a password hash and update `modules/common.nix`:
|
Generate a password hash and save it to `/etc/nixos/secrets/<username>/password.hash` (replace `<username>` with your actual username):
|
||||||
```bash
|
```bash
|
||||||
mkpasswd -m sha-512
|
sudo mkdir -p /etc/nixos/secrets/<username>
|
||||||
# Copy the output and replace <replace-with-password-hash> in common.nix
|
sudo chmod 700 /etc/nixos/secrets/<username>
|
||||||
|
mkpasswd -m sha-512 | sudo tee /etc/nixos/secrets/<username>/password.hash
|
||||||
|
sudo chmod 600 /etc/nixos/secrets/<username>/password.hash
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setup MangoWC
|
### Setup MangoWC
|
||||||
@@ -225,4 +227,4 @@ cat /proc/sys/vm/max_map_count # Should be 2147483642 on gaming profile
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
14
flake.nix
@@ -37,15 +37,25 @@
|
|||||||
outputs = { self, nixpkgs, mango, quickshell, noctalia, nix-gaming, home-manager, ... }@inputs:
|
outputs = { self, nixpkgs, mango, quickshell, noctalia, nix-gaming, home-manager, ... }@inputs:
|
||||||
let
|
let
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
|
hostname = "atlas";
|
||||||
|
username = "pinj";
|
||||||
lib = nixpkgs.lib;
|
lib = nixpkgs.lib;
|
||||||
specialArgs = { inherit inputs system; };
|
usernameValid =
|
||||||
|
builtins.match "^[a-z_][a-z0-9_]*$" username != null
|
||||||
|
&& builtins.match "^_+$" username == null
|
||||||
|
|
|||||||
|
&& builtins.match "^nix.*" username == null
|
||||||
|
&& username != "root";
|
||||||
|
hostConfig = assert builtins.pathExists (./hosts + "/${hostname}/hardware-configuration.nix");
|
||||||
|
./hosts + "/${hostname}/hardware-configuration.nix";
|
||||||
|
passwordHashPath = "/etc/nixos/secrets/${username}/password.hash";
|
||||||
|
The assertion for The assertion for `hostConfig` will fail at evaluation time with a cryptic error if the path doesn't exist. The assert statement should provide a helpful error message to guide users. Consider using a let-binding with an abort statement that provides a clear message like: "Hardware configuration not found at ./hosts/${hostname}/hardware-configuration.nix. Please ensure the directory exists and contains the hardware configuration file."
```suggestion
hostConfig =
let
hardwarePath = ./hosts + "/${hostname}/hardware-configuration.nix";
in
if builtins.pathExists hardwarePath then
hardwarePath
else
builtins.abort "Hardware configuration not found at ./hosts/${hostname}/hardware-configuration.nix. Please ensure the directory exists and contains the hardware configuration file.";
```
|
|||||||
|
specialArgs = { inherit inputs system hostname username usernameValid passwordHashPath; };
|
||||||
|
The The `passwordHashPath` is hardcoded to a system location that may not exist on first installation, but there's no validation or assertion to check if this file exists. This will cause the system build to fail with an unclear error. Consider adding an assertion in `common.nix` to check if the password hash file exists, with a helpful error message directing users to the password setup instructions in the README. Alternatively, document that users must create this file before their first build.
```suggestion
passwordHashPath =
let
path = "/etc/nixos/secrets/${username}/password.hash";
in
if builtins.pathExists path then
path
else
builtins.throw ''
Password hash file not found at ${path}.
Please create this file before your first build.
See the password setup instructions in the project README.
'';
```
|
|||||||
|
|
||||||
# Verify mango flake exports the expected module
|
# Verify mango flake exports the expected module
|
||||||
mangoModule = assert lib.hasAttrByPath [ "nixosModules" "mango" ] mango;
|
mangoModule = assert lib.hasAttrByPath [ "nixosModules" "mango" ] mango;
|
||||||
mango.nixosModules.mango;
|
mango.nixosModules.mango;
|
||||||
|
|
||||||
commonModules = [
|
commonModules = [
|
||||||
./hosts/atlas/hardware-configuration.nix
|
hostConfig
|
||||||
./modules/common.nix
|
./modules/common.nix
|
||||||
mangoModule
|
mangoModule
|
||||||
# Home Manager module - Foundation for user-level package management
|
# Home Manager module - Foundation for user-level package management
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
{ config, pkgs, inputs, system, ... }:
|
{ config, pkgs, inputs, system, hostname, username, usernameValid, passwordHashPath, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = usernameValid;
|
||||||
|
message = "username must start with a-z or _, contain only lowercase letters, digits, and underscores, and must not be root or start with nix.";
|
||||||
|
}
|
||||||
|
];
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# BOOT
|
# BOOT
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
@@ -10,7 +16,7 @@
|
|||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# SYSTEM
|
# SYSTEM
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
networking.hostName = "atlas";
|
networking.hostName = hostname;
|
||||||
time.timeZone = "Europe/Berlin";
|
time.timeZone = "Europe/Berlin";
|
||||||
i18n.defaultLocale = "en_US.UTF-8";
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
|
||||||
@@ -57,12 +63,11 @@
|
|||||||
# RADV (Mesa) is the default and performs better for gaming
|
# RADV (Mesa) is the default and performs better for gaming
|
||||||
};
|
};
|
||||||
|
|
||||||
# RADV is already the default Vulkan driver
|
|
||||||
# This variable is optional but makes it explicit
|
|
||||||
environment.variables.AMD_VULKAN_ICD = "RADV";
|
|
||||||
|
|
||||||
# Wayland session variables for proper app integration
|
# Wayland session variables for proper app integration
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
|
# RADV is already the default Vulkan driver
|
||||||
|
# This variable is optional but makes it explicit
|
||||||
|
AMD_VULKAN_ICD = "RADV";
|
||||||
QT_QPA_PLATFORM = "wayland";
|
QT_QPA_PLATFORM = "wayland";
|
||||||
MOZ_ENABLE_WAYLAND = "1";
|
MOZ_ENABLE_WAYLAND = "1";
|
||||||
NIXOS_OZONE_WL = "1"; # Electron apps (VS Code, Discord, etc.)
|
NIXOS_OZONE_WL = "1"; # Electron apps (VS Code, Discord, etc.)
|
||||||
@@ -101,19 +106,19 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
settings.default_session = {
|
settings.default_session = {
|
||||||
command = "mango";
|
command = "mango";
|
||||||
user = "pinj";
|
user = username;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# USER ACCOUNT
|
# USER ACCOUNT
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
users.users.pinj = {
|
users.users.${username} = {
|
||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
extraGroups = [ "wheel" "networkmanager" "video" "seat" ];
|
extraGroups = [ "wheel" "networkmanager" "video" "seat" ];
|
||||||
# IMPORTANT: Generate a password hash with: mkpasswd -m sha-512
|
# IMPORTANT: Generate a password hash with: mkpasswd -m sha-512
|
||||||
# Then replace the placeholder below with the generated hash
|
# Save it to /etc/nixos/secrets/${username}/password.hash (ensure permissions are 600)
|
||||||
hashedPassword = "<replace-with-password-hash>";
|
hashedPasswordFile = passwordHashPath;
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
# -- Noctalia Shell --
|
# -- Noctalia Shell --
|
||||||
inputs.quickshell.packages.${system}.default
|
inputs.quickshell.packages.${system}.default
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, username, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# Identification tag (shows in boot menu and `nixos-version`)
|
# Identification tag (shows in boot menu and `nixos-version`)
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
# NOTE: After first enabling/applying this dev profile, you must log out and
|
# NOTE: After first enabling/applying this dev profile, you must log out and
|
||||||
# log back in (or reboot) for the docker group membership to take effect.
|
# log back in (or reboot) for the docker group membership to take effect.
|
||||||
users.users.pinj.extraGroups = [ "docker" ];
|
users.users.${username}.extraGroups = [ "docker" ];
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# DEVELOPMENT TOOLS
|
# DEVELOPMENT TOOLS
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
nix-direnv.enable = true; # Caches nix shells
|
nix-direnv.enable = true; # Caches nix shells
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.pinj.packages = with pkgs; [
|
users.users.${username}.packages = with pkgs; [
|
||||||
# -- Git --
|
# -- Git --
|
||||||
lazygit
|
lazygit
|
||||||
gh # GitHub CLI
|
gh # GitHub CLI
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{ pkgs, inputs, ... }:
|
{ pkgs, inputs, username, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# Identification tags (shows in boot menu)
|
# Identification tags (shows in boot menu)
|
||||||
@@ -62,12 +62,12 @@
|
|||||||
# programs to function correctly. These groups are only added when using
|
# programs to function correctly. These groups are only added when using
|
||||||
# the gaming profile. If you need consistent group membership across
|
# the gaming profile. If you need consistent group membership across
|
||||||
# both profiles, add these groups to common.nix instead.
|
# both profiles, add these groups to common.nix instead.
|
||||||
users.users.pinj.extraGroups = [ "corectrl" "gamemode" ];
|
users.users.${username}.extraGroups = [ "corectrl" "gamemode" ];
|
||||||
|
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
# GAMING PACKAGES
|
# GAMING PACKAGES
|
||||||
# --------------------------------------------------------------------------
|
# --------------------------------------------------------------------------
|
||||||
users.users.pinj.packages = with pkgs; [
|
users.users.${username}.packages = with pkgs; [
|
||||||
# -- Performance Overlays --
|
# -- Performance Overlays --
|
||||||
mangohud # FPS counter, GPU stats
|
mangohud # FPS counter, GPU stats
|
||||||
goverlay # MangoHud GUI config
|
goverlay # MangoHud GUI config
|
||||||
|
|||||||
The username validation regex allows usernames that consist only of underscores followed by other characters (e.g., "___abc"), but the second check
builtins.match "^_+$" username == nullonly rejects usernames that are entirely underscores. According to standard Unix username conventions, usernames starting with underscore are typically reserved for system accounts. Consider strengthening the validation to reject any username starting with underscore unless that's intentionally allowed for system accounts.