Power-user WSL setup from scratch
If you use Windows but want a serious Linux command-line environment, WSL is the best compromise I know. It gives you fast access to Linux tools without forcing you into a VM, without the friction of dual boot, and without turning your machine into a desktop science project.
This guide is for the setup I actually recommend to power users: a clean Ubuntu-based WSL install with a strong terminal workflow, sane filesystem habits, Git and SSH ready to go, Python tooling, optional Node, and GUI apps used the right way through WSLg.
This is not a guide for forcing a full Linux desktop into WSL. That path is possible, but it is usually brittle and not worth the complexity. WSL shines when you use it as a powerful Linux layer on top of Windows, not as a replacement for Windows itself.
What this setup is trying to achieve
The goals are simple:
| Goal | Why it matters |
|---|---|
| Fast Linux shell | Real Linux tools without leaving Windows |
| Clean, reproducible base | Easy to rebuild if something gets messy |
| Strong terminal UX | Better navigation, search, history, and editing |
| Good project layout | Fewer permission and performance headaches |
| Python and Git ready | Useful from day one |
| GUI apps only where they make sense | Avoid full desktop instability |
| Minimal environment hacks | Fewer weird breakages later |
The mindset that keeps WSL clean
The biggest WSL problems usually come from using it like a full Linux machine when it is better understood as a Linux subsystem with first-class tooling support.
A few rules prevent most pain:
- Use WSL2, not WSL1.
- Use Linux filesystems for code and tooling.
- Use Windows filesystems for shared documents and downloads.
- Use WSLg for individual GUI apps, not full desktop sessions.
- Do not hand-edit
DISPLAY,WAYLAND_DISPLAY, or related graphics variables unless you have a very specific reason. - Do not mix WSLg, XRDP, and desktop-environment session hacks unless you want a debugging hobby.
Start from a clean install
Open an elevated PowerShell window and install Ubuntu:
wsl --install -d Ubuntu
If WSL is already installed but you want a fresh distro:
wsl -l -v
wsl --unregister Ubuntu
wsl --install -d Ubuntu
After installation, Ubuntu will ask you to create a username and password. Use your normal non-root account for daily work. Do not live as root.
Once you are inside Ubuntu, bring the system up to date:
sudo apt update
sudo apt upgrade -y
At this point, you have a clean base. Everything after this is about making it efficient and comfortable.
Core packages: the first useful layer
Install a practical set of tools:
sudo apt install -y \
build-essential \
git curl wget unzip zip \
ca-certificates gnupg software-properties-common \
htop btop tree jq \
ripgrep fd-find fzf \
neovim vim tmux \
python3 python3-pip python3-venv pipx \
zsh \
x11-apps
Here is why these matter:
| Package | Purpose |
|---|---|
build-essential |
Compilers and basic build tools |
git |
Version control |
curl, wget |
Downloading and scripting |
htop, btop |
System monitoring |
tree |
Directory visualization |
jq |
JSON parsing |
ripgrep |
Fast code and text search |
fd-find |
Better file finding |
fzf |
Fuzzy finding |
neovim |
Terminal editor |
tmux |
Persistent terminal sessions |
python3-* |
Python runtime and virtual environments |
pipx |
Isolated Python CLI installs |
zsh |
Alternative shell if you want it |
x11-apps |
Basic GUI test tools |
Set up pipx on your path:
pipx ensurepath
Then restart your shell, or source the appropriate profile file.
Create a sane working directory layout
Keep your projects in Linux space, not under /mnt/c.
Create a few directories:
mkdir -p ~/projects
mkdir -p ~/bin
mkdir -p ~/.local/bin
A good pattern is:
| Path | Use |
|---|---|
~/projects |
Source code, scripts, repos |
~/bin |
Personal helper scripts |
/mnt/c/Users/<you>/Downloads |
Files coming from Windows |
/mnt/c/Users/<you>/Documents |
Shared human documents |
~/.config |
App config |
~/.ssh |
SSH keys |
Why this matters: projects built on the Linux filesystem are usually faster and less error-prone than projects developed directly on mounted Windows paths.
Configure WSL itself
Edit /etc/wsl.conf:
sudo nano /etc/wsl.conf
Use:
[automount]
options = "metadata"
[network]
generateHosts = true
generateResolvConf = true
[interop]
enabled = true
appendWindowsPath = true
Then shut WSL down from PowerShell so the changes take effect:
wsl --shutdown
The metadata option improves permission handling on mounted Windows drives. It does not make /mnt/c the ideal place for builds, but it does make cross-boundary work less awkward.
Basic shell quality-of-life improvements
Even a few aliases and defaults make the shell much more pleasant.
If you are staying on Bash, add this to ~/.bashrc:
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias gs='git status'
alias gd='git diff'
alias gl='git log --oneline --graph --decorate'
alias ..='cd ..'
alias ...='cd ../..'
alias grep='grep --color=auto'
alias cls='clear'
export EDITOR=nvim
export VISUAL=nvim
if command -v fdfind >/dev/null 2>&1; then
alias fd='fdfind'
fi
If you want Zsh instead:
chsh -s /usr/bin/zsh
Then start a new shell. If you want Oh My Zsh, install it with the standard script from the project, but keep the plugin list small. A restrained shell setup is usually better than a flashy one that adds latency and fragility.
A practical plugin set is:
plugins=(git sudo history)
Git: make it ready immediately
Set your Git identity:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Useful defaults:
git config --global init.defaultBranch main
git config --global pull.rebase false
git config --global core.editor nvim
git config --global color.ui auto
Optional but nice:
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit
git config --global alias.lg "log --oneline --graph --decorate --all"
If you frequently work across Windows and Linux editors, consider normalizing line endings carefully. For many WSL users, this is a safe default:
git config --global core.autocrlf input
That preserves LF on commit without trying to “help” too aggressively.
SSH: get keys in place early
Generate a key:
ssh-keygen -t ed25519 -C "you@example.com"
Then:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub
Add that public key to GitHub, GitLab, your server, or wherever else you need it.
A simple ~/.ssh/config is worth having:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Set safe permissions:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/config 2>/dev/null || true
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
Python: the clean power-user setup
Ubuntu’s system Python is fine, but do not treat it like a global junk drawer. Use virtual environments for projects and pipx for CLI tools.
Good global CLI installs through pipx:
pipx install uv
pipx install ruff
pipx install black
pipx install httpie
That gives you a very strong baseline:
| Tool | Why use it |
|---|---|
uv |
Fast Python package and environment management |
ruff |
Extremely fast linting and formatting support |
black |
Consistent formatting |
httpie |
Better command-line HTTP client |
For project work:
mkdir -p ~/projects/demo-python
cd ~/projects/demo-python
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
Or, if you prefer uv, build around that instead of manually managing venv and pip.
The key idea is simple: keep project dependencies inside the project, and keep your global environment boring.
Node.js: optional, but common
If you work with modern web tooling, install Node with nvm rather than Ubuntu packages:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
Restart your shell, then:
nvm install --lts
node --version
npm --version
This keeps Node isolated and easy to change later.
Neovim or Vim: pick one and commit
You do not need a huge editor configuration to be productive. You need one editor you can trust from anywhere.
A minimal ~/.vimrc or ~/.config/nvim/init.vim can already carry a lot of weight:
set number
set relativenumber
set expandtab
set shiftwidth=4
set tabstop=4
set smartindent
set ignorecase
set smartcase
set incsearch
set hlsearch
set clipboard=unnamedplus
That last line may depend on clipboard integration and environment details, but the rest is a good minimal core.
tmux: the productivity multiplier
A simple tmux setup turns WSL into something much more resilient.
Create ~/.tmux.conf:
set -g mouse on
set -g history-limit 100000
setw -g mode-keys vi
set -g default-terminal "screen-256color"
Then start a session:
tmux new -s main
Now you can split panes, keep long-running processes alive, and recover from terminal accidents without losing your place.
GUI apps in WSL: use WSLg the right way
On current Windows 11 systems, WSLg is the intended GUI path. That means individual Linux GUI applications can open directly on your Windows desktop.
Install a few useful apps:
sudo apt install -y \
xfce4-terminal \
thunar \
file-roller \
mousepad \
gedit
Then just run them:
thunar
xfce4-terminal
mousepad
This is the sweet spot. You get Linux GUI tools without needing a full desktop environment. Resist the temptation to install a complete desktop session unless you truly need one and are willing to own the complexity.
What not to do with graphics
There are a few traps that repeatedly waste time:
- Do not set
DISPLAYmanually unless you know exactly why. - Do not mix old X-server advice with modern WSLg assumptions.
- Do not expect
startxfce4,startplasma-x11, or a full GNOME session to behave like a real Linux login. - Do not install three competing graphics/session approaches and then wonder which one is breaking things.
The clean WSL approach is: use the shell for most work, and launch GUI apps individually when needed.
Windows Terminal: make the front end worthy of the back end
WSL becomes dramatically better when paired with Windows Terminal.
Good settings to consider:
| Setting | Why |
|---|---|
| Use a Nerd Font or good monospaced font | Better symbols and readability |
| Set Ubuntu as default profile | Faster launch into useful work |
| Increase scrollback | Better command history review |
| Use acrylic sparingly or not at all | Looks nice, but clarity matters more |
| Enable copy-on-select only if it fits your habits | Prevent accidental copies |
If you use multiple environments, create separate Windows Terminal profiles for different WSL distros or startup directories.
Interop: make Windows and Linux cooperate
WSL can call Windows programs, and Windows can access Linux files. That can be extremely useful if kept under control.
Examples:
Open the current Linux directory in Explorer:
explorer.exe .
Open a file in Windows from WSL:
notepad.exe README.md
Open VS Code in the current directory:
code .
From Windows, your Linux files are available under the special network path for WSL. That interoperability is powerful, but remember the general rule: build and run Linux projects in Linux space.
Backup and rebuild philosophy
A strong WSL setup is not one you can never break. It is one you can rebuild without drama.
That means:
- Prefer a small number of meaningful tools.
- Keep dotfiles in Git if you customize heavily.
- Avoid random environment hacks copied from forum posts.
- Document non-obvious changes.
- Be willing to blow away and rebuild the distro if it gets ugly.
In practice, this mindset makes WSL much less stressful.
A practical bootstrap sequence
If I were rebuilding from scratch, the sequence would look like this:
1. Install Ubuntu
wsl --install -d Ubuntu
2. Update packages
sudo apt update
sudo apt upgrade -y
3. Install core tools
sudo apt install -y \
build-essential git curl wget unzip zip \
htop btop tree jq \
ripgrep fd-find fzf \
neovim tmux \
python3 python3-pip python3-venv pipx \
zsh \
xfce4-terminal thunar file-roller mousepad
4. Configure WSL
sudo tee /etc/wsl.conf > /dev/null <<'EOF'
[automount]
options = "metadata"
[network]
generateHosts = true
generateResolvConf = true
[interop]
enabled = true
appendWindowsPath = true
EOF
5. Set up directories
mkdir -p ~/projects ~/bin ~/.local/bin
6. Set up Git
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global core.editor nvim
git config --global core.autocrlf input
7. Set up Python CLI tools
pipx ensurepath
pipx install uv
pipx install ruff
pipx install black
pipx install httpie
8. Shut WSL down from PowerShell
wsl --shutdown
That sequence gets you to a very capable system quickly without overengineering anything.
A sample .bashrc section worth keeping
Here is a compact shell block that earns its keep:
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias gs='git status'
alias gd='git diff'
alias gl='git log --oneline --graph --decorate'
alias v='nvim'
alias ..='cd ..'
alias ...='cd ../..'
export EDITOR=nvim
export VISUAL=nvim
if command -v fdfind >/dev/null 2>&1; then
alias fd='fdfind'
fi
if command -v dircolors >/dev/null 2>&1; then
eval "$(dircolors -b)"
alias ls='ls --color=auto'
fi
It improves daily usability without turning your shell config into a museum of cleverness.
Common mistakes that make WSL feel worse than it is
| Mistake | Better approach |
|---|---|
Doing development in /mnt/c |
Keep repos in ~/projects |
Running as root for normal work |
Use your regular user and sudo when needed |
| Forcing a full desktop environment | Use WSLg for individual apps |
| Hand-editing graphics environment variables | Let WSLg manage them |
| Installing too many overlapping tools | Keep the stack intentional |
| Treating WSL as sacred and unrebuildable | Make it easy to recreate |
Who this setup is for
This setup is good for:
- developers who live in terminals
- Windows users who want Linux tooling without abandoning Windows
- Python and scripting workflows
- Git-heavy work
- web development with Node as needed
- people who want a durable daily-driver environment
It is not ideal for:
- users who want a full Linux desktop as the primary experience
- heavy GPU-native Linux desktop workflows
- people who want WSL to behave exactly like a bare-metal Linux install
Those are different use cases and deserve different tools.
Final recommendation
If your goal is a power-user workstation on Windows, the best WSL setup is usually the least theatrical one.
Install Ubuntu. Keep your code in Linux space. Add a strong terminal stack. Use Git and SSH properly. Use Python virtual environments and pipx. Launch Linux GUI apps individually through WSLg when they are actually useful. Avoid the urge to turn WSL into an ersatz desktop distro.
That path is stable, fast, and rebuildable. More importantly, it leaves your energy available for real work instead of continuous environment repair.