diff --git a/README.org b/README.org new file mode 100644 index 0000000..b835a82 --- /dev/null +++ b/README.org @@ -0,0 +1,89 @@ +#+TITLE: Installing NixOS on a Proxmox VM using nixos-anywhere +#+AUTHOR: +#+DATE: +#+OPTIONS: toc:t num:nil + +*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. + +* Table of Contents :TOC: +- [[#prerequisites-on-the-target-vm][Prerequisites on the Target VM]] +- [[#installation-process][Installation Process]] + - [[#deploying-nixos][Deploying NixOS]] + - [[#note-on-hardware-configuration][Note on Hardware Configuration]] +- [[#key-configuration-details][Key Configuration Details]] + - [[#disko-configuration-for-proxmox-mbr-boot][Disko Configuration for Proxmox (MBR Boot)]] +- [[#todos][TODOs]] + +* 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. + +1. Boot the Proxmox VM using the minimal NixOS installation ISO. +2. Open a terminal on the VM's console. +3. Set a password for the =root= user by running the following command: + #+begin_src sh + passwd + #+end_src + You 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. + +#+begin_src sh +nix run github:nix-community/nixos-anywhere -- \ + --flake .#susano-minimal \ + --target-host root@192.168.1.85 +#+end_src + +** Note on Hardware Configuration +While not used in the command above, =nixos-anywhere= 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. + +#+begin_src sh +nix run github:nix-community/nixos-anywhere -- \ + --flake .#your-flake-output \ + --target-host root@192.168.1.85 \ + --generate-hardware-config ./hardware-configuration.nix +#+end_src + +* Key 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: + +#+begin_src nix +{ + 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. + }; + }; + }; + }; + }; +} +#+end_src + +For a complete example, you can refer to the official =disko= repository: [[https://github.com/nix-community/disko/blob/master/example/gpt-bios-compat.nix][gpt-bios-compat.nix]]. + +* TODOs +- [ ] Refactor the =disko= configuration to make the disk device name (e.g., =/dev/sda=) a variable. This will avoid hardcoding the value and make the configuration more portable across different hardware setups. diff --git a/flake.lock b/flake.lock index 2598158..1deb0ea 100644 --- a/flake.lock +++ b/flake.lock @@ -20,6 +20,27 @@ "type": "github" } }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1753479839, + "narHash": "sha256-E/rPVh7vyPMJUFl2NAew+zibNGfVbANr8BP8nLRbLkQ=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "0b9bf983db4d064764084cd6748efb1ab8297d1e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "ref": "release-25.05", + "repo": "home-manager", + "type": "github" + } + }, "nixos-hardware": { "locked": { "lastModified": 1753122741, @@ -55,6 +76,7 @@ "root": { "inputs": { "disko": "disko", + "home-manager": "home-manager", "nixos-hardware": "nixos-hardware", "nixpkgs": "nixpkgs" } diff --git a/flake.nix b/flake.nix index 2b0e212..b003570 100644 --- a/flake.nix +++ b/flake.nix @@ -9,6 +9,10 @@ url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; + home-manager = { + url = "github:nix-community/home-manager/release-25.05"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = { @@ -16,15 +20,20 @@ nixpkgs, nixos-hardware, disko, + home-manager, ... } @ inputs: let inherit (self) outputs; + extraHomeModules = [ + ./hm-modules + ]; in { nixosConfigurations = { susano-minimal = nixpkgs.lib.nixosSystem { - specialArgs = {inherit inputs outputs;}; + specialArgs = {inherit inputs outputs extraHomeModules; }; modules = [ disko.nixosModules.disko + home-manager.nixosModules.home-manager ./minimal ]; }; diff --git a/hm-modules/default.nix b/hm-modules/default.nix new file mode 100644 index 0000000..3454290 --- /dev/null +++ b/hm-modules/default.nix @@ -0,0 +1,7 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ./shell + ]; +} diff --git a/hm-modules/shell/default.nix b/hm-modules/shell/default.nix new file mode 100644 index 0000000..902e7f8 --- /dev/null +++ b/hm-modules/shell/default.nix @@ -0,0 +1,7 @@ +{ config, lib, pkgs, ... }: + +{ + imports = [ + ./zsh + ]; +} diff --git a/hm-modules/shell/zsh/default.nix b/hm-modules/shell/zsh/default.nix new file mode 100644 index 0000000..57bd2c6 --- /dev/null +++ b/hm-modules/shell/zsh/default.nix @@ -0,0 +1,57 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.dov.shell.zsh; +in { + options.dov.shell.zsh = { + enable = mkEnableOption "zsh config"; + shellAliases = mkOption { + type = types.attrs; + default = {}; + }; + }; + + config = mkIf cfg.enable { + programs.zsh = { + enable = true; + history = { + save = 10000; + }; + + initContent = '' + ''; + + plugins = [ + { + # will source zsh-autosuggestions.plugin.zsh + name = "zsh-autosuggestions"; + src = pkgs.fetchFromGitHub { + owner = "zsh-users"; + repo = "zsh-autosuggestions"; + rev = "v0.7.0"; + sha256 = "0z6i9wjjklb4lvr7zjhbphibsyx51psv50gm07mbb0kj9058j6kc"; + }; + } + { + # will source zsh-autosuggestions.plugin.zsh + name = "zsh-syntax-highlighting"; + src = pkgs.fetchFromGitHub { + owner = "zsh-users"; + repo = "zsh-syntax-highlighting"; + rev = "0.7.0"; + sha256 = "eRTk0o35QbPB9kOIV0iDwd0j5P/yewFFISVS/iEfP2g="; + }; + } + ]; + oh-my-zsh = { + enable = true; + theme = "bira"; + plugins = [ "git" "sudo" ]; + }; + } // (lib.optionalAttrs (cfg.shellAliases != null) { + shellAliases = cfg.shellAliases; + }); + }; +} diff --git a/minimal/default.nix b/minimal/default.nix index 0246ff7..2ff7cf7 100644 --- a/minimal/default.nix +++ b/minimal/default.nix @@ -1,6 +1,8 @@ -{ config, pkgs, ... }: +{ config, pkgs, extraHomeModules, inputs, ... }: -{ +let + username = "susano"; +in { imports = [ # Include the results of the hardware scan. ./hardware-configuration.nix @@ -9,10 +11,9 @@ # Bootloader. boot.loader.grub.enable = true; - # boot.loader.grub.device = "/dev/sda"; boot.loader.grub.useOSProber = true; - networking.hostName = "susano"; + networking.hostName = username; networking.networkmanager.enable = true; # Set your time zone. @@ -35,23 +36,57 @@ security.rtkit.enable = true; - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.susano = { + users.users.${username} = { isNormalUser = true; - description = "susano"; + description = "NixOS Proxmox Homelab"; initialPassword = "test"; extraGroups = [ "networkmanager" "wheel" ]; packages = with pkgs; [ ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBcGhVpjmWEw1GEw0y/ysJPa2v3+u/Rt/iES/Se2huH2 alexander0derevianko@gmail.com" + ]; + + shell = pkgs.zsh; }; - - programs.firefox.enable = true; - environment.systemPackages = with pkgs; [ vim wget + ripgrep ]; + services.openssh = { + enable = true; + settings = { + # Opinionated: forbid root login through SSH. + PermitRootLogin = "no"; + # Opinionated: use keys only. + # Remove if you want to SSH using passwords + PasswordAuthentication = false; + }; + }; + + programs = { + zsh.enable = true; + }; + + ### + # Home Manger configuration + ### + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + backupFileExtension = "backup"; + extraSpecialArgs = { inherit inputs; }; + + users."${username}" = { + imports = [ + ./home.nix + ] ++ extraHomeModules; + }; + }; + + # DO NOT CHANGE AT ANY POINT! system.stateVersion = "25.05"; } diff --git a/minimal/home.nix b/minimal/home.nix new file mode 100644 index 0000000..9a2c708 --- /dev/null +++ b/minimal/home.nix @@ -0,0 +1,35 @@ +{ config, lib, pkgs, inputs, extraHomeModules, ... }: + +let + username = "susano"; +in { + imports = [ + ]; + + + home = { + stateVersion = "25.05"; + username = username; + homeDirectory = "/home/${username}"; + }; + + dov = { + shell = { + zsh = { + enable = true; + shellAliases = { + ll = "eza -al"; + sc = "source $HOME/.zshrc"; + psax = "ps ax | grep"; + cp = "rsync -ah --progress"; + }; + }; + }; + }; + + programs.home-manager.enable = true; + + home.packages = with pkgs; [ + eza + ]; +}