NixOS 101

A variant of Linux that uses declarative approach. Like how Cisco use a single IOS config file to define the function of a switch, router, firewall, NixOS can use a single configuration.nix file to declare all its settings.
Instead of using Puppet or Chef to configure the OS, NixOS natively use its own declarative language to define how the OS is to be configured. Their emphasis is on the "what" of the config instead of the "how". ie. define that you need an apache httpd server, instead of finding what rpm to install. But fact is, all the unix admin knowledge is still there, just condensed into a single parameter definition file. eg. enable sshd. use port 22. define user foo. assign the home dir /home/foo. give it /bin/zsh as shell.
I also blogged another reason why declarative OS like NixOS is the right new paradigm.

Ref: About NixOS


Initial install

  1. Create a bootable USB using Unetbootin based on a live dvd iso. (Unetbootin is like Lili usb creator, but this didn't work as of 2015.09.15 as it didn't know about NixOS yet and used generic Linux, which failed to boot). ref: NixOS wiki
  2. Pre create the file system on the desired hard drive (fdisk, mkfs, lvm if desired) ref: NixOS manual install page
  3. mount /dev/sda1 /mnt
  4. swapon /dev/sda2
  5. nixos-generate-config --root /mnt
  6. vi /mnt/etc/nixos/configuration.nix
    enable grub boot loader. add additional desired pkg. (nano is avail if vi is not)
  7. cat /mnt/etc/nixos/hardware-config.nix
    ensure right disk is defined as device#1. use blkid /dev/sda1 to check disk UID.
  8. nixos-install # this command must somehow be preprogrammed to write to /mnt, and look for configuration.nix rooted in there.
  9. give a pw for the root acc when prompted. If it didn't ask to set a password, something went wrong and nixos install need to be run again.
  10. reboot
TBA: how to install behing a proxy. this seems to be a difficult task at this time.
Basic configuration.nix for a laptop with KDE gui

# Edit this configuration file to define what should be installed on
# your system.  Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running 'nixos-help').

## run sudo nixos-rebuild switch 
## to apply changes

