Nix Flakes on WSL
Read time in minutes: 12About five years ago, Microsoft released the Windows Subsystem for Linux (WSL). This allows you to run Linux programs on a Windows machine. When they released WSL version 2 in 2019, this added support for things like Docker and systemd. As a result, this is enough to run NixOS on Windows.
Installation
Head to the NixOS-WSL CI
feed
and download the installer.zip
file to your Downloads folder.
Extract the nixos-wsl-installer.tar.gz
file from installer.zip
. Do
not extract nixos-wsl-installer.tar.gz
, the wsl
command will for
you.
Then open Powershell and make a folder called WSL
:
New-Item -Path .\WSL -ItemType Directory
wget
out of instinct
to download things. In order to avoid your muscle memory betraying you, the
Powershell CMDlets are shown here in their full overly verbose glory.
Then enter the directory with Set-Location
:
Set-Location -Path .\WSL
%APPDATA%
will work, just as long as it's on an NTFS volume
somewhere.
Make a folder for the NixOS filesystem:
New-Item -Path .\NixOS -ItemType Directory
Then install the NixOS root image with the wsl
command:
wsl --import NixOS .\NixOS\ ..\Downloads\nixos-wsl-installer-fixed.tar.gz --version 2
And start NixOS once to have it install itself:
wsl -d NixOS
Once that finishes, press control-D (or use the exit
command) to exit out of
NixOS and restart the WSL virtual machine:
exit
wsl --shutdown
wsl -d NixOS
And then you have yourself a working NixOS environment! It's very barebones, but
we can use it to test the nix run
command against our gohello command:
$ nix run github:Xe/gohello
Hello reader!
Local Services
We can also use this NixOS environment to run a local nginx server. Open
/etc/nixos/configuration.nix
:
{ lib, pkgs, config, modulesPath, ... }:
with lib;
let
nixos-wsl = import ./nixos-wsl;
in
{
imports = [
"${modulesPath}/profiles/minimal.nix"
nixos-wsl.nixosModules.wsl
];
wsl = {
enable = true;
automountPath = "/mnt";
defaultUser = "nixos";
startMenuLaunchers = true;
# Enable integration with Docker Desktop (needs to be installed)
# docker.enable = true;
};
# Enable nix flakes
nix.package = pkgs.nixFlakes;
nix.extraOptions = ''
experimental-features = nix-command flakes
'';
}
Right after the wsl
block, add this nginx configuration to the file:
services.nginx.enable = true;
services.nginx.virtualHosts."test.local.cetacean.club" = {
root = "/srv/http/test.local.cetacean.club";
};
This will create an nginx configuration that points the domain
test.local.cetacean.club
to the contents of the folder /srv/http/test.local.cetacean.club
.
/srv
folder is set aside
for site-specific data, which is code for "do whatever you want with this
folder". In many cases people make a separate /srv/http
folder and
put each static subdomain in its own folder under that, however I am also told
that it is idiomatic to put stuff in /var/www
. Pick your poison.
Then you can test the web server with the curl
command:
$ curl http://test.local.cetacean.club
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
This is good! Nginx is running and since we haven't created the folder with our website content yet, this 404 means that it can't find it! Let's create the folder so that nginx has permission to it and we can modify things in it:
sudo mkdir -p /srv/http/test.local.cetacean.club
sudo chown nixos:nginx /srv/http/test.local.cetacean.club
Finally we can make an amazing website. Open
/srv/http/test.local.cetacean.club/index.html
in nano:
nano /srv/http/test.local.cetacean.club/index.html
And paste in this HTML:
<title>amazing website xD</title>
<h1>look at my AMAZING WEBSITE</h1>
It's so cool *twerks*
root
of
a nginx virtual host to point to a Nix package as well. This will allow you to
automatically generate your website somehow and deploy it with the rest of the
system. Including being able to roll back changes.And then you can see it show up with curl
:
$ curl http://test.local.cetacean.club
<title>amazing website xD</title>
<h1>look at my AMAZING WEBSITE</h1>
It's so cool *twerks*
You can also check this out in a browser:
Installing gohello
To install the gohello
service, first we will need to convert this machine to
use NixOS flakes. We can do that really quick and easy by adding this file to
/etc/nixos/flake.nix
:
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
# add things here
];
};
};
}
Then run nix flake check
to make sure everything is okay:
sudo nix flake check /etc/nixos
And finally activate the new configuration with flakes:
sudo nixos-rebuild switch
--flake
flag here? Based on what I read in the documentation, I thought you had to have
it there.
nixos-rebuild
will
auomatically detect flakes in /etc/nixos
. The only major thing it
cares about is the hostname matching. If you want to customize the hostname of
the WSL VM, change the nixos
in
nixosConfigurations.nixos
above and set
networking.hostName
to the value you want to use. To use flakes
explicitly, pass --flake /etc/nixos#hostname
to your
nixos-rebuild
call.
After it thinks for a bit, you should notice that nothing happened. This is
good, we have just converted the system over to using Nix flakes instead of the
classic nix-channel
rebuild method.
To get gohello
in the system, first we need to add git
to the commands
available on the system in configuration.nix
:
environment.systemPackages = with pkgs; [ git ];
Then we can add gohello
to our system flake:
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
# XXX(Xe): this URL may change for you, such as github:Xe/gohello-http
gohello.url = "git+https://tulpa.dev/cadey/gohello-http?ref=main";
};
outputs = { self, nixpkgs, gohello, ... }: {
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
# add things here
gohello.nixosModule
({ pkgs, ... }: {
xeserv.services.gohello.enable = true;
})
];
};
};
}
gohello.nixosModule
is an inline NixOS module. If we put
gohello.nixosModule
before the ./configuration.nix
reference, we could put the xeserv.services.gohello.enable = true;
line inside ./configuration.nix
. This is an exercise for the
reader.And rebuild the system with gohello
enabled:
sudo nixos-rebuild switch
Finally, poke it with curl
:
$ curl http://gohello.local.cetacean.club
hello world :)
To update it, update the flake inputs in /etc/nixos
and run nixos-rebuild
:
sudo nix flake update /etc/nixos
sudo nixos-rebuild switch
And from here you can do whatever you want with NixOS. You can use containers, set up arbitrary services, or plan for world domination as normal.
I will use this setup in future posts to make this more accessible and easy to hack at without having to have a dedicated NixOS machine laying around.