NixOs Native Flake Deployment With LUKS Drive Encryption and LVM

NixOS Logo

In this series of tutorials, I will not cover Nix or NixOS. You can probably find many tutorials with detailed descriptions of the advantages of using nix declarative, functional configuration management language.

I will tackle a specific problem I was trying to solve, and as a result, I can share and expand on potential options available.

Some time back, I was looking to reinstall my NixOS “that I was running for the past four years” with a new nix feature like a flake and make it more flexible from a storage management standpoint “using LVM” and to secure with full disk encryption “using LUKS.”

Flake

Flakes are a new feature in the Nix ecosystem. Flakes replace stateful channels and introduce a more intuitive and consistent CLI interface.

LVM

A Linux, Logical Volume Manager (LVM) is a device mapper framework that provides logical volume management for the Linux kernel. The main advantage is using LVM multiple Disk management becomes very easy, and adding new disk storage is a breeze. A good description for LVM you can find in Chris Titus Blog Post

LUKS

LUKS stands for ”Linux Unified Key Setup.” I will use cryptsetup to use to encrypt the entire disk using LUKS2. For more information on specifications for LUKS2

Before you start a good recommendation, use hypervisor VirtualBox or QEMU/KVM to get familiarised with the setup and available options. In the below example, I am using QEMU/KVM.

Installation

Prerequisites

Download latest NixOS ISO image Download min Minimal ISO image.

Make sure you have a git repository with all configuration files. In the below example, I will use my Github systst repository.

Setup Virtualization with QEMU/KVM

1st step is to create a Virtual Machine that will install NixOS using nix flakes.
Download min Minimal ISO image.

virt-install \
  --name nixos \
  --boot uefi \
  --ram 8196 \
  --vcpus 4 \
  --network bridge:virbr0 \
  --os-type linux \
  --os-variant nixos-unstable \
  --disk path=/var/lib/libvirt/images/nixos.qcow2,size=30 \
  --console pty,target_type=serial \
  --cdrom ~/Downloads/iso/nixos-minimal-21.05.1555.6b940846e99-x86_64-linux.iso


Note: Adjust --cdrom and -disk path locations. Feel free to adjust --ram and --vcpus accommodate underlying hardware.

Hard Drive Preparation

Once VM is up and running, we will need to identify the drive NixOS will be installed on by running;

[nixos@nixos:~]$ lsblk
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0   7:0    0 614.2M  1 loop /nix/.ro-store
sr0    11:0    1   661M  0 rom  /iso
vda   253:0    0    30G  0 disk 


Note: We will use vda disk that was provisioned with 30G of free storage.
Note: Good proactive to have a minimum of 20G of storage due to the nature of NixOS to create derivation for recovery.

Drive Partitioning

Once we know on what drive we will use, install nixos is time to create the necessary partitions. Will become root for easier access to the resources requiring root access.

[nixos@nixos:~]$ sudo -i

[root@nixos:~]# export ROOT_DISK=/dev/vda

[root@nixos:~]# parted -a opt --script "${ROOT_DISK}" \
    mklabel gpt \
    mkpart primary fat32 0% 512MiB \
    mkpart primary 512MiB 100% \
    set 1 esp on \
    name 1 boot \
    set 2 lvm on \
    name 2 root

[root@nixos:~]# fdisk /dev/vda -l
fdisk /dev/vda -l
Disk /dev/vda: 30 GiB, 32212254720 bytes, 62914560 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4E4E582E-8CC3-4901-93B4-3D8DD429FA7E

Device       Start      End  Sectors  Size Type
/dev/vda1     2048  1048575  1046528  511M EFI System
/dev/vda2  1048576 62912511 61863936 29.5G Linux LVM


Note: I am installing the nixos on UEFI partition type fat32 with 512 Mib of the allocated storage. The rest of the storage is allocated for the root partition.
Note: Except partitioning the disk I labeled the partition /dev/vda1 as boot and /dev/vda1 as root that will help us later in the system setup.

Partition Encryption