{ config, pkgs, ... }:

  imports =
    [ # Include the results of the hardware scan.

  # Use the GRUB 2 boot loader.
  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  # Define on which hard drive you want to install Grub.
  # boot.loader.grub.device = "/dev/sda";
  boot.loader.grub.device = "/dev/sda";

  # networking.hostName = "nixos"; # Define your hostname.
  networking.hostName = "nixon"; # Define your hostname.
  networking.hostId = "b6e466c1";
  networking.firewall.enable = true;
  networking.firewall.allowPing = true;
  networking.networkmanager.enable = true;  # 10.1
  #networking.wireless.enable = true;  	# true means use wpa_supplicant
  #networking.useDHCP = false; 		# Don't run dhclient on wlan0, but break DNS
  networking.wicd.enable = false;	# wicd-gtk to run gui client

  # Select internationalisation properties.
  # i18n = {
  #   consoleFont = "lat9w-16";
  #   consoleKeyMap = "us";
  #   defaultLocale = "en_US.UTF-8";
  # };

  # List packages installed in system profile. To search by name, run:
  # $ nix-env -qaP | grep wget
  # environment.systemPackages = with pkgs; [
  #   wget
  # ];

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  # services.openssh.enable = true;
  services.openssh.enable = true;

  # Enable CUPS to print documents.
  # services.printing.enable = true;

  # Enable the X11 windowing system.
   services.xserver.enable = true;
   services.xserver.layout = "us";
  # services.xserver.xkbOptions = "eurosign:e";

  # Enable the KDE Desktop Environment.
   services.xserver.displayManager.kdm.enable = true;
   services.xserver.desktopManager.kde4.enable = true;

  # Define a user account. Don't forget to set a password with 'passwd'.
  # users.extraUsers.guest = {
  #   isNormalUser = true;
  #   uid = 1000;
  # }; = {
    isNormalUser = true;
    uid = 1001;
    home = "/home/sn";
    extraGroups = [ "wheel" "networkmanager" ];
    openssh.authorizedKeys.keys = [ "ssh-dss AABB..." ];

  users.extraUsers.sa9 = {
    isNormalUser = true;
    uid = 999;
    home = "/home/sa9";
    extraGroups = [ "networkmanager" ];
    openssh.authorizedKeys.keys = [ "ssh-dss AABB..." ];
    hashedPassword = "testtesttest";
  # removing a user from the config file will trigger a userdel.  
  #but the home dir remains (understandably don't want to delete files)

  environment.systemPackages = with pkgs; [
        zsh wget htop nmap netcat telnet wireshark-qt
	vim vimPlugins.ipython vimPlugins.vim-addon-syntax-checker vimPlugins.vim-addon-nix
 	vimNox #vimHugeX
	python27Packages.ipython 	python34Packages.ipython
	gpgme dos2unix bzip2 		#gzip avail by def
	# commenting out pkg will remove the sym links and take them out of the path, 
	# but pkg and executable is actually still avail in /nix/store
	# automake 	autoconf 	cmake 		gnumake
	#couchdb			# unable to compile :(
	aws		awscli		
	docker 		kubernetes 	vagrant
 	# uge   			# gridengine not yet avail
        #chromiumWrapper    		# this doens't seems to exist anymore
	firefoxWrapper 	firefox   

	# virtualisation need pkg installed, plus config param (see below)

        kde4.networkmanagement 	kde4.kdemultimedia 	kde4.kdegraphics
        kde4.kdeutils 		kde4.applications 	#pkgs.kde4.kdegames
	kde4.kdebindings 	kde4.kdeaccessibility 	kde4.kde_baseapps
        kde4.kactivities 	kde4.kdeadmin 		kde4.kdeartwork
        kde4.kde_base_artwork 	kde4.kdenetwork 	kde4.kdepim
        kde4.kdepimlibs 	kde4.kdeplasma_addons 	kde4.kdesdk
        kde4.kdetoys 		kde4.kde_wallpapers 	kde4.kdewebdev
        kde4.oxygen_icons 	kde4.kdebase_workspace 	kde4.kdelibs
        kde4.kdevelop 		kde4.kdevplatform 	kde4.qtcurve
        kde4.ColorSchemes 	kde4.desktopthemes 	kde4.kscreensaver
        kde4.kwin_styles 	kde4.partitionManager 	kde4.qt4
        kde4.yakuake 		kde4.kgpg

	tightvnc 		ssvnc 			xterm
	x86info  		binutils


  # package configuration
  nixpkgs.config.allowUnfree = true;
  nixpkgs.config.firefox.enableAdobeFlash = true; # for Firefox

  nixpkgs.config.chromium.enableAdobeFlash = true; # for Chromium
  nixpkgs.config.chromium.enablePepperFlash = true;
  nixpkgs.config.chromium.enablePepperPDF = true;

  security.sudo.wheelNeedsPassword = false;

  # apparently virtualbox should NOT be added just as a package
  # but could not get below to work, so just added as a package afterall
  # run it by calling VirtualBox
  # = true;
  # probably changed to this clause below:
  # services.virtualboxGuest.enable = true;
  users.extraGroups.vboxusers.members = [ "sn" ];
  # virtualisation.xen.enable = true;


This is an example of configuration.nix from my last nixos install.
Basic hardware-configuration.nix
# Do not modify this file!  It was generated by 'nixos-generate-config'
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, ... }:

  imports =

  boot.initrd.availableKernelModules = [ "ehci_pci" "ata_piix" "firewire_ohci" "usb_storage" ];
  boot.kernelModules = [ "kvm-intel" ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    ##{ device = "/dev/disk/by-uuid/81c298dc-64e4-4dde-9986-069753dcdece";
    { device = "/dev/sda1";
      # aka /dev/sda1  label=nixos
      fsType = "ext4";

  swapDevices =
    ##[ { device = "/dev/disk/by-uuid/3a9de093-d26c-464a-b900-0ca5e1243bb8"; }
    [ { device = "/dev/sda5"; }
      # aka /dev/sda5  label=swapspace

  nix.maxJobs = 4;
This is an example of hardware-configuration.nix from my last nixos install.

One can create many additional *.nix config and import them into the configuration.nix. Some like the modularity of it. The default config separate the hardware into its own specific file. Other may place a GUI desktop part into its own file, thus easy to trim it out for a headless server. Beyond that, I personally like one monolithic file, so that it is easy to run a diff between two servers to find what difference have been made that may explain functionality differences.
Other example config: ordinatechnic

Notes on *.nix config file
There should be a single { config, pkgs, ... }: section. If needed additional clause, change it , but don't add new {section}. eg: { config, lib, pkgs, ... }: .
There are a couple of ways to add software package, I like:
environment.systemPackages = with pkgs; [      # it is a semi-colon in there, i do find it weired...

Another format used often in the NixOS manual
environment.systemPackages =
  [ pkgs.thunderbird

# not sure for  pkgs.kde4.pgpg        

This is the list of available packages as of 2015.09

Changing config

  1. sudo vi /etc/nixos/configuration.nix
  2. sudo nixos-rebuild switch Reboot is NOT needed.
  3. nixpkgs is for creating new Nix Packages. But sometime may need to refer to it to see what config parameters are exposed for setting in configuration.nix. eg of nixpkgs locations: /nix/store/pilijx70f4bf81w1i01pp63s5lrqlqya-nixos-14.12.875.bb79e19/nixos/nixpkgs ~/.nixpkgs

Update package and OS

nix-channel --update		# apt-get update.  
				# run as root for system-wide update (root env is used by everyone)
				# run as user for personal's env update only.
				# need to run this at least once to get an initial db, eg use by command-not-found
				# This update w/in current channel, so just get bug fixes, minor changes.

sudo nix-channel --add nixos 	# eg upgrade from 14.12 to 15.09
sudo nix-channel --add nixos 	# bleeding edge

nixos-rebuild  switch		# apt-get upgrade
				# run this after channel update to update the whole OS (pkg in environment.systemPackages)

nixos-rebuild  switch --upgrade	# ie nix-channel --update nixos; nixos-rebuild switch

nix-channel --list		# run as root for system-wide config
				# generally safe to switch back and forth b/w channels, so long as they did not have Nix schema upgrade!

nix-store --verify --check-contents		# verify all installed packages.  eg apt-get check, debsums
nix-store --verrify --check-contents --repair	# fix/reinstall broken package (ie failed checksum)

nix-env -u --keep-going				# per-user package upgrade
nix-env -u --keep-going	-leq			# -leq will update if the dependencies are the one that changed 

nix-channel --list
            --add	# Add additional channel (eg yum repository)
            --remove CHANNELNAME

ref: NixOS manual ch 4 - Upgrade

SW Pakcage Versioning

The configuration.nix file has provision to specify a specific version of the software to install. eg remove software shows an example in using nixpkgs.config.packageOverrides to specify an older version of KDE.

However, there may not be any easy provision to switch mix of different software versions and combination at will, as could be done with SoftEnv or modules. Theoretically, the different versions can all just be installed. They are symlinks anyway, so it is just a matter of having a wrapper to change out the links to pick the right versions and combinations into the user's profile.

On the other hand, for shops that setup a large respository of software in a centralized NFS location such as /mnt/programs, and use SoftEnv or Modules to switch between desired version depending on user's desire, Nix/NixOS will not hinter such setup. Such NFS world is essentially a parallel universe :)

As to compiling program from source because Nix didn't provide it, this is still possible, but not as straight forward as say compiling a program in Ubuntu or RedHat. These problems are likely transient as NixOS matures and get wider support from the community. Example complications are:
  1. Depenencies are no longer in a centralized place such as /lib. One would have to hunt for such location and feed them into ./configure . It is worth noting that the dependencies can still be provided thru Nix, one does not have to install everything from source. It is just that ./configure may need help finding where these dependencies are, since there is no "centralized" LD_LIBRARY_PATH where dependencies would typically be installed in most other Unix OS.
  2. ./configure may not correctly determine it is running in NixOS, and may use flags designating compilation for a wrong OS Environment. eg, my last compilation of couchdb, I had to seed CFLAGS="-D _DEFAULT_SOURCE" so that configure did not create makefile for BSD.

Ad-hoc package addition

NixOS allows the use of nix-env -i PKGNAME to add package. this is similar to yum install PKGNAME. But for a declarative OS, I think it is best to put everything in the config file (system-wide configuration.nix or per-user ~/nixpkgs/config.nix..
One nice thing, say for a development machine, user can add their own package without needing root password and so such commands would be run by the user.

nix-env -i PKGNAME 		# add   package, like yum install PKGNAME.
nix-env -e PKGNAME 		# erase package, like rpm -e ...
nix-env -u 			# upgrade all pkg that has update
nix-env -q			# list packages installed by user and not as root
nix-env -q --installed		# no diff than above
??				# rpm -qa 
				# no equiv of nix-env -q for root/system-wide settings (as of 8jun2011)
nix-store -q --references /var/run/current-system/sw | cut -d'-' -f2- 	# list all downloaded packages for all user (root and per-user basis), incl deleted pkg (but not yet cleaned/garbage collected)

nix-env -qa \*			# list avail pkg for install.  ie: yum list
nix-env -qaP '*' --description	# --query --available --attr-path
nix-env --rollback		# undo last "nix-env -i" (eg user pkg install, could be root if done as sudo and with -p)
nix-env -p /nix/var/nix/profiles/system --list-generations	# list avail generations (one generation created per each nixos-rebuild)
								# generation list is also present in grub menu

nix-env --delete-generations old	# remove sw that is no longer needed to free up space, but can no longer rollback
nix-collect-garbage -d

nix-search  vim
nix-install vim

Cheatsheet says that as a user, can run dpkg -i packagename.deb to add a debian package!! (not sure where files will be installed). Need to have the dpkg command/package installed in NixOS for this.

Per-User package collection

# personal's collection, here called 'all'
# TBA, was not able to change name to sn-pkg
# it is really just like any other pkg
# Place file in ~/.nixpkg/config.nix
# add the whole collection via nix-env -i all
# NOTE: pkg installed on cli via nix-env -i dropbox would 
# conflict with a dup listed in this file
# also, nix-env -q will only show "all" as installed, not the individual pkg.
# this is perhaps a problem of treating it as pkg rather than a container, now things are opaque.
  packageOverrides = pkgs_: with pkgs_; {
    all = with pkgs; buildEnv {
    #sn-pkg = with pkgs; buildEnv {
      name = "all";
      paths = [
	#dropbox 	roxterm 	transmission
	vlc 		w3m 		tcsh


nixos-rebuild switch	# change/update system as per /etc/nixos/configuration.nix 
nixos-rebuild boot
nixos-rebuild switch -p test
nixos-rebuild build
nixos-rebuild switch --rollback		# undo last "nixos-rebuild switch"  this will stop service, etc, whatever that were enabled would be reverted back.
					# but will not rewrite /etc/nixos/configuration.nix (it just uses a diff cached version stored in /nix/store?)
					# ref

nixos-option services.xserver.enable	# find out what the config file has resulted.  ie, this is a read, not a set.

systemctl start apache		# start a service (apache daemon), need to run as root, but best to set it perm in configuration.nix
systemctl stop  apache		

command-not-found xterm		# tell what package to install to provide a given command 
				# DB is updated via nix-channel --update
nox xterm                     	# present a list of packages matching the queried command

nix-store --query --requisites $(readlink -f /run/current-system) 	# list package dependencies, eg
									# apt-cache depends couchdb
nix-store --query --references $(which roxterm)				# for installed package at user level

??				# list files installed by a pkg,    eg dpkg -L nmap
??				# which pkg installed a given file, eg dpkg -S /usr/bin/vim

nixos-version			# tell version of running os 
passwd username			# 


environment.env # settings for default ?

Pros and Cons of NixOS/Nix dogma

  1. From debian devel:
    1. Not everything can be functional. solution such as ridding ldcache may make system slow.
    2. run time and build time dependcies are intermingled.
    3. Being able to go back to any previous version means never getting ride of any code, even those with security flaws.
    4. May not be scalable to OS the size of Debian
  2. From Y combinator
    1. Idempotency, atomicity
  3. Why Puppet/Chef/Ansible aren't good enough (and we can do better)
    1. Chef and Fabric provides Automated Imperative Configuration
    2. Puppet and Ansible provides Declarative Configuration
    3. Docker... ??
    4. NixOS/Nix provides stateless Declarative Config



Copyright info about this work

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike2.5 License. Pocket Sys Admin Survival Guide: for content that I wrote, (CC) some rights reserved. 2005,2012 Tin Ho [ tin6150 (at) ]
Some contents are "cached" here for easy reference. Sources include man pages, vendor documents, online references, discussion groups, etc. Copyright of those are obviously those of the vendor and original authors. I am merely caching them here for quick reference and avoid broken URL problems.

Where is PSG hosted these days?