NixOS WSL on Corporate Networks

[GunnarGrop] - - 7 mins read

Abstract

Last year I started exclusively using Guix System on my personal computers and fell in love with it. Since then I’ve started to grow a bit “bored” with more traditional GNU/Linux system, and whenever I have to use one I quickly start missing the declarative nature of configuring guix/nix systems.

Until very recently I’ve been stuck using openSUSE Tumbleweed via WSL2 on my work laptop (since I have no option for anything other than Windows). It’s worked well and I still think Tumbleweed is a great distro, but like I said, I was just a bit bored of it.

At first I obviosuly looked into using Guix System on WSL2, which is possible via the “WSL2” image type that guix offers. But, I deemed it a bit of a hassle, mostly because there are no pre-built images available. If you didn’t know, you can see available image types by running:

guix system image --list-image-types

Anyway, around the same time I saw that there are community built WSL2 NixOS images available via the NixOS-WSL project. Not only that, but they also provide WSL-related configuration options for NixOS. So, this was the easier starting point. I think most of my colleagues would be more interested in Nix over Guix, anyhow.

Challanges

The main challanges on my corporate network are these:

  • A corporate HTTP proxy for all outgoing traffic.
  • The proxy handles authentication via NTLM.
  • The proxy serves a TLS certificate signed by an in-house CA.

Installation

The Proxy

First of all, setting HTTP_PROXY and HTTPS_PROXY in Linux, as per usual, doesn’t work very well with NTLM.

To get around this I installed a proxy on the Windows host that handle authentication with the upstream proxy, then I just use that one via HTTP_PROXY and HTTPS_PROXY in Linux.

My proxy of choice is Px, because it’s very easy to setup. We just need to download it and change one line in the config file (px.ini).

[proxy]

; NTLM server(s) to connect through. IP:port, hostname:port
;   Multiple proxies can be specified comma separated. Px will iterate through
;   and use the one that works
server = http://proxy.example.com:8080

...

Then start it with:

.\px.exe

Now Px should be running and is listening on the default host and port.

http://127.0.0.1:3128

Install NixOS

  1. Download the latest release image of NixOS-WSL.
  2. Install the image with:
    wsl --install --from-file nixos.wsl
    
  3. Start NixOS with:
    wsl -d NixOS
    

Now that NixOS is started we can finally start configuring it.

We’ll start by (temporarily) telling NixOS to use our proxy (documentation).

# Set HTTP proxy to the Px proxy we installed earlier
proxy_url="http://localhost:3128/"
export http_proxy="$proxy_url"
export HTTP_PROXY="$proxy_url"
export https_proxy="$proxy_url"
export HTTPS_PROXY="$proxy_url"

Before continuing, you’ll need to check if your upstream corporate HTTP proxy serves a custom TLS certificate. This can easily be done by just checking if you get any SSL/TLS issues when requesting a regular website.

curl https://duckduckgo.com

If you get any errors with the previous command, you’ll have to fetch a copy of whatever public CA certificate is used to trust your proxy’s TLS certificate.

From here I’ll assume you have all CA certificates you need in a file called ca.pem.

Now we need to update NixOS.

# Let's temporarily trust our CA certificate
# https://nix.dev/manual/nix/2.28/installation/env-variables.html?highlight=certi#nix_ssl_cert_file
export NIX_SSL_CERT_FILE=/path/to/ca.pem

# Update NixOS
# We'll use 'sudo -E' to preserve the environment variables we just set
sudo -E nix-channel -v --update

Note: If your upstream proxy has any kind of malware scanning (like mine does), the update can potentially take a very long time. For me it took about ~60 minutes.

Configure NixOS

Now it’s time to configure NixOS for real. I’ll provide you with a simple NixOS and home-manager configuration that you can build upon later.

I’ve based these configs on the excellent minimal nix-starter-config provided by Misterio77 on GitHub.

The structure:

.
├── flake.nix              # The "init" file
├── home-manager
│   └── home.nix           # Home configuration
└── nixos
    └── configuration.nix  # System configuration

