Skip to content
WSLDeep Dive Published Updated 7 min readViews unavailable

Loading Linux Kernel Modules in WSL 2: Runtime Checks and Startup Configuration

Use WSL 2's documented module-loading settings carefully, distinguish module names from a modules VHD, and verify the shared guest kernel.

WSL 2 does not boot a separate Linux kernel for every distribution. Its distributions use a shared utility VM and Linux kernel, so a module-loading change can affect more than the shell where it was configured. Current Microsoft documentation exposes two distinct global settings for module handling: loadDefaultKernelModules controls WSL’s startup loading of the default module set, and loadKernelModules is a comma-separated list of additional modules to load when the WSL 2 VM starts. The documented default set is tun, ip_tables, and br_netfilter.

Those names should not be confused with .wslconfig’s kernelModules path, which points to a custom Linux kernel modules virtual hard disk. One option is a module-name list; the other is a file path supplying a modules VHD. Neither setting can load a module that the active kernel does not contain or that is incompatible with the exact kernel build.

Establish whether the feature is needed

Before changing module configuration, capture the WSL package and guest kernel:

wsl.exe --version
wsl.exe --status
wsl.exe --list --verbose
wsl.exe --distribution Ubuntu --exec uname -r

Then inspect a module from Linux:

grep -E '^(tun|ip_tables|br_netfilter|overlay) ' /proc/modules || true
if command -v modinfo >/dev/null 2>&1; then
  modinfo tun 2>&1 | sed -n '1,12p'
fi
if command -v modprobe >/dev/null 2>&1; then
  modprobe --dry-run --verbose tun
fi

/proc/modules lists currently loaded modules; a module built directly into the kernel will not appear there. modinfo reads available module metadata, and modprobe --dry-run plans an action without loading it. These checks do not guarantee that an application can use a device or that a module’s feature is supported by WSL. Inspect the precise kernel configuration and module tree for the WSL kernel version in use.

The intended module may already be available. For example, container networking, a VPN, and a packet-processing tool can have dependencies on kernel features, but they may use built-in code, different modules, or different configuration paths. Diagnose the application’s error and kernel logs before extending the startup list. Do not add modules simply because a Linux distribution’s bare-metal guide includes them.

Understand the two configuration interfaces

The current .wslconfig reference lists loadDefaultKernelModules=true as the default, loading tun, ip_tables, and br_netfilter when the WSL 2 VM starts. It lists loadKernelModules as an optional comma-separated list of additional modules. Those additional modules load alongside the defaults unless loadDefaultKernelModules is set to false.

Both settings belong in the Windows user’s global .wslconfig under [wsl2]:

[wsl2]
loadDefaultKernelModules=true
loadKernelModules=overlay

overlay is an example only; first verify that it exists for the running kernel and is not already built in. Do not copy the example blindly. If a required module is missing, determine whether it is built in, present in the matching WSL modules tree, or requires a supported custom kernel/modules image. The module loader’s successful return is not a substitute for checking modinfo, kernel logs, and the consuming application’s own test.

The separate kernelModules setting is a Windows absolute path to a modules VHD, typically paired with a custom kernel. Microsoft documents path values as Windows paths with escaped backslashes. A modules VHD is not the comma-separated loadKernelModules list and cannot be substituted by typing a filesystem path into that list.

Module availability is tied to the exact kernel

Linux modules are built against a particular kernel configuration and release. A module file from a generic Ubuntu kernel is not automatically compatible with Microsoft’s WSL kernel. Check uname -r, the module’s vermagic, and the exact WSL kernel/modules artifact. A module that exists for a different kernel release may be rejected or fail to load. Do not force-load it to bypass a compatibility mismatch.

Some features are compiled into the kernel and need no module loading. Others require a module package or a custom kernel build. The WSL Linux kernel project publishes Microsoft’s WSL kernel source and build information; use its current instructions if a required feature is absent. A custom kernel changes a global component for all WSL 2 distributions and increases the maintenance burden. Keep a known-good fallback and test rollback before using a custom kernel on a workstation that depends on WSL.

Do not assume installing a distro’s linux-modules-extra package supplies modules for the Microsoft WSL kernel. Distribution packages are usually built for that distribution’s own kernel package and release. If modinfo reports a vermagic that differs from uname -r, or the module is absent from the matching module tree, stop before attempting to load it. The supported decision is then to use the available WSL kernel feature set or maintain a compatible custom kernel and module artifact using the WSL project’s current instructions.

The shared-kernel model also affects the test plan. Starting two WSL 2 distros does not create two independent module inventories. A module loaded for a WSL VM can be visible to processes in multiple distributions, subject to their namespaces and permissions. Do not use module presence as evidence that a per-distro container, device node, or policy is configured identically.

Apply a change with a controlled restart

.wslconfig settings apply globally to WSL 2, so inspect and preserve existing memory, processor, swap, networking, kernel, and disk options. Edit the existing [wsl2] section instead of replacing the whole file. Stop the WSL VM so the startup module list is re-read:

wsl.exe --shutdown
wsl.exe --distribution Ubuntu --exec sh -lc 'uname -r; grep -E "^(tun|ip_tables|br_netfilter|overlay) " /proc/modules || true'

wsl.exe --shutdown terminates all running WSL distributions and the utility VM; save work and coordinate services first. A distro-only termination may not restart the shared VM if other distros are still active. Confirm that the next invocation actually boots the VM before concluding that startup settings were applied.

After restart, inspect dmesg or the journal for module-loading errors and run the exact application operation that required the module. If module autoloading is expected, verify the module’s loaded state after the application attempts to use it; some modules load only on demand. Capture both pre- and post-change output with WSL version, kernel release, effective .wslconfig, and application version.

Avoid common misdiagnoses

If modinfo cannot find a module, adding its name to loadKernelModules does not install it. If the module is already built into the kernel, its absence from /proc/modules is not proof of failure. If it loads but the feature is still absent, inspect device access, namespace boundaries, configuration, and userspace packages. If a container cannot use a feature while the host distro can, test inside the container and inspect its runtime configuration instead of adding the module again.

Capture dmesg around the load attempt. A missing symbol, invalid module format, or missing dependency points to a different problem than a successful insert followed by a userspace error. A module can also load on demand after an application opens a device or protocol socket. Compare module state before and after the operation rather than expecting every useful module to be present immediately after a shell opens.

Setting loadDefaultKernelModules=false disables WSL’s documented default module loading. Use it only when you have confirmed that none of the expected default modules is needed by the workloads, or when an intentional custom kernel/modules plan replaces them. A missing tun or packet filtering module can change VPN, container, or network behavior. Test those workloads before applying the setting across a development fleet.

Do not use insmod with an arbitrary .ko file as a deployment workflow. It bypasses module dependency resolution and still cannot fix an ABI mismatch. For transient diagnosis, use the distribution’s supported module tools, inspect the returned error and kernel log, then move the requirement into an explicitly maintained WSL configuration or supported kernel build process.

Acceptance criteria and maintenance

Define the acceptance condition before editing: the module is present in the exact kernel’s module tree or built in, the configured startup behavior is reflected after a full VM restart, and the application feature succeeds in the intended distro and container. Re-run the test after wsl --update, a Windows feature update, a custom-kernel change, or a module VHD replacement. Record which distribution initiated the test and whether other WSL 2 distributions were running.

The startup list should remain as small as the requirements permit. Extra modules enlarge the set of kernel code active in the shared VM and can complicate diagnosis when multiple tools use the same subsystem. Keep module names, source, kernel version, and test evidence in the WSL operations runbook. If no supported matching module exists, report that limitation rather than implying that .wslconfig can manufacture kernel functionality.

Related:

Sources:

Comments