Windows 10 WSL 2 终极配置指南:从零到生产力环境

对于长期在 Windows 上开发的程序员来说,环境配置总是个头疼的问题:工具链与 Linux 服务器不一致、Docker 运行效率低下、终端体验原始… 而 Windows Subsystem for Linux (WSL) 正是微软给出的最佳答案。它让我们能在 Windows 10/11 上原生运行 Linux 环境,是开发者提升效率的利器。

然而,一个默认的 WSL 环境远非完美。网络代理如何设置?终端如何美化?繁琐的 sudo 密码能否简化?

本篇将从零开始,一步步带你完成 WSL 2 (以 Ubuntu 22.04 为例) 的安装、基础配置和一系列高级定制,最终目标是打造一个强大、美观且顺手的终极开发环境。

安装WSL

移除WSL

# 查看已安装的WSL
wsl -l -v
# 移除WSL
wsl --unregister Ubuntu-22.04

安装WSL ubuntu22.04

wsl --install -d Ubuntu-22.04

配置WSL

正常已经是可以免密直接登录的,只有在sudo时需要输入密码。

配置oh my zsh1

# 安装oh my zsh
sudo apt install zsh
# 配置oh my zsh
sh -c "$(curl -fsSL https://gitee.com/pocmon/ohmyzsh/raw/master/tools/install.sh)"
#载入配置
source ~/.zshrc

可以在win10中用ConEmu打开wsl,我不喜欢cmd命令行。

换源

更换为浙江大学的镜像源

# 查看系统信息
cat /etc/os-release
sudo sed -i 's@//.*archive.ubuntu.com@//mirrors.zju.edu.cn@g' /etc/apt/sources.list

配置git2

  • 安装git
sudo apt-get git
  • 配置git
git config --global user.name "XXXX"
git config --global user.email XXX@XX.com
  • git 的 ssh 设置[^ssh]
ssh-keygen -t ed25519 -C "xxxx@xxx.com"
  • 编辑 ssh 配置
# .ssh/config
# GitHub.com
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa
  • 测试 ssh
ssh -T git@github.com

配置代理

如果在win10主机上使用了科学上网来解决github等网站的联通性问题,则我会这样配置代理。

这是跟AI协作得到的。

  • 建立 proxy.sh 配置文件
