2025-12-15 16:20:04 +01:00
{
self ,
virtwl ,
sidebus ,
} :
{
pkgs ,
lib ,
utils ,
config ,
. . .
} :
let
2025-11-03 17:14:28 +01:00
useTTY = {
TTYPath = " / d e v / h v c 0 " ;
StandardOutput = " t t y " ;
StandardInput = " t t y " ;
StandardError = " t t y " ;
} ;
runtimeDir = " / r u n / v m - u s e r " ;
2025-12-15 16:20:04 +01:00
userbornConfig = {
groups = lib . mapAttrsToList ( username : opts : {
inherit ( opts ) name gid members ;
} ) config . users . groups ;
users = lib . mapAttrsToList ( username : opts : {
inherit ( opts )
name
uid
group
description
home
password
hashedPassword
hashedPasswordFile
initialPassword
initialHashedPassword
;
isNormal = opts . isNormalUser ;
shell = utils . toShellPath opts . shell ;
} ) ( lib . filterAttrs ( _ : u : u . enable ) config . users . users ) ;
} ;
userbornConfigJson = pkgs . writeText " u s e r b o r n . j s o n " ( builtins . toJSON userbornConfig ) ;
userbornResults =
pkgs . runCommand " b a k e d u s e r b o r n " { }
" m k d i r - p $ o u t ; ${ lib . getExe pkgs . userborn } ${ userbornConfigJson } $ o u t " ;
2025-12-04 07:24:51 -03:00
system = pkgs . stdenv . hostPlatform . system ;
2025-12-15 16:20:04 +01:00
in
{
options . virtualisation . munix . defaultCommand = lib . mkOption {
type = lib . types . str ;
default = " b a s h " ;
description = " D e f a u l t c o m m a n d t o r u n w h e n s t a r t i n g t h e V M w i t h o u t a r g u m e n t s . " ;
2025-11-03 17:14:28 +01:00
} ;
2025-12-15 16:20:04 +01:00
config = {
boot . isContainer = true ;
fileSystems . " / " . device = lib . mkDefault " / d e v / s d a " ; # dummy
2025-11-03 17:14:28 +01:00
2025-12-15 16:20:04 +01:00
# Disable unused things
environment . defaultPackages = lib . mkDefault [ ] ;
documentation = {
enable = lib . mkDefault false ;
doc . enable = lib . mkDefault false ;
info . enable = lib . mkDefault false ;
man . enable = lib . mkDefault false ;
nixos . enable = lib . mkDefault false ;
2025-12-04 23:48:17 -03:00
} ;
2025-12-15 16:20:04 +01:00
services . logrotate . enable = false ;
services . udisks2 . enable = false ;
system . tools . nixos-generate-config . enable = false ;
system . activationScripts . specialfs = lib . mkForce " " ;
systemd . coredump . enable = false ;
networking . firewall . enable = false ;
powerManagement . enable = false ;
boot . kexec . enable = false ;
console . enable = false ;
2025-11-03 17:14:28 +01:00
2025-12-15 16:20:04 +01:00
# Configure activation / systemd
boot . initrd . systemd . enable = true ; # for etc.overlay, but we don't have initrd
system . etc . overlay . enable = true ; # erofs
system . etc . overlay . mutable = false ;
system . switch . enable = false ;
services . udev . enable = lib . mkDefault true ;
services . udev . packages = lib . mkDefault [ ] ;
services . resolved . enable = false ;
environment . etc . " r e s o l v . c o n f " . source = " / r u n / r e s o l v . c o n f " ;
environment . etc . " m a c h i n e - i d " . source = " / r u n / m a c h i n e - i d " ;
environment . etc . " s y s t e m d / s y s t e m " . source = lib . mkForce (
utils . systemdUtils . lib . generateUnits {
type = " s y s t e m " ;
units = config . systemd . units ;
upstreamUnits = [
" s y s i n i t . t a r g e t "
" l o c a l - f s . t a r g e t "
" n s s - u s e r - l o o k u p . t a r g e t "
" u m o u n t . t a r g e t "
" s o c k e t s . t a r g e t "
" s h u t d o w n . t a r g e t "
" r e b o o t . t a r g e t "
" e x i t . t a r g e t "
" f i n a l . t a r g e t "
" s y s t e m d - e x i t . s e r v i c e "
" s y s t e m d - j o u r n a l d . s o c k e t "
" s y s t e m d - j o u r n a l d - a u d i t . s o c k e t "
" s y s t e m d - j o u r n a l d - d e v - l o g . s o c k e t "
" s y s t e m d - j o u r n a l d . s e r v i c e "
" s y s t e m d - u d e v d - k e r n e l . s o c k e t "
" s y s t e m d - u d e v d - c o n t r o l . s o c k e t "
" u s e r . s l i c e "
] ;
upstreamWants = [ " m u l t i - u s e r . t a r g e t . w a n t s " ] ;
}
) ;
2025-11-03 17:14:28 +01:00
2025-12-15 16:20:04 +01:00
# systemd.package = pkgs.systemdMinimal; # no analyze
systemd . defaultUnit = " m i c r o v m . t a r g e t " ;
systemd . targets . microvm = {
description = " M i n i m a l m i c r o V M s y s t e m " ;
wants = [
" s y s t e m d - j o u r n a l d . s o c k e t "
" s y s t e m d - u d e v d . s e r v i c e "
" d b u s . s o c k e t "
2025-11-14 06:20:44 -03:00
] ;
2025-12-15 16:20:04 +01:00
unitConfig . AllowIsolate = " y e s " ;
} ;
systemd . services . generate-shutdown-ramfs . enable = lib . mkForce false ;
systemd . services . systemd-remount-fs . enable = lib . mkForce false ;
systemd . services . systemd-pstore . enable = lib . mkForce false ;
systemd . services . lastlog2-import . enable = lib . mkForce false ;
systemd . services . suid-sgid-wrappers . enable = lib . mkForce false ;
systemd . services . systemd-udevd = {
# Redefine to remove the Before deps and get out of the critical chain
enable = true ;
description = " R u l e - b a s e d M a n a g e r f o r D e v i c e E v e n t s a n d F i l e s " ;
unitConfig . DefaultDependencies = " n o " ;
serviceConfig = {
CapabilityBoundingSet = " ~ C A P _ S Y S _ T I M E C A P _ W A K E _ A L A R M " ;
Delegate = " " ;
DelegateSubgroup = " u d e v " ;
Type = " n o t i f y - r e l o a d " ;
OOMScoreAdjust = " - 1 0 0 0 " ;
Sockets = " s y s t e m d - u d e v d - c o n t r o l . s o c k e t s y s t e m d - u d e v d - k e r n e l . s o c k e t s y s t e m d - u d e v d - v a r l i n k . s o c k e t " ;
Restart = " a l w a y s " ;
RestartSec = " 0 " ;
ExecStart = " ${ pkgs . systemd } / l i b / s y s t e m d / s y s t e m d - u d e v d " ;
FileDescriptorStoreMax = " 5 1 2 " ;
FileDescriptorStorePreserve = " y e s " ;
KillMode = " m i x e d " ;
TasksMax = " i n f i n i t y " ;
PrivateMounts = " y e s " ;
ProtectHostname = " y e s " ;
MemoryDenyWriteExecute = " y e s " ;
RestrictAddressFamilies = " A F _ U N I X A F _ N E T L I N K A F _ I N E T A F _ I N E T 6 " ;
RestrictRealtime = " y e s " ;
RestrictSUIDSGID = " y e s " ;
SystemCallFilter = [
" @ s y s t e m - s e r v i c e @ m o d u l e @ r a w - i o b p f "
" ~ @ c l o c k "
] ;
SystemCallErrorNumber = " E P E R M " ;
SystemCallArchitectures = " n a t i v e " ;
LockPersonality = " y e s " ;
IPAddressDeny = " a n y " ;
WatchdogSec = " 3 m i n " ;
} ;
} ;
2025-11-03 17:14:28 +01:00
2025-12-15 16:20:04 +01:00
# Configure user accounts
# The immutable overlay wants userborn or sysusers.. we just want baked-in files w/o running a service.
# So we can just run userborn at system closure build time!
systemd . sysusers . enable = false ;
services . userborn . enable = true ;
systemd . services . userborn . enable = false ;
environment . etc . " p a s s w d " = lib . mkForce {
source = " ${ userbornResults } / p a s s w d " ;
mode = " 0 4 4 4 " ;
} ;
environment . etc . " g r o u p " = lib . mkForce {
source = " ${ userbornResults } / g r o u p " ;
mode = " 0 4 4 4 " ;
} ;
environment . etc . " s h a d o w " = lib . mkForce {
source = " ${ userbornResults } / s h a d o w " ;
mode = " 0 4 4 0 " ;
} ;
users . mutableUsers = false ;
users . users . appvm = {
uid = 1337 ;
group = " a p p v m " ;
isNormalUser = false ;
isSystemUser = true ;
home = " / h o m e / a p p v m " ;
description = " m i c r o V M U s e r " ;
extraGroups = [
" w h e e l "
" v i d e o "
" i n p u t "
" s y s t e m d - j o u r n a l "
] ;
} ;
users . groups . appvm . gid = 1337 ;
users . allowNoPasswordLogin = true ;
2025-11-03 17:14:28 +01:00
2025-12-15 16:20:04 +01:00
# Configure services
systemd . settings . Manager . DefaultEnvironment = " X D G _ R U N T I M E _ D I R = ${ runtimeDir } " ;
systemd . services . muvm-remote = {
enable = true ;
description = " m i c r o V M A p p l i c a t i o n r u n n e r " ;
onFailure = [ " e x i t . t a r g e t " ] ;
onSuccess = [ " e x i t . t a r g e t " ] ;
wants = [ " s o c k e t s . t a r g e t " ] ;
after = [ " s o c k e t s . t a r g e t " ] ;
wantedBy = [ " m i c r o v m . t a r g e t " ] ;
serviceConfig = {
Type = " e x e c " ;
PassEnvironment = [
" T E R M "
" M E S A _ L O A D E R _ D R I V E R _ O V E R R I D E "
" M U V M _ R E M O T E _ C O N F I G "
] ; # "KRUN_CONFIG"];
Environment = [
" W A Y L A N D _ D I S P L A Y = w a y l a n d - 1 "
" D B U S _ S E S S I O N _ B U S _ A D D R E S S = u n i x : p a t h = ${ runtimeDir } / d b u s . s o c k "
" P A T H = / r u n / c u r r e n t - s y s t e m / s w / b i n "
] ;
User = " a p p v m " ;
Group = " a p p v m " ;
ExecStartPre = " + / r u n / c u r r e n t - s y s t e m / s w / b i n / c h o w n a p p v m : a p p v m ${ runtimeDir } " ;
ExecStart = " / o p t / b i n / m u v m - r e m o t e " ;
ExecStopPost = '' + ${ pkgs . python3 } / b i n / p y t h o n - c " i m p o r t o s , f c n t l , s t r u c t ; p r i n t ( o s . g e t e n v ( ' E X I T _ S T A T U S ' , ' 1 ' ) ) ; f c n t l . i o c t l ( o s . o p e n ( ' / ' , o s . O _ R D O N L Y ) , 0 x 7 6 0 2 , i n t ( o s . g e t e n v ( ' E X I T _ S T A T U S ' , ' 1 ' ) ) ) " '' ;
}
// useTTY ;
} ;
systemd . services . muvm-configure-network = {
enable = true ;
description = " m i c r o V M N e t w o r k c o n f i g u r a t i o n " ;
wantedBy = [ " m i c r o v m . t a r g e t " ] ;
serviceConfig . Type = " o n e s h o t " ;
serviceConfig . ExecStart = " / o p t / b i n / m u v m - c o n f i g u r e - n e t w o r k " ;
} ;
systemd . sockets . muvm-pwbridge = {
enable = true ;
description = " P i p e W i r e c r o s s - d o m a i n p r o x y s o c k e t " ;
wantedBy = [ " m i c r o v m . t a r g e t " ] ;
partOf = [ " m u v m - p w b r i d g e . s e r v i c e " ] ;
listenStreams = [ " ${ runtimeDir } / p i p e w i r e - 0 " ] ;
socketConfig = {
SocketUser = " a p p v m " ;
SocketGroup = " a p p v m " ;
} ;
} ;
systemd . services . muvm-pwbridge = {
enable = true ;
description = " P i p e W i r e c r o s s - d o m a i n p r o x y " ;
requires = [ " m u v m - p w b r i d g e . s o c k e t " ] ;
serviceConfig . Type = " e x e c " ;
serviceConfig . ExecStart = " / o p t / b i n / m u v m - p w b r i d g e " ;
} ;
systemd . sockets . wayland-proxy-virtwl = {
enable = true ;
description = " W a y l a n d c r o s s - d o m a i n p r o x y s o c k e t " ;
wantedBy = [ " m i c r o v m . t a r g e t " ] ;
partOf = [ " w a y l a n d - p r o x y - v i r t w l . s e r v i c e " ] ;
listenStreams = [ " ${ runtimeDir } / w a y l a n d - 1 " ] ;
socketConfig = {
SocketUser = " a p p v m " ;
SocketGroup = " a p p v m " ;
FileDescriptorName = " w a y l a n d " ;
} ;
} ;
systemd . services . wayland-proxy-virtwl = {
enable = true ;
description = " W a y l a n d c r o s s - d o m a i n p r o x y " ;
requires = [ " w a y l a n d - p r o x y - v i r t w l . s o c k e t " ] ;
serviceConfig = {
ExecStartPre = " + / r u n / c u r r e n t - s y s t e m / s w / b i n / c h m o d 0 6 6 6 / d e v / d r i / c a r d 0 / d e v / d r i / r e n d e r D 1 2 8 " ;
ExecStart = " ${ virtwl . packages . ${ system } . proxy } / b i n / w a y l a n d - p r o x y - v i r t w l - - v i r t i o - g p u " ;
User = " a p p v m " ;
Group = " a p p v m " ;
} ;
} ;
systemd . sockets . session-bus = {
enable = true ;
description = " D - B u s s e s s i o n b u s s o c k e t " ;
wantedBy = [ " m i c r o v m . t a r g e t " ] ;
partOf = [ " s e s s i o n - b u s . s e r v i c e " ] ;
listenStreams = [ " ${ runtimeDir } / d b u s . s o c k " ] ;
socketConfig = {
SocketUser = " a p p v m " ;
SocketGroup = " a p p v m " ;
} ;
} ;
systemd . services . session-bus = {
enable = true ;
description = " D - B u s s e s s i o n b u s " ;
requires = [ " s e s s i o n - b u s . s o c k e t " ] ;
serviceConfig = {
ImportCredential = " s i d e b u s . p o r t " ; # inherited by the activated agent..
ExecStart = " ${ pkgs . dbus } / b i n / d b u s - d a e m o n - - s e s s i o n - - a d d r e s s = s y s t e m d : - - n o f o r k - - n o p i d f i l e - - s y s l o g - o n l y " ; # no systemd activation, we don't run a *session* systemd
User = " a p p v m " ;
Group = " a p p v m " ;
} ;
} ;
services . dbus . packages = [
( pkgs . writeTextDir " / s h a r e / d b u s - 1 / s e r v i c e s / o r g . f r e e d e s k t o p . p o r t a l . D e s k t o p . s e r v i c e " ''
[ D-BUS Service ]
Name = org . freedesktop . portal . Desktop
Exec = $ { sidebus . packages . ${ system } . sidebus-agent } /bin/sidebus-agent
'' )
] ;
hardware . graphics . enable = true ;
hardware . graphics . package = self . packages . ${ system } . mesa ;
system . build . munix = pkgs . symlinkJoin {
name = " m u n i x " ;
paths = [ self . packages . ${ system } . munix ] ;
buildInputs = [ pkgs . makeWrapper ] ;
postBuild = ''
wrapProgram $ out/bin/munix \
- - add-flags $ { config . system . build . toplevel } \
- - set MICROVM_DEFAULT_COMMAND $ { lib . escapeShellArg config . virtualisation . munix . defaultCommand }
'' ;
2025-11-03 17:14:28 +01:00
} ;
} ;
}