Skip to content

Nix

Install

Nix package manager

Linux

bash
# Install Nix via the recommended multi-user installation:
sh <(curl -L https://nixos.org/nix/install) --daemon

# Single-user installation
sh <(curl -L https://nixos.org/nix/install) --no-daemon

Docker

bash
# Start a Docker shell with Nix
docker run -it nixos/nix
# Or start a Docker shell with Nix exposing a workdir directory
mkdir workdir
docker run -it -v $(pwd)/workdir:/workdir nixos/nix
# The workdir example from above can be also used to start hacking on nixpkgs
git clone --depth=1 https://github.com/NixOS/nixpkgs.git
docker run -it -v $(pwd)/nixpkgs:/nixpkgs nixos/nix
docker> nix-build -I nixpkgs=/nixpkgs -A hello
docker> find ./result # this symlink points to the build package


# Start a Docker shell with NixOS
docker run -it --name nix-flakes -d --rm nixpkgs/nix-flakes
docker exec -it nix-flakes bash
bash-5.2# nix run github:helix-editor/helix/master

NixOS

1. Obtaining NixOS

2. Manual Installation

Partitioning
bash
# UEFI(GPT)
# Create a GPT partition table
parted /dev/sda -- mklabel gpt
# Add the boot partition.
parted /dev/sda -- mkpart ESP fat32 1MB 512MB
# Add the root partition.
parted /dev/sda -- mkpart root ext4 512MB 100%
# NixOS by default uses the ESP (EFI system partition) as its /boot partition. It uses the initially reserved 512MiB at the start of the disk.
parted /dev/sda -- set 1 esp on


# Legacy Boot(MBR)
# Create a MBR partition table.
parted /dev/sda -- mklabel msdos
parted /dev/sda -- mkpart primary 1MB -2GB
parted /dev/sda -- set 1 boot on
parted /dev/sda -- mkpart primary linux-swap -2GB 100%

![[/Operations/System/attachements/Pasted image 20240321172907.png]]

Formatting
bash
# Format
mkfs.fat -F 32 -n boot /dev/sda1
mkfs.ext4 -L nixos /dev/sda2


## Examples
# For initialising Ext4 partitions: mkfs.ext4. It is recommended that you assign a unique symbolic label to the file system using the option -L label, since this makes the file system configuration independent from device changes. For example:
mkfs.ext4 -L nixos /dev/sda1

# For creating swap partitions: mkswap. Again it’s recommended to assign a label to the swap partition: -L label. For example:
mkswap -L swap /dev/sda2

# UEFI systems
# For creating boot partitions: mkfs.fat. Again it’s recommended to assign a label to the boot partition: -n label. For example:
mkfs.fat -F 32 -n boot /dev/sda3

# For creating LVM volumes, the LVM commands, e.g., pvcreate, vgcreate, and lvcreate.

# For creating software RAID devices, use mdadm.
Installing
bash
# Mount the target file system on which NixOS should be installed on /mnt, e.g.
mount /dev/sda2/ /mnt

# UEFI systems
# Mount the boot file system on /mnt/boot
mkdir -p /mnt/boot
mount /dev/sda1/ /mnt/boot

# Generate and edit config
nixos-generate-config --root /mnt
cat >> /mnt/etc/nixos/configuration.nix << "EOF"
{ config, lib, pkgs, ... }:

{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # (for BIOS systems only)
  # boot.loader.grub.device = "/dev/sda";
  # (for UEFI systems only)
  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "logic-nixos"; # Define your hostname.

  # Set your time zone.
  time.timeZone = "Asia/Shanghai";

  # Define a user account. Don't forget to set a password with ‘passwd’.
  users.users.logic = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
    openssh.authorizedKeys.keys = [
      # replace with your own public key
      "ssh-rsa <public-key> logic@nixos"
    ];
    packages = with pkgs; [
      tree
    ];
  };

  # Enable experimental-features Flakes and nix-command
  nix.settings.experimental-features = [ "nix-command" "flakes" ];

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    git
    vim
    wget
    curl
    # inputs.helix.packages."${pkgs.system}".helix
  ];
  environment.variables.EDITOR = "vim";

  # Enable the OpenSSH daemon.
  services.openssh = {
    enable = true;
    settings = {
      X11Forwarding = true;
      PermitRootLogin = "no";
      PasswordAuthentication = false;
    };
    openFirewall = true;
  }

  system.stateVersion = "23.11"; # Did you read the comment?
}
EOF

# Install NixOS
nixos-install
# set root password and reboot

3. Upgrading

bash
# switch channel
nix-channel --list
nixos https://nixos.org/channels/nixos-23.11
# add new channel
nix-channel --add https://channels.nixos.org/nixos-23.11 nixos
nix-channel --add https://channels.nixos.org/nixos-23.11-small nixos

# upgrade
nixos-rebuild switch --upgrade

NixCommand

nixos-rebuild

bash
# build new configuration and try to realise the configuration in the running system
nixos-rebuild switch

# to build the configuration and switch the running system to it, but without making it the boot default.(so it will get back to a working configuration after the next reboot).
nixos-rebuild test

# to build the configuration and make it the boot default, but not switch to it now (so it will only take effect after the next reboot).
nixos-rebuild boot

# You can make your configuration show up in a different submenu of the GRUB 2 boot screen by giving it a different profile name
nixos-rebuild switch -p test

# to build the configuration but nothing more. can check syntax
nixos-rebuild build

# rollback
nixos-rebuild switch --rollback

# verbose argument
--show-trace --print-build-logs --verbose

nix-channel

bash
# list
nix-channel list

# add new
nix-channel --add https://channels.nixos.org/channel-name nixos

nix-shell

bash
# nodejs env
bash-5.2# nix-shell -p nodejs
[nix-shell:/]# node -e "console.log(1+1)"

# nix-shell
cat > /default.nix << "EOF"
{ pkgs ? import <nixpkgs> {}
}:
pkgs.mkShell {
  name = "logic-test";
  buildInputs = [
    pkgs.nodejs
  ];
  shellHook = ''
    echo "Start developing..."
  '';
}
EOF
bash-5.2# nix-shell
[nix-shell:/]# node -e "console.log(1+1)"

nix-build

bash
# create normal redis nix file
cat > ./docker-redis.nix << "EOF"
{ pkgs ? import <nixpkgs> { system = "x86_64-linux";}
}:
pkgs.dockerTools.buildLayeredImage {
  name = "nix-redis";
  tag = "latest";
  contents = [ pkgs.redis ];
}
EOF
# build a normal docker image
nix-build docker-redis.nix -o ./result
docker load -i ./result
docker images


# create redis-minimal.nix
cat > ./redis-minimal.nix << "EOF"
{ pkgs ? import <nixpkgs> {}
}:
pkgs.redis.overrideAttrs (old: {
  makeFlags = old.makeFlags ++ ["USE_SYSTEMD=no"];
  preBuild = ''
    makeFlagsArray=(PREFIX="$out"
                    CC="${pkgs.musl.dev}/bin/musl-gcc -static"
                    CFLAGS="-I{pkgs.musl.dev/include}"
                    LDFLAGS="-L{pkgs.musl.dev/lib}");
  '';
  postInstall = "rm -f $out/bin/redis-{benchmark,check-*,cli}";
})
EOF
# create minimal redis nix file
cat > ./docker-redis.nix << "EOF"
{ pkgs ? import <nixpkgs> { system = "x86_64-linux";}
}:
let
  redisMinimal = import ./redis-minimal.nix { inherit pkgs; };
in
pkgs.dockerTools.buildLayeredImage {
  name = "nix-redis-minimal";
  tag = "latest";
  contents = [ redisMinimal ];
}
EOF
# build a minimal docker image
nix-build redis-minimal.nix -o ./result
docker load -i ./result
docker images

Flakes

nix flake

enable experimental features

bash
cat /etc/nixos/configuration.nix
{ config, pkgs, inputs, ... }:
{
  # ...
  nix.settings.experimental-features = [ "nix-command" "flakes" ];
  environment.systemPackages = with pkgs; [
    git
    vim
    wget
    curl
  ];
  # ...
}

init flake.nix

bash
# show flakes templates
nix flake show templates
# init
nix flake init -t templates#full
cat ./flake.nix


# create flake.nix
cat > /etc/nixos/flake.nix << "EOF"
{
  description = "A simple NixOS flake";

  inputs = {
    # NixOS official software source
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
	# helix editor, use the master branch
    helix.url = "github:helix-editor/helix/master";
  };

  outputs = { self, nixpkgs, ... }@inputs: {
    nixosConfigurations.logic-nixos = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        ./configuration.nix
        # 将所有 inputs 参数设为所有子模块的特殊参数,子模块直接引用 inputs 中所有依赖项
		{ _module.args = { inherit inputs; };}
      ];
    };
  };
}
EOF
# modified configuration.nix
cat /etc/nixos/configuration.nix
{ config, pkgs, inputs, ... }:
{
  # ...
  environment.systemPackages = with pkgs; [
    git
    vim
    wget
    curl
    # install helix from inputs
    inputs.helix.packages."${pkgs.system}".helix
  ];
  # ...
}
...


# switch to flakes
nixos-rebuild switch
# switch to flaskes from specify directory or remote repo
nixos-rebuild switch --flake /path/flake#your-hostname
nixos-rebuild switch --flake github:owner/repo#your-hostname


# flake update
# update all to flake.lock
nix flake update
# or only update home-manager
nix flake lock --update-input home-manager

	#
sudo nixos-rebuild switch --flake .

nix-command

bash
# nix-channel
# no need

# nix-env
nix profile

# nix-shell
nix develop
nix shell
nix run
# eg: only run helix, do not install to system
nix run github:helix-editor/helix/master

# nix-build
nix build

# nix-collect-garbage
nix storage gc --debug

# Interactive environment
nix repl

home-manager

bash
# init home.nix
cat > /etc/nixos/home.nix << "EOF"
{ config, pkgs, ... }:

{
  # user infomation
  home.username = "logic";
  home.homeDirectory = "/home/logic";

  # 直接将当前文件夹的配置文件,链接到 Home 目录下的指定位置
  # home.file.".config/i3/wallpaper.jpg".source = ./wallpaper.jpg;

  # 递归将某个文件夹中的文件,链接到 Home 目录下的指定位置
  # home.file.".config/i3/scripts" = {
  #   source = ./scripts;
  #   recursive = true;   # 递归整个文件夹
  #   executable = true;  # 将其中所有文件添加「执行」权限
  # };

  # 直接以 text 的方式,在 nix 配置文件中硬编码文件内容
  # home.file.".xxx".text = ''
  #     xxx
  # '';

  # 设置鼠标指针大小以及字体 DPI(适用于 4K 显示器)
  # xresources.properties = {
  #   "Xcursor.size" = 16;
  #   "Xft.dpi" = 172;
  # };

  # 通过 home.packages 安装一些常用的软件
  # 这些软件将仅在当前用户下可用,不会影响系统级别的配置
  # 建议将所有 GUI 软件,以及与 OS 关系不大的 CLI 软件,都通过 home.packages 安装
  home.packages = with pkgs;[
    # archives
    zip
    xz
    unzip
    p7zip

    # utils
    jq # A lightweight and flexible command-line JSON processor
    yq-go # yaml processor https://github.com/mikefarah/yq

    # networking tools
    mtr # A network diagnostic tool
    iperf3
    dnsutils  # `dig` + `nslookup`
    ldns # replacement of `dig`, it provide the command `drill`
    socat # replacement of openbsd-netcat
    nmap # A utility for network discovery and security auditing
    ipcalc  # it is a calculator for the IPv4/v6 addresses

    # misc
    cowsay
    file
    which
    tree
    gnused
    gnutar
    gawk
    zstd
    gnupg

    # nix related
    #
    # it provides the command `nom` works just like `nix`
    # with more details log output
    nix-output-monitor

    # productivity
    glow # markdown previewer in terminal

    # system call monitoring
    strace # system call monitoring
    ltrace # library call monitoring
    lsof # list open files

    # system tools
    btop  # replacement of htop/nmon
    iotop # io monitoring
    iftop # network monitoring
    sysstat
    lm_sensors # for `sensors` command
    ethtool
    pciutils # lspci
    usbutils # lsusb
  ];

  # git 相关配置
  programs.git = {
    enable = true;
    userName = "Logic";
    userEmail = "[email protected]";
  };

  # 启用 starship,这是一个漂亮的 shell 提示符
  programs.starship = {
    enable = true;
    # 自定义配置
    settings = {
      add_newline = false;
      aws.disabled = true;
      gcloud.disabled = true;
      line_break.disabled = true;
    };
  };

  # alacritty - 一个跨平台终端,带 GPU 加速功能
  programs.alacritty = {
    enable = true;
    # 自定义配置
    settings = {
      env.TERM = "xterm-256color";
      font = {
        size = 12;
        draw_bold_text_with_bright_colors = true;
      };
      scrolling.multiplier = 5;
      selection.save_to_clipboard = true;
    };
  };

  programs.bash = {
    enable = true;
    enableCompletion = true;
    # TODO 在这里添加你的自定义 bashrc 内容
    bashrcExtra = ''
      export PATH="$PATH:$HOME/bin:$HOME/.local/bin:$HOME/go/bin"
    '';

    # TODO 设置一些别名方便使用,你可以根据自己的需要进行增删
    shellAliases = {
      k = "kubectl";
      urldecode = "python3 -c 'import sys, urllib.parse as ul; print(ul.unquote_plus(sys.stdin.read()))'";
      urlencode = "python3 -c 'import sys, urllib.parse as ul; print(ul.quote_plus(sys.stdin.read()))'";
    };
  };

  home.stateVersion = "23.11";

  programs.home-manager.enable = true;
}
EOF


# generate flake.nix
nix flake new example -t github:nix-community/home-manager#nixos
vim /etc/nixos/flake.nix
{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11";
    home-manager = {
      url = "github:nix-community/home-manager/release-23.11";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = inputs@{ nixpkgs, home-manager, ... }: {
    nixosConfigurations = {
      logic-nixos = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix

          # 将 home-manager 配置为 nixos 的一个 module
          home-manager.nixosModules.home-manager
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.logic = import ./home.nix;
          }
        ];
      };
    };
  };
}


# switch to home-manager
nixos-rebuild switch


# all configuration
# 自动生成的版本锁文件,它记录了整个 flake 所有输入的数据源、hash 值、版本号,确保系统可复现
/etc/nixos/flake.lock
# flake 的入口文件,执行 sudo nixos-rebuild switch 时会识别并部署它
/etc/nixos/flake.nix
# 在 flake.nix 中被作为系统模块导入,目前所有系统级别的配置都写在此文件中
/etc/nixos/configuration.nix
# 在 flake.nix 中被 home-manager 作为用户的配置导入,包含了用户的所有 Home Manager 配置,负责管理其 Home 文件夹
/etc/nixos/home.nix
# hardware configuration
/etc/nixos/hardware-configuration.nix

module imports

bash
# example
tree /etc/nixos
/etc/nixos
├── flake.lock
├── flake.nix
├── home
   ├── default.nix         # 在这里通过 imports = [...] 导入所有子模块
   ├── fcitx5              # fcitx5 中文输入法设置,我使用了自定义的小鹤音形输入法
   ├── default.nix
   └── rime-data-flypy
   ├── i3                  # i3wm 桌面配置
   ├── config
   ├── default.nix
   ├── i3blocks.conf
   ├── keybindings
   └── scripts
   ├── programs
   ├── browsers.nix
   ├── common.nix
   ├── default.nix   # 在这里通过 imports = [...] 导入 programs 目录下的所有 nix 文件
   ├── git.nix
   ├── media.nix
   ├── vscode.nix
   └── xdg.nix
   ├── rofi              # rofi 应用启动器配置,通过 i3wm 中配置的快捷键触发
   ├── configs
   ├── arc_dark_colors.rasi
   ├── arc_dark_transparent_colors.rasi
   ├── power-profiles.rasi
   ├── powermenu.rasi
   ├── rofidmenu.rasi
   └── rofikeyhint.rasi
   └── default.nix
   └── shell             # shell 终端相关配置
       ├── common.nix
       ├── default.nix
       ├── nushell
   ├── config.nu
   ├── default.nix
   └── env.nu
       ├── starship.nix
       └── terminals.nix
├── hosts
   ├── msi-rtx4090      # PC 主机的配置
   ├── default.nix  # 之前的 configuration.nix,大部分内容都拆出到 modules
   └── hardware-configuration.nix  # 与系统硬件相关的配置,安装 nixos 时自动生成的
   └── my-nixos       # 测试用的虚拟机配置
       ├── default.nix
       └── hardware-configuration.nix
├── modules          # 从 configuration.nix 中拆分出的一些通用配置
   ├── i3.nix
   └── system.nix
└── wallpaper.jpg    # 桌面壁纸,在 i3wm 配置中被引用


# repl lib
nix repl -f '<nixpkgs>'
nix-repl> :e lib.mkDefault
##
lib.mkDefault
lib.mkForce
lib.mkOrder
lib.mkBefore
lib.mkAfter

Reference:

  1. NixOS Official Manual
  2. NixOS 与 Flakes
  3. NixOS 中文文档
  4. NixOS Packages Search
  5. NixOS Options Search
  6. Nix Home Manager Manual