{ config, lib, pkgs, ... }: let cfg = config.services.windows-oci; inherit (lib) mkEnableOption mkIf mkOption mkOverride optional types ; in { options.services.windows-oci = { enable = mkEnableOption "Windows in an OCI container using Podman"; volume = mkOption { type = types.str; default = "/opt/windows"; description = "Path to the volume for Windows data."; }; sharedVolume = mkOption { type = types.nullOr types.str; default = null; description = "Path to a shared volume to mount inside the Windows container. You have to create this directory manually."; }; settings = { version = mkOption { type = types.str; default = "11"; example = "2025"; description = "Windows version to use."; }; ramSize = mkOption { type = types.str; default = "8G"; description = "Amount of RAM to allocate to the Windows container."; }; cpuCores = mkOption { type = types.str; default = "4"; description = "Number of CPU cores to allocate to the Windows container."; }; diskSize = mkOption { type = types.str; default = "64G"; description = "Size of the virtual disk for the Windows container."; }; username = mkOption { type = types.str; default = "admin"; description = "Username for the Windows installation."; }; password = mkOption { type = types.str; default = "admin"; description = "Password for the Windows installation."; }; language = mkOption { type = types.str; default = "English"; description = "Language for the Windows installation."; }; region = mkOption { type = types.str; default = "en-DE"; description = "Region for the Windows installation."; }; keyboard = mkOption { type = types.str; default = "de-DE"; description = "Keyboard layout for the Windows installation."; }; }; }; config = mkIf cfg.enable { systemd.tmpfiles.rules = [ "d ${cfg.volume} 0755 root podman -" ]; virtualisation.podman = { enable = true; autoPrune.enable = true; dockerCompat = true; defaultNetwork.settings = { dns_enabled = true; }; }; # https://github.com/NixOS/nixpkgs/issues/226365 networking.firewall.interfaces."podman+".allowedUDPPorts = [ 53 ]; virtualisation.oci-containers.backend = "podman"; virtualisation.oci-containers.containers."windows" = { image = "dockurr/windows"; environment = with cfg.settings; { "VERSION" = version; "RAM_SIZE" = ramSize; "CPU_CORES" = cpuCores; "DISK_SIZE" = diskSize; "USERNAME" = username; "PASSWORD" = password; "LANGUAGE" = language; "REGION" = region; "KEYBOARD" = keyboard; }; volumes = [ "${cfg.volume}:/storage:rw" ] ++ optional (cfg.sharedVolume != null) "${cfg.sharedVolume}:/shared:rw"; ports = [ "8006:8006/tcp" "3389:3389/tcp" "3389:3389/udp" ]; log-driver = "journald"; extraOptions = [ "--cap-add=NET_ADMIN" "--device=/dev/kvm:/dev/kvm:rwm" "--device=/dev/net/tun:/dev/net/tun:rwm" "--network-alias=windows" "--network=windows_default" ]; }; systemd.services."podman-windows" = { serviceConfig = { Restart = mkOverride 90 "always"; }; after = [ "podman-network-windows_default.service" ]; requires = [ "podman-network-windows_default.service" ]; partOf = [ "podman-compose-windows-root.target" ]; wantedBy = [ "podman-compose-windows-root.target" ]; }; systemd.services."podman-network-windows_default" = { path = [ pkgs.podman ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStop = "podman network rm -f windows_default"; }; script = '' podman network inspect windows_default || podman network create windows_default ''; partOf = [ "podman-compose-windows-root.target" ]; wantedBy = [ "podman-compose-windows-root.target" ]; }; systemd.targets."podman-compose-windows-root" = { unitConfig = { Description = "Root target generated by compose2nix."; }; wantedBy = [ "multi-user.target" ]; }; }; }