NixOS-WSL
Matrix Chat nixpkgs 23.11 Downloads

Modules for running NixOS on the Windows Subsystem for Linux

Documentation is available here

Quick Start

  1. Enable WSL if you haven't done already:
  • wsl --install --no-distribution
    
  1. Download nixos-wsl.tar.gz from the latest release.

  2. Import the tarball into WSL:

  • wsl --import NixOS $env:USERPROFILE\NixOS\ nixos-wsl.tar.gz
    
  1. You can now run NixOS:
  • wsl -d NixOS
    

For more detailed instructions, refer to the documentation.

License

Apache License, Version 2.0. See LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html for details.

Installation

System requirements

NixOS-WSL is tested with the Windows Store version of WSL 2, which is now available on all supported Windows releases (both 10 and 11). Support for older "inbox" versions is best-effort.

Install NixOS-WSL

First, download the latest release.

Then open up a PowerShell and run:

wsl --import NixOS $env:USERPROFILE\NixOS\ nixos-wsl.tar.gz

Or for Command Prompt:

wsl --import NixOS %USERPROFILE%\NixOS\ nixos-wsl.tar.gz

This sets up a new WSL distribution NixOS that is installed in a directory called NixOS inside your user directory. nixos-wsl.tar.gz is the path to the file you downloaded earlier. You can adjust the installation path and distribution name to your liking.

To get a shell in your NixOS environment, use:

wsl -d NixOS

If you chose a different name for your distro during import, adjust this command accordingly.

Post-Install

After the initial installation, you need to update your channels once, to be able to use nixos-rebuild:

sudo nix-channel --update

If you want to make NixOS your default distribution, you can do so with

wsl -s NixOS

Design

Getting NixOS to run under WSL requires some workarounds:

  • instead of directly loading systemd, we use a small shim that runs the NixOS activation scripts first
  • some additional binaries required by WSL's internal tooling are symlinked to FHS paths on activation

Running on older WSL versions also requires a workaround to spawn systemd by hijacking the root shell and spawning a container with systemd inside. This method of running things is deprecated and not recommended, however still available as nixos-wsl-legacy.tar.gz or via wsl.nativeSystemd = false.

Building your own system tarball

This requires access to a system that already has Nix installed. Please refer to the Nix installation guide if that's not the case.

If you have a flakes-enabled Nix, you can use the following command to build your own tarball instead of relying on a prebuilt one:

sudo nix run github:nix-community/NixOS-WSL#nixosConfigurations.modern.config.system.build.tarballBuilder

Or, if you want to build with local changes, run inside your checkout:

sudo nix run .#nixosConfigurations.your-hostname.config.system.build.tarballBuilder

Without a flakes-enabled Nix, you can build a tarball using:

nix-build -A nixosConfigurations.mysystem.config.system.build.tarballBuilder && sudo ./result/bin/nixos-wsl-tarball-builder

The resulting tarball can then be found under nixos-wsl.tar.gz.

How-To

How to configure NixOS-WSL with flakes?

First add a nixos-wsl input, then add nixos-wsl.nixosModules.default to your nixos configuration.

Below is a minimal flake.nix for you to get started:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    nixos-wsl.url = "github:nix-community/NixOS-WSL/main";
  };

  outputs = { self, nixpkgs, nixos-wsl, ... }: {
    nixosConfigurations = {
      nixos = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [
          nixos-wsl.nixosModules.default
          {
            system.stateVersion = "24.05";
            wsl.enable = true;
          }
        ];
      };
    };
  };
}

Troubleshooting

This section contains information on how to debug your NixOS-WSL installation.

Recovery Shell

A recovery shell can be started with

wsl -d NixOS --system --user root -- /mnt/wslg/distro/bin/nixos-wsl-recovery

This will load the WSL "system" distribution, activate your configuration, then chroot into your NixOS system, similar to what nixos-enter would do on a normal NixOS install.

You can choose an older generation to load with

wsl -d NixOS --system --user root -- /mnt/wslg/distro/bin/nixos-wsl-recovery --system /nix/var/nix/profiles/system-42-link

(note that the path is relative to the new root)

wsl.enable

Whether to enable support for running NixOS as a WSL distribution.

Type: boolean

Default: false

Example: true

