Skip to content

Instantly share code, notes, and snippets.

@nocoolnametom
Last active January 28, 2023 17:42
Show Gist options
  • Save nocoolnametom/a359624afce4278f16e2760fe65468cc to your computer and use it in GitHub Desktop.
Save nocoolnametom/a359624afce4278f16e2760fe65468cc to your computer and use it in GitHub Desktop.

Installing on Linode

There are now official docs, so follow those as they'll be up-to-date and easier to follow.

Click here to view the old directions

Installing on Linode

I copied the bulk of this guide from Andrew Miller's NixOS-On-Linode.md instructions. It's a very well-written guide, but I felt we could make things a bit more simple than he left them in his original guide.

This tutorial is written for people who want to run NixOS on a Linode instance. The installation is pretty straightforward, but it involves some bootstrapping using Linode's tools.

In this tutorial, we will show you how to set up NixOS on Linode by setting up disks (including the installation live CD) using the rescue OS, and use the minimal live CD to install NixOS onto your disk.

Create a Linode

To start, create a Linode of any size and in any data center. Linode will then direct you to the Dashboard tab of the Linode Manager.

Setup Disks

Since NixOS isn't officially supported by Linode we will have to bootstrap the installation.

Create disk images

In the dashboard there is an option Create a new disk that you can use to create a disk. We'll need to create a disk that will hold the installation CD. Create an ext4 disk that is 1000 MB (large enough to hold the disk ISO image); call it "installer".

Now the disk we'll install NixOS on. You will want to create an ext4 disk that is at least 4GB. You can do this by selecting ext4 in the type menu. Call it "nixos" or something similar.

If you want to use a swap disk you will need to create another disk. For this disk you will want to choose the swap type from the menu. Linode recommends using a 256MB swap disk, but you can make it as large as you want.

Boot into Finnix

Now that we have some disks, we need to boot the Linode into Finnix. Finnix is the recovery mode that Linode uses to allow you to rescue and repair your disks, but we will be using it to install NixOS on the disks we made.

You can boot Finnix by going to the Rescue tab in the Linode Manager. To follow along with this guide you will want to make sure that your "installer" ext4 disk is selected for /dev/sda, the disk we are going to install to (I called mine "nixos" as above) is selected as /dev/sdb, and if you have a swap disk that it is selected as /dev/sdc.

Once you boot into Finnix you will need to connect to your Linode. Linode offers a serial console called LISH that you can use for this, since Finnix doesn't boot with an ssh daemon running.

You can access LISH by going to the Remote Access tab of the Linode Manager. You have two options for LISH, the web console which can be accessed through the Launch Lish Console link or through SSH which can be accessed through the Lish via SSH link. If you use SSH you will be asked for a password which is the password for the Linode Manager.

The LISH console may have some strange behavior as it is a simple serial console. It is only intended for recovery and repair purpose, so you may encounter some frustration with scrollback and very long lines.

Filesytems

All of Linode's tools assume that you are using a partitionless disk, so if you partition your disk in any way these tools will fail. Since these tools, such as their backup service and root password resets, are an important part of Linode's platform we should try and set up our disks to support them.

If you did want to use a partitioning scheme, we recommend that you use additional disks instead of partitions. For example, you can create another disk to use as /var instead of another partition. Since all the disks are virtual creating new disks is simple and there isn't much point in partitioning.

So since we are going to use the disk as a partitionless disk everything is already set up. We'll only need to mount our disks during installation. To aid in mounting disks now and in the future we're going to label them.

The following commands will apply labels to the disks you've made:

e2label /dev/sda installer ;
e2label /dev/sdb nixos ;
swaplabel -L swap /dev/sdc ;

Now that the disks are labeled we need to get the installation medium for NixOS and write it to the installer disk. Get the address for the minimal installation CD ISO from https://nixos.org/nixos/download.html and use it in the following commands:

curl -k <minimal_iso_path>.iso | dd bs=1M of=/dev/disk/by-label/installer ;
sync ;
halt ;

The Finnix rescue environment should shut down, but leave your terminal connection open. We'll need to make a configuration profile that will allow us to boot into the installation CD where we'll install the system.

Install NixOS

On the Dashboard page click "Create a new Configruation Profile". Use the following information:

  • Label: "Installation"
  • Kernel: "Direct Disk"
  • Block Device Assignment
    • /dev/sda: "installer"
    • /dev/sdb: "nixos"
    • /dev/sdc: "swap"
  • Filesystem/Boot Helpers (turn all of these off)

Click "Save Changes" and once back on the dashboard select the profile and click "Reboot". You'll see the live CD's GRUB menu appear. Quickly press TAB and you'll be able to add to GRUB's initialization command. Add console=ttyS0 and press ENTER. You should see Linux starting up in the Lish terminal (you left that open, right?) and soon you'll be at a root terminal, ready to install NixOS.

First we need to mount the disk we want to install to (I labeled this as "nixos").

mount /dev/disk/by-label/nixos /mnt ;

You can also activate the swap now if you made one.

swapon /dev/disk/by-label/swap ;

Generate configuration files

This will generate sample configuration files in /mnt/etc/nixos/.

nixos-generate-config --root /mnt ;

Linode specific configuration

Linode doesn't recommend using UUIDs to identify devices, so we'll use the labels we applied during our first use of the Finnix Rescue environment.

We will need to edit /mnt/etc/nixos/hardware-configuration.nix to replace the UUIDs with the labels we applied.

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

If you created a swap disk earlier you will want to do the same thing for swap devices.

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

We'll be using the GRUB controlled by Linode for booting up the virtual machine, but we'll have NixOS generate the boot images it uses. In /mnt/etc/nixos/configuration.nix make sure that these values for GRUB and boot are configured as follows (add them if they're missing):

  boot.loader.grub.enable = true;
  boot.loader.grub.version = 2;
  boot.loader.grub.device = "nodev";
  boot.loader.grub.copyKernels = true;
  boot.loader.grub.fsIdentifier = "label";
  boot.loader.grub.extraConfig = "serial; terminal_input serial; terminal_output serial";
  boot.kernelParams = [ "console=ttyS0" ];

@jsonrm found a solution to an error that can occur where Linode changes the name of the ethernet interface and the NixOS box is then unable to connect to the network (and thus can't really do anything at all).

The solution is to disable predictable interface names, which allows NixOS to apply the given configuration in order to the network connections found during boot. Since we're only having one connection, this should be fine for us. Set the networking.usePredictableInterfaceNames value to false:

networking.useDHCP = false;
networking.usePredictableInterfaceNames = false;
networking.interfaces.eth0 = {
  # for public ip, default gateway, and dns
  useDHCP = true;
  # for private ip
  ipv4 = {
    addresses = [
      {
        address = "192.168.1.2";
        prefixLength = 17;
      }
    ];
  };
};

If you plan on using Linode's Longview tools include the following snippet in /mnt/etc/nixos/configuration.nix:

  services.longview = {
    enable = false;
    apiKey = "";

    apacheStatusUrl = "";
    nginxStatusUrl = "";

    mysqlUser = "";
    mysqlPassword = "";
  };

Longview uses an API key to indentify machines. If you've already generated a Longview API key that you plan on using for this virtual machine go ahead and enable the service and put it in:

  services.longview = {
    enable = true;
    apiKey = "<your API key>";
    ...

Make any other initial changes to the NixOS configuration you want. Once you're finished with /mnt/etc/nixos/configuration.nix we just need to install everything! Run the following command to install NixOS.

nixos-install ;

Assuming everything went well we just need to shutdown in prepation for the first boot of our shiny new NixOS system.

shutdown now ;

Use Linode to Boot Up Your new NixOS environment

We need to make another configuration profile. On the Dashboard page click "Create a new Configruation Profile". Use the following information:

  • Label: "Boot"
  • Kernel: "GRUB 2"
  • Block Device Assignment
    • /dev/sda: "nixos"
    • /dev/sdb: "swap"
  • Filesystem/Boot Helpers (Turn any of these on that you'd like, except)
    • "Distro Helper" (turn this off)
    • "Auto-configure Networking" (turn this off)

Click "Save Changes". Select the "Boot" configuration profile and click "Reboot". If you left the Lish console open you should see Linode's GRUB menu with NixOS options followed by your system booting up.

Congrats! You're got an installation of NixOS running on Linode.

Cleanup

Now that we're done, feel free to remove the "installer" disk and the "Installation" configuration profile. We don't need them anymore.

@nocoolnametom
Copy link
Author

@JBetz @emiller88 I'm sorry you're having trouble. I haven't really had much opportunity to revisit this guide for a while now and it might have fallen behind on something important. I'll try and figure out what. In the meantime, do you have the ability to ping and comment to ip addresses directly (e.g., ping 8.8.8.8)? There might be an issue with nameserver resolution if you are able to get a response. Not sure what the solution would be at that point, but hopefully that would help narrow down the issue. I'll see if I can find some time to reproduce the error myself on Linode.

@nashamri
Copy link

It could be this:
NixOS/nixpkgs#71273

@jasonrm
Copy link

jasonrm commented Feb 20, 2021

In my couple of days of testing on Linode I found the interface name would be different across some restarts as the host wasn't assigning the same network interface (enp0s3 vs enp0s4 for example).

As Linode currently only connects a single interface, I disable the (usually) predictable interface names.

{ config, pkgs, ... }:
{
# -- snip --
networking.useDHCP = false;
networking.usePredictableInterfaceNames = false;
  networking.interfaces.eth0 = {
    # for public ip, default gateway, and dns
    useDHCP = true;
    # for private ip
    ipv4 = {
      addresses = [
        {
          address = "192.168.1.2";
          prefixLength = 17;
        }
      ];
    };
  };
# -- snip --
}

@sevanspowell
Copy link

Thank you so much for this @nocoolnametom.

Just one thing I ran into:

We'll need to create a disk that will hold the installation CD. Create an ext4 disk that is 400 MB; call it "installer".

The 64-bit minimal ISO is now ~800 MB, so you'll want to make the installation disk at least that big.

❤️

@nocoolnametom
Copy link
Author

I've spent the past few years working with AWS through work, so I haven't been able to take a look at this since. I'm going to edit it in preparation for using my old Linode to get a Mastodon server up and running on NixOS. Thanks for all of the comments, I'll try and get them all in the doc.

@michaelshmitty
Copy link

@nocoolnametom Thanks! I had to add -L to the curl command, like so because curl wasn't following a redirect for the download:

curl -kL <minimal_iso_path>.iso | dd bs=1M of=/dev/disk/by-label/installer

@chessai
Copy link

chessai commented Jan 22, 2023

There are official Linode docs on this now: https://www.linode.com/docs/guides/install-nixos-on-linode

Tried it just now, and it works.

EDIT: Wish it was scriptable/able to be done via API; it's a bit of a PITA to do manually.

@nocoolnametom
Copy link
Author

nocoolnametom commented Jan 28, 2023

Awesome! That's really relieving, I kinda knew a lot of people were using this guide, far more than I had assumed ever would when I first made it, but I never had the time to really go through it and make meaningful changes. An official doc is 1000% better!

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