dark_mode format_list_bulleted
Getting Started with NixOS: Guideline for FHS users
Migrating to NixOS from Fedora: making the non-FHS environment to be FHS-compatible.
history
History
Updated at Sat, 28 Dec 2024 14:30:00 GMT
Published at Fri, 06 Dec 2024 09:25:00 GMT
nix-os
visibility public group

Since 2020, I had always been a loyal Fedora user. Fedora is always providing the latest technologies, features and experience to users, also provides btrfs support I love which is not available in the Red Hat kernel.

But since Nov 2024, I was motivated by derivation from configuration in NixOS.

My NixOS configuration is available at github.com/jellyterra/nixos-config. It may help you get started and set your NixOS up.

This tutorial will help configure …

What do we really need from Nix and NixOS?

Nix is very valuable for environment reproduction in academic papers.

I strongly recommend researchers to take Nix as their environment manager. They are almost environmental reproducible at least for the projects that provides Nix configuration.

It’s an ideal solution for the Replication Crisis at the software level in the computer science related works.

— Jelly Terra

What are still lacking in NixOS?

When you need not NixOS?

[!TIP]

For individual or enterprise users who want pure FHS in production environment: Ansible, Ignition and Terraform/OpenTofu might be more suitable choices rather than Nix.

The Eden

Installation of one distro is super easy. But the trouble appears around us is mostly the post-installation configuration and maintenance.

Ofc, NixOS certainly provides the best introduction of them.

NixOS is configured via generating by the /etc/nixos/configuration.nix.

Graphical or manual installation

Official manual is the best guideline. The process is simple. You can do it yourself.

I choose KDE on my workstation.

Pre-installation mirror setup

If the connection to cache.nixos.org is slow. You can prepend mirrors in /etc/nix/nix.conf.

ll /etc/nix/nix.conf
nix.conf -> /etc/static/nix/nix.conf
# Backup
cp /etc/nix/nix.conf .../nix.conf
# Remove symlink.
rm /etc/nix/nix.conf
# Copy back.
cp .../nix.conf /etc/nix/nix.conf
# Modify.
nano /etc/nix/nix.conf
# Prepend the mirror before cache.nixos.org
substituters = https://mirror.sjtu.edu.cn/nix-channels/store https://cache.nixos.org/

Install packages on NixOS

# Deprecated. Not recommended.
nix-env -i
# /etc/nixos/configuration.nix
environment.systemPackages = with pkgs; [
  # Correct way.
];
# Apply changes to one new generation and switch to it.
nixos-rebuild switch

[!IMPORTANT]

In NixOS, everything is derived from the Nix expressions in the NixOS configuration file. The user shouldn’t edit the generated configuration files, or modify software packages. Every change should be done by editing the NixOS configuration file in Nix language, then switch to the new generation has been built.

Build the NixOS Environment with FHS-Compatibility

NixOS is designed to be non-FHS. They choose to let the users configure the FHS environment by themselves. Rather than making one FHS-compatible default preset.

All system-wide binaries and libraries will be symlinked to /run/current-system/sw after nix-rebuild switch. Almost like another system root in FHS.

For users who prefer FHS, there are many ways to build one FHS-compatible environment. One of them is buildFHSEnv, but we will not take this.

In the examples we’ll see next, we’ll try build it in system-wide environment through one more elegant way.

[!NOTE]

The changes are based on the configuration.nix after the NixOS installation. Most settings are well-documented in comment blocks and the NixOS Wiki.

Nix and NixOS

nix.settings.substituters = lib.mkBefore [ "https://mirror.sjtu.edu.cn/nix-channels/store" ];

nixpkgs.config.allowUnfree = true;

system.stateVersion = "24.11";

systemd.targets = {
  sleep.enable = false;
  suspend.enable = false;
  hibernation.enable = false;
  hybrid-sleep.enable = false;
};

Filesystems

nixos-generate-config would automatically detect the partitions on the disks and generate options for you and save to hardware-configuration.nix.

Use lib.mkForce to override them with your changes.

Example:

fileSystems."/home" = {
  device = "/dev/nvme0n1p2";
  fsType = "btrfs";
  options = [ "compress=zstd:3" "nosuid" "subvol=@/home" ];
};

fileSystems."/opt" = {
  device = "/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000";
  fsType = "btrfs";
  options = [ "compress=zstd:3" "nosuid" "subvol=@/opt" ];
};

fileSystems."/external" = lib.mkForce {
  device = "/dev/sda";
  fsType = "xfs";
  options = [ "nofail" "noexec" ];
};

Networking

Choose one from the solutions below.

Direct

networking = {
  nameservers = [ "1.1.1.1" ];
  # If using dhcpcd:
  dhcpcd.extraConfig = "nohook resolv.conf";
  # If using NetworkManager:
  networkmanager.dns = "none";
}

