Skip to content

Instantly share code, notes, and snippets.

@clample
Last active March 29, 2024 09:03
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clample/e3c51bf8026098fded9628d3e0ee7967 to your computer and use it in GitHub Desktop.
Save clample/e3c51bf8026098fded9628d3e0ee7967 to your computer and use it in GitHub Desktop.
NixOS Ubuntu Dual Boot

NixOS Ubuntu Dual Boot

Why?

After using NixOS for a year, I've found it to be a great operating system. When the software I need is on nixpkgs, things work out great. When I need to install software from outside of nixpkgs, though, it can become a pain. Trying to figure out the quirks of some closed source application can become pretty complicated. It would be great to package it and contribute it back to nixpkgs, but a lot of the time I just want to have the application working as soon as possible.

Since Ubuntu is a more standard linux distribution, I hope that it's better supported by some of these closed source applications. By dual booting, it's possible to get the best of both worlds.

Alternatives to Dual Booting

While dual booting works great for me, it may not be the best solution for you.

One option is to run one of the operating systems in a virtual machine. I tried this, but it's just too slow on my old Thinkpad.

NixOS offers some escape hatches too - for example buildFHSUserEnv. This is worth trying out if a particular application is giving you problems. I couldn't figure out how to apply this to all of the applications that I want to run, though.

Another solution might just be to run nix (the package manager, not nixOS) on Ubuntu. I've never tried this. Personally, I'm generally happy with NixOS and want to stick with it as much as possible.

Other Resources

A lot of this post is taken from Chris Martin - Installing NixOS. It covers how to install NixOS with an encrypted disk partition, but doesn't cover dual booting. There is also the NixOS Manual and NixOS Bootloader Wiki.

Overview

We will use GRUB as a bootloader and use UEFI. For the NixOS filesystem, we will encrypt it with LUKS, but for the Ubuntu filesystem we won't bother.

First, back up all of the important data on your hard drive. We will be clearing the hard drive and starting from scratch, so everything will be lost. Basically all commands will need to run with sudo. For convenience, you can run sudo -i so that your whole terminal session will be run as root.

Bootable USB drive

We will be installing NixOS first. Download the Graphical Live CD here. We will create a bootable USB drive from the downloaded .iso file.

If you are on Windows, you will need to find another guide on creating a bootable USB drive and skip to the next section (Ubuntu has a tutorial here).

With the USB drive plugged in, run lsblk to find how it is named:

# lsblk
NAME   MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
...
sda      8:0    0 298,1G  0 disk 
├─sda1   8:1    0   100M  0 part 
├─sda2   8:2    0   500M  0 part /boot/efi
├─sda3   8:3    0  97,7G  0 part 
└─sda4   8:4    0  97,7G  0 part /
sdb      8:16   1   2,8G  0 disk 
├─sdb1   8:17   1     2G  0 part /media/chris/Ubuntu 18.04.4 LTS amd64
└─sdb2   8:18   1   2,4M  0 part 

On my machine, this USB drive corresponds to /dev/sdb (I can tell since my USB has 3G, and not 298G).

Next, we format the drive. You may need to replace /dev/sdb with the path to your USB. This will overwrite whatever is in the USB drive, so be careful and make sure nothing important is on the drive.

# dd bs=4M if=/<path to your downloads>/nixos.iso of=/dev/sdb status=progress

Bios settings

Now it is necessary to update the BIOS settings on your computer to make sure that UEFI is used for booting. This step will depend completely on your particular computer, so unfortunately I can't help much with this.

On my Thinkpad, I've set "UEFI/Legacy Boot" to "UEFI Only":

NixOS Installation

At this point, we are ready to install NixOS. Restart your computer and interrupt the normal boot process to boot from the USB drive. The way to do this will depend on your specific computer model.

Even though we downloaded the graphical installer, we will be greeted by a command prompt. To open the graphical desktop, run sudo systemctl start display-manager. If you don't already have an ethernet connection, connect to wifi. Open a terminal for the following steps (you can use the "Konsole" program).

We should check that we've booted into UEFI, rather than Legacy mode by running [ -d /sys/firmware/efi/efivars ] && echo "UEFI" || echo "Legacy". If you see UEFI, then all is good. If you see Legacy, check the BIOS settings again. I'm not sure why it matters how we boot, since we are just booting the installer. Still, my installed NixOS failed to boot when installed from "Legacy" but worked fine when installed from UEFI, so I think it makes a difference.

We can now begin partitioning the disk. You can ignore any errors about /etc/fstab when running the following commands.

# parted /dev/sda -- mklabel gpt                           

First, we create a partition that will be used by GRUB:

# parted /dev/sda -- mkpart primary 1MiB 100MiB

We again create another partition that will be used by GRUB:

# parted /dev/sda -- mkpart ESP fat32 101MiB 600MiB 

We can now create a partition for NixOS. Depending on the size of your disk, you will probably want to change the end position. I set it to 100000MiB giving me a size of 100GB.

# parted /dev/sda -- mkpart primary 601MiB 100000MiB  

We now create a partition for Ubuntu. Again, you may want to change the start and end position. Just make sure that the start position is just after the end of the previous partition.

