My NixOS Journey Part 1

Part One | Part Two | Part Three

Welcome to my journey.  I'm documenting how I make my way down the rabbit hole, failures, successes, lessons learned all in hopes that I don't do it again, and maybe you'll be able to take away something from this too.

Where to discuss this article or contact me

Matrix:
#my-nixos-journey:beardedtek.com
#nixnerds:jupiterbroadcasting.com
@beardedtek:beardedtek.com
Telegram:
@beardedtek
Twitter:
@beardedtek
Email:
contact@beardedtek.com

I've been wanting to try NixOS for quite some time.  The idea of an immutable system to use as a server platform seems very interesting, however, it's fairly intimidating to get started.

I plan on documenting everything along the way.  All my mistakes, pitfalls, and bad habits I've brought along with me.  It may not be flattering, but it comes from a place of truth.

I've been using Linux in one way or another since the late 90s starting with Slackware 3 point something and OG Red Hat.  I've had laptops where I damaged the screen because my XFree86 config was way off.  I've run Debian on a Pentium Pro 100 with dialup and a static IP running on a 28.8kbps dialup modem.  OpenSUSE Tumbleweed, Ubuntu Server 23.04 and Debian have become my go-to distributions.

If you see me going down a wrong path or just want to discuss this article, please join me on Matrix at #my-nixos-journey:beardedtek.com.

Thanks to Jupiter Broadcasting and their Nix community which can be found on matrix at #nixnerds:jupiterbroadcasting.com, I'm at least starting to test the waters with my pinky toe.