Declared by:

wsl.defaultUser

The name of the default user

Type: string

Default: "nixos"

Declared by:

wsl.docker-desktop.enable

Whether to enable Docker Desktop integration.

Type: boolean

Default: false

Example: true

Declared by:

wsl.extraBin

Additional files to be added to /bin

Type: list of (submodule)

Declared by:

wsl.extraBin.*.copy

Whether or not the file should be copied instead of symlinked

Type: boolean

Default: false

Declared by:

wsl.extraBin.*.name

The name the file should be created as in /bin

Type: string

Default: baseNameOf src

Declared by:

wsl.extraBin.*.src

Path of the file that should be added

Type: string

Declared by:

wsl.interop.includePath

Include Windows PATH in WSL PATH

Type: boolean

Default: true

Declared by:

wsl.interop.register

Explicitly register the binfmt_misc handler for Windows executables

Type: boolean

Default: false

Declared by:

wsl.nativeSystemd

Use native WSL systemd support

Type: boolean

Default: true

Declared by:

wsl.startMenuLaunchers

Whether to enable shortcuts for GUI applications in the windows start menu.

Type: boolean

Default: false

Example: true

Declared by:

wsl.tarball.configPath

Path to system configuration which is copied into the tarball

Type: null or path

Default: null

Declared by:

wsl.usbip.enable

Whether to enable USB/IP integration.

Type: boolean

Default: false

Example: true

Declared by:

wsl.usbip.autoAttach

Auto attach devices with provided Bus IDs.

Type: list of string

Default: [ ]

Example:

[
  "4-1"
]

Declared by:

wsl.usbip.snippetIpAddress

This snippet is used to obtain the address of the Windows host where Usbipd is running. It can also be a plain IP address in case networkingMode=mirrored or wsl-vpnkit is used.

Type: string

Default: "$(ip route list | sed -nE 's/(default)? via (.*) dev eth0 proto kernel/2/p')"

Example: "127.0.0.1"

Declared by:

wsl.useWindowsDriver

Whether to enable OpenGL driver from the Windows host.

Type: boolean

Default: false

Example: true

Declared by:

wsl.wslConf.automount.enabled

Automatically mount windows drives under /mnt

Type: boolean

Default: true

Declared by:

wsl.wslConf.automount.ldconfig

Wether to modify /etc/ld.so.conf.d/ld.wsl.conf to load OpenGL drivers provided by the Windows host in /usr/lib/wsl/lib with /sbin/ldconfig. This way of providing OpenGL drivers does not work with NixOS and wsl.useWindowsDriver should be used instead.

Type: boolean

Default: false

Declared by:

wsl.wslConf.automount.mountFsTab

Mount entries from /etc/fstab through WSL. You should probably leave this on false, because systemd will mount those for you.

Type: boolean

Default: false

Declared by:

wsl.wslConf.automount.options

Comma-separated list of mount options that should be used for mounting windows drives.

Type: strings concatenated with “,”

Default: "metadata,uid=1000,gid=100"

Declared by:

wsl.wslConf.automount.root

The directory under which to mount windows drives.

Type: string matching the pattern ^/.*[^/]$

Default: "/mnt"

Declared by:

wsl.wslConf.boot.command

A command to run when the distro is started.

Type: string

Default: ""

Declared by:

wsl.wslConf.boot.systemd

Use systemd as init. There’s no need to enable this manually, use the wsl.nativeSystemd option instead

Type: boolean

Default: false

Declared by:

wsl.wslConf.interop.enabled

Support running Windows binaries from the linux shell.

Type: boolean

Default: true

Declared by:

wsl.wslConf.interop.appendWindowsPath

Include the Windows PATH in the PATH variable

Type: boolean

Default: true

Declared by:

wsl.wslConf.network.generateHosts

Generate /etc/hosts through WSL

Type: boolean

Default: true

Declared by:

wsl.wslConf.network.generateResolvConf

Generate /etc/resolv.conf through WSL

Type: boolean

Default: true

Declared by:

wsl.wslConf.network.hostname

The hostname of the WSL instance

Type: string

Default: "config.networking.hostName"

Declared by:

wsl.wslConf.user.default

Which user to start commands in this WSL distro as

Type: string

Default: "root"

Declared by: