Installing NixOS on a Proxmox VM using nixos-anywhere
- TL;DR: Quick Install Guide
- Table of Contents
- Prerequisites on the Target VM
- Installation Process
- Post-Installation: Secrets Management
- Optional NixOS Modules
- Notes and Configuration Details
- TODOs
Abstract
This guide documents the process for a minimal installation of NixOS on a Proxmox virtual machine. It leverages the nixos-anywhere tool for remote deployment and disko for declarative disk partitioning. It also covers the essential post-installation steps for integrating the new host with sops-nix for secrets management and lists available custom modules.
TL;DR: Quick Install Guide
-
Prepare VM: Boot the target Proxmox VM from a NixOS ISO and set a root password:
passwd -
Deploy NixOS: From your workstation, run
nixos-anywhere, pointing to your flake and the VM's IP address.nix run github:nix-community/nixos-anywhere -- \ --flake .#your-machine-name \ --target-host root@<vm-ip-address> -
Get Host Key: After installation, SSH into the new VM and get its host AGE key.
ssh root@<vm-ip-address> nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age' -
Update Secrets: On your workstation, add the new AGE key to
.sops.yamland re-encrypt secrets.sops updatekeys secrets/secrets.yaml
Table of Contents TOC
Prerequisites on the Target VM
Before attempting to install NixOS with nixos-anywhere, you must first perform a critical setup step on the target Proxmox VM.
The minimal NixOS installation ISO does not have a default password for the root user. The nixos-anywhere command requires SSH access, which necessitates a password.
- Boot the Proxmox VM using the minimal NixOS installation ISO.
- Open a terminal on the VM's console.
-
Set a password for the
rootuser by running the following command:passwdYou will be prompted to enter and confirm a new password.
Installation Process
Deploying NixOS
With the root password set on the target VM, you can now run nixos-anywhere from your local machine to deploy your NixOS configuration.
The following command uses nix run to execute nixos-anywhere, pointing it to a specific flake output (.#susano-minimal) and the IP address of the target VM.
nix run github:nix-community/nixos-anywhere -- \
--flake .#susano-minimal \
--target-host root@192.168.1.85
Post-Installation: Secrets Management
Step 1: Generating the Host AGE Key
After the initial installation is complete, you will need its host AGE key to manage secrets with tools like sops-nix. This key is derived from the host's SSH key.
-
SSH into the newly installed NixOS machine.
ssh root@192.168.1.85 -
Run the following command. It temporarily installs the
ssh-to-ageutility and pipes the public SSH host key to it, converting it to an AGE public key.nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age' - The command will output the new AGE public key. Copy this key for the next step.
Step 2: Updating SOPS and Re-encrypting Secrets
The new AGE key must be added to your .sops.yaml configuration file. This allows sops to encrypt secrets in a way that the new host (susano) can decrypt them.
- Open the
.sops.yamlfile in the root of your Nix flake. -
Replace the old key for the
susanohost with the new key you generated.keys: - &primary age19wvqtn4ju6k4vs8fxr34unl6xx4cv04jw0lx9ps20xlde927zfssgl4qke - &susano age1vkfq9gpqfpyq3s9e79e6vw8kv9485tzna4fm3dy6p0u9uz9feu8qr9sgcf # <--- REPLACE THIS WITH THE NEW KEY creation_rules: - path_regex: secrets/secrets.yaml$ key_groups: - age: - *primary - *susano -
After saving the updated
.sops.yamlfile, run theupdatekeyscommand. This re-encrypts the specified secrets file with the new set of keys defined in.sots.yaml. For more information, see the official documentation.sops updatekeys secrets/secrets.yamlYour secrets are now encrypted for both the primary key and the new host's key.
Optional NixOS Modules
Reverse Proxies
The following modules can be enabled to provide a reverse proxy.
Note: Currently, none of the available reverse proxy modules (NGINX, Traefik, Caddy) are functional. This is a known issue that needs to be investigated.
NGINX
The initial switch to this configuration may be slow as it waits for ACME to issue SSL certificates.
dov = {
# Reverse Proxy
reverse-proxy = {
nginx.enable = true;
};
};
Traefik
This module is currently considered to be in a broken state.
dov = {
# Reverse Proxy
reverse-proxy = {
traefik.enable = true;
};
};
Caddy
dov = {
# Reverse Proxy
reverse-proxy = {
caddy.enable = true;
};
};
Notes and Configuration Details
Disko Configuration for Proxmox (MBR Boot)
A critical requirement for ensuring a NixOS VM can boot correctly in Proxmox is the disk partition scheme. Proxmox expects a Master Boot Record (MBR) compatible setup.
When using disko for declarative disk management, you must configure it to create a GPT partition table that includes a special 1M BIOS boot partition (type EF02). This partition is specifically used by GRUB for MBR compatibility.
Here is an example snippet for the disko configuration:
{
disko.devices = {
disk = {
main = {
device = "/dev/sda";
type = "disk";
content = {
type = "gpt";
partitions = {
boot = {
size = "1M";
type = "EF02"; # for grub MBR
};
# ... your other partitions like root, swap, etc.
};
};
};
};
};
}
For a complete example, you can refer to the official disko repository: gpt-bios-compat.nix.
Generating Hardware Configuration
The nixos-anywhere tool can automatically generate a hardware configuration file from the target machine. This is useful for capturing machine-specific settings.
To do this, include the --generate-hardware-config flag in your command. The following example shows how to generate the file and save it as ./hardware-configuration.nix in your local flake directory.
nix run github:nix-community/nixos-anywhere -- \
--flake .#your-flake-output \
--target-host root@192.168.1.85 \
--generate-hardware-config ./hardware-configuration.nix
TODOs
- Investigate and fix the issue preventing any of the reverse proxy modules (NGINX, Traefik, Caddy) from working correctly.
- Troubleshoot and fix an issue that occurs when reloading the NixOS configuration remotely, which breaks the SSH pipe and requires entering the root password three times.
- Investigate and resolve the issue where updating a user's password declaratively using a secret managed by
sopsfailed after the initial installation. - Refactor the
diskoconfiguration to make the disk device name (e.g.,/dev/sda) a variable. This will avoid hardcoding the value and make the configuration more portable. - Create a custom ISO image to streamline the installation process, potentially pre-configuring items like the root user to avoid manual console steps.
- Develop an automated installation script to handle the post-install process, such as fetching the AGE key and updating sops, based on this guide.