Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

salad

todo

acknowledgements (ACK)

todo

installing nixos on oracle free tier

don't care about the writeup? skip to the installation instructions

always free

at the time of writing this oracle cloud offers a suprisingly generous always free tier. you get:

  • AMD: 2 VMs with 1/8 OCPU and 1GB RAM each
  • Arm (Ampere A1): 24GB RAM and 4 OCPU, which can be split across 1-4 VMs

in total that is 26GB of RAM and 4.25 OCPUs - completely free! (assuming you can get a spot. as you might expect, this offering is extremely popular.)

that's awesome - what's the catch?

there's no real catch - but one major limitation is that nixos isn't available as a default image.

not to worry though - i've written a few simple scripts that lets you install nixos from just about any other os that has a bash shell.

installation

step 1

ssh into your vm and run the following command:

curl -sSL https://salad.newty.dev/guides/oracle/kexec.sh | sudo bash

this will download and run a script that installs a nixos installation environment matching your vm's architecture, then reboots into it using kexec.

warning

you'll be disconnected from ssh once the system reboots.

step 2

ssh back into your machine, this time as the root user. run the following commands:

curl -sSL https://salad.newty.dev/guides/oracle/install.sh -o install.sh
bash install.sh "<ssh key>" "<swap size>"

replace <ssh key> with your public ssh key and <swap size> with the swap size you'd like (e.g. 1G or 512M).

this script will:

  • partition and format the disk
  • configure and install a minimal nixos system
  • setup networking and ssh access
  • enable your specified ssh key
  • reboot into your fresh nixos installation

conclusion

once you've followed the steps above, you'll have a fully functional nixos installation running on oracle cloud.

from here, you can configure it just like any other nixos system.

appendix: script contents

just for transparency, here are all of the files installed to your virtual machine when running the scripts:

kexec.sh

#!/bin/bash

ARCH=$(uname -m)

echo "Detected architecture: $ARCH"

case $ARCH in
    aarch64)
        INSTALLER="https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-kexec-installer-noninteractive-aarch64-linux.tar.gz"
        ;;
    x86_64)
        INSTALLER="https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-kexec-installer-noninteractive-x86_64-linux.tar.gz"
        ;;
esac

sudo bash -c "
    curl -L '$INSTALLER' | tar -xzf- -C /root
    /root/kexec/run
"

install.sh

#!/bin/bash

# check if ssh key and swap size are provided
if [ $# -lt 2 ]; then
    echo "Usage: $0 '<ssh-public-key>' '<swap-size>'"
    echo "Example: $0 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGm... user@host' '1G'"
    echo "Swap size examples: 1G, 2G, 512M"
    exit 1
fi

SSH_KEY="$1"
SWAP_SIZE="$2"

# --- partition ---

# see: https://mdleom.com/blog/2021/03/09/nixos-oracle/
# uses 1G swap by default
fdisk /dev/sda << EOF
g
n
1

+512M
n
2

-${SWAP_SIZE}
n
3


t
1
uefi
p
w
EOF

fdisk -l /dev/sda

# --- format ---
mkfs.fat -F 32 -n boot /dev/sda1
mkfs.ext4 -L nixos /dev/sda2
mkswap -L swap /dev/sda3

# --- mount ---
mkdir -p /mnt
mount /dev/disk/by-label/nixos /mnt
mkdir -p /mnt/boot
mount /dev/disk/by-label/boot /mnt/boot
swapon /dev/sda3

# --- configuration ---
nix-channel --add https://nixos.org/channels/nixos-unstable nixpkgs
nix-channel --update

nixos-generate-config --root /mnt
curl -L https://salad.newty.dev/guides/oracle/configuration.nix -o /mnt/etc/nixos/configuration.nix
sed -i "s|<ssh key>|$SSH_KEY|g" /mnt/etc/nixos/configuration.nix

# --- installation ---
nixos-install
reboot

configuration.nix

{
  pkgs,
  ...
}:

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

  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "nixos";
  networking.networkmanager.enable = true;

  time.timeZone = "Europe/London";

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

  environment.systemPackages = with pkgs; [
    curl
    git
  ];

  services.openssh.enable = true;
  users.users.root.openssh.authorizedKeys.keys = [
    "<ssh key>"
  ];

  system.stateVersion = "25.11";
}