# parted /dev/sda -- mkpart primary 100001MiB 200000MiB

We now set some flags for the two GRUB partitions:

# parted /dev/sda -- set 1 bios_grub on
# parted /dev/sda -- set 2 boot on

Checking the result, we should obtain something like:

# parted -l
Number  Start   End    Size   File system  Name     Flags
 1      1049kB  105MB  104MB               primary  bios_grub
 2      106MB   629MB  523MB  fat16        ESP      boot, esp
 3      630MB   105GB  104GB               primary
 4      105GB   210GB  105GB               primary

We now encrypt the disk partition for NixOS. You will need to set a password:

# cryptsetup luksFormat /dev/sda3

From the physical partition for NixOS, we create virtual partitions:

# cryptsetup luksOpen /dev/sda3 enc-pv
# pvcreate /dev/mapper/enc-pv 
# vgcreate vg /dev/mapper/enc-pv 
# lvcreate -n swap vg -L 10G
# lvcreate -n root vg -l 100%FREE

We also format the partitions:

# mkfs.vfat -n BOOT /dev/sda2
# mkfs.ext4 -L root /dev/vg/root
# mkfs.ext4 /dev/sda4
# mkswap -L swap /dev/vg/swap

Now we mount the partitions needed to install NixOS:

# mount /dev/vg/root /mnt
# mkdir /mnt/boot
# mount /dev/sda2 /mnt/boot
# swapon /dev/vg/swap

Now we generate the NixOS configuration files:

# nixos-generate-config --root /mnt

We now edit the configuration file we just created in /mnt/etc/nixos/configuration.nix. Personally, I used the editor nano by running nano /mnt/etc/nixos/configuration.nix

In the configuration file, delete boot.loader.systemd-boot.enable and add:

  boot = {
    initrd.luks.devices = [{
      name = "root";
      device = "/dev/sda3";
      preLVM = true;
    }];
    loader.grub = {
      device = "/dev/sda";
      enable = true;
      version = 2;
      useOSProber = true;
      efiSupport = true;
    };
    loader.efi.canTouchEfiVariables = true;
  };

To make sure we boot into a usable environment, set:

networking.networkmanager.enable = true;
services.xserver.enable = true;
services.xserver.layout = "us"; # Update if you have some other layout
services.xserver.desktopManager.plasma5.enable = true;

and uncomment services.xserver.layout.

We will also install Firefox so that we can browse the internet. If you need any other software, you can add it here as well. You can search for avaialable packages here. It will still be possible to add more applications later, this is just to have some important initial ones:

environment.systemPackages = with pkgs; [
     firefox
];

Finally, add a new user:

users.users.chris = {
  isNormalUser = true;
  extraGroups = [ "wheel" ];
};

and add a password for the user: passwd --root /mnt chris

With the NixOS configuration saved, we can install NixOS by running: # nixos-install. There are some errors, but these can be ignored for now:

mktemp: failed to create directory via template ‘/tmp/os-prober.XXXXXX’: No such file or directory
grub-probe: error: cannot find a GRUB drive for /dev/sdb1.  Check your device.map.
installing the GRUB 2 boot loader on /dev/sda...
Installing for i386-pc platform.
Installation finished. No error reported.
installing the GRUB 2 EFI boot loader into /boot...
Installing for x86_64-efi platform.
modprobe: can't change directory to '/lib/modules': No such file or directory

NixOS is now installed installed, and you can reboot the system. During the boot process, you will be prompted for a password to the encrypted disk partition and also need to log in using the user added in configuration.nix.

Installing Ubuntu

With NixOS installed, we can setup Ubuntu. If you're tired and want a break, this is a good stopping point - NixOS is running fine.

Let's again prepare a bootable USB drive, but this time with Ubuntu. Don't forget to change /dev/sdb based on the path to your USB drive.

 sudo dd bs=4M if=~/Downloads/ubuntu.iso of=/dev/sdb status=progress

Now reboot the computer and again interrupt the normal boot process to boot from USB. After booting from the USB, you should see a GRUB menu . At this point, select "try Ubuntu" since the default installer won't work for us.

With Ubuntu open, open the terminal and run ubiquity --no-bootloader.This will start a graphical interface for installation. We add --no-bootloader since we don't want to overwrite the GRUB bootloader we already installed. When you reach the page "Installation Type", select "Something Else" .

On the menu of disk partitions, select /dev/sda4, which we setup earlier and press "change". Select "Ext4 Journaling file system" and set the mount point to /. You can now continue the installation process and reboot when it's finished installing.

One last step

After rebooting, you'll notice that Ubuntu still doesn't show up in the GRUB boot menu. We still have one step left.

Boot into NixOS again and run nixos-rebuild --install-bootloader switch. This will update GRUB and it should automatically detect Ubuntu. It should now be possible to select Ubuntu or NixOS from the boot menu.

@jsalix
Copy link

jsalix commented Sep 22, 2021

Thanks for the writeup!

@trzpiot
Copy link

trzpiot commented Nov 28, 2021

Thanks for the tutorial! My system has been running for a few weeks. No problems. 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment