Nixos based Proxmox VMs
After two years with NixOS, I have grown to love having my entire system declared in one place. When I started building Proxmox VMs, I wanted the same thing. I wanted neovim, tmux, and all my settings ready from the first boot, not bolted on afterwards.
NixOS makes this surprisingly simple. With nixos-rebuild build-image, what used to require external tools like nixos-generators is now built in. In this post I will show how I set up a minimalistic VM that can be used as a boilerplate for the coming VMs that will be built.
Bare minimum configuration
To create a Proxmox .vma file there are a few things we need to have in order, we need to import the correct virtualisation module, we need to configure the baseline for Proxmox resources, for remote builds we need a user with SSH-keys and sudo privileges without password, and finally since I use Home Manager, we need to set the hostname explicitly since in my user configuration I import by hostname.
Things not displayed in the configuration below is the virtualisation import, that lives in the configuration.nix, and my user configuration, which is in hosts/common/users
{
config,
pkgs,
lib,
...
}: {
# Platform
nixpkgs.hostPlatform = "x86_64-linux";
# Hostname
networking.hostName = lib.mkOverride 40 "test-vm"; # need to take precedence over proxmox-img which has mkdefault with a value of 50
# Locale
console.keyMap = "no";
i18n.defaultLocale = "en_US.UTF-8";
i18n.extraLocaleSettings = {
LC_TIME = "nb_NO.UTF-8";
};
time.timeZone = "Europe/Oslo";
# Boot
boot.growPartition = true;
boot.loader.grub = {
efiSupport = true;
efiInstallAsRemovable = true;
device = "nodev";
};
# Filesystems
fileSystems."/" = {
device = "/dev/disk/by-label/nixos";
autoResize = true;
fsType = "ext4";
};
# Proxmox VMA Image Settings
proxmox.qemuConf = {
cores = 2;
memory = 4096;
name = "test-vm";
net0 = "virtio,bridge=vmbr0";
bios = "ovmf";
ostype = "l26";
};
virtualisation.diskSize = 16384;
# SSH
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
settings.KbdInteractiveAuthentication = false;
};
security.sudo.wheelNeedsPassword = false;
# Packages
environment.systemPackages = with pkgs; [
vim
curl
git
];
# System State Version
system.stateVersion = "24.11";
home-manager.users.fredrik.home.stateVersion = lib.mkDefault "24.11";
}
Building and applying the VMA file
With the configuration ready we only need to generate a VMA file and move it to the Proxmox server!
Creating and moving the image:
# creating the image
nixos-rebuild build-image --image-variant proxmox --flake .#test-vm
# moving the image
scp result/vzdump-test-vm.vma.zst root@<proxmox-ip>:/var/lib/vz/template/cache/
With the image safely transported to the Proxmox server, we need to restore it and apply cloud-init configurations:
# SSH to the server
ssh root@<proxmox-ip>
# restore the VM
qmrestore /var/lib/vz/template/cache/vzdump-test-vm.vma.zst <vm-id> --unique true --storage local-lvm
# Set up IP addresses, static IPv4 and SLAAC ipv6
qm set <vm-id> --ipconfig0 ip=192.168.10.233/24,gw=192.168.10.1,ip6=auto # Note that I set this up in a test network before I converted to the new IP schema
# start the VM
qm start <vm-id>
Now we have a running VM with sshd server running and our keys in authorized keys! Since I have the same username on my desktop as the new VM I can SSH by just specifying the IP
ssh 192.168.10.233
With this we now have a fully... well, functional VM! With it now built we can use nixos-rebuild with --target-host to update it! The big benefit is that we can use our main machine to build from with beefier specs and one cache that can build for all our VMs
Remote build
During my little exploration in to building VM images I quickly saw the great benefits of the remote building. My beefy main computer to build and push, utilizing the cache for each subsequent build. And this is the part where we need the sudo to be passwordless!
nixos-rebuild switch --flake .#test-vm --target-host fredrik@<ip> --sudo
Conclusion
After going down the rabbit hole of building images for Proxmox and remote builds I am very happy with the outcome, and the ease of use when I need to set up a new VM from my normal flake setup. Having the ability to quickly add in a new template that pulls my user and Home Manager configuration is really a nice way to do it. And it stays declarative in case I need to set up a new machine with the same setup. I have said it before, and can't say it enough, I love having things declaratively
Discussion in the ATmosphere