Running X11 Applications on WSL
Running graphical Linux applications from WSL still trips up otherwise competent setups because the problem sits at the intersection of Linux display protocols, Windows networking, firewall policy, and GPU virtualisation. This guide walks through every working approach — from manual X server configuration on WSL 1 through to WSLg's integrated Wayland and X11 compositing on WSL 2 — based on configurations tested across multiple Windows builds and WSL distributions. The coverage includes display server selection, the DISPLAY environment variable, firewall exceptions, GPU passthrough, multi-monitor behaviour, and the specific troubleshooting steps for the most common failure modes. If something launches from your terminal but never renders a window, the answer is almost certainly in this page. This guide is part of the how-to section and connects to the broader Linux on Windows topic.
The short version
If you are on a recent Windows 11 build with WSL 2, graphical applications should work out of the box through WSLg — no external X server required. If they do not, check that your WSL version is current with wsl --update, verify that /tmp/.X11-unix/X0 exists inside your distribution, and confirm that DISPLAY is set to :0. If you are on WSL 1 or an older Windows 10 build, you need a third-party X server on the Windows side and manual DISPLAY configuration pointing to your Windows host IP.
Understanding the display problem
A Linux graphical application needs a display server to render its interface. On a native Linux desktop, that server is either X11 (Xorg) or Wayland, running locally. Inside WSL, there is no local display server by default — WSL was originally a terminal-only environment. The application launches, tries to connect to a display, finds nothing listening, and exits with an error like cannot open display or Error: no display specified.
The solution has always been to provide a display server. What changed over the years is where that server runs and how the connection between the Linux application and the display server is established.
Before WSLg, you installed a third-party X server on Windows (VcXsrv, Xming, X410), configured the Linux side to connect to the Windows host IP over TCP port 6000, opened firewall rules to allow the connection, and set DISPLAY to the Windows host address. This broke frequently — Windows updates changed network adapters, firewall resets closed the port, and the WSL virtual network adapter changed IP addresses between reboots.
WSLg bundles a Weston-based compositor inside the WSL 2 lightweight VM, providing both Wayland and X11 (via XWayland) support transparently. Applications connect to a Unix socket at /tmp/.X11-unix/X0 with DISPLAY=:0. No external X server, no firewall rules, no TCP networking. GPU acceleration passes through via the /dev/dxg device.
WSLg: the modern approach
WSLg shipped as part of the Windows 11 initial release and was backported to Windows 10 build 19044+ through Windows Update. It runs a system distribution (wslg) alongside your installed distributions, hosting a Weston compositor that handles both Wayland-native and X11 applications through XWayland.
Verifying WSLg is active
ls -la /tmp/.X11-unix/
You should see a socket file X0. If the directory is empty or missing, WSLg is not running. Common causes:
- WSL has not been updated: run
wsl --updatefrom PowerShell - The system distribution is corrupted: run
wsl --shutdownthen restart - Your Windows build predates WSLg support
echo $DISPLAY
The output should be :0. If it shows an IP address like 172.x.x.x:0, your shell configuration is overriding the WSLg default with an older manual setting — check .bashrc, .zshrc, or .profile for legacy DISPLAY exports and remove them.
Testing with a simple application
sudo apt install x11-apps -y
xclock &
xeyes &
If xclock renders a window on your Windows desktop, the display pipeline is working. If it does not, the troubleshooting section below covers the failure modes.
GPU acceleration under WSLg
WSLg provides GPU passthrough through the d3d12 Mesa driver, which translates OpenGL and Vulkan calls into DirectX 12 on the host. This means GPU-accelerated applications — glxgears, Blender, graphical IDEs — can use hardware rendering.
glxinfo | grep "OpenGL renderer"
The output should reference your actual GPU (e.g., D3D12 (Intel UHD Graphics 630)). If it says llvmpipe or softpipe, rendering is falling back to software — usually because the GPU driver on the Windows side is outdated. Update your Windows GPU driver, not the Linux one. The Linux side uses the d3d12 translation layer; the actual hardware driver lives on the Windows host.
Do not install Mesa drivers from your distribution's repositories expecting them to fix GPU acceleration. The WSL GPU pipeline depends on the Windows-side driver and the /dev/dxg kernel device. Installing a standard Linux GPU driver inside WSL will not help and may interfere with the existing passthrough mechanism.
The manual X server approach (WSL 1 and older WSL 2)
If you are on WSL 1, a Windows 10 build that predates WSLg, or an environment where WSLg is disabled, you need an X server running on the Windows side.
Choosing an X server
The practical options:
- VcXsrv — free, open source, most commonly recommended. Works well but has not been actively maintained. Launch with
vcxsrv.exe -multiwindow -clipboard -wgl -acfor maximum compatibility. - X410 — paid, available from the Microsoft Store. More polished, handles DPI scaling better, supports VSYNC modes. Integrates well with Windows 10/11 taskbar conventions.
- Xming — free version is old; the paid version is more current. Functional but less commonly used now.
All three do the same fundamental thing: open a listening X server on the Windows side that WSL applications can connect to.
Setting the DISPLAY variable
On WSL 1, the networking is shared with Windows — localhost works:
export DISPLAY=localhost:0.0
On WSL 2, the Linux environment runs inside a lightweight VM with its own virtual network adapter. localhost from inside WSL does not reach the Windows host. You need the Windows host IP as seen from WSL:
export DISPLAY=$(grep nameserver /etc/resolv.conf | awk '{print $2}'):0.0
This extracts the IP from /etc/resolv.conf, which WSL populates with the Windows host address. It is reliable unless you have modified /etc/resolv.conf manually — something covered in the Debian DNS resolv.conf guide.
On some Windows builds, the IP in /etc/resolv.conf does not match the address the X server is listening on, particularly when VPN software creates additional network adapters. In those cases, the most reliable approach is to extract the IP from the default route: export DISPLAY=$(ip route show default | awk '{print $3}'):0.0.
Firewall configuration
This is where most manual X server setups fail. Windows Defender Firewall blocks inbound connections to the X server by default, and the WSL 2 virtual network adapter is classified as a "Public" network — the most restrictive profile.
You need an inbound rule allowing TCP port 6000 from the WSL subnet:
New-NetFirewallRule -DisplayName "WSL X Server" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 6000 -RemoteAddress 172.16.0.0/12
The 172.16.0.0/12 range covers the default WSL virtual network. If your WSL instance uses a different subnet (check with ip addr inside WSL), adjust accordingly.
VcXsrv prompts to create a firewall rule during first launch, but it creates the rule for the wrong network profile — typically "Private" rather than "Public". Since WSL's virtual adapter is classified as Public, the rule does not apply. You need to either change the rule to cover all profiles or create a new rule specifically for the Public profile as shown above.
Audio forwarding
WSLg includes PulseAudio support, so applications that produce sound work without additional configuration. The PulseAudio socket is mounted automatically at /tmp/pulse-server.
For manual X server setups without WSLg, audio requires a separate PulseAudio server on the Windows side. This is possible but fragile — PulseAudio on Windows is not well-maintained. Most people who need audio with a manual X server setup find it simpler to upgrade to a WSLg-capable Windows build.
Multi-monitor and DPI considerations
WSLg renders applications at the DPI of the primary monitor. On multi-monitor setups where monitors have different scaling factors, applications may appear blurry or incorrectly scaled on non-primary displays. This is a known limitation of the XWayland layer. GTK and Qt applications sometimes handle this better if their per-monitor DPI awareness is configured, but most X11 applications assume a single DPI value for the entire session.
With a manual X server, DPI handling depends on the server. X410 handles per-monitor DPI better than VcXsrv. VcXsrv renders at a single DPI and scales with Windows, which produces blurry output on high-DPI displays unless you disable Windows scaling for the VcXsrv process in its compatibility properties.
Networking modes and their impact
WSL 2 has introduced multiple networking modes over time, and the choice affects display forwarding directly.
NAT mode (default)
The default mode. WSL gets an IP on a virtual subnet. The Windows host is reachable via the gateway IP. Manual DISPLAY configuration uses this gateway IP. Firewall rules are required because the traffic crosses a network boundary.
Mirrored mode
Available on Windows 11 23H2+, mirrored networking gives WSL the same IP addresses as the Windows host. localhost works from both sides. This eliminates the need for gateway IP extraction and simplifies firewall rules, but introduces other considerations — port conflicts between Windows and Linux services, for example.
To enable mirrored mode, add to .wslconfig in your Windows user profile:
[wsl2]
networkingMode=mirrored
The mirrored networking mode was introduced in late 2023. If you are reading guides written before that date, they universally assume NAT mode. The DISPLAY extraction commands using resolv.conf or default route are NAT-mode techniques. Under mirrored mode, DISPLAY=localhost:0.0 works for manual X servers, just as it did on WSL 1 — but for different architectural reasons.
Troubleshooting common failures
"Cannot open display" or "Error: no display specified"
This means the application cannot connect to any display server. Check in order:
- Is
DISPLAYset? Runecho $DISPLAY. If empty, set it. - Is a display server running? For WSLg, check
/tmp/.X11-unix/X0. For manual servers, confirm the X server process is running on Windows. - Is the connection blocked? For manual servers, test with
nc -zv <windows-ip> 6000. If the connection is refused or times out, it is a firewall issue. - Is the IP correct? For WSL 2 NAT mode, the Windows host IP changes between reboots. Hardcoded IPs in shell profiles will break.
Window appears but is blank or black
This usually indicates a rendering pipeline problem rather than a connectivity issue. The connection to the display server is working, but the application cannot render its content.
- Under WSLg, try setting
LIBGL_ALWAYS_SOFTWARE=1to force software rendering. If the window renders correctly with that variable set, the issue is GPU passthrough — update your Windows GPU driver. - Under a manual X server, ensure the server was launched with
-wgl(VcXsrv) or hardware acceleration enabled. Some applications fail when the X server does not support the GLX extension they expect.
Application launches but crashes immediately
Check dmesg inside WSL for kernel-level errors. Under WSLg, the most common cause is a library version mismatch — the application expects a newer version of a shared library than is installed. This is a distribution packaging issue, not a display issue. Run the application from the terminal rather than a launcher to see the error output directly.
Clipboard not working between Linux and Windows
WSLg handles clipboard integration through Wayland protocols. If clipboard sync stops working:
wsl --shutdown
Then restart your WSL distribution. The clipboard bridge runs in the system distribution, and restarting WSL resets it. For manual X servers, ensure the server was launched with -clipboard (VcXsrv) or clipboard mode enabled.
What about Wayland-native applications?
WSLg's compositor is Weston, which natively supports Wayland. Applications that use Wayland directly (many modern GTK 4 and Qt 6 applications) connect to the Wayland socket rather than going through XWayland. This typically produces better rendering, particularly for HiDPI and fractional scaling.
To force a GTK application to use Wayland:
GDK_BACKEND=wayland firefox
Not all applications support this. Firefox does. Electron-based applications generally do not (they require --ozone-platform=wayland flags and the support is still maturing). Most applications default to X11 under WSLg, which is fine — XWayland handles the translation transparently.
WSL version differences that matter for display
The LXSS and lxrun technical note covers the architectural history in depth, but the key differences for display forwarding are:
| Aspect | WSL 1 | WSL 2 (pre-WSLg) | WSL 2 (WSLg) |
|---|---|---|---|
| Networking | Shared with host | NAT (virtual subnet) | NAT or mirrored |
| Display server | External (Windows) | External (Windows) | Built-in (Weston) |
DISPLAY value | localhost:0.0 | <host-ip>:0.0 | :0 |
| Firewall rules | Not needed | Required for TCP | Not needed |
| GPU acceleration | Not available | Not available | Via d3d12 passthrough |
| Audio | External PulseAudio | External PulseAudio | Built-in PulseAudio |
Security considerations
Running a third-party X server with -ac (access control disabled) on the Windows side is common advice but poor practice. The -ac flag disables all authentication on the X server, meaning any process on the network — not just WSL — can connect to it and capture keystrokes, screen content, or inject input events.
For manual X server setups, the safer approach is to use xauth cookies:
xauth generate $DISPLAY . trusted
This generates an authentication token that the X server validates. Only clients with the matching cookie can connect. It is marginally more setup effort than -ac but meaningfully more secure, particularly on shared networks.
Under WSLg, security is handled through Unix socket permissions. The display socket is only accessible within the WSL VM, and there is no TCP listener to attack from the network.
Practical recommendations
For most users today, the right approach is straightforward: ensure you are on a current Windows 11 build with WSL 2, run wsl --update, and use WSLg. It works, it handles GPU acceleration, it does not require firewall rules, and the clipboard and audio integration are functional.
If you are stuck on Windows 10 or cannot use WSLg for organisational reasons, VcXsrv with the firewall and DISPLAY configuration described above is the most reliable manual approach. Budget five minutes of setup and expect to revisit the firewall rule occasionally after Windows updates.
For a deeper understanding of how the WSL subsystem evolved from the original LXSS translation layer to the current lightweight VM architecture, the LXSS and lxrun technical note provides the historical and architectural context. The rm -rf in WSL note covers an important safety consideration for anyone working with files across the WSL filesystem boundary. Microsoft's WSL documentation covers the latest configuration options and release notes for WSLg and networking modes.