The next step is to encrypt the root partition. I will use cryptsetup with luksFormat.

[root@nixos:~]# cryptsetup luksFormat /dev/disk/by-partlabel/root


WARNING!
========
This will overwrite data on /dev/disk/by-partlabel/root irrevocably.

Are you sure? (Type 'yes' in capital letters): YES
Enter passphrase for /dev/disk/by-partlabel/root: 
Verify passphrase: 


Note: Make sure you use a secure password.

Open encrypted partition:

[root@nixos:~]# cryptsetup luksOpen /dev/disk/by-partlabel/root root

Enter passphrase for /dev/disk/by-partlabel/root:


Setting Up LVM

System readout of volumes and partitions:

[root@nixos:~]# lvmdiskscan
  /dev/loop0         [    <614.18 MiB] 
  /dev/gpt-auto-root [      29.48 GiB] 
  /dev/vda1          [     511.00 MiB] 
  /dev/vda2          [     <29.50 GiB] 
  1 disk
  3 partitions
  0 LVM physical volume whole disks
  0 LVM physical volumes


Create a physical volume from /dev/mapper/root that is mapped to /dev/vda2:

[root@nixos:~]# pvcreate /dev/mapper/root
  Physical volume "/dev/mapper/root" successfully created.


Create a volume group from /dev/mapper/root:

[root@nixos:~]# vgcreate vg /dev/mapper/root
  Volume group "vg" successfully created


Create a 4 GB logical volume on volume group vg that will be used for swap partition:

[root@nixos:~]# lvcreate -L 4G -n swap vg
  Logical volume "swap" created.


Create a logical volume on the volume group vg using all the rest of the storage space that will be used for the root partition:

[root@nixos:~]# lvcreate -l '100%FREE' -n root vg
  Logical volume "root" created.


View volumes and partitions created:

[root@nixos:~]# lvdisplay
  --- Logical volume ---
  LV Path                /dev/vg/swap
  LV Name                swap
  VG Name                vg
  LV UUID                BEZroA-bKry-jAz2-dW2v-jQDY-uqUB-bIdJQa
  LV Write Access        read/write
  LV Creation host, time nixos, 2021-07-20 14:44:52 +0000
  LV Status              available
  # open                 0
  LV Size                4.00 GiB
  Current LE             1024
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           254:1
   
  --- Logical volume ---
  LV Path                /dev/vg/root
  LV Name                root
  VG Name                vg
  LV UUID                KJHdcu-CLvf-saWV-Kp3r-qSTw-HcMg-7SePkt
  LV Write Access        read/write
  LV Creation host, time nixos, 2021-07-20 14:46:11 +0000
  LV Status              available
  # open                 0
  LV Size                25.48 GiB
  Current LE             6523
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           254:2


Partition Formatting

Formatting the boot partition with FAT32:

[root@nixos:~]# mkfs.fat -F 32 -n boot /dev/disk/by-partlabel/boot
mkfs.fat 4.1 (2017-01-24)
mkfs.fat: warning - lowercase labels might not work properly with DOS or Windows


Formatting the root partition with EXT4 file system:

[root@nixos:~]# mkfs.ext4 -L root /dev/vg/root
mke2fs 1.46.2 (28-Feb-2021)
Creating filesystem with 6679552 4k blocks and 1671168 inodes
Filesystem UUID: e78f4a6b-5d85-458a-9757-f722d657c091
Superblock backups stored on blocks: 
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
    4096000

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done


Formatting the swap partition:

[root@nixos:~]# mkswap -L swap /dev/vg/swap
Setting up swapspace version 1, size = 4 GiB (4294963200 bytes)
LABEL=swap, UUID=3feeb8e9-9843-401b-93dc-128047b8c08b


Mounting Newly Created Partitions and Swap Activation

[root@nixos:~]# mount /dev/disk/by-label/root /mnt

[root@nixos:~]# mkdir -p /mnt/boot

[root@nixos:~]# mount /dev/disk/by-label/boot /mnt/boot

[root@nixos:~]# swapon /dev/vg/swap

[root@nixos:~]# swapon -s
Filename                Type        Size    Used    Priority
/dev/dm-1               partition   4194300    0    -2


NixOS Installation Options

We have a few available options to use nix flakes.

Base Example

Bellow, you can find the most basic example where you can use flake and ingest configuration.nix as a module.

{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-21.05";
  };

  outputs = { nixpkgs, ... }: {
    nixosConfigurations = {
      nixtst = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
        ];
      };
    };
  };
}


Home Manager Integration

If you are a single user for underlying hardware and want to have a single management workspace, you can integrate the system config with the home manager config under the same nix flake.

{
  description = "NixOS configuration and Home Manager configuration";

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

  outputs = { home-manager, nixpkgs, ... }: {
    nixosConfigurations = {
      nixtst = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ./configuration.nix
          home-manager.nixosModules.home-manager
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.mudrii = import ./users/$USER/home.nix;
          }
        ];
      };
    };
  };
}


Full Flake Integration

Another option is to get rid of configuration.nix and add all entries into flake.nix.

{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-21.05";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
  };

  outputs = { nixpkgs, nixpkgs-unstable, ... }: {
    nixosConfigurations = {
      nixtst = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ({ config, pkgs, ... }:
            let
              overlay-unstable = final: prev: {
                unstable = nixpkgs-unstable.legacyPackages.x86_64-linux;
              };
            in
            {
              imports =
                [ ./hardware-configuration.nix ];

              fileSystems."/" = { options = [ "noatime" "nodiratime" ]; };

              boot = {
                kernelPackages = pkgs.linuxPackages_latest;

                loader = {
                  efi.canTouchEfiVariables = true;
                  grub = {
                    enable = true;
                    version = 2;
                    efiSupport = true;
                    enableCryptodisk = true;
                    device = "nodev";
                  };
                };

                initrd.luks.devices = {
                  crypt = {
                    device = "/dev/vda2";
                    preLVM = true;
                  };
                };
              };

              time.timeZone = "Asia/Singapore";

              networking = {
                useDHCP = false;
                interfaces.enp1s0.useDHCP = true;
                hostName = "nixtst"; # Define your hostname.
              };

              security = {
                sudo = {
                  enable = true;
                  wheelNeedsPassword = false;
                };
              };
...
..
.


Note: Full example can be found here.

Mix and Match

In the below example, I am using a combination of available options.
The reason is to have a structure to allow for multi-user support. Some users may not have root access but should manage the user packages using a separate implementation of the Home Manager that will cover in a separate tutorial.

{
  description = "NixOS configuration";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-21.05";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
  };

  outputs = { nixpkgs, nixpkgs-unstable, ... }: {
    nixosConfigurations = {
      nixtst = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          ({ config, pkgs, ... }:
            let
              overlay-unstable = final: prev: {
                unstable = nixpkgs-unstable.legacyPackages.x86_64-linux;
              };
            in
            {
              nixpkgs.overlays = [ overlay-unstable ];

              imports =
                [
                  ./hardware-configuration.nix
                  ./configuration.nix
                  ./packages.nix
                  ./users/admin_users.nix
                  ./users/dev_users.nix
                ];
            }
          )
        ];
      };
    };
  };
}


Note: I added nixpkgs.overlays to allow some packages to be installed selected from the unstable branch.

*.nix Dissected

hardware-configuration.nix

The only change in hardware-configuration.nix is the device from by-uuid to by-label that adds portability and adds swap device to the mix.

{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [
      (modulesPath + "/profiles/qemu-guest.nix")
    ];

  boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ];
  boot.initrd.kernelModules = [ "dm-snapshot" ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" = {
    device = "/dev/disk/by-label/root";
    fsType = "ext4";
  };

  fileSystems."/boot" = {
    device = "/dev/disk/by-label/boot";
    fsType = "vfat";
  };

  swapDevices =
    [{ device = "/dev/disk/by-label/swap"; }];

  nix.maxJobs = lib.mkDefault 4;

}


configuration.nix

fileSystems

