If you’re going through hell, keep on going, Winston Churchill
NixOS is a unique, innovative, and powerful Linux distribution that leverages the Nix package manager. Unlike traditional Linux distributions that update packages and system configurations in-place, NixOS uses a purely functional and declarative approach to define the system state, reducing the risk of system breakage.
NixOS is a Linux distribution that uses the Nix package manager to handle packages and system configuration in a purely functional manner. This approach ensures that builds are reproducible and that the system state can be reliably replicated or rolled back.
sudo nix-env ‐‐rollback is a command used to revert your system to the previous configuration. It’s a powerful tool for undoing unintended changes or recovering from failed package installations. Before rolling back, consider if there’s a more targeted solution, like uninstalling specific packages or reverting configuration files.
Home Manager is a separate NixOS tool that manages user-specific configuration independently of the system configuration (system services, globally installed packages, and system-wide settings). It follows the same declarative approach as NixOS, allowing you to manage dotfiles (files like .zshrc, .config/i3/config, .config/picom/picom.conf), environment variables, user-level services and packages, and more in a structured and reproducible way.
It is a better way to manage your dotfiles. Let’s enable Home Manager as a NixOS module.
First, we are going to add the Home Manager channel. Channels are references to collections of Nix expressions. They tell Nix where to fetch packages and configurations from.
# Add Home Manager's channel
sudo nix-channel --add https://github.com/nix-community/home-manager/archive/release-24.05.tar.gz home-manager
# This sets up a channel named home-manager pointing to the release-24.05 branch of the Home Manager repository.
# Update our channels. This command fetches the latest changes from the channels we have subscribed to.
sudo nix-channel --update
# Since we’re using Home Manager as a NixOS module (integrate into configuration.nix or a separated file imported by it),
# we just need to rebuild the system to update all channels (apply the updates):
sudo nixos-rebuild switch
# After this step, Home Manager is ready to be used alongside the system configuration.
# To list all channels that are available in our system:
sudo nix-channel --list
# To remove a channel, type the following command:
sudo nix-channel --remove channel-alias
# Replace channel-alias with the name of the channel you want to remove.
We are going to create a dotfiles directory, and inside it a HomeManager configuration file: ∼/dotfiles/home-manager.nix. Below is a Home Manager configuration file:
{ config, pkgs, ... }:
{
# This command allows using global packages to avoid duplications
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true; # Enables user-specific packages in Home Manager.
home-manager.backupFileExtension = "backup"; # Extension for backup files generated by Home Manager
# Configuration settings for the user 'nmaximo7'
home-manager.users.nmaximo7 = { pkgs, ... }:
let # It uses a let expression to define variables (username, dotfiles) so we can reuse it throughout the configuration.
username = "nmaximo7"; # Set the username variable
dotfiles = "/home/${username}/dotfiles"; # Path to the user's dotfiles directory
in {
# User-level packages to be installed via Home Manager
home.packages = with pkgs; [
cowsay # Fun command-line utility that generates ASCII art.
fastfetch # An actively maintained, feature-rich neofetch like system information tool.
lshw # Hardware listing tool.
# Add more user-level packages as desired or needed.
];
home.stateVersion = "24.05"; # Specify the version of Home Manager. Remember to update it as needed for compatibility
home.username = username; # Set the Home Manager's username
home.homeDirectory = "/home/${username}"; # Set the user's home directory path
# Include other configuration files from the dotfiles directory
imports = [
"${dotfiles}/shell.nix" # Shell configuration
"${dotfiles}/kitty.nix" # Kitty terminal configuration
"${dotfiles}/zsh.nix" # Zsh shell configuration
"${dotfiles}/alacritty.nix" # Alacritty terminal configuration
"${dotfiles}/rofi.nix" # Rofi application launcher configuration
"${dotfiles}/vscode.nix" # VSCode configuration
# Add other configuration files as needed
];
# Enable Home Manager to manage its own configuration
programs.home-manager.enable = true;
# Links to Espanso, i3, i3status, Picom, and Fastfetch configuration files
home.file.".config/espanso/match/base.yml".source = "/home/${username}/dotfiles/base.yml";
home.file.".config/i3/config".source = "/home/${username}/dotfiles/i3/config";
home.file.".config/i3status/i3status.conf".source = "/home/${username}/dotfiles/i3/i3status.conf";
home.file.".config/picom/picom.conf".source = "/home/${username}/dotfiles/i3/picom.conf";
home.file.".config/fastfetch/config.jsonc".source = "/home/${username}/dotfiles/fastfetch/config.jsonc";
};
}
Neovim is a modern, hyperextensible Vim-based text editor. vim-plug is a minimalist Vim plugin manager, vim ~/dotfiles/nvim.nix. With Home Manager, we can declaratively configure Neovim plugins, settings, and themes.
This configuration is a Nix expression that sets up Neovim with specific settings, plugins, and Python support.
{ config, pkgs, ... }:
{
programs.neovim = {
# Ensure Neovim is installed and enabled in your NixOS system.
enable = true;
# Specify the Neovim package version and enable Python support
withPython3 = true;
extraPython3Packages = ps: with ps; [ pynvim ];
# Configuration for Neovim
extraConfig = ''
" Set leader key
let mapleader = " " " Use space as the leader key
" General settings
set number " Show line numbers
set relativenumber " Show relative line numbers
set tabstop=4 " Number of spaces per tab
set shiftwidth=4 " Number of spaces for autoindent
set expandtab " Convert tabs to spaces
set nowrap " Disable line wrapping
" Enable syntax highlighting
syntax on
" Set the colorscheme to gruvbox
colorscheme gruvbox
" Key mappings
nnoremap n :NERDTreeToggle " Toggle NERDTree
nnoremap f :FZF " Open FZF
'';
# Specify additional plugins if needed
plugins = with pkgs.vimPlugins; [
# Add any additional plugins here
vim-sensible # This is a collection of default settings and sensible defaults for Vim.
nerdtree # A file explorer plugin for Vim/Neovim that provides a tree view of your files and directories.
fzf-vim # A Vim plugin that integrates fzf, a fast fuzzy file finder.
# It allows users to quickly search for files, buffers, and more using fuzzy matching.
gruvbox
# A popular color scheme for Vim/Neovim that provides a warm, retro aesthetic with good contrast.
];
};
}
After opening Neovim (nvim), you can use the defined key mappings:
You can store your shell environment variables, defaults, and locales in a shell.nix file:
{ config, pkgs, ... }:
let
# Reference to the home configuration from NixOS
home = config.home;
in
{
# Sets environment variables for the user's login session
home.sessionVariables = {
# Set the default text editor to Neovim
EDITOR = "nvim";
# Set the visual editor (used by some applications) to Neovim
VISUAL = "nvim";
# Set the default language for the environment to US English
LANG = "en_US.UTF-8";
# Set the default web browser to Firefox
BROWSER = "firefox";
# Set the default terminal to Alacritty
TERMINAL = "alacritty";
};
# Configuration for Zsh will be imported from an external file `zsh.nix`
}
Sometimes, applications freeze or become unresponsive. NixOS, like other Linux distributions, offers several tools to handle such situations:
Install xkill and killall.
environment.systemPackages = with pkgs; [
psmisc # This package includes killall
xorg.xkill # This package includes xkill
];
After adding these lines in /etc/nixos/configuration.nix, run sudo nixos-rebuild switch to apply changes.
Type “xkill” in a terminal and press enter. This will transform your mouse cursor into an “x” or into a scull. Now you could simply left-click whatever window is not responding and it’ll be gone. killall command allows you to kill a process by name, e.g., sudo killall sshd, killall htop, etc.
Use the i3, Hyprland, etc. force kill shortcut, e.g., i3, Mod + Shift + Q where Mod is usually the Windows key or Alt, bindsym $mod+Shift+q kill or Hyprland, Mod + Q, bind = ${modifier},Q,killactive.
Find the PID (PID stands for process identification name) with ps aux | grep [application_name] and kill the process from the terminal: kill -9 [PID].
If your system is completely frozen, you may need to switch to a virtual terminal or console, e.g., Ctrl+Alt+F2 and kill the stubborn process from there or even reboot.
NixOS boot failures can be frustrating, but they are not cause for despair or panic. Remain Calm: It’s natural to feel frustrated when your system fails to boot, but panicking won’t help. Take a deep breath and approach the problem systematically.
First, you can attempt to repair it using a NixOS Live USB and tools like chroot. The steps below will guide you through identifying your root partition, mounting your file systems, chrooting into your installed environment, and fixing the bootloader. The goal is to restore your system to a working state without having to reinstall everything from scratch and wasting your time miserably.
Step 1. Create a NixOS Live USB. Download a NixOS ISO image from the official website and create a bootable USB using tools like dd, balenaEtcher or Ventoy: sudo dd if=nixos-graphical-*.iso of=/dev/sdX bs=4M conv=fsync
.
Step 2. Boot from the NixOS Live USB. Insert the USB into your machine and reboot. Access your firmware or BIOS boot menu (often by pressing a key like F12, F2, or Del/Supr) and select your USB. You will then enter the NixOS live environment.
Step 3. Identify Your Root Partition. In the NixOS live environment, open a terminal, and run the command: sudo fdisk -l
. This command lists all disk partitions. You’ll need to identify the correct root partition (e.g., /dev/nvme0n1p1, /dev/sda2) where your NixOS root filesystem resides.
Step 4. Create a mount point: sudo mkdir /mnt. This command creates a directory at /mnt
where you will mount your root partition.
Step 5. Mount the root partition: sudo mount /dev/nvme0n1p1 /mnt. Replace /dev/nvme0n1p1 with your actual root partition.Mounting the root partition allows you to access your system’s files and configurations.
Step 6. Mount essential virtual filesystems:
sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount --bind /proc /mnt/proc
sudo mount --bind /run /mnt/run
sudo mount --bind /sys /mnt/sys
These commands mount essential virtual filesystems that are necessary for the chroot environment to function correctly.
Step 7. Chroot into Your System:
sudo chroot /mnt /nix/store/*-bash-*/bin/bash --login
The `chroot` command changes the root directory to `/mnt`, effectively giving you a shell and allowing you to run commands as if you were booted into your installed system. Specifying the path to bash
from the Nix store ensures you use the correct shell in the NixOS environment.
Step 8. Fix the Bootloader: nixos-rebuild boot
. This command rebuilds the bootloader configuration.
Step 9. Exit the chroot environment: exit
Step 10: Unmount all filesystems you have previously mounted:
sudo umount /mnt/dev/pts
sudo umount /mnt/dev
sudo umount /mnt/proc
sudo umount /mnt/run
sudo umount /mnt/sys
sudo umount /mnt/boot
sudo umount /mnt
Step 11: Reboot the system: sudo reboot
and remove the USB.
One of NixOS’s strengths is the ability to roll back to previous generations of configurations. NixOS keeps generations of system configurations (historical versions of your system configuration) allowing you to roll back to a previous working configuration.
Step 1: Access GRUB Menu. During booting, press and hold the Shift
or Esc
key to access the GRUB menu, allowing you to choose between different boot options and see a list of “NisOS - Bootable generations.”
Step 2: Select a Previous Generation. Navigate to NixOS - Bootable generations
and choose an earlier generation. This is useful if the current configuration is causing boot failures, sudden crashes or any other types of problems.
Step 3: Boot into the Selected Generation. Using the arrow keys, select an older generation that you know was working and press Enter
to boot into it.
Step 4: Make the Previous Generation the Default. Once you have booted into a working generation:
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
. This lists all available generations of your system configuration, allowing you to see which ones are available for rollback.sudo nix-env --switch-generation X --profile /nix/var/nix/profiles/system
. Replace X
with the generation number you want to switch to. This effectively sets the chosen generation as your current configuration.sudo nixos-rebuild boot
. After switching generations, this command updates the bootloader to reflect the new default configuration, ensuring that the system boots with the selected generation next time.When the nixos-rebuild process hangs, it can be frustrating. Here are some steps to help you diagnose and resolve the issue:
Previous step. Ensure you have sufficient disk space, as a full disk can cause builds to hang (df -h
) and test that your network connection is stable (ping -c 4 cache.nixos.org). If you recently added or modified services in your configuration, disable them and then rebuild again because they might be causing conflicts.
Interrupt the Current Process. Press Ctrl + C to attempt to gracefully stop the rebuild process or force Termination. If the process does not respond to Ctrl + C, you can forcefully terminate it: sudo killall -9 nixos-rebuild
or sudo pkill -9 nixos-rebuild
.
Check for Stuck Nix Processes.
ps aux | grep nix
# Identify any stuck and suspicious processes related to Nix.
sudo kill -9 < PID > # Forcefully terminate (kill) any suspicious processes. Replace PID with the actual process ID related to Nix.
sudo rm -rf /nix/var/nix/building/
and caches sudo rm -rf /nix/var/cache/nix/
. Nix uses lock files and caches to manage builds. Corrupted or leftover locks can cause rebuilds to hang.sudo nix-collect-garbage -d
. The -d flag deletes all unused Nix stores path.sudo nix-store ‐‐optimize
. This command deduplicates identical files in the Nix store, saving disk space and potentially resolving issues related to corrupted files.sudo nix-channel ‐‐update
.sudo nixos-rebuild switch ‐‐show-trace ‐‐keep-going ‐‐max-jobs 4
‐‐show-trace: Provides detailed error messages. ‐‐keep-going: Continues the build even if some derivations fail, allowing you to see all errors at once. ‐‐max-jobs 4: Limits the number of parallel jobs to reduce resource consumption. Another option is ‐‐fallback. If a binary cache is unavailable for a package, this option allows Nix to build it from source instead of failing.
journalctl -xe
nixos-rebuild dry-build
checks the syntax and validity of the configuration without building it;You can also use nix-linter /etc/nixos/configuration.nix
to detect common issues (you may need to install nix-linter).
Reset the Nix Database (Last Resort): sudo rm -rf /nix/var/nix/db (it deletes the Nix database, which keeps track of installed packages), sudo nix-store ‐‐repair (it attempts to rebuild the database based on the current contents of the Nix store.)
Reboot. Sometimes, a simple reboot can resolve lingering issues: sudo reboot
By following these steps, you should be able to identify and resolve most issues causing the nixos-rebuild process to hang. If problems persist, consider restoring from a previous backup, reinstalling NixOS again (please backup important and sensitive data), seeking assistance from the NixOS community forums (when seeking help, include any relevant information such as logs or error messages, and steps you’ve already taken) or support channels.