The path I've decided to take will be the following:

  • Install a simple system in a VM with the graphical installer
  • Install a simple system in a VM with the manual text minimal installer
  • Configure Nix to be a simple docker host (Not exactly the Nix way, but that's okay)
  • See where this all leads me!
Article continues below

While you're here, check out my Etsy Store where I produce 3D Printed Nerdery

15% OFF 2 or more items throughout July 2023!

Preparation

Prerequisites to install NixOS

There's a couple things we need to do before we get started.

Download the installer, the current version as of writing this is 23.05:

Screenshot of https://nixos.org/download.html NixOS section (July 3, 2023)

I acquired both the Plasma Desktop, 64-bit Intel/AMD and the Minimal 64-bit Intel/AMD version.  Make sure you download the version that matches your hardware.

Download Nix / NixOS | Nix & NixOS
Nix is a tool that takes a unique approach to package management and system configuration. Learn how to make reproducible, declarative and reliable systems.

Create a Virtual Machine and attach our installer iso as a bootable CDROM/ISO

4vCPU 4GB Memory 50GB Storage

NixOS Graphical Installer

"The Easy Way"

The Graphical Installer is actually quite easy to use.  It took about 4 minutes to install the system.  That's right 4 minutes.  Impressive.

0:00
/

NixOS Manual Install

Setting it up as a basic docker host with cockpit

Conducting a manual install from the stock install medium is a bit more intense for someone not comfortable on the command line.  However, most Linux users used to the command line should be fairly familiar with most of the required commands.

I followed the Manual Installation Instructions available on nix.org.  I'll outline them here, but for the most up to date information follow the link above.

Here's the highlights of what I changed in my configation.nix

For EFI Boot:

# Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

Set Timezone:

  time.timeZone = "America/Anchorage";

User Setup

  users = {
    # Make configuration.nix the source of truth for users.
    # When set to false, you will NOT be able to add users from the shell.
    mutableUsers = false;
    users = {
      beardedtek = {
        isNormalUser = true;
        description = "The Bearded Tek";
        createHome = true;
        home = "/home/beardedtek";
        group = "beardedtek";
        extraGroups = [ 
          "wheel"           # Enable sudo
          "docker"          # Enable docker
          "systemd-journal"
        ];
        hashedPassword = "$6$gUid22Le9ZVHH1qo$fzLvtkwTcPBDc7PuGN73eHGxCPRUW7Hvtnc/tQ2UYTWBdwBXPBz.9OtaI8mCtxnLGz0YPHjBR2neZI0PWsoSc/";
        openssh.authorizedKeys.keys = [
          (builtins.readFile ./sshkey_beardedtek)
        ];
        packages = with pkgs; [ ];
        uid = 1000;
      };
    };
    groups = {
      # Setup custom groups
      beardedtek = {
        name = "beardedtek";
        members = [ "beardedtek" ];
        gid = 1000;
      };
    };
  };

Allow Non-Free packages (Unfree as Nix calls it)

  nixpkgs.config.allowUnfree = true;

Define packages to install
I decided on docker-compose, python311, plex, and cockpit

   environment.systemPackages = with pkgs; [
     nano # Why would I ever want vim to touch my system :)
     wget
     docker-compose
     nerdctl
     python311
     plex
     cockpit
   ];

Enable services on boot:

  virtualisation.docker.enable = true;
  services = {
    openssh.enable = true;
    plex.enable = true;
    cockpit.enable = true;
  };

Set Up Networking:
NOTE: Make sure to set your network interface if it doesn't match
You can find this out by issuing the command ip -a in a terminal

I disabled the firewall in this example since it is on my home network with no access from the outside world.

  networking = {
    interfaces.enp1s0.ipv4.addresses = [ {
      address = "192.168.2.15";
      prefixLength = 24;
    } ];
    defaultGateway = "192.168.2.1";
    nameservers = [
      "192.168.2.10"
      "192.168.2.145"
      "9.9.9.9"
      ];
    enableIPv6 = false;
    firewall = {
      enable = false;
    };
  };

Here's the whole thing together


{ config, pkgs, ... }:
{
  imports =
    [ # Include the results of the hardware scan.
      ./hardware-configuration.nix
    ];

  # Use the systemd-boot EFI boot loader.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  # Set your time zone.
  time.timeZone = "America/Anchorage";

  # User Setup

  users = {
    # Make configuration.nix the source of truth for users.
    # When set to false, you will NOT be able to add users from the shell.
    mutableUsers = false;
    users = {
      # Define each user here
      # Set user passwords by using the following command:
      #   export PW_USER=$(mkpasswd -m sha-512)
      # Set authorized ssh key using:
      #   export SSH_KEY_USER="your_ssh_key_here"
      beardedtek = {
        isNormalUser = true;
        description = "The Bearded Tek";
        createHome = true;
        home = "/home/beardedtek";
        group = "beardedtek";
        extraGroups = [ 
          "wheel"           # Enable sudo
          "docker"          # Enable docker
          "systemd-journal"
        ];
        hashedPassword = "$6$gUid22Le9ZVHH1qo$fzLvtkwTcPBDc7PuGN73eHGxCPRUW7Hvtnc/tQ2UYTWBdwBXPBz.9OtaI8mCtxnLGz0YPHjBR2neZI0PWsoSc/";
        openssh.authorizedKeys.keys = [
          (builtins.readFile ./sshkey_beardedtek)
        ];
        packages = with pkgs; [ ];
        uid = 1000;
      };
      root = {
        hashedPassword = "$6$gUid22Le9ZVHH1qo$fzLvtkwTcPBDc7PuGN73eHGxCPRUW7Hvtnc/tQ2UYTWBdwBXPBz.9OtaI8mCtxnLGz0YPHjBR2neZI0PWsoSc/";
      };
    };
    groups = {
      # Setup custom groups
      beardedtek = {
        name = "beardedtek";
        members = [ "beardedtek" ];
        gid = 1000;
      };
    };
  };

  # Allow non-free (Unfree) packages
  nixpkgs.config.allowUnfree = true;

  # List packages installed in system profile. To search, run:
  # $ nix search wget
   environment.systemPackages = with pkgs; [
     nano # Why would I ever want vim to touch my system :)
     wget
     docker-compose
     nerdctl
     python311
     plex
     cockpit
   ];
  
  # Enable docker
  virtualisation.docker.enable = true;

  # Enable Services
  services = {
    openssh.enable = true;
    plex.enable = true;
    cockpit.enable = true;
  };

  # Setup Networking
  networking = {
    interfaces.enp1s0.ipv4.addresses = [ {
      address = "192.168.2.15";
      prefixLength = 24;
    } ];
    defaultGateway = "192.168.2.1";
    nameservers = [
      "192.168.2.10"
      "192.168.2.145"
      "9.9.9.9"
      ];
    enableIPv6 = false;
    firewall = {
      enable = false;
    };
  };

  system.stateVersion = "23.05";

}

Now issue the command nixos-install and it will attempt to build.

If you come across errors, it will give you some basic information on where to look for your errors.


Please check back soon for more.  I'll be adding to this mostly daily with what I've learned until I get my first system tuned exactly how I want it.