fileSystems SSD optimization for EXT4:

 fileSystems."/" = { options = [ "noatime" "nodiratime" ]; };

boot.loader

Adding latest Linux kernel with kernelPackages = pkgs.linuxPackages_latest;.
Allowing grub support for UEFI and LUKS encryption.

  boot = {
    kernelPackages = pkgs.linuxPackages_latest;
    loader = {
      efi.canTouchEfiVariables = true;
      grub = {
        enable = true;
        version = 2;
        efiSupport = true;
        enableCryptodisk = true;
        device = "nodev";
      };
    };
    initrd.luks.devices = {
      crypt = {
        device = "/dev/vda2";
        preLVM = true;
      };
    };
  };


networking

Please change to your desired hostname and correct the interface name.

  networking = {
    useDHCP = false;
    interfaces.enp1s0.useDHCP = true; # Add correct network interface name to find out run "ip a"
    hostName = "nixtst"; # Define your hostname.
  };


console and fonts

I am adding default system-wide encoding and adding additional fonts, useful for the modern shell.

  i18n = {
    defaultLocale = "en_US.UTF-8";
    supportedLocales = [ "en_US.UTF-8/UTF-8" ];
  };

  console = {
    font = "Lat2-Terminus16";
    keyMap = "us";
  };

  fonts = {
    fontDir.enable = true;
    enableGhostscriptFonts = true;
    fonts = with pkgs; [
      powerline-fonts
      nerdfonts
    ];
  };


services

We are enabling ssh on port 2022 but disabling root login and password authentication.

  services = {
    openssh = {
      enable = true;
      permitRootLogin = "no";
      passwordAuthentication = false;
      ports = [2022];
    };
  };


virtualisation

Adding docker as an example:

  virtualisation = {
    docker = {
      enable = true;
      autoPrune.enable = true;
      enableOnBoot = true;
    };
  };


nix Optimizations

Allowing unfree allowUnfree = true; packages like Nvidia drivers etc.
Make nix compatible with flakes pkgs.nixFlakes;.
Garbage collection and optimization gc and optimise.

  nixpkgs = {
    config = {
      allowBroken = true;
      allowUnfree = true;
    };
  };

  nix = {
    package = pkgs.nixFlakes;
    useSandbox = true;
    autoOptimiseStore = true;
    readOnlyStore = false;
    allowedUsers = [ "@wheel" ];
    trustedUsers = [ "@wheel" ];
    extraOptions = ''
      experimental-features = nix-command flakes
      keep-outputs = true
      keep-derivations = true
    '';
    gc = {
      automatic = true;
      dates = "weekly";
      options = "--delete-older-than 7d --max-freed $((64 * 1024**3))";
    };
    optimise = {
      automatic = true;
      dates = [ "weekly" ];
    };
  };


system

Configure system auto-update compatible with flakes you will need to change Github repo to point to your repo location.

  system = {
    stateVersion = "21.05"; # Did you read the comment?
    autoUpgrade = {
      enable = true;
      allowReboot = true;
      flake = "github:mudrii/systst";
      flags = [
        "--recreate-lock-file"
        "--no-write-lock-file"
        "-L" # print build logs
       ];
      dates = "daily";
    };
  };


Note: Complete content of the configuration.nix file can be found in Github.

packages.nix

System-Wide Packages

With environment.systemPackages we specify packages that will be installed for all users.

   systemPackages = with pkgs; [
      git
      gh
      kubernetes
      kubernetes-helm
      kubeseal
      helmfile
      helmsman
      unstable.kind
      kube3d
      argo
      argocd
      kustomize
      k9s
      kubectx
      binutils
      gnutls
      wget
      curl
      bind
      mkpasswd
      direnv
      nix-direnv
    ];


shellAliases

We can specify system-wide shell aliases for all users.

    shellAliases = {
      cp = "cp -i";
      diff = "diff --color=auto";
      dmesg = "dmesg --color=always | lless";
      egrep = "egrep --color=auto";
      fgrep = "fgrep --color=auto";
      grep = "grep --color=auto";
      mv = "mv -i";
      ping = "ping -c3";
      ps = "ps -ef";
      sudo = "sudo -i";
      vdir = "vdir --color=auto";
    };


programs

We specify native nix application to be installed and/or enable/disable. We can add package-specific configurations for all users like nano editor.

  programs = {
    ssh.startAgent = false;
    vim.defaultEditor = true;
    fish.enable = true;
    nano.nanorc = ''
      unset backup
      set nonewlines
      set nowrap
      set tabstospaces
      set tabsize 4
      set constantshow
    '';
  };


users

To manage multiple users, I decided to segregate admin users having root access with non-admin users. The only difference is in the wheel group allocation.
You can specify packages that will install only for the user and add ssh public keys and generate the password.

  users = {
    mutableUsers = false;
    users.mudrii = {
      isNormalUser = true;
      extraGroups = [ "wheel" "docker" ];
      shell = pkgs.fish;
      # mkpasswd -m sha-512 password
      hashedPassword = "$6$ewXNcoQRNG$czTic9vE8CGH.eo4mabZsHVRdmTjtJF4SdDnIK0O/4STgzB5T2nD3Co.dRpVS3/uDD24YUxWrTDy2KRv7m/3N1";
      openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8/tE2+oIwLnCnfzPSTqiZaeW++wUPNW5fOi124eGzWfcnOQGrjuwir3sZDKMS9DLqSTDNtvJ3/EZf6z/MLN/uxUE8lA+aKaSs0yopE7csQ89Aqkvp5fvCpz3BJuZgpxtwebPZyTc7QRGQWE4lM3fix3aJhfj827bdxA+sCiq8OnNiwYSXrIag1cQigafhLy6tYtCKdWcxzJq2ebGJF2wu2LU0zArb1SAOanhEOXxz0dG1I/7yMDBDC92R287nWpL+BwxuQcDv0xh/sWnViKixKv+B9ewJnz98iQPcg3WmYWe9BYAcaqkbgMqbwfUPqOHhFXmiQWUpOjsni2O6VoiN mudrii@nixos" ];
      packages = with pkgs; [
        python39Full
        (
          python39.withPackages (
            ps: with ps; [
              #poetry
              pip
              powerline
              pygments
              pygments-markdown-lexer
              xstatic-pygments
              pylint
              numpy
              pynvim
            ]
          )
        )
      ];
    };
  };  


Prerequisites

Before starting the installation, we need to use git nf Flakes that we cat use nix-shell that allows us to use binaries that are not installed in the system.

[root@nixos:~]# nix-shell -p git nixFlakes
these paths will be fetched (12.56 MiB download, 75.48 MiB unpacked):
  /nix/store/0f92b8kgaki9s5rwdj81pni3wj7ca8k6-git-2.31.1-doc
  /nix/store/39j27lcvm8sn17k4589v7kxwic58qgsg-libcpuid-0.5.1
  /nix/store/3bk9dhdkzg11qm9g1zkv7vxqkvcaqnp6-lowdown-0.8.4-lib
  /nix/store/3ghvl0b0bd0pmrkczciy1i9gzlmi47mp-perl5.32.1-CGI-Fast-2.15
  /nix/store/47qr4rksqfi8kgc3kwjvrjy9ym1bj89g-gettext-0.21
  /nix/store/54dmlydl9lwvrmjjcgf5xrsydhnvasd0-nix-2.4pre20210601_5985b8b
  /nix/store/8sxrh4g1zan8lriwfqzw6iimqcaj4asi-perl5.32.1-CGI-4.51
  /nix/store/a95f72avd2r70w1rszb6mvyiabydr2nc-perl5.32.1-FCGI-0.79
  /nix/store/b9bisjs01ijfw60g8qjk59v843bkldbx-nlohmann_json-3.9.1
  /nix/store/c3vb6fvq802hckzz8xrgc6ja39k51af4-git-2.31.1
  /nix/store/ln6mp01fyp2dlxfihrnj64js699yzvvn-boehm-gc-8.0.4-dev
  /nix/store/p1m2imc7xbp5lf9298v2yndb3gqcr4la-libarchive-3.5.1-lib
  /nix/store/p4qkqk2rxcyxfhyv6gzj7inc388azgli-perl5.32.1-HTML-TagCloud-0.38
  /nix/store/ppwys502zs735azzksgs5wdya4rar626-nix-2.4pre20210601_5985b8b-dev
  /nix/store/qima3mpp9bb5gnarr5z1dw7zvlaj0r8d-nix-2.4pre20210601_5985b8b-man
  /nix/store/wzach25vwapl3sa6f7gylqank3jhhsin-bash-interactive-4.4-p23-dev
  /nix/store/x24qskawy3d4mj2vqpl0hr5pdhpa8d6i-perl5.32.1-FCGI-ProcManager-0.28
  /nix/store/zqf5dhf2pr6sxfgdpbq7gs1ajzknv2hm-perl5.32.1-TermReadKey-2.38
