Installing NixOS with nixos-anywhere and disko
nixos-anywhere enables remote NixOS installation over SSH. Combined with disko for declarative disk partitioning, you can fully automate system provisioning.
Overview
nixos-anywhere: Installs NixOS on any Linux system accessible via SSH. Boot a live environment, run one command, get a configured NixOS system.
disko: Declarative disk partitioning. Define your partition layout in Nix, apply it consistently.
Together, they enable fully reproducible infrastructure deployment.
Prerequisites
On Your Local Machine
- Nix installed with flakes enabled
- SSH access to the target machine
- Target machine booted into any Linux with SSH (rescue mode, live ISO, etc.)
On the Target Machine
- Root SSH access
- Network connectivity
- At least 1GB RAM (2GB+ recommended)
Disko Configuration
Create a disko configuration defining your disk layout:
Basic ext4 Setup
# disko-config.nix
{
disko.devices = {
disk = {
main = {
device = "/dev/sda";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = "512M";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
};
}ZFS Setup
# disko-config.nix
{
disko.devices = {
disk = {
main = {
device = "/dev/nvme0n1";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = {
type = "EF00";
size = "1G";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
};
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "rpool";
};
};
};
};
};
};
zpool = {
rpool = {
type = "zpool";
rootFsOptions = {
compression = "lz4";
"com.sun:auto-snapshot" = "false";
};
datasets = {
root = {
type = "zfs_fs";
mountpoint = "/";
};
nix = {
type = "zfs_fs";
mountpoint = "/nix";
};
home = {
type = "zfs_fs";
mountpoint = "/home";
};
};
};
};
};
}Flake Setup
Structure your flake for nixos-anywhere:
# flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
disko.url = "github:nix-community/disko";
disko.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, disko, ... }: {
nixosConfigurations = {
my-server = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
disko.nixosModules.disko
./disko-config.nix
./configuration.nix
];
};
};
};
}System Configuration
# configuration.nix
{ config, pkgs, ... }: {
# Boot loader
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# For ZFS
boot.supportedFilesystems = [ "zfs" ];
networking.hostId = "abcd1234"; # Required for ZFS
# Network
networking.hostName = "my-server";
networking.networkmanager.enable = true;
# SSH access (important for remote management!)
services.openssh.enable = true;
users.users.root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAA... your-key"
];
# Create a regular user
users.users.admin = {
isNormalUser = true;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAA... your-key"
];
};
system.stateVersion = "24.05";
}Running the Installation
Basic Installation
nix run github:nix-community/nixos-anywhere -- \
--flake .#my-server \
root@target-ipWith SSH Key
nix run github:nix-community/nixos-anywhere -- \
--flake .#my-server \
-i ~/.ssh/id_ed25519 \
root@target-ipTest Mode (Dry Run)
nix run github:nix-community/nixos-anywhere -- \
--flake .#my-server \
--vm-testThis boots the configuration in a VM for testing.
What Happens
- nixos-anywhere connects via SSH
- Builds a minimal kexec image on your local machine
- Uploads and boots the target into this image
- Runs disko to partition disks
- Installs NixOS
- Reboots into the new system
The entire process takes 5-15 minutes depending on network speed and system specs.
Advanced Usage
Multiple Disks (Mirror)
{
disko.devices = {
disk = {
disk1 = {
device = "/dev/sda";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = { /* ... */ };
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "rpool";
};
};
};
};
};
disk2 = {
device = "/dev/sdb";
type = "disk";
content = {
type = "gpt";
partitions = {
ESP = { /* ... */ };
zfs = {
size = "100%";
content = {
type = "zfs";
pool = "rpool";
};
};
};
};
};
};
zpool = {
rpool = {
type = "zpool";
mode = "mirror";
# ...
};
};
};
}Secrets During Installation
nix run github:nix-community/nixos-anywhere -- \
--flake .#my-server \
--extra-files /path/to/secrets \
root@target-ipFiles in /path/to/secrets are copied to the target system.
Troubleshooting
SSH Connection Fails
Ensure root login is enabled on the target:
# On target in rescue/live mode
passwd root
sed -i 's/PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
systemctl restart sshdDisk Not Found
Verify disk path on target:
lsblk
ls -la /dev/disk/by-id/Use /dev/disk/by-id/ paths for reliability.
Out of Memory
The kexec phase needs RAM. Ensure at least 1.5GB available.
Next Steps
- Set up ZFS snapshots for backups
- Configure automated deployments for updates