Arch Linux Remote Desktop via WSL2
Full XFCE desktop through WSL2 without router changes — GitHub ★5
Overview
This project is a complete guide and automation script set for running a full Arch Linux with XFCE4 graphical desktop inside WSL2 on Windows 11, accessible remotely via RDP from any device — without modifying router settings or opening any firewall ports. This is the key differentiator: instead of port-forwarding RDP (port 3389) through the router (which is often impossible on restricted networks, dorms, or corporate environments), the RDP traffic is tunneled outward through Cloudflare Tunnel.
The architecture works by running xrdp inside the WSL2 Arch Linux environment
on the standard RDP port, then running a cloudflared tunnel daemon that creates
an encrypted outbound connection to Cloudflare's edge network. Remote clients connect to the
Cloudflare-assigned hostname using any standard RDP client, and the traffic is routed through
the tunnel to xrdp. No inbound ports, no static IP required, no router access needed.
The project earned 5 GitHub stars from users who found the router-free approach useful.
Architecture
Tech Stack
- Arch Linux — rolling-release Linux distribution running inside WSL2
- WSL2 — Windows Subsystem for Linux 2, Hyper-V-based VM layer in Windows 11
- XFCE4 — lightweight GTK desktop environment for the graphical session
- xrdp + xorgxrdp — open-source RDP server for Linux, compiled from AUR
- Cloudflare Tunnel (cloudflared) — outbound tunnel daemon, eliminates need for port forwarding
- Windows 11 — host OS with WSL2 and Hyper-V enabled
- pacman / yay — Arch package manager and AUR helper
Build Process
Install Arch Linux in WSL2
WSL2 does not ship with Arch Linux by default, so it is installed from a bootstrap
tarball. The Arch Linux WSL bootstrap tarball is imported using
wsl --import. Alternatively, the ArchWSL package from the Microsoft
Store can be used. After import, the distribution is set as default and a non-root
user is created.
# In PowerShell (as Administrator):
# Enable WSL2 (if not already)
wsl --install
wsl --set-default-version 2
# Download Arch Linux bootstrap tarball
# from https://archlinux.org/download/
# Then import it:
wsl --import Arch C:\WSL\Arch .\archlinux-bootstrap-x86_64.tar.zst
# Launch Arch and do initial setup
wsl -d Arch
# Inside Arch:
pacman-key --init
pacman-key --populate archlinux
pacman -Syu --noconfirm
# Create user
useradd -m -G wheel -s /bin/bash yourusername
passwd yourusername
echo "%wheel ALL=(ALL) ALL" >> /etc/sudoers
Install XFCE4 Desktop Environment
XFCE4 and its additional utilities are installed via pacman. The
xfce4-goodies meta-package includes terminal, file manager,
panel plugins, and screensaver. Fonts and the GTK theme are also installed
for a complete desktop experience over RDP.
pacman -S xfce4 xfce4-goodies \
xorg-server xorg-xinit \
ttf-dejavu ttf-liberation \
gtk3 adwaita-icon-theme \
dbus --noconfirm
# Verify XFCE components are installed
pacman -Qs xfce4 | grep "local/"
Install xrdp and xorgxrdp from AUR
xrdp is the RDP server and xorgxrdp provides the
Xorg video driver module that xrdp uses for hardware-accelerated rendering.
Both are available in the AUR (Arch User Repository) and must be compiled from
source. The yay AUR helper is installed first.
# Install yay AUR helper (run as non-root user)
pacman -S git base-devel --noconfirm
git clone https://aur.archlinux.org/yay.git /tmp/yay
cd /tmp/yay && makepkg -si --noconfirm
# Install xrdp and xorgxrdp from AUR
yay -S xrdp xorgxrdp --noconfirm
# These packages compile from source - takes 10-20 minutes
# Verify installation
xrdp --version
Configure .xsession for XFCE4
When xrdp starts a session, it reads ~/.xsession to know which
desktop environment to launch. Without this file, xrdp launches a blank session
or fails with a black screen. The file must be executable and contain the correct
start command.
# Create the .xsession file for your user
echo "startxfce4" > ~/.xsession
chmod +x ~/.xsession
# Also create a system-wide fallback
sudo bash -c 'echo "startxfce4" > /etc/xrdp/startwm.sh'
sudo chmod +x /etc/xrdp/startwm.sh
# Verify the file content and permissions
cat ~/.xsession
ls -la ~/.xsession
Enable systemd and Start xrdp
WSL2 does not run systemd by default. It must be enabled in
/etc/wsl.conf so that systemctl works. After enabling
systemd and restarting the WSL2 instance, xrdp is enabled and started as a
systemd service.
# /etc/wsl.conf
[boot]
systemd=true
# Save the file, then restart WSL2 from PowerShell:
# wsl --shutdown
# wsl -d Arch
# Back inside Arch, start xrdp
sudo systemctl enable xrdp xrdp-sesman
sudo systemctl start xrdp xrdp-sesman
sudo systemctl status xrdp
# Confirm xrdp is listening on port 3389
ss -tlnp | grep 3389
Install cloudflared and Create Tunnel
The cloudflared daemon is installed and authenticated with a
Cloudflare account. A named tunnel is created for the RDP service. The tunnel
config routes TCP traffic on the tunnel URL to localhost:3389 inside
the WSL2 VM. The tunnel is started as a systemd service so it reconnects after
WSL2 restarts.
# Install cloudflared (AUR)
yay -S cloudflared --noconfirm
# Authenticate with Cloudflare (opens browser)
cloudflared tunnel login
# Create a named tunnel
cloudflared tunnel create rdp-tunnel
# Create tunnel config
mkdir -p ~/.cloudflared
cat > ~/.cloudflared/config.yml << 'EOF'
tunnel: rdp-tunnel
credentials-file: /home/yourusername/.cloudflared/.json
ingress:
- service: rdp://localhost:3389
EOF
# Start the tunnel
cloudflared tunnel run rdp-tunnel
# Or run as systemd service
cloudflared service install
systemctl enable cloudflared
systemctl start cloudflared
# Get the tunnel hostname (e.g. rdp-tunnel.tyfsadik.org)
cloudflared tunnel info rdp-tunnel
Connect RDP Client to Tunnel URL
Any RDP client can connect to the Cloudflare tunnel URL. On Windows, the built-in Remote Desktop Connection app is used. On macOS, the Microsoft Remote Desktop app from the App Store works. The tunnel URL is used as the hostname; no port number or VPN is needed.
# On the remote machine (Windows):
# Open Remote Desktop Connection (mstsc)
# Computer: rdp-tunnel.tyfsadik.org
# Username: yourusername
# Connect and enter your Linux password
# On macOS:
# Open Microsoft Remote Desktop app
# Add PC > PC name: rdp-tunnel.tyfsadik.org
# On Linux (using rdesktop or freerdp):
xfreerdp /v:rdp-tunnel.tyfsadik.org /u:yourusername /p:yourpassword /dynamic-resolution
Request Flow
Challenges & Solutions
-
xrdp black screen on connect: The most common issue with xrdp on Linux is
connecting successfully but seeing only a black screen. This is caused by the
~/.xsessionfile being absent, empty, or not executable. Resolved by creating the file withecho "startxfce4" > ~/.xsession && chmod +x ~/.xsessionand ensuring the file belongs to the correct user account. -
systemd not available in WSL2 by default: Before enabling systemd,
systemctlcommands returned errors and xrdp could not be managed as a service. Resolved by adding[boot] systemd=trueto/etc/wsl.confand runningwsl --shutdownfrom PowerShell to restart the WSL2 instance with systemd as PID 1. -
xorgxrdp AUR compilation failures: Building xorgxrdp from the AUR required
specific Xorg development headers that were not pulled in automatically. Resolved by
installing
xorg-server-develandxorgprotobefore running the AUR build, and ensuringbase-develwas fully installed. -
Cloudflare Tunnel not reconnecting after WSL2 restart: The cloudflared
process terminated when WSL2 was shut down and did not restart automatically. Resolved by
running
cloudflared service installto register it as a systemd service, which then starts automatically when WSL2 boots with systemd enabled.
What I Learned
- WSL2 internals: Hyper-V-based VM, network bridge, and the role of
wsl.conf - xrdp session lifecycle:
xsessionfile, display allocation, and xorgxrdp module loading - Cloudflare Tunnel architecture: outbound-only tunnels, credential files, and ingress routing
- AUR package compilation: makepkg, PKGBUILD review, and dependency resolution
- systemd in WSL2: enabling it, service unit management, and boot sequence changes
- Remote desktop protocol fundamentals: session negotiation, display encoding, and input forwarding