I’ll assume the hostname is nixos and the user account is nixos, which are both default in NixOS-WSL.

flake.nix:

{
  description = "NixOS config for WSL2";

  inputs = {
    # Nixpkgs
    nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";

    # NixOS WSL
    nixos-wsl.url = "github:nix-community/NixOS-WSL/main";

    # Home manager
    home-manager.url = "github:nix-community/home-manager/release-25.11";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = {
    self,
      nixpkgs,
      nixos-wsl,
      home-manager,
      ...
  } @ inputs: let
  in {
    # NixOS configuration entrypoint
    # Available through 'nixos-rebuild --flake .#nixos'
    nixosConfigurations = {
      nixos = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        specialArgs = {inherit inputs;};
        modules = [
          ./nixos/configuration.nix
          nixos-wsl.nixosModules.default
          {
            system.stateVersion = "25.11";
            wsl.enable = true;
          }
        ];
      };
    };

    # Standalone home-manager configuration entrypoint
    # Available through 'home-manager --flake .#nixos@nixos'
    homeConfigurations = {
      "nixos@nixos" = home-manager.lib.homeManagerConfiguration {
        # Home-manager requires 'pkgs' instance
        pkgs = nixpkgs.legacyPackages.x86_64-linux; # FIXME replace x86_64-linux with your architecture
        extraSpecialArgs = {inherit inputs;};
        modules = [./home-manager/home.nix];
      };
    };
  };
}

home.nix:

# This is your home-manager configuration file
# Use this to configure your home environment (it replaces ~/.config/nixpkgs/home.nix)
{
  inputs,
  lib,
  config,
  pkgs,
  ...
}: {
  nixpkgs = {
    config = {
      # Disable if you don't want unfree packages
      allowUnfree = true;
    };
  };

  home = {
    username = "nixos";
    homeDirectory = "/home/nixos";
  };

  programs.home-manager.enable = true;

  # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
  home.stateVersion = "25.11";
}

configuration.nix:

# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).

# NixOS-WSL specific options are documented on the NixOS-WSL repository:
# https://github.com/nix-community/NixOS-WSL

{ config, lib, pkgs, ... }:

{
  wsl.enable = true;
  wsl.defaultUser = "nixos";
  wsl.startMenuLaunchers = true;

  nix.settings.experimental-features = [ "nix-command" "flakes" ];

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It's perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "25.11"; # Did you read the comment?

  networking.proxy.default = "http://127.0.0.1:3128";
  # FIXME replace with your actual no_proxy settings
  networking.proxy.noProxy = "localhost,127.0.0.1,mycompany.com";

  security.pki.certificates = [
    # FIXME replace with your actual company CA certificate
    # The certificate(s) for your corporate proxy
    ''
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
    ''
  ];
}

Now that we have the configuration files we can configure evertyhing. I’ll assume your configuration files are in a directory called /home/nixos/.dotfiles, with the exact directory structure I showed above.

# We'll enable experimental nix features (only needs doing once)
export NIX_CONFIG="experimental-features = nix-command flakes"

# Configure the system
sudo -E nixos-rebuild switch --flake /home/nixos/.dotfiles#nixos

# Bootstrap home-manager (only needs doing once)
nix shell nixpkgs#home-manager

# Configure home
home-manager switch --flake /home/nixos/.dotfiles#nixos@nixos

Alright, now it’s all done! Assuming you correctly setup the proxy config and TLS config in configuration.nix, you should now have a working NixOS container in WSL. In the future you can just build upon configuration.nix and home.nix for further configuration. You should also preferably put everything in a version controlled git repository, for safe-keeping.

Conclusion

As you can see, and depending on your companys networking, it’s not just plug-and-play with NixOS for WSL. But, it’s not exactly rocket science either.

I’ve been using NixOS on WSL based on this setup for a while now, and I love using it.

Of course, I would still want to try out Guix System for WSL as well, but it looks like it’s a fair amount of extra work to get it working. Mostly because I’ll have to write a working config (proxy/TLS and all that) and then build an image based on it before I can even install it in WSL. But that will probably be a future blog post. 🙂

Enjoy NixOS!