copying path '/nix/store/0f92b8kgaki9s5rwdj81pni3wj7ca8k6-git-2.31.1-doc' from 'https://cache.nixos.org'...
copying path '/nix/store/x24qskawy3d4mj2vqpl0hr5pdhpa8d6i-perl5.32.1-FCGI-ProcManager-0.28' from 'https://cache.nixos.org'...
copying path '/nix/store/p4qkqk2rxcyxfhyv6gzj7inc388azgli-perl5.32.1-HTML-TagCloud-0.38' from 'https://cache.nixos.org'...
copying path '/nix/store/wzach25vwapl3sa6f7gylqank3jhhsin-bash-interactive-4.4-p23-dev' from 'https://cache.nixos.org'...
copying path '/nix/store/ln6mp01fyp2dlxfihrnj64js699yzvvn-boehm-gc-8.0.4-dev' from 'https://cache.nixos.org'...
copying path '/nix/store/47qr4rksqfi8kgc3kwjvrjy9ym1bj89g-gettext-0.21' from 'https://cache.nixos.org'...
copying path '/nix/store/p1m2imc7xbp5lf9298v2yndb3gqcr4la-libarchive-3.5.1-lib' from 'https://cache.nixos.org'...
copying path '/nix/store/39j27lcvm8sn17k4589v7kxwic58qgsg-libcpuid-0.5.1' from 'https://cache.nixos.org'...
copying path '/nix/store/3bk9dhdkzg11qm9g1zkv7vxqkvcaqnp6-lowdown-0.8.4-lib' from 'https://cache.nixos.org'...
copying path '/nix/store/qima3mpp9bb5gnarr5z1dw7zvlaj0r8d-nix-2.4pre20210601_5985b8b-man' from 'https://cache.nixos.org'...
copying path '/nix/store/b9bisjs01ijfw60g8qjk59v843bkldbx-nlohmann_json-3.9.1' from 'https://cache.nixos.org'...
copying path '/nix/store/8sxrh4g1zan8lriwfqzw6iimqcaj4asi-perl5.32.1-CGI-4.51' from 'https://cache.nixos.org'...
copying path '/nix/store/a95f72avd2r70w1rszb6mvyiabydr2nc-perl5.32.1-FCGI-0.79' from 'https://cache.nixos.org'...
copying path '/nix/store/zqf5dhf2pr6sxfgdpbq7gs1ajzknv2hm-perl5.32.1-TermReadKey-2.38' from 'https://cache.nixos.org'...
copying path '/nix/store/3ghvl0b0bd0pmrkczciy1i9gzlmi47mp-perl5.32.1-CGI-Fast-2.15' from 'https://cache.nixos.org'...
copying path '/nix/store/c3vb6fvq802hckzz8xrgc6ja39k51af4-git-2.31.1' from 'https://cache.nixos.org'...
copying path '/nix/store/54dmlydl9lwvrmjjcgf5xrsydhnvasd0-nix-2.4pre20210601_5985b8b' from 'https://cache.nixos.org'...
copying path '/nix/store/ppwys502zs735azzksgs5wdya4rar626-nix-2.4pre20210601_5985b8b-dev' from 'https://cache.nixos.org'...