Local DNS Resolver - systemd-resolved

services.resolved = {
  enable = true;
  fallbackDns = [ "1.1.1.1" ];
};

Firewall

networking.firewall = {
  enable = true;
  allowedTCPPorts = [];
};

nix-ld

When running FHS-based generic-linux programs, the ld reports the program is not compatible with NixOS. That’s the time we need nix-ld to locate and load the libraries from various packages and paths.

You really need it!

programs.nix-ld.enable = true;
programs.nix-ld.libraries = with pkgs; [
  # Add the packages here.
  bubblewrap
  busybox
  gcc
  openssl
  pkg-config
  wineWowPackages.staging
  libxcrypt-legacy
];

Now the programs are able to be running with the libraries.

For users who want running IntelliJ IDEA, fill the dependencies to nix-ld.libraries. Refer to NixOS Wiki for JetBrains Tools.

System-wide packages

environment.systemPackages = with pkgs; [
  # Add the packages here.

  (chromium.override {
    enableWideVine = true;
    commandLineArgs = [
      "--enable-wayland-ime"
      "--enable-features=UseOzonePlatform,ScrollableTabStrip:minTabWidth/140"
      "--ozone-platform-hint=wayland"
    ];
  })

] ++ config.programs.nix-ld.libraries;

[!TIP]

It’s recommended to add all the packages have to be overridden to <environment.systemPackages>. And others to <nix-ld.libraries>.

Environment variables

Some Nix options do have default value. I usually choose to override them. It’s troublesome to me to prepend or append them.

environment.variables = rec {
  # NOTE: You may have to prepend the default value or nobody knows what problem will be caused.
  LD_LIBRARY_PATH = lib.mkForce (with pkgs; lib.makeLibraryPath config.programs.nix-ld.libraries);

  # For Chromium users.
  GOOGLE_API_KEY = "";
  GOOGLE_DEFAULT_CLIENT_ID = "";
  GOOGLE_DEFAULT_CLIENT_SECRET = "";
};

bashrc

programs.bash.shellInit = ''

# Shell script here.
alias la='ls -a'

''

PAM

Fingerprint

services.fprintd.enable = true;
security.pam.services.login.fprintAuth = lib.mkForce true;

Udev Rules

services.udev.extraRules = ''

# CH340
SUBSYSTEMS=="usb", ATTR{idVendor}=="1a86", ATTR{idProduct}=="7522", GROUP="plugdev", MODE:="0666"

''; }

Desktop Environment

These are configured by NixOS installer with KDE installed chosen by user:

Fonts

fonts.packages = with pkgs; [
  noto-fonts
  noto-fonts-cjk-sans
  noto-fonts-emoji
];

Flatpak

services.flatpak.enable = true;

GDM & Plasma 6

services.xserver = {
  enable = true;
  displayManager.gdm = {
    enable = true;
    wayland = true;
  };
  xkb = {
    layout = "us";
    variant = "";
  };
};

services.desktopManager.plasma6.enable = true;

Input Method

i18n.inputMethod = {
  enable = true;
  type = "fcitx5";
  fcitx5.waylandFrontend = true;
  fcitx5.addons = with pkgs; [
    fcitx5-chinese-addons
  ];
};

Choose Fcitx 5 in Settings -> Keyboard -> Virtual Keyboard to launch the Fcitx on session start.

Hardware Acceleration

hardware.graphics = {
  enable = true;
  extraPackages = with pkgs; [
    # Intel Hardware Codec
    vpl-gpu-rt
  ];
};

Maintenance

Update packages

nix-channel --update
nixos-rebuild switch --upgrade-all

Upgrade to newer NixOS release

system.stateVersion = "24.11";
nix-channel --add https://nixos.org/channels/24.11 nixos
nix-channel --update
nixos-rebuild boot --upgrade-all

Garbage collection

After the generation whatever caused by installation, configuration or upgrade. Let Nix remove unused packages and boot entries to free storage space.

# Delete all.
nix-collect-garbage --delete-old

# Delete expired only.
nix-collect-garbage --delete-older-than 7d

[!CAUTION]

You will be unable to roll back to the deleted generations and boot entries. They are GONE!

All Done!

Now you’ve got your NixOS configuration and can be re-used on other machines!

Install and run toolchains, IDEs and EDAs. Rust-up, Julia-up, JetBrains IDEA/CLion, Xilinx Vivado and more things. These FHS-based programs are now able to be running on your system.

Append missing dependencies required by the programs to programs.nix-ld.libraries. No third-party source such as Nixpkgs needed.

If you want, push your NixOS configuration to one Git repo!

[!TIP]

Do not forget to do sensitive data redaction when you share the configuration.

What do you think about it?