#!/bin/bash
# .proxy/proxy.sh
# --- 用户配置 ---
# 请将这里的端口号修改为您在 Windows 上代理软件的实际端口
PROXY_PORT=10809
# --- 用户配置结束 ---
# --- 自动检测 ---
# 1. 从 /etc/resolv.conf 中自动获取 Windows 主机的 IP 地址
# 这是 WSL 与 Windows 网络互通的关键
WIN_IP=$(grep nameserver /etc/resolv.conf | awk '{print $2}')
# 2. 拼接成完整的代理服务器 URL
PROXY_URL="http://$WIN_IP:$PROXY_PORT"
# 3. 检查 WIN_IP 是否为空,如果为空则无法继续
if [ -z "$WIN_IP" ]; then
echo "? 无法获取 Windows 主机 IP 地址,请检查 /etc/resolv.conf 文件。"
return 1 # 使用 return 可以在 source 时停止执行
fi
# --- 核心逻辑 ---
# 使用 nc (netcat) 工具来探测 Windows 主机上的代理端口是否开放
# -z:  表示 Zero-I/O 模式,只进行扫描,不发送任何数据
# -w1: 表示设置1秒的超时时间,如果1秒内连不上就放弃
# 2>/dev/null: 将错误输出重定向到 "黑洞",这样在端口关闭时我们就不会看到 "Connection refused" 的提示
if nc -z -w1 "$WIN_IP" "$PROXY_PORT" 2>/dev/null; then
# 如果 nc 命令成功退出 (退出码为0),说明端口是开放的
echo "? 检测到代理服务开启 ( $WIN_IP:$PROXY_PORT ),正在为您设置全局代理..."  
# a. 设置终端环境变量 (大小写都设置以兼容不同程序)
export http_proxy="$PROXY_URL"
export https_proxy="$PROXY_URL"
export HTTP_PROXY="$PROXY_URL"
export HTTPS_PROXY="$PROXY_URL"
export ALL_PROXY="$PROXY_URL" # 某些工具会使用这个变量   
# b. 设置 Git 代理
git config --global http.proxy "$PROXY_URL"
git config --global https.proxy "$PROXY_URL"   
# c. 设置 npm 代理
npm config set proxy "$PROXY_URL"
npm config set https-proxy "$PROXY_URL"   
# d. 设置 apt 代理 (需要 sudo 权限)
echo "Acquire::http::Proxy \"$PROXY_URL\";" | sudo tee /etc/apt/apt.conf.d/proxy.conf >/dev/null
echo "Acquire::https::Proxy \"$PROXY_URL\";" | sudo tee -a /etc/apt/apt.conf.d/proxy.conf >/dev/null   
echo "?? 所有代理已设置完毕!
else
# 如果 nc 命令失败退出 (退出码非0),说明端口是关闭的
echo "?? 未检测到代理服务,正在为您清除所有代理设置..."    
# a. 取消终端环境变量
unset http_proxy
unset https_proxy
unset HTTP_PROXY
unset HTTPS_PROXY
unset ALL_PROXY    
# b. 取消 Git 代理
git config --global --unset http.proxy
git config --global --unset https.proxy    
# c. 取消 npm 代理
npm config delete proxy
npm config delete https-proxy    
# d. 删除 apt 代理配置文件 (需要 sudo 权限)
sudo rm -f /etc/apt/apt.conf.d/proxy.conf    
echo "?? 所有代理已清除,您现在将使用直接连接。"
fi
  • 赋执行权限
chmod +x ~/.proxy/proxy.sh
  • 如何使用? 这一点至关重要!为了让 export 和 unset 对您当前的终端会话生效,不能直接像 sh proxy.sh 或 ./proxy.sh 这样执行它。必须使用 source 命令或者 . 命令

  • 创建别名 编辑 ~/.zshrc ,在文件的末尾添加下面这行:

# 设置网络代理的别名
alias setproxy="source ~/.proxy/proxy.sh"

sudo 密码

我不想将系统密码设置得很简单,但是又不想记忆,所以我想的是设置加密保存,使用我的其他密码解密输出,实现在命令行中直接拿密码。

  • 临时保存密码 先将你的真实密码保存在一个临时文件中,比如:
echo -n "MyP@ssw0rd!_123\n" > ~/.temp_pass.txt
  • 使用 openssl 加密 它会提示你输入并确认一个新的“主密码”。这个主密码是你用来保护真实密码的。
openssl enc -aes-256-cbc -salt -pbkdf2 -in ~/.temp_pass.txt -out ~/pathoffile

执行后,它会提示:

enter AES-256-CBC encryption password:
Verifying - enter AES-256-CBC encryption password:

在这里输入你的“主密码”(例如 MasterKey456)。

这里的密码末尾最好带上换行符,这样解密后才会有换行符。如果没有会有什么问题呢,zsh 为了防止字符不换行的时候与终端的引导符粘在一起,会在字符末尾自动添加换行,这本来是好事,但是并不多。因为 zsh 为了表示自己加了换行,提示用户注意,还会在原来字符的末尾加上一个百分号,这导致显示出来看上去密码是不对的,而且复制字面量容易出错

  • 删除临时的明文密码文件:
rm ~/.temp_pass.txt
  • 创建解密脚本 我们将脚本放在 ~/.local/bin/ 目录下,这是一个用于存放用户自定义命令的标准位置。
nano ~/.local/bin/pathoffile

这是 unlock 的内容

