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. ↩︎