NixOS on WSL
I recently set up a new Windows machine for gaming, but I’m actually using it more to play around with Linux via WSL. I set up NixOS on WSL using the aptly named NixOS on WSL project, but ran into a few issues during setup that bricked my environment1-->. Below are the steps that ended up working for me in the end:
Goals
- Set up NixOS in WSL 2 on a new Windows 11 install (version 22H2.)
- Reuse my flake-based configuration from my other NixOS 22.11 installations.
- Take advantage of native systemd support in WSL.
Step 1: Install WSL 2
Per Microsoft’s documentation:
-
Open PowerShell as an admin by right-clicking on it and selecting “Run as administrator.”
-
Run
wsl --install
Step 2: Install NixOS
Per NixOS-WSL’s documentation:
-
Download the installer listed in NixOS-WSL’s 22.05 release.
-
Move the file where you want your NixOS installation to live. I put it in
C:\Users\<my username>\AppData\Local\NixOS
, which I think follows Windows’s conventions. -
Open PowerShell as a normal user, change to the directory you just made, and run
wsl --import NixOS . nixos-wsl-installer.tar.gz --version 2
-
Run
wsl -d NixOS
to start NixOS. It’ll run through initial setup, then hang on “Starting systemd…” Press Ctrl + C to get back to PowerShell, and then runwsl --shutdown
followed bywsl -d NixOS
to get back into NixOS.
Step 3: Configure NixOS
At this point you should have a basic NixOS 22.05 installation! Let’s finish up by setting a username, switching over to flakes, updating to NixOS 22.11, and enabling native systemd:
-
Edit
/etc/nixos/configuration.nix
and make the following changes. Usesudo
or some such to edit the file as root. You may want tonix-shell -p
your favorite editor at this point – maybe Helix?- Change
wsl.defaultUser
to your desired username, and add something likeusers.users.<your username>.isNormalUser = true;
- Remove references to
./nixos-wsl
since we’ll set NixOS-WSL as a flake input:{ lib, pkgs, config, modulesPath, ... }: - - with lib; - let - nixos-wsl = import ./nixos-wsl; - in { imports = [ "${modulesPath}/profiles/minimal.nix" - - nixos-wsl.nixosModules.wsl ];
- Add
wsl.nativeSystemd = true;
- Add
networking.hostName
, and set it to your Windows 11 “Device name.” You can find this in the Windows Settings app under System > About.
- Change
-
Add
/etc/nixos/flake.nix
as root with contents like the following. Replace<host-name>
with your actual host name fromconfiguration.nix
.{ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-22.11"; NixOS-WSL = { url = "github:nix-community/NixOS-WSL"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, NixOS-WSL }: { nixosConfigurations."<host-name>" = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ { nix.registry.nixpkgs.flake = nixpkgs; } ./configuration.nix NixOS-WSL.nixosModules.wsl ]; }; }; }
-
Run
sudo nixos-rebuild switch
-
exit
out of NixOS, then runwsl --shutdown
followed bywsl -d NixOS
. You should be logged in as the new default user. -
At this point you should have a stable base to make any configuration changes you’d like.
Step 4: Cleaning up
- Rename
wsl.automountPath
towsl.wslConf.automount.root
inconfiguration.nix
to match NixOS-WSL’s latest configuration. - Delete the now unused
/etc/nixos/nixos-wsl
directory. - Delete
/home/nixos
since you’ve changed your username. - You can run
sudo nix-channel --remove nixos
if you don’t want the channel hanging around now that we’re using flakes.
Addendum: Share .ssh
directory with Windows
It turns out that file permissions set in WSL are preserved in NTFS2-->. You can store your SSH configuration files in Windows, and still use them from WSL with no permissions issues:
- Set up your
~/.ssh
in NixOS like normal. - Move your
~/.ssh
directory to Windows withmv ~/.ssh /mnt/c/Users/<your Windows username>/.ssh
- Soft link it back to your WSL VM with
ln -s /mnt/c/Users/<your Windows username>/.ssh/ ~/.ssh
That’s it! You can verify that permissions carried over with ls -al ~/.ssh/
Addendum: Set up fish in NixOS the right way
I use fish as my shell, but when I set it up in WSL I started getting errors like this:
fish: Unknown command: ls
/nix/store/lkf5vmavnxa0s37imb03gv7hs6dh5pll-fish-3.5.1/share/fish/functions/ls.fish (line 64):
command $__fish_ls_command $__fish_ls_color_opt $opt $argv
^
in function 'ls'
Uh oh. Obviously, there are important directories missing from my path. It turns out that I was missing some configuration3-->:
programs.fish.enable = true;
I don’t know why this issue only appeared in WSL, but fish users should probably set programs.fish.enable
in NixOS
whether the issue appears or not.
See also
-
I think I changed the default user without actually setting up that user? Or I switched to native systemd before upgrading to a version of NixOS on WSL that supports it?
-
Thanks to this Stack Exchange answer for pointing me in the right direction. You don’t have to follow the instructions in this post – NixOS on WSL already mounts Windows’s drives with the necessary options.
-
Thanks to this GitHub issue for alerting me to the problem.