2026-02-27 18:26:41 +02:00
|
|
|
{
|
|
|
|
|
lib,
|
|
|
|
|
config,
|
|
|
|
|
modulesPath,
|
|
|
|
|
pkgs,
|
2026-03-02 10:49:32 +02:00
|
|
|
uvmsPkgs,
|
2026-02-27 18:26:41 +02:00
|
|
|
...
|
|
|
|
|
}:
|
|
|
|
|
let
|
|
|
|
|
inherit (lib) mkOption types concatStringsSep;
|
|
|
|
|
jsonType = (pkgs.formats.json { }).type;
|
|
|
|
|
|
|
|
|
|
inherit (config.system.build) initialRamdisk;
|
|
|
|
|
inherit (config.system.boot.loader) initrdFile;
|
|
|
|
|
inherit (config.boot.kernelPackages) kernel;
|
|
|
|
|
kernelTarget = pkgs.stdenv.hostPlatform.linux-kernel.target;
|
|
|
|
|
waylandSock = "/run/user/1000/wayland-1";
|
|
|
|
|
env = {
|
2026-03-11 17:38:49 +02:00
|
|
|
DBUS_SESSION_BUS_ADDRESS = "unix:path=/run/user/1000/bus";
|
2026-02-27 18:26:41 +02:00
|
|
|
XDG_RUNTIME_DIR = "/run/user/1000";
|
|
|
|
|
WAYLAND_DISPLAY = "wayland-1";
|
|
|
|
|
|
|
|
|
|
# MESA_LOADER_DRIVER_OVERRIDE = "zink";
|
|
|
|
|
|
|
|
|
|
ELECTRON_OZONE_PLATFORM_HINT = "wayland";
|
|
|
|
|
MOZ_ENABLE_WAYLAND = "1";
|
|
|
|
|
QT_QPA_PLATFORM = "wayland"; # Qt Applications
|
|
|
|
|
GDK_BACKEND = "wayland"; # GTK Applications
|
|
|
|
|
XDG_SESSION_TYPE = "wayland"; # Electron Applications
|
|
|
|
|
SDL_VIDEODRIVER = "wayland";
|
|
|
|
|
CLUTTER_BACKEND = "wayland";
|
|
|
|
|
NIXOS_OZONE_WL = "1";
|
|
|
|
|
};
|
|
|
|
|
in
|
|
|
|
|
{
|
|
|
|
|
imports = [
|
|
|
|
|
(modulesPath + "/profiles/minimal.nix")
|
|
|
|
|
./debug-closure.nix
|
|
|
|
|
./minimal.nix
|
|
|
|
|
./on-failure.nix
|
|
|
|
|
];
|
|
|
|
|
config = {
|
2026-03-02 10:49:32 +02:00
|
|
|
_module.args.uvmsPkgs = lib.mkDefault (pkgs.callPackage ../pkgs { });
|
2026-03-02 05:07:52 +02:00
|
|
|
# some.failure-handler.enable = true;
|
2026-02-27 18:26:41 +02:00
|
|
|
hardware.graphics.enable = true;
|
2026-03-10 02:01:54 +02:00
|
|
|
# boot.kernelPackages = pkgs.linuxPackagesFor uvmsPkgs.linux-uvm;
|
2026-02-27 18:26:41 +02:00
|
|
|
# boot.isContainer = true;
|
|
|
|
|
boot.initrd.kernelModules = [
|
|
|
|
|
"drm"
|
|
|
|
|
"virtio_blk"
|
|
|
|
|
"virtiofs"
|
|
|
|
|
"virtio_gpu"
|
|
|
|
|
"virtio_mmio"
|
|
|
|
|
"virtio_pci"
|
|
|
|
|
"overlay"
|
|
|
|
|
];
|
|
|
|
|
boot.kernelModules = [
|
|
|
|
|
"drm"
|
|
|
|
|
"erofs"
|
|
|
|
|
"overlay"
|
|
|
|
|
"virtio_blk"
|
|
|
|
|
"virtiofs"
|
|
|
|
|
"virtio_gpu"
|
|
|
|
|
"virtio_mmio"
|
|
|
|
|
"virtio_pci"
|
|
|
|
|
];
|
|
|
|
|
boot.initrd.systemd.initrdBin = [
|
|
|
|
|
pkgs.fuse
|
|
|
|
|
pkgs.fuse3
|
|
|
|
|
];
|
|
|
|
|
fileSystems = {
|
|
|
|
|
"/" = lib.mkDefault {
|
|
|
|
|
device = "rootfs"; # how does this work? does this assign a label to the tmpfs?
|
|
|
|
|
fsType = "tmpfs";
|
|
|
|
|
options = [ "size=20%,mode=0755" ];
|
|
|
|
|
neededForBoot = true;
|
|
|
|
|
};
|
|
|
|
|
"/nix/store" = {
|
|
|
|
|
fsType = "overlay";
|
|
|
|
|
overlay.lowerdir = [
|
|
|
|
|
"/nix/.ro-stores/system"
|
|
|
|
|
"/nix/.ro-stores/apps"
|
|
|
|
|
];
|
|
|
|
|
neededForBoot = true;
|
|
|
|
|
};
|
|
|
|
|
"/nix/.ro-stores/system" = {
|
|
|
|
|
device = "system";
|
|
|
|
|
fsType = "virtiofs";
|
|
|
|
|
options = [
|
|
|
|
|
"defaults"
|
|
|
|
|
"ro"
|
|
|
|
|
"x-systemd.requires=systemd-modules-load.service"
|
|
|
|
|
];
|
|
|
|
|
neededForBoot = true;
|
|
|
|
|
};
|
|
|
|
|
"/nix/.ro-stores/apps" = {
|
|
|
|
|
device = "apps";
|
|
|
|
|
fsType = "virtiofs";
|
|
|
|
|
options = [
|
|
|
|
|
"defaults"
|
|
|
|
|
"ro"
|
|
|
|
|
"x-systemd.requires=systemd-modules-load.service"
|
|
|
|
|
];
|
|
|
|
|
neededForBoot = true;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-11 17:38:49 +02:00
|
|
|
programs.dconf.enable = true;
|
2026-02-27 18:26:41 +02:00
|
|
|
systemd.mounts = [
|
|
|
|
|
{
|
|
|
|
|
type = "virtiofs";
|
|
|
|
|
where = "/home/user";
|
|
|
|
|
what = "home";
|
|
|
|
|
after = [ "systemd-modules-load.service" ];
|
|
|
|
|
wantedBy = [ "local-fs.target" ];
|
|
|
|
|
before = [ "local-fs.target" ];
|
|
|
|
|
requires = [ "systemd-modules-load.service" ];
|
|
|
|
|
options = lib.concatStringsSep "," [
|
|
|
|
|
"defaults"
|
|
|
|
|
"rw"
|
|
|
|
|
"X-mount.owner=1000"
|
|
|
|
|
"X-mount.group=100"
|
|
|
|
|
];
|
|
|
|
|
unitConfig = {
|
|
|
|
|
ConditionKernelCommandLine = "uvms.persist-home=1";
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
type = "virtiofs";
|
|
|
|
|
where = "/home/user/send";
|
|
|
|
|
what = "send";
|
|
|
|
|
wants = [
|
|
|
|
|
"home-user.mount"
|
|
|
|
|
"-.mount"
|
|
|
|
|
];
|
|
|
|
|
after = [
|
|
|
|
|
"systemd-modules-load.service"
|
|
|
|
|
"home-user.mount"
|
|
|
|
|
"-.mount"
|
|
|
|
|
];
|
|
|
|
|
wantedBy = [ "local-fs.target" ];
|
|
|
|
|
before = [ "local-fs.target" ];
|
|
|
|
|
options = lib.concatStringsSep "," [
|
|
|
|
|
"defaults"
|
|
|
|
|
"rw"
|
|
|
|
|
"X-mount.owner=1000"
|
|
|
|
|
"X-mount.group=100"
|
|
|
|
|
];
|
|
|
|
|
unitConfig = {
|
|
|
|
|
DefaultDependencies = false;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
# systemd.services."mount-home-user-send" = {
|
|
|
|
|
# wants = [ "home-user.mount" ];
|
|
|
|
|
# after = [
|
|
|
|
|
# "systemd-modules-load.service"
|
|
|
|
|
# "home-user.mount"
|
|
|
|
|
# "-.mount"
|
|
|
|
|
# ];
|
|
|
|
|
# wantedBy = [ "local-fs.target" ];
|
|
|
|
|
# before = [ "local-fs.target" ];
|
|
|
|
|
# unitConfig = {
|
|
|
|
|
# DefaultDependencies = false;
|
|
|
|
|
# };
|
|
|
|
|
# environment.PATH = lib.mkForce (
|
|
|
|
|
# lib.makeBinPath [
|
|
|
|
|
# pkgs.fuse
|
|
|
|
|
# pkgs.fuse3
|
|
|
|
|
# pkgs.coreutils
|
|
|
|
|
# ]
|
|
|
|
|
# );
|
|
|
|
|
# serviceConfig = {
|
|
|
|
|
# Type = "oneshot";
|
|
|
|
|
# RemainsAfterExit = true;
|
|
|
|
|
# ExecStart = [
|
|
|
|
|
# "/run/current-system/sw/bin/mkdir -p /home/user/send"
|
|
|
|
|
# "/run/current-system/sw/bin/chown user /home/user/send"
|
|
|
|
|
# "/run/current-system/sw/sbin/mount -t virtiofs -o defaults,rw send /home/user/send"
|
|
|
|
|
# ];
|
|
|
|
|
# StandardOutput = "journal+console";
|
|
|
|
|
# StandardError = "journal+console";
|
|
|
|
|
# };
|
|
|
|
|
# };
|
|
|
|
|
|
|
|
|
|
systemd.network.enable = true;
|
|
|
|
|
networking.useNetworkd = true;
|
|
|
|
|
networking.nftables.enable = true;
|
|
|
|
|
networking.useDHCP = true;
|
|
|
|
|
networking.nameservers = [ "1.1.1.1" ];
|
|
|
|
|
services.resolved.enable = lib.mkForce true;
|
|
|
|
|
|
|
|
|
|
system.activationScripts.specialfs = lib.mkForce "";
|
|
|
|
|
# networking.firewall.enable = false;
|
|
|
|
|
console.enable = false;
|
|
|
|
|
services.udev.packages = lib.mkDefault [ ];
|
|
|
|
|
systemd.services."systemd-oomd".enable = false;
|
|
|
|
|
|
|
|
|
|
users.mutableUsers = false;
|
|
|
|
|
users.users.root.password = "hacktheplanet!";
|
|
|
|
|
users.groups.users = { };
|
|
|
|
|
users.users.user = {
|
|
|
|
|
uid = 1000;
|
|
|
|
|
isNormalUser = true;
|
|
|
|
|
password = "hacktheplanet!";
|
|
|
|
|
extraGroups = [
|
|
|
|
|
"video"
|
|
|
|
|
"render"
|
|
|
|
|
"users"
|
|
|
|
|
"wheel"
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
2026-03-04 01:41:33 +02:00
|
|
|
environment.profileRelativeSessionVariables.PATH = lib.mkForce [ "/bin\${PATH:+:}$PATH" ];
|
2026-03-15 02:15:58 +02:00
|
|
|
environment.profileRelativeSessionVariables.XDG_DATA_DIRS = lib.mkForce [ "/run/current-system/sw/share/\${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS" ];
|
2026-03-11 17:38:49 +02:00
|
|
|
environment.sessionVariables = env;
|
2026-02-27 18:26:41 +02:00
|
|
|
environment.variables = env;
|
|
|
|
|
systemd.globalEnvironment = env;
|
|
|
|
|
|
|
|
|
|
systemd.tmpfiles.settings."10-xdg" = {
|
|
|
|
|
${env.XDG_RUNTIME_DIR}.d = {
|
|
|
|
|
user = "user";
|
|
|
|
|
group = "users";
|
|
|
|
|
mode = "0755";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.sockets."wayland-proxy" = {
|
|
|
|
|
listenStreams = [
|
|
|
|
|
waylandSock
|
|
|
|
|
];
|
|
|
|
|
socketConfig = {
|
|
|
|
|
SocketUser = "user";
|
|
|
|
|
SocketGroup = "users";
|
|
|
|
|
FileDescriptorName = "wayland";
|
|
|
|
|
};
|
|
|
|
|
wantedBy = [ "sockets.target" ];
|
|
|
|
|
partOf = [ "wayland-proxy.service" ];
|
|
|
|
|
};
|
|
|
|
|
systemd.services."wayland-proxy" = {
|
|
|
|
|
wantedBy = [ "default.target" ];
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
User = "user";
|
|
|
|
|
Group = "users";
|
|
|
|
|
ExecStart = "${lib.getExe pkgs.wayland-proxy-virtwl} --virtio-gpu";
|
|
|
|
|
# ExecStart = "${lib.getExe uvmsPkgs.wl-cross-domain-proxy} --listen-fd --filter-global wp_presentation";
|
|
|
|
|
ExecStartPre = [
|
|
|
|
|
"+/run/current-system/sw/bin/chmod 0666 /dev/dri/card0 /dev/dri/renderD128"
|
|
|
|
|
];
|
|
|
|
|
StandardOutput = "journal+console";
|
|
|
|
|
StandardError = "journal+console";
|
|
|
|
|
Restart = "on-failure";
|
|
|
|
|
RestartSec = 5;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
systemd.sockets."uvms-guest" = {
|
2026-03-10 02:01:54 +02:00
|
|
|
requiredBy = [ "multi-user.target" ];
|
|
|
|
|
before = [ "multi-user.target" ];
|
2026-02-27 18:26:41 +02:00
|
|
|
listenStreams = [
|
|
|
|
|
"vsock::24601"
|
|
|
|
|
];
|
|
|
|
|
partOf = [ "uvms-guest.service" ];
|
|
|
|
|
};
|
|
|
|
|
systemd.services."uvms-guest" = {
|
2026-03-10 02:01:54 +02:00
|
|
|
before = [ "multi-user.target" ];
|
2026-03-02 05:07:52 +02:00
|
|
|
onFailure = [ "shutdown.service" ];
|
2026-02-27 18:26:41 +02:00
|
|
|
serviceConfig = {
|
|
|
|
|
User = "user";
|
|
|
|
|
Group = "users";
|
2026-03-10 02:01:54 +02:00
|
|
|
ExecStart = "${lib.getExe' uvmsPkgs.uvmslib "uvms-guest"}";
|
2026-03-02 05:07:52 +02:00
|
|
|
ExecStop = [
|
2026-03-04 01:41:33 +02:00
|
|
|
"/run/current-system/sw/bin/echo GUEST DOWN"
|
|
|
|
|
"/run/current-system/sw/bin/systemctl poweroff"
|
2026-03-02 05:07:52 +02:00
|
|
|
];
|
|
|
|
|
StandardOutput = "journal+console";
|
|
|
|
|
StandardError = "journal+console";
|
|
|
|
|
Restart = "no";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
systemd.services."shutdown" = {
|
|
|
|
|
serviceConfig = {
|
|
|
|
|
ExecStart = [ "/run/current-system/sw/bin/systemctl poweroff" ];
|
2026-02-27 18:26:41 +02:00
|
|
|
StandardOutput = "journal+console";
|
|
|
|
|
StandardError = "journal+console";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fonts.enableDefaultPackages = true;
|
|
|
|
|
|
|
|
|
|
boot.kernelParams = [
|
|
|
|
|
"earlyprintk=ttyS0"
|
|
|
|
|
"console=ttyS0"
|
|
|
|
|
"reboot=t"
|
|
|
|
|
"panic=-1"
|
|
|
|
|
# "rootfstype=virtiofs"
|
|
|
|
|
# "root=rootstore"
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
system.build.ch = mkOption {
|
|
|
|
|
type = types.package;
|
|
|
|
|
default = (pkgs.formats.json { }).generate "vm.json" config.uvms.ch.settings;
|
|
|
|
|
};
|
|
|
|
|
uvms.ch.settings = mkOption {
|
|
|
|
|
default = { };
|
2026-03-07 21:16:53 +02:00
|
|
|
type = types.submodule (
|
2026-03-11 17:38:49 +02:00
|
|
|
let
|
|
|
|
|
osConfig = config;
|
|
|
|
|
in
|
2026-03-07 21:16:53 +02:00
|
|
|
{ config, ... }:
|
|
|
|
|
{
|
|
|
|
|
freeformType = jsonType;
|
|
|
|
|
options = {
|
|
|
|
|
payload = {
|
|
|
|
|
cmdline = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = concatStringsSep " " (
|
|
|
|
|
osConfig.boot.kernelParams
|
|
|
|
|
++ [
|
|
|
|
|
# "init=${lib.removePrefix "/nix/store" "${osConfig.system.build.toplevel}"}/init"
|
|
|
|
|
"init=${osConfig.system.build.toplevel}/init"
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
defaultText = ''concatStringsSep " " ${osConfig.boot.kernelParams}'';
|
|
|
|
|
};
|
|
|
|
|
kernel = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "${kernel}/${kernelTarget}";
|
|
|
|
|
};
|
|
|
|
|
initramfs = mkOption {
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = "${initialRamdisk}/${initrdFile}";
|
|
|
|
|
};
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
vsock = {
|
|
|
|
|
cid = mkOption {
|
|
|
|
|
type = types.int;
|
|
|
|
|
default = 4;
|
|
|
|
|
};
|
|
|
|
|
socket = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "vsock.sock";
|
|
|
|
|
};
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
"api-socket" = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "vmm.sock";
|
|
|
|
|
};
|
|
|
|
|
"serial".mode = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "File";
|
|
|
|
|
};
|
|
|
|
|
"serial".file = mkOption {
|
2026-02-27 18:26:41 +02:00
|
|
|
type = types.nullOr types.str;
|
2026-03-07 21:16:53 +02:00
|
|
|
default = "serial";
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
"console".mode = mkOption {
|
2026-02-27 18:26:41 +02:00
|
|
|
type = types.str;
|
2026-03-07 21:16:53 +02:00
|
|
|
default = "Pty";
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
"console".file = mkOption {
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
# "watchdog" = true;
|
|
|
|
|
# "seccomp" = true;
|
|
|
|
|
disks = mkOption {
|
|
|
|
|
default = [ ];
|
|
|
|
|
type = types.listOf (
|
|
|
|
|
types.submodule {
|
|
|
|
|
freeformType = jsonType;
|
|
|
|
|
options = {
|
|
|
|
|
path = mkOption {
|
|
|
|
|
type = types.oneOf [
|
|
|
|
|
types.path
|
|
|
|
|
types.str
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
readonly = mkOption {
|
|
|
|
|
type = types.bool;
|
|
|
|
|
default = true;
|
|
|
|
|
};
|
|
|
|
|
id = mkOption { type = types.str; };
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
memory = mkOption {
|
|
|
|
|
default = { };
|
|
|
|
|
type = types.submodule {
|
2026-02-27 18:26:41 +02:00
|
|
|
freeformType = jsonType;
|
|
|
|
|
options = {
|
2026-03-07 21:16:53 +02:00
|
|
|
size = mkOption {
|
|
|
|
|
type = types.int;
|
2026-03-10 02:01:54 +02:00
|
|
|
default = 4 * 1024 * 1048576;
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
shared = mkOption {
|
2026-02-27 18:26:41 +02:00
|
|
|
type = types.bool;
|
|
|
|
|
default = true;
|
|
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
mergeable = mkOption {
|
|
|
|
|
type = types.bool;
|
|
|
|
|
default = true;
|
|
|
|
|
};
|
|
|
|
|
hotplug_method = mkOption {
|
|
|
|
|
default = "VirtioMem";
|
|
|
|
|
type = types.enum [
|
|
|
|
|
"Acpi"
|
|
|
|
|
"VirtioMem"
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
hotplugged_size = mkOption {
|
|
|
|
|
type = types.int;
|
|
|
|
|
default = 512 * 1048576;
|
|
|
|
|
};
|
|
|
|
|
hotplug_size = mkOption {
|
|
|
|
|
type = types.int;
|
|
|
|
|
default = config.memory.size;
|
|
|
|
|
};
|
|
|
|
|
# hugepages = mkOption {
|
|
|
|
|
# type = types.bool;
|
|
|
|
|
# default = true;
|
|
|
|
|
# };
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
cpus = mkOption {
|
|
|
|
|
default = { };
|
|
|
|
|
type = types.submodule {
|
|
|
|
|
freeformType = jsonType;
|
|
|
|
|
options = {
|
|
|
|
|
boot_vcpus = mkOption {
|
|
|
|
|
type = types.int;
|
|
|
|
|
default = 4;
|
|
|
|
|
};
|
|
|
|
|
max_vcpus = mkOption {
|
|
|
|
|
type = types.int;
|
|
|
|
|
default = 4;
|
|
|
|
|
};
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2026-03-07 21:16:53 +02:00
|
|
|
}
|
|
|
|
|
);
|
2026-02-27 18:26:41 +02:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
}
|