Last active
March 30, 2026 22:47
-
-
Save andir/48c2969b82d3eeaea6f3f0bc8cc3e8d2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| pkgs ? import <nixpkgs> { }, | |
| lib ? pkgs.lib, | |
| }: | |
| with (import <nixpkgs/nixos/lib/qemu-flags.nix> { inherit pkgs; }); | |
| { | |
| mkVM = | |
| { | |
| name, | |
| config ? { }, | |
| memory ? 512, | |
| cores ? 2, | |
| statefulDisks ? false, | |
| networking ? false, | |
| monitorPath ? "/run/vm-${name}/monitor.socket", | |
| hostPath ? "/var/lib/vm-${name}", | |
| }: | |
| rec { | |
| inherit hostPath; | |
| nixos = import <nixpkgs/nixos/lib/eval-config.nix> { | |
| modules = [ | |
| ( | |
| { | |
| pkgs, | |
| lib, | |
| config, | |
| ... | |
| }: | |
| { | |
| fileSystems."/" = { | |
| device = "tmpfs"; | |
| fsType = "tmpfs"; | |
| options = [ "mode=0755" ]; | |
| }; | |
| fileSystems."/nix/store" = { | |
| device = "store"; | |
| fsType = "9p"; | |
| options = [ | |
| "trans=virtio" | |
| "version=9p2000.L" | |
| "cache=loose" | |
| ]; | |
| neededForBoot = true; | |
| }; | |
| fileSystems."/var/" = { | |
| device = "state"; | |
| fsType = "9p"; | |
| options = [ | |
| "trans=virtio" | |
| "version=9p2000.L" | |
| "cache=loose" | |
| ]; | |
| neededForBoot = true; | |
| }; | |
| swapDevices = [ ]; | |
| networking.wireless.enable = lib.mkForce false; | |
| networking.connman.enable = false; | |
| boot.loader.grub.enable = false; | |
| boot.kernelParams = [ "boot.shell_on_fail" ]; | |
| boot.initrd.availableKernelModules = [ | |
| "virtio_net" | |
| "virtio_pci" | |
| "virtio_mmio" | |
| "virtio_blk" | |
| "virtio_scsi" | |
| "9p" | |
| "9pnet_virtio" | |
| ]; | |
| networking.dhcpcd.extraConfig = "noarp"; | |
| networking.usePredictableInterfaceNames = false; | |
| system.requiredKernelConfig = | |
| with config.lib.kernelConfig; | |
| [ | |
| (isEnabled "VIRTIO_BLK") | |
| (isEnabled "VIRTIO_PCI") | |
| (isEnabled "VIRTIO_NET") | |
| (isEnabled "EXT4_FS") | |
| (isYes "BLK_DEV") | |
| (isYes "PCI") | |
| (isYes "EXPERIMENTAL") | |
| (isYes "NETDEVICES") | |
| (isYes "NET_CORE") | |
| (isYes "INET") | |
| (isYes "NETWORK_FILESYSTEMS") | |
| ] | |
| ++ optional (!cfg.graphics) [ | |
| (isYes "SERIAL_8250_CONSOLE") | |
| (isYes "SERIAL_8250") | |
| ]; | |
| } | |
| ) | |
| (import <nixpkgs/nixos/modules/profiles/minimal.nix>) | |
| # (import <nixpkgs/nixos/modules/virtualisation/qemu-vm.nix>) | |
| ( | |
| { pkgs, lib, ... }: | |
| { | |
| networking.hostName = lib.mkDefault name; | |
| } | |
| ) | |
| config | |
| ]; | |
| }; | |
| toplevel = nixos.config.system.build.toplevel; | |
| script = pkgs.writeScript "run-${name}" '' | |
| #! ${pkgs.runtimeShell} | |
| ls -la /dev/ | |
| test -e /dev/kvm || exit 1 | |
| ${qemuBinary qemu} \ | |
| -name "${name}" \ | |
| -cpu host \ | |
| -m ${toString memory} \ | |
| -smp ${toString cores} \ | |
| -device virtio-rng-pci \ | |
| -virtfs local,path=/nix/store,security_model=none,mount_tag=store \ | |
| -virtfs local,path=${hostPath},security_model=mapped,mount_tag=state \ | |
| -kernel ${toplevel}/kernel \ | |
| -initrd ${toplevel}/initrd \ | |
| -append "${lib.concatStringsSep " " kernelParams}" \ | |
| -monitor unix:${monitorPath},server,nowait \ | |
| -device e1000,netdev=net0 \ | |
| -netdev user,id=net0,hostfwd=tcp::5555-:22 \ | |
| -nographic | |
| ''; | |
| hostname = nixos.config.networking.hostName; | |
| qemu = pkgs.qemu_kvm; | |
| closure = pkgs.closureInfo { rootPaths = [ toplevel ]; }; | |
| closurePaths = | |
| let | |
| exportedGraph = builtins.fromJSON ( | |
| builtins.readFile ( | |
| pkgs.runCommand "closure.json" { | |
| exportReferencesGraph.closure = [ | |
| toplevel | |
| script | |
| ]; | |
| __structuredAttrs = true; | |
| PATH = "${pkgs.coreutils}/bin"; | |
| builder = builtins.toFile "bulider" '' | |
| . .attrs.sh | |
| cp .attrs.json ''${outputs[out]} | |
| ''; | |
| } "" | |
| ) | |
| ); | |
| in | |
| map (e: e.path) exportedGraph.closure; | |
| kernelParams = nixos.config.boot.kernelParams ++ [ | |
| "init=${toplevel}/init" | |
| "regInfo=${closure}/registration" | |
| "console=ttyS0" | |
| ]; | |
| service = { | |
| serviceConfig = { | |
| DynamicUser = true; | |
| ExecStart = script; | |
| BindReadOnlyPaths = lib.concatStringsSep " " (closurePaths); | |
| MountAPIVFS = true; | |
| TemporaryFileSystem = "/:ro"; | |
| BindPaths = "/dev/kvm"; | |
| RuntimeDirectory = "vm-${name}"; | |
| NoNewPrivileges = true; | |
| # StateDirectory = "vm-${name}"; | |
| }; | |
| }; | |
| }; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { pkgs, ... }: | |
| let | |
| inherit (pkgs.callPackage ./mk-vm.nix { }) mkVM; | |
| user = "xxxx"; | |
| name = "backups-${user}"; | |
| vm = mkVM { | |
| inherit name; | |
| cores = 1; | |
| memory = 1024; | |
| monitorPath = "/run/vm-${name}/monitor.socket"; | |
| hostPath = "/var/lib/vm-xxxxx"; | |
| config = ( | |
| { pkgs, ... }: | |
| { | |
| services.openssh = { | |
| enable = true; | |
| hostKeys = [ | |
| { | |
| path = "/var/ssh/ssh_host_ed25519_key"; | |
| type = "ed25519"; | |
| } | |
| ]; | |
| }; | |
| systemd.services.sshd = { | |
| after = [ "systemd-tmpfiles-setup.service" ]; | |
| unitConfig.RequiresMountsFor = "/var/lib"; | |
| }; | |
| users.users.root.initialHashedPassword = ""; | |
| users.users.andi.isNormalUser = true; | |
| users.users.andi.openssh.authorizedKeys.keys = [ | |
| ]; | |
| users.users.${user} = { | |
| isNormalUser = true; | |
| }; | |
| boot.kernelParams = [ "systemd.log_level=debug" ]; | |
| systemd.tmpfiles.rules = [ | |
| "d /var/data 0700 root - - -" | |
| "d /var/data/${user} 0700 ${user} - - -" | |
| "d /var/ssh 0700 root root -" | |
| ]; | |
| environment.systemPackages = with pkgs; [ | |
| borgbackup | |
| ncdu | |
| vim | |
| pciutils | |
| ]; | |
| users.motd = '' | |
| Put your data into /var/data or it might be gone after the next system update. | |
| ''; | |
| } | |
| ); | |
| }; | |
| in | |
| { | |
| users.users.grahamc = { | |
| isSystemUser = true; | |
| }; | |
| systemd.tmpfiles.rules = [ | |
| "d '/run/backup-vms/${name}' 0700 ${user} - - -" | |
| "d '/var/lib/vm-grahamc' 0700 ${user} - - -" | |
| ]; | |
| networking.firewall.allowedTCPPorts = [ 5555 ]; | |
| systemd.services.backup-vm = { | |
| serviceConfig = vm.service.serviceConfig // { | |
| StateDirectory = vm.hostPath; | |
| BindPaths = vm.hostPath; | |
| DynamicUser = false; | |
| User = "grahamc"; | |
| }; | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment