I’m currently in the process of migrating my personal cloud services over to Scaleway and I’m also switching to NixOS.

Scaleway is a service that offers a variety of hosting options, including ARM servers and x86 servers in either virtual or dedicated form. The appeal to us is that the company is based in the European Union (EU) and regulated by the EU instead of the United States (US). Since the recent repeal of net neutrality in the US, we wanted to have our data hosted in a place that has policies that are more in line with ours.

NixOS, in brief, simplifies server configuration and provides the safety of atomic upgrades and rollbacks. To get NixOS onto Scaleway, I followed the wiki page Install NixOS on Scaleway X86 Virtual Cloud Server. There’s a current limitation of only being able to install NixOS on an x86 virtual server for Scaleway; the wiki page NixOS on ARM/Scaleway C1 explains (at the time of writing this article) that the NixOS ARM kernel won’t boot and there’s some investigation that needs to be done to see what’s different between the NixOS ARM kernel and the one Scaleway provides.

Build a NixOS kexec Tarball

First, you need to have the Nix package manager installed to build a NixOS kexec tarball. Nix can be installed on most Linux distributions and MacOS. I haven’t tried this on MacOS, however. If you’re running NixOS, you won’t need to install Nix, since it comes with the operating system.

Once you have Nix, on a machine, use git to clone the cleverca22/nix-tests.git repository.

1
2
$ git clone https://github.com/cleverca22/nix-tests.git
$ cd nix-tests/kexec/

Then you’ll want to edit the kexec/configuration.nix file. Here’s what it may look like:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# new cmd: nix-build '<nixpkgs/nixos>' -A config.system.build.kexec_tarball -I nixos-config=./configuration.nix -Q -j 4

{ lib, pkgs, config, ... }:

with lib;

{
  imports = [ <nixpkgs/nixos/modules/installer/netboot/netboot-minimal.nix> ./autoreboot.nix ./kexec.nix ./justdoit.nix ];

  #boot.supportedFilesystems = [ "zfs" ];
  boot.loader.grub.enable = false;
  boot.kernelParams = [
    "console=ttyS0,115200"          # allows certain forms of remote access, if the hardware is setup right
    "panic=30" "boot.panic_on_fail" # reboot the machine upon fatal boot issues
  ];
  systemd.services.sshd.wantedBy = mkForce [ "multi-user.target" ];
  networking.hostName = "kexec";
  # example way to embed an ssh pubkey into the tar
  users.users.root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAB3... Your-SSH-key" ];
}

You’ll likely want to change the value of users.users.root.openssh.authorizedKeys to contain your personal SSH key.

Next, run nix-build to create the kexec tarball:

1
$ nix-build '<nixpkgs/nixos>' -A config.system.build.kexec_tarball -I nixos-config=./configuration.nix -Q -j 4

This will create a symbolic link in the folder you run it in to a folder containing the output of nix-build which should contain the file: result/tarball/nixos-system-x86_64-linux.tar.xz.

Setup the Scaleway Instance

Through the Scaleway web UI, create a new server instance. You must select an instance type that starts with either V or X such as VC1S or X64-15GB.

Select “Debian Sid” as your image, since this is known to have a kexec enabled kernel.

Add the following tags, separated by commas, to your instance (this can be added later if you forget):

  • KEXEC_KERNEL=/boot/nixos-kernel
  • KEXEC_INITRD=/boot/nixos-initrd
  • KEXEC_APPEND=init=/boot/nixos-init

Create your instance and wait for it to initialize.

Once the new server is initialized, you can send it the kexec tarball via scp:

1
$ scp result/tarball/nixos-system-x86_64-linux.tar.xz root@1.2.3.4:

You’ll need to replace the IP address 1.2.3.4 in the example above with the IP address of your newly created server.

Once the tarball is transfered, you can extract it and run the kexec script. The following should be run as root on the remote server:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# cd /
# tar -xf /root/nixos-system-x86_64-linux.tar.xz
# ./kexec_nixos
++ mktemp -d
+ cd /tmp/tmp.LK5BWie5Xq
+ pwd
/tmp/tmp.LK5BWie5Xq
+ mkdir initrd
+ pushd initrd
/tmp/tmp.LK5BWie5Xq/initrd /tmp/tmp.LK5BWie5Xq
+ cat /ssh_pubkey
cat: /ssh_pubkey: No such file or directory
+ find -type f
+ cpio -o -H newc
+ gzip -9
1 block
+ popd
/tmp/tmp.LK5BWie5Xq
+ cat /nix/store/ssaxnbprgbfi52ndf95ayl1v96nvzppy-image/initrd extra.gz
+ kexec -l /nix/store/ssaxnbprgbfi52ndf95ayl1v96nvzppy-image/kernel --initrd=final.gz '--append=init=/nix/store/j2mapg6v213ni0ly9hzp15dwvbpkz13b-nixos-system-kexec-18.03pre125264.d982c61f1af/init loglevel=4 console=ttyS0,115200 panic=30 boot.panic_on_fail'
+ sync
+ echo 'executing kernel, filesystems will be improperly umounted'
executing kernel, filesystems will be improperly umounted
+ kexec -e

There will be some output then after awhile, your SSH session will either hang or disconnect. Once it hangs or disconnects, go back to Scaleway and use their web UI to bring up the web console of your server.

You may have to press the <enter> key for the prompt to display but you should see the following prompt in the Scaleway console:

1
[root@kexec:~]#

Install NixOS

Installing NixOS at this point is pretty much the same as if you were doing an install via the minimal install ISO of NixOS. The first step in our case is to mount /dev/vda:

1
# mount /dev/vda /mnt

Next, we want to delete the previous Debian installation:

1
# rm -rf /mnt/*

Now, we want to generate the base configuration for NixOS:

1
# nixos-generate-config --root /mnt

We need to edit /mnt/etc/nixos/configuration.nix and remove the grub entries and replace them with the following:

1
2
3
4
5
6
{
  boot.loader.initScript.enable = true;
  boot.loader.generationsDir.enable = true;
  boot.loader.generationsDir.copyKernels = true;
  boot.loader.grub.enable = false;
}

You may also want to take this opportunity to configure a superuser account for yourself that authorizes your public SSH key. The following is an example that sets up the root user to authorize a public SSH key and a user named super that will be able to use sudo. You can rename this to your own preferred username and your own SSH key. It also sets the locale, time-zone, default editor (normally nano), and runs the OpenSSH service.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{ config, pkgs, ... }:

{
  imports = [
    ./hardware-configuration.nix
  ];

  networking.hostName = "nixos";

  system.stateVersion = "18.03";

  boot.loader.initScript.enable = true;
  boot.loader.generationsDir.enable = true;
  boot.loader.generationsDir.copyKernels = true;
  boot.loader.grub.enable = false;

  i18n = {
    defaultLocale = "en_US.UTF-8";
  };

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

  # Further program configuration
  programs.vim.defaultEditor = true;

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

  users.users.root.openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAB3... Your-SSH-key"
  ];

  users.extraUsers.super = {
    description = "Super User";
    isNormalUser = true;
    extraGroups = [
      "wheel"
    ];
    uid = 1000;
    openssh.authorizedKeys.keys = [
      "ssh-ed25519 AAAAB3... Your-SSH-key"
    ];
  };
}

Once you are done editing, run the install:

1
# nixos-install

If everything succeeds, you will be prompted to set the root user’s password. Once that’s set you can restart the server.

Post Install

Once the server is rebooted, you should be able to login as the root user via SSH. Then you can setup your superuser account’s password:

1
# passwd super

Now you should be able to login as the superuser and use sudo.