Repo Clone

Now we can clone the repository where we have out configuration files needed for the nixos flake installation.

[nix-shell:~]# git clone https://github.com/mudrii/systst.git /mnt/etc/nixos
Cloning into '/mnt/etc/nixos'...
remote: Enumerating objects: 229, done.
remote: Counting objects: 100% (229/229), done.
remote: Compressing objects: 100% (160/160), done.
remote: Total 229 (delta 127), reused 149 (delta 57), pack-reused 0
Receiving objects: 100% (229/229), 67.03 KiB | 4.47 MiB/s, done.
Resolving deltas: 100% (127/127), done.


NixOs Flake Installation

The nixos-install script supports native NixOS Flake installation.

[nix-shell:~]# nixos-install --root /mnt --flake /mnt/etc/nixos#nixtst
building the flake in git+file:///mnt/etc/nixos?ref=master&rev=72a8edfd9d6bea0a314d561cdc15c4d72d8b9fb6...

copying channel...
installing the boot loader...
setting up /etc...
/etc/tmpfiles.d/journal-nocow.conf:26: Failed to resolve specifier: uninitialized /etc detected, skipping
All rules containing unresolvable specifiers will be skipped.
updating GRUB 2 menu...
installing the GRUB 2 EFI boot loader into /boot...
Installing for x86_64-efi platform.
/nix/store/gsf4bnf0pg5k8pyzbprx5l26gnq9w93n-grub-2.06-rc1/sbin/grub-install: warning: cannot open directory `/nix/store/gsf4bnf0pg5k8pyzbprx5l26gnq9w93n-grub-2.06-rc1/share/locale': No such file or directory.
Installation finished. No error reported.
setting up /etc...
/etc/tmpfiles.d/journal-nocow.conf:26: Failed to resolve specifier: uninitialized /etc detected, skipping
All rules containing unresolvable specifiers will be skipped.
setting up /etc...
/etc/tmpfiles.d/journal-nocow.conf:26: Failed to resolve specifier: uninitialized /etc detected, skipping
All rules containing unresolvable specifiers will be skipped.
setting root password...
New password: 
Retype new password: 
passwd: password updated successfully
installation finished!


Post-Installation

Once installation is completed, we can reboot the OS and log in as a user we declared in our configuration files.

[nix-shell:~]# reboot


System Update and Management

Once we have our system up and running is a good practice to keep the system up to date.

System update requires a two-step process:

  1. Flake update to lock the flake on the latest GitHub commit.
  2. nix rebuild switches to update the system.

Following the below steps will keep your system up to date:

mudrii@nixtst ~> sudo nix flake update /etc/nixos/
warning: updating lock file '/etc/nixos/flake.lock':
* Updated 'nixpkgs': 'github:nixos/nixpkgs/4181644d09b96af0f92c2f025d3463f9d19c7790' -> 'github:nixos/nixpkgs/63ee5cd99a2e193d5e4c879feb9683ddec23fa03'
* Updated 'nixpkgs-unstable': 'github:NixOS/nixpkgs/967d40bec14be87262b21ab901dbace23b7365db' -> 'github:NixOS/nixpkgs/16105403bdd843540cbef9c63fc0f16c1c6eaa70'
warning: Git tree '/etc/nixos' is dirty

mudrii@nixtst ~> sudo nixos-rebuild switch --flake /etc/nixos/#nixtst
warning: Git tree '/etc/nixos' is dirty
building the system configuration...
warning: Git tree '/etc/nixos' is dirty
updating GRUB 2 menu...
NOT restarting the following changed units: systemd-fsck@dev-disk-by\x2dlabel-boot.service
activating the configuration...
setting up /etc...
reloading user units for mudrii...
setting up tmpfiles
reloading the following units: dbus.service


In the follow-up tutorial, we will cover home manager installation and configuration using native flake implementation.

 

 

 

 

Top