quinneden/virby-nix-darwin

A vfkit-based linux builder for Nix-darwin

Go

95

179 commits

updated Jul 2, 2026

See the code

README

Virby - Linux Builder for Nix-darwin

Virby is a module for nix-darwin that configures a lightweight linux VM as a remote build machine for nix, allowing linux packages to be built on macOS. This project is modeled after nix-rosetta-builder, which provides a similar service, using lima to manage the VM. Some parts of the code in this repository are directly borrowed and adapted from that project.

Quick Start

Add virby to your flake inputs:

{
  inputs = {
    virby.url = "github:quinneden/virby-nix-darwin";
    # It is important that you dont add the line:
    # 
    #   inputs.nixpkgs.follows = "nixpkgs";
    #
    # until after you've activated with `darwin-rebuild`. This way, the cached
    # image can be used and you won't have to build from source (which requires
    # an existing aarch64-linux builder).
  };

  outputs = { virby, ... }: {
    darwinConfigurations."myHost" = {
      # Import the module
      modules = [ virby.darwinModules.default ];
    };
  };
}

[!Important] When enabling Virby for the first time, you must add the binary cache to your Nix configuration. This ensures that the prebuilt VM image is available for download, rather than having to be built locally, which requires an existing linux builder. You can do this in one of two ways:

Add the binary cache to your configuration before enabling Virby:

{
  nix.settings.extra-substituters = [ "https://virby-nix-darwin.cachix.org" ];
  nix.settings.extra-trusted-public-keys = [
    "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="
  ];
  
  services.virby.enable = false;
}

Run darwin-rebuild, then enable Virby:

{
  nix.settings.extra-substituters = [ "https://virby-nix-darwin.cachix.org" ];
  nix.settings.extra-trusted-public-keys = [
    "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="
  ];
  
  # Don't configure any other Virby options until after you've switched to the new
  # configuration. If the hash for the disk image derivation doesn't match the one
  # in the binary cache, then nix will try to build the image locally.
  services.virby.enable = true;
}

Finally, rebuild again.

OR

Run the darwin-rebuild command with the following options:

sudo darwin-rebuild switch --flake .#myHost \
  --option "extra-substituters" "https://virby-nix-darwin.cachix.org" \
  --option "extra-trusted-public-keys" "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="

If you prefer building the image locally, you can enable the nix.linux-builder option before enabling Virby:

{
  nix.linux-builder.enable = true;

  services.virby.enable = false;
}

Key Features

  • On-demand activation (optional) - VM is started when needed, then shuts down after a period of inactivity
  • Rosetta support (optional) - Build x86_64-linux packages on Apple Silicon using Rosetta translation
  • Secure by default - Host-only access via loopback (i.e. 127.0.0.1), with automatic ED25519 key generation
  • Fully configurable - Adjust VM resources and add custom NixOS modules

Configuration

Available Options

OptionTypeDefaultDescription
enableboolfalseEnable the service
allowUserSshboolfalseAllow non-root users to SSH into the VM
coresint8CPU cores allocated to VM
debugboolfalseEnable debug logging for the VM
driverstring ("vfkit" or "krunkit")"vfkit"The virtualization driver used to run the VM
diskSizestring"100GiB"VM disk size
extraConfigmodule{}Additional NixOS modules to include in the VM's system configuration
memoryint or string6144Memory in MiB or string format (e.g. "6GiB")
onDemand.enableboolfalseEnable on-demand activation of the VM
onDemand.ttlint180The number of minutes of inactivity which must pass before the VM shuts down
portint31222SSH port for VM access
rosettabooltrueEnable Rosetta support for the VM
sharedDirectoriesattrs of string{}An attribute set of directories that will be shared with the VM as virtio-fs devices
speedFactorint1Speed factor for Nix build machine
supportDeterminateNixboolfalseEnable support for using Virby with Determinate Nix

Use krunkit instead of vfkit

By default, vfkit is used to run the VM. Optionally, you can configure Virby to use krunkit instead:

{
  services.virby.driver = "krunkit";
}

Unlike vfkit, krunkit does not support NAT networking, so the network is proxied via vmnet-helper.

On-demand Activation

{
  services.virby.onDemand.enable = true;
  services.virby.onDemand.ttl = 180;  # Idle timeout in minutes
}

Rosetta Support

{
  services.virby.rosetta = true;
}

Custom NixOS Configuration

[!Warning] This option allows you to arbitrarily change the NixOS configuration, which could expose the VM to security risks.

{
  services.virby.extraConfig = {
    inherit (config.nix) settings;
    # Some NixOS options which are defined in the default VM configuration cannot
    # be overridden, such as `networking.hostName`. Others may be overridden with
    # `lib.mkForce`. Also note that anything changed here will cause a rebuild of
    # the VM image, and SSH keys will be regenerated.
  };
}

Debug Options (insecure, for troubleshooting only)

{
  services.virby.debug = true;         # Enable verbose logging
  services.virby.allowUserSsh = true;  # Allow non-root SSH access with a separate shared key copy
}

Architecture

Virby integrates three components:

  • nix-darwin Module - Configures VM as a Nix build machine for host
  • VM Image - Minimal NixOS disk image configured for secure ssh access and build isolation
  • VM Runner - Go package managing VM lifecycle and SSH proxying

Security model:

  • VM doesn't accept remote connections as it binds to the loopback interface
  • SSH keys are generated and copied to the VM on first run.
  • builder user has minimal permissions, root access is restricted by default

Troubleshooting

Debug logging

{
  # Enable debug logging to `/tmp/virbyd.log`
  services.virby.debug = true;
}
# View daemon logs
tail -f /tmp/virbyd.log

SSH into VM

# Requires `allowUserSsh = true`
ssh virby-vm
# or use sudo

Acknowledgments


License: MIT - see LICENSE file for details.

golang
nix
nix-darwin
rosetta2
vfkit
virtualization-framework

Contributors

quinneden

172 commits

n-hass

5 commits

hgl

1 commits

nolith

1 commits

quinneden/virby-nix-darwin

A vfkit-based linux builder for Nix-darwin

Go

95

179 commits

updated Jul 2, 2026

See the code

README

Virby - Linux Builder for Nix-darwin

Virby is a module for nix-darwin that configures a lightweight linux VM as a remote build machine for nix, allowing linux packages to be built on macOS. This project is modeled after nix-rosetta-builder, which provides a similar service, using lima to manage the VM. Some parts of the code in this repository are directly borrowed and adapted from that project.

Quick Start

Add virby to your flake inputs:

{
  inputs = {
    virby.url = "github:quinneden/virby-nix-darwin";
    # It is important that you dont add the line:
    # 
    #   inputs.nixpkgs.follows = "nixpkgs";
    #
    # until after you've activated with `darwin-rebuild`. This way, the cached
    # image can be used and you won't have to build from source (which requires
    # an existing aarch64-linux builder).
  };

  outputs = { virby, ... }: {
    darwinConfigurations."myHost" = {
      # Import the module
      modules = [ virby.darwinModules.default ];
    };
  };
}

[!Important] When enabling Virby for the first time, you must add the binary cache to your Nix configuration. This ensures that the prebuilt VM image is available for download, rather than having to be built locally, which requires an existing linux builder. You can do this in one of two ways:

Add the binary cache to your configuration before enabling Virby:

{
  nix.settings.extra-substituters = [ "https://virby-nix-darwin.cachix.org" ];
  nix.settings.extra-trusted-public-keys = [
    "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="
  ];
  
  services.virby.enable = false;
}

Run darwin-rebuild, then enable Virby:

{
  nix.settings.extra-substituters = [ "https://virby-nix-darwin.cachix.org" ];
  nix.settings.extra-trusted-public-keys = [
    "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="
  ];
  
  # Don't configure any other Virby options until after you've switched to the new
  # configuration. If the hash for the disk image derivation doesn't match the one
  # in the binary cache, then nix will try to build the image locally.
  services.virby.enable = true;
}

Finally, rebuild again.

OR

Run the darwin-rebuild command with the following options:

sudo darwin-rebuild switch --flake .#myHost \
  --option "extra-substituters" "https://virby-nix-darwin.cachix.org" \
  --option "extra-trusted-public-keys" "virby-nix-darwin.cachix.org-1:z9GiEZeBU5bEeoDQjyfHPMGPBaIQJOOvYOOjGMKIlLo="

If you prefer building the image locally, you can enable the nix.linux-builder option before enabling Virby:

{
  nix.linux-builder.enable = true;

  services.virby.enable = false;
}

Key Features

  • On-demand activation (optional) - VM is started when needed, then shuts down after a period of inactivity
  • Rosetta support (optional) - Build x86_64-linux packages on Apple Silicon using Rosetta translation
  • Secure by default - Host-only access via loopback (i.e. 127.0.0.1), with automatic ED25519 key generation
  • Fully configurable - Adjust VM resources and add custom NixOS modules

Configuration

Available Options

OptionTypeDefaultDescription
enableboolfalseEnable the service
allowUserSshboolfalseAllow non-root users to SSH into the VM
coresint8CPU cores allocated to VM
debugboolfalseEnable debug logging for the VM
driverstring ("vfkit" or "krunkit")"vfkit"The virtualization driver used to run the VM
diskSizestring"100GiB"VM disk size
extraConfigmodule{}Additional NixOS modules to include in the VM's system configuration
memoryint or string6144Memory in MiB or string format (e.g. "6GiB")
onDemand.enableboolfalseEnable on-demand activation of the VM
onDemand.ttlint180The number of minutes of inactivity which must pass before the VM shuts down
portint31222SSH port for VM access
rosettabooltrueEnable Rosetta support for the VM
sharedDirectoriesattrs of string{}An attribute set of directories that will be shared with the VM as virtio-fs devices
speedFactorint1Speed factor for Nix build machine
supportDeterminateNixboolfalseEnable support for using Virby with Determinate Nix

Use krunkit instead of vfkit

By default, vfkit is used to run the VM. Optionally, you can configure Virby to use krunkit instead:

{
  services.virby.driver = "krunkit";
}

Unlike vfkit, krunkit does not support NAT networking, so the network is proxied via vmnet-helper.

On-demand Activation

{
  services.virby.onDemand.enable = true;
  services.virby.onDemand.ttl = 180;  # Idle timeout in minutes
}

Rosetta Support

{
  services.virby.rosetta = true;
}

Custom NixOS Configuration

[!Warning] This option allows you to arbitrarily change the NixOS configuration, which could expose the VM to security risks.

{
  services.virby.extraConfig = {
    inherit (config.nix) settings;
    # Some NixOS options which are defined in the default VM configuration cannot
    # be overridden, such as `networking.hostName`. Others may be overridden with
    # `lib.mkForce`. Also note that anything changed here will cause a rebuild of
    # the VM image, and SSH keys will be regenerated.
  };
}

Debug Options (insecure, for troubleshooting only)

{
  services.virby.debug = true;         # Enable verbose logging
  services.virby.allowUserSsh = true;  # Allow non-root SSH access with a separate shared key copy
}

Architecture

Virby integrates three components:

  • nix-darwin Module - Configures VM as a Nix build machine for host
  • VM Image - Minimal NixOS disk image configured for secure ssh access and build isolation
  • VM Runner - Go package managing VM lifecycle and SSH proxying

Security model:

  • VM doesn't accept remote connections as it binds to the loopback interface
  • SSH keys are generated and copied to the VM on first run.
  • builder user has minimal permissions, root access is restricted by default

Troubleshooting

Debug logging

{
  # Enable debug logging to `/tmp/virbyd.log`
  services.virby.debug = true;
}
# View daemon logs
tail -f /tmp/virbyd.log

SSH into VM

# Requires `allowUserSsh = true`
ssh virby-vm
# or use sudo

Acknowledgments


License: MIT - see LICENSE file for details.

golang
nix
nix-darwin
rosetta2
vfkit
virtualization-framework

Contributors

quinneden

172 commits

n-hass

5 commits

hgl

1 commits

nolith

1 commits

Languages

Go

56.1%

Nix

43.9%