#!/bin/bash
# ~/.local/bin/unlock文件内容
# 检查用户是否提供了主密码作为参数
if [ -z "$1" ]; then
# 如果没有提供参数,就打印错误信息和用法到标准错误输出
echo "错误: 未提供主密码。" >&2
echo "用法: $(basename "$0") <主密码>" >&2
exit 1 # 以错误码退出
fi
# 从命令行第一个参数获取主密码
MASTER_PASS=$1
# 使用 openssl 解密文件
# -d 表示解密 (decrypt)
# 选项必须与加密时完全一致
# -pass pass:"$MASTER_PASS" 从变量中读取主密码
# 2>/dev/null 将任何错误信息 (如密码错误) 重定向到 "黑洞",这样错误时就不会有任何输出
# tee >(clip.exe)是将终端输出复制一份到剪贴板
openssl enc -d -aes-256-cbc -pbkdf2 -in ~/.pwd/.encrypted -pass pass:"$MASTER_PASS" 2>/dev/null | tee >(clip.exe)

自定义命令

通过给 ohmyzsh 加自定义插件的方式增加自定义命令。这的确会更有挑战性,但是更优雅。这个章节的用法有 AI 的协助。

  • 建立插件目录
mkdir ~/.oh-my-zsh/custom/plugins/wsltools
  • 创建入口文件
# ~/.oh-my-zsh/custom/plugins/wsltools/wsltools.plugin.zsh
# Get the directory where this script is located
plugin_dir="${0:A:h}"
# 1. Add the 'functions' subdirectory to the fpath array.
# This tells Zsh WHERE to look for autoloadable functions.
fpath=("$plugin_dir/functions" $fpath)
# 2. Explicitly declare which functions are available for autoloading.
# This tells Zsh WHAT to look for. It's a robust way to register
# the function and avoids potential conflicts or environment issues.
autoload -U np3
autoload -U touch
  • 创建函数文件
# ===================================================================
# 
# ~/.oh-my-zsh/custom/plugins/wsltools/functions/np3
# 
# 函数名: np3
# 
# 功能: 从 WSL 内部调用 Windows 里的 Notepad3 程序来打开一个文件。
# 
# 特性:
# - 参数检查: 确保用户提供了一个文件名作为参数。
# - 环境检查: 验证 Notepad3 的 .exe 文件是否存在且可以执行。
# - 自动创建: 如果目标文件不存在,会自动创建该文件。
# - 路径转换: 使用 wslpath 命令将 WSL 路径正确转换为 Windows 路径。
# - 后台运行: 将 Notepad3 进程在后台启动,不阻塞当前终端。
# 
# ===================================================================
np3() {
# ---------------------------------------------------------------
# 1. 配置区域
# ---------------------------------------------------------------
# !! 请根据你的实际情况修改此路径 !!
# 这是 Notepad3.exe 在 WSL 中的访问路径 (C盘 -> /mnt/c, D盘 -> /mnt/d, 以此类推)
local win_app_path="/mnt/d/Portable/WSLTools/Notepad3/Notepad3.exe"
# ---------------------------------------------------------------
# 2. 输入参数验证
# 检查用户是否提供了文件名。如果没有,则报错并退出。
# ---------------------------------------------------------------
if [[ -z "$1" ]]; then
    echo "错误: 未指定文件名。" >&2
    echo "用法: np3 <文件路径>" >&2
    return 1 # 返回一个非零状态码,表示函数执行失败
fi   
# 将第一个参数赋值给 file_path 变量,使其更具可读性
local file_path="$1"    
# ---------------------------------------------------------------
# 3. 运行环境验证
# 检查 Notepad3 的可执行文件是否存在。-x 标志检查文件是否存在且可执行。
# ---------------------------------------------------------------
if [[ ! -x "$win_app_path" ]]; then
    echo "错误: Notepad3 可执行文件未找到或没有执行权限。" >&2
    echo "请检查路径: '$win_app_path'" >&2
    return 1
fi    
# ---------------------------------------------------------------
# 4. 文件存在性检查
# 如果用户指定的文件不存在,则先创建它,避免 Notepad3 报错。
# ---------------------------------------------------------------
if [[ ! -f "$file_path" ]]; then
    echo "文件 '$file_path' 不存在,正在为您创建..."
    # 使用 touch 命令安全地创建空文件
    touch "$file_path"
fi    
# ---------------------------------------------------------------
# 5. 核心逻辑: 路径转换与执行
# ---------------------------------------------------------------
# 使用 wslpath -w 将 WSL 路径 (例如 /home/user/test.txt)
# 转换为 Windows 路径 (例如 C:\Users\user\test.txt)
local win_file_path
win_file_path=$(wslpath -w "$file_path")    
echo "正在使用 Notepad3 打开: $win_file_path"   
# 执行命令:
# ( ... &) 将整个命令放入子 shell 并在后台运行,彻底与当前终端分离。
# nohup 确保在你关闭终端后,程序还能继续运行 (虽然对图形界面程序意义不大,但是个好习惯)。
# &> /dev/null 将标准输出和标准错误都重定向到“黑洞”,保持终端干净。
# "$win_app_path" 和 "$win_file_path" 使用双引号包裹,以处理路径中可能存在的空格。
(nohup "$win_app_path" "$win_file_path" &>/dev/null &)
}
  • 下面是增强 touch 的函数文件
# ==============================================================================
# 增强版 touch 命令
# 功能:在创建文件时,如果父目录不存在,则自动创建。
# ==============================================================================
touch() {
# 遍历所有传递给此函数的参数(例如 "path/to/file.txt", "-a", "-m" 等)。
# "$@" 是一个特殊的 shell 变量,代表所有传递进来的参数,并能正确处理带空格的参数。
for arg in "$@"; do
  # 判断参数是否为文件路径。一个简单的检查方法是看它是否以连字符(-)开头。
  # 如果不是以 "-" 开头,我们就假定它是一个文件路径,而不是一个命令选项(如 -a, -m)。
  if [[ "$arg" != -* ]]; then
    # 声明一个局部变量 dir,这样它就不会影响到函数外部的同名变量,这是一个好习惯。
    local dir
    # 使用 'dirname' 命令来提取参数中的目录部分。
    # 例如,如果参数是 "path/to/my/file.txt",那么 'dirname' 会返回 "path/to/my"。
    dir=$(dirname "$arg")

    # 使用 'mkdir -p' 命令来创建目录。
    # '-p' 选项是关键:它会创建所有必需的父目录,并且如果目录已经存在,它也不会报错。
    # 这使得我们的脚本非常健壮。
    mkdir -p "$dir"
  fi
done
# 在确保所有目录都创建完毕后,调用【真正】的 touch 命令。
# 这里的 'command' 是一个 shell 内置命令,它的作用是忽略任何同名的函数或别名,
# 直接执行系统路径($PATH)中的原始命令。这可以防止函数无限次地调用自己(无限递归)。
# "$@" 会将【所有原始参数】(包括文件路径和命令选项)原封不动地传递给真正的 touch 命令。
command touch "$@"
}

总结

恭喜你!跟随本指南,你不仅成功安装和配置了 WSL 2,还拥有了一个高度定制化和自动化的开发环境。现在你的 WSL 具备了:

  • 美观且高效的 Oh My Zsh 终端。
  • 与主机无缝协作的网络代理。
  • 安全便捷的密码管理方案。
  • 实用的自定义命令。

这套环境将成为你在 Windows 上进行开发、学习和实验的强大基石。如果你在配置过程中遇到任何问题,或有更好的技巧,大家可以互相交流。


  1. zsh 安装与配置,使用 oh-my-zsh 美化终端 | Leehow的小站  ↩︎

  2. git 配置 ssh  ↩︎