Ubuntu 与 WSL2 初始环境配置与常用工具安装教程

适用于 Ubuntu 24.04 LTS(云厂商镜像、官方 ISO 或 WSL2 安装后),从 SSH 远程连接到常用工具一站式配置。


目录


一、文档总览

flowchart TD A["🟣 Ubuntu 初始环境配置"]:::root --> B["🔵 SSH 远程服务"]:::l1 A --> C["🔵 网络与系统"]:::l1 A --> D["🔵 常用工具集"]:::l1 A --> E["🔵 安全与优化"]:::l1 A --> F["🔵 命令速查"]:::l1 B --> B1["🟢 安装 openssh-server"]:::l2 B --> B2["🟢 配置 sshd_config"]:::l2 B --> B3["🟢 密钥免密登录"]:::l2 B --> B4["🟢 防火墙放行"]:::l2 C --> C1["🟢 静态 IP / DNS"]:::l2 C --> C2["🟢 主机名 / hosts"]:::l2 C --> C3["🟢 时区 / NTP"]:::l2 C --> C4["🟢 系统更新源"]:::l2 D --> D1["🟢 网络工具 net-tools"]:::l2 D --> D2["🟢 编辑器 / 上传"]:::l2 D --> D3["🟢 开发工具链"]:::l2 D --> D4["🟢 效率 / 监控"]:::l2 E --> E1["🟢 ufw 防火墙"]:::l2 E --> E2["🟢 fail2ban"]:::l2 E --> E3["🟢 内核参数 / FD 限制"]:::l2 classDef root fill:#ffffff,stroke:#9b59b6,stroke-width:3px,color:#9b59b6 classDef l1 fill:#ffffff,stroke:#3498db,stroke-width:2px,color:#3498db classDef l2 fill:#ffffff,stroke:#2ecc71,stroke-width:2px,color:#2ecc71

章节索引:

序号 章节 说明
文档总览 流程图 + 索引
初始环境检查 确认系统版本 / 初始账号 / 设置 root 密码
SSH 远程服务 核心:安装 + 配置 + 密钥免密
网络与系统配置 静态 IP / DNS / 时区 / 更新源
常用工具集 网络、编辑器、开发、效率工具
安全与优化 ufw / fail2ban / 内核参数
验证检查清单 一键自检
常用命令速查 CentOS ↔ Ubuntu 对照表

二、初始环境检查

在动手前,先确认当前系统的版本、内核、当前用户、是否已装 SSH。

# 系统版本
cat /etc/os-release

# 内核版本
uname -r

# 当前用户与权限
whoami
id

# 是否已安装 SSH(Ubuntu 桌面版/部分云镜像默认未装)
dpkg -l | grep -E "openssh-server|openssh-client"
ss -tlnp 2>/dev/null | grep :22 || netstat -tlnp 2>/dev/null | grep :22

2.1 设置 root 密码

Ubuntu 默认禁用 root 直接登录,且初始 root 账户通常没有设置密码。建议先为 root 设置一个强密码,便于后续 su - 切换和系统维护。

# 为 root 用户设置密码(按提示输入两次)
sudo passwd root

验证切换是否成功

# 切换到 root 用户
su -

# 确认当前身份
whoami
id

💡 提示

  • 设置 root 密码后,root 仍可通过 su - 切换,但 SSH 默认仍禁止 root 登录(PermitRootLogin prohibit-password)。
  • 如需允许 root 通过 SSH 密码登录,需修改 /etc/ssh/sshd_config 中的 PermitRootLogin 项,并重启 SSH 服务(生产环境不建议)。
  • WSL 环境下建议设置 root 密码,否则很多需要 root 权限的维护操作会受阻。

🔐 安全建议

  • root 密码应使用强密码(长度 12 位以上,包含大小写字母、数字、特殊字符)。
  • 日常操作优先使用 sudo,仅在必要时切换到 root。

三、SSH 远程服务(核心)

本章为优先配置项。所有运维操作几乎都依赖 SSH,建议首先完成配置。

3.1 安装 openssh-server

⚠️ 先换源,再更新

如果你在国内或默认源访问较慢,建议先完成 4.5 节的 apt 换源配置,再返回本节执行安装。否则第一次 apt update 可能非常慢,甚至超时失败。

# 更新软件源索引(如已按 4.5 节换源,会直接从镜像站更新)
sudo apt update

# 安装 SSH 服务端与客户端
sudo apt install -y openssh-server openssh-client

# 启动并设置开机自启
sudo systemctl enable --now ssh

🔧 验证

sudo systemctl status ssh   # 输出中出现 active (running) 即表示成功
ss -tlnp | grep :22         # 看到 0.0.0.0:22 或 *:22 监听中

📋 WSL 用户必读:配置完 SSH 后,如果需要从 Windows 侧通过 WSL 的 IP(如 192.168.x.x)连接到此 WSL 实例,还需要额外开启 hostAddressLoopback 实验特性。否则 localhost:<端口> 正常,但 WSL_IP:<端口> 会超时。详见 5.6.8.15 镜像网络下 Windows 通过 WSL IP 访问服务超时

3.2 配置文件结构

📄 文件 📝 用途
/etc/ssh/sshd_config 服务端主配置(修改后要重启 ssh 服务)
/etc/ssh/ssh_config 客户端配置(一般不动)
~/.ssh/authorized_keys 存放客户端公钥,启用免密登录
~/.ssh/known_hosts 客户端记录过的服务端指纹
~/.ssh/id_rsa / id_rsa.pub 客户端的私钥 / 公钥

修改 sshd_config强烈建议先备份:

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

3.3 修改 sshd_config(生产推荐配置)

sudo vim /etc/ssh/sshd_config
# =============================================
# 基础配置
# =============================================
# 监听端口(生产建议改为非默认端口,降低被扫描爆破概率)
Port 22

# 监听地址(0.0.0.0 = 所有网卡;如仅内网访问可改为内网IP)
ListenAddress 0.0.0.0

# 协议版本(v2 比 v1 安全)
Protocol 2

# =============================================
# 登录认证(关键)
# =============================================
# 禁止 root 直接登录(必开)
PermitRootLogin no

# 是否允许密码登录。生产推荐 no + 改用密钥登录
PasswordAuthentication yes

# 是否允许空密码(生产环境应设为 no)
PermitEmptyPasswords no

# 公钥认证(密钥免密登录)
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys

# 密钥强度
PubkeyAcceptedKeyTypes=+ssh-rsa,ssh-dss

# =============================================
# 安全加固
# =============================================
# 最大重试次数
MaxAuthTries 3

# 最大并发未认证连接
MaxSessions 5

# 登录超时(30 秒无输入断开)
LoginGraceTime 30

# 客户端空闲超时(600 秒无操作断开)
ClientAliveInterval 60
ClientAliveCountMax 10

# 禁止 X11 转发(图形转发,服务器无必要)
X11Forwarding no

# 限制登录用户/组(白名单)
AllowUsers ubuntu
# AllowGroups ssh-users

# =============================================
# 显示与日志
# =============================================
# 登录前后显示的 banner 文件路径(可选)
# Banner /etc/issue.net

# 日志级别
LogLevel VERBOSE

📋 配置说明

  • PermitRootLogin no:禁止 root 直登,运维需用普通用户 + sudo 提权。
  • PasswordAuthentication yes → 后续验证完密钥登录后可改为 no
  • AllowUsers ubuntu:把 ubuntu 替换为你的实际登录用户,多用户用空格分隔

3.4 重启 SSH 并验证

# 检查配置语法(非常关键,避免配错导致无法登录)
sudo sshd -t
# 若命令无输出,则表示语法正确

# 重启服务
sudo systemctl restart ssh

# 查看状态
sudo systemctl status ssh

⚠️ 高危提醒:修改 SSH 配置后,不要立即关闭当前会话。应新开一个窗口测试能正常登录,确认没问题再退出,避免配置错误导致锁在外面。

3.5 配置密钥免密登录(推荐)

3.5.1 在客户端生成密钥对

Windows(PowerShell / CMD):

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 一直回车即可,会在 C:\Users\你的用户\.ssh\ 下生成 id_rsa 和 id_rsa.pub

Linux / macOS:

ssh-keygen -t rsa -b 4096
# 提示 passphrase 时可设置密码(更安全),也可直接回车

3.5.2 上传公钥到服务器

方法一:ssh-copy-id(最简单)

# Linux / macOS / Windows 11 (PowerShell 自带 OpenSSH)
ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@服务器IP
# 输入一次密码后即完成

方法二:手动复制

# 在客户端打印公钥
cat ~/.ssh/id_rsa.pub

# 在服务器上操作
mkdir -p ~/.ssh
chmod 700 ~/.ssh
vim ~/.ssh/authorized_keys   # 粘贴公钥,一行一个
chmod 600 ~/.ssh/authorized_keys

3.5.3 关闭密码登录

验证密钥能登录后,编辑服务端配置:

sudo vim /etc/ssh/sshd_config
PasswordAuthentication no
sudo sshd -t
sudo systemctl restart ssh

3.6 防火墙放行 SSH

Ubuntu 默认使用 ufw(Uncomplicated Firewall),操作比 firewalld 简单:

# 查看 ufw 状态
sudo ufw status verbose

# 默认策略:拒绝入站、允许出站
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 放行 SSH(推荐显式指定端口)
sudo ufw allow 22/tcp comment "SSH default port"
# 如改了端口:sudo ufw allow 2222/tcp

# 启用防火墙
sudo ufw enable
# 会提示 "Command may disrupt existing ssh connections"
# 按提示输入 y 确认继续(启用前已放行 22 端口,不会中断现有连接)

# 查看规则
sudo ufw status numbered

🔧 验证:用另一台机器 ssh ubuntu@服务器IP 测试能连即可。

3.6.1 兜底:ufw 不存在时(Debian 最小化镜像 / 自定义容器 / 误卸载)

若执行 sudo ufw statuscommand not found,说明系统不是标准 Ubuntu 桌面/服务器(常见于 Debian 最小化版、Docker 基础镜像 debian:slim、部分云厂商轻量镜像等)。先用以下命令确认系统类型,再选择对应防火墙:

# 确认系统类型
cat /etc/os-release
# 确认 ufw 是否真的没装(不是 PATH 问题)
which ufw || dpkg -l | grep -i ufw || rpm -qa | grep -i ufw

情况 A:确实是 Ubuntu,但 ufw 被精简掉了 —— 装回来即可:

sudo apt update
sudo apt install -y ufw
sudo ufw allow 22/tcp
sudo ufw enable

情况 B:Debian 最小化系统 —— 同样装 ufw 即可(Debian 官方源里有):

sudo apt update && sudo apt install -y ufw
sudo ufw allow 22/tcp
sudo ufw enable

情况 C:容器 / Alpine / RHEL 家族 —— 没有 ufw,需用底层工具:

# ===== iptables(Debian/Ubuntu 默认自带,ufw 底层也是它)=====
# 查看规则(-L 列表,-n 数字显示,-v 详细,--line-numbers 显示行号便于删除)
sudo iptables -L INPUT -n -v --line-numbers

# 临时放行 SSH(重启失效)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 持久化:Debian/Ubuntu 安装 iptables-persistent
sudo apt install -y iptables-persistent
sudo netfilter-persistent save

# ===== nftables(Ubuntu 24.04+、Debian 12+ 推荐的现代替代)=====
# 查看规则
sudo nft list ruleset

# 放行 SSH
sudo nft add rule inet filter input tcp dport 22 accept

# ===== firewalld(CentOS / RHEL / Fedora 默认)=====
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload

⚠️ 重要提醒

  • 远程主机上启用防火墙前,先放行 22 端口(否则启用瞬间就会被踢出,连不上)。
  • 容器内(Docker/LXC)通常不需要操作防火墙,端口由宿主机或 docker run -p 控制。
  • 不确定系统类型时,cat /etc/os-release 是最准的判断方式。

四、网络与系统配置

4.1 配置静态 IP(Netplan)

Ubuntu 18.04+ 统一使用 Netplan 管理网络(取代传统的 /etc/network/interfaces)。

# 查看网卡名称
ip -br link
# 一般为 ens33 / ens160 / enp0s3 等

ls /etc/netplan/
sudo vim /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    ens33:                          # 替换为你的网卡名
      dhcp4: no
      dhcp6: no
      addresses:
        - 192.168.1.100/24          # 静态 IP
      routes:
        - to: default
          via: 192.168.1.1          # 网关
      nameservers:
        addresses:
          - 223.5.5.5               # 阿里 DNS
          - 8.8.8.8                 # Google DNS
          - 114.114.114.114         # 114 DNS
# 验证配置(不会应用,但会显示问题)
sudo netplan try

# 应用配置
sudo netplan apply

⚠️ 远程操作注意netplan try 会临时应用配置并等待 120 秒回车确认;直接 netplan apply 会立即生效,可能导致远程连接短暂中断

⚠️ WSL 用户注意:本节讲的 Netplan 配置对 WSL2 不生效。WSL 的网络由 Windows 虚拟网卡管理,配置在 Windows 侧的 %USERPROFILE%\.wslconfig。详见 5.6.8 WSL 网络配置与 Windows 互通

4.2 配置主机名

# 查看当前主机名
hostnamectl

# 设置主机名(替换 dev-workspace 为你想要的名字)
sudo hostnamectl set-hostname dev-workspace

⚠️ hostnamectl 改了 /etc/hostname,但不会自动改 /etc/hosts!

hostnamectl set-hostname 只负责:

  • 写入 /etc/hostname
  • 通知 systemd-hostnamed 更新主机名状态

不会自动写入 /etc/hosts,所以改完主机名后必须手动追加一行,否则 sudo 会报 unable to resolve host

# 追加新主机名到 /etc/hosts(追加,不是覆盖!)
echo "127.0.1.1 dev-workspace" | sudo tee -a /etc/hosts

# 验证 sudo 不再报警
sudo whoami

完整的 /etc/hosts 应该长这样

127.0.0.1   localhost
127.0.1.1   dev-workspace

⚠️ WSL 用户注意:WSL 启用 systemd 后(见 5.6.8.11 WSL 启用 systemd),hostnamectl set-hostname 可直接用。配置修改后需要完全重启 WSL 才生效,详见 5.6.8.11.1 WSL 重启的正确方式。主机名持久化配置见 5.6.8.9 WSL 主机名设置

4.3 时区与时间同步

# 查看当前时区
timedatectl

# 设置时区
sudo timedatectl set-timezone Asia/Shanghai

# Ubuntu 默认自带 systemd-timesyncd
sudo systemctl enable --now systemd-timesyncd
timedatectl status

📋 说明

  • 服务器与客户端的时间偏差超过 5 分钟会导致部分协议(如 Kerberos)失败。
  • 如需更高精度,可安装 chronysudo apt install -y chrony

⚠️ WSL 用户注意:启用 systemd 后(见 5.6.8.11 WSL 启用 systemd),timedatectl set-timezone 可直接用,无需手动 ln -s

4.4 关闭 Ubuntu 默认组件(按需)

# 关闭 Snap 服务(部分场景下不需要)
sudo systemctl disable --now snapd.service snapd.socket snapd.seeded.service

# 关闭无关服务(如自动更新)
sudo systemctl disable --now unattended-upgrades.service

4.5 配置 apt 更新源(deb822 格式,Ubuntu 24.04+)

💡 本节针对 Ubuntu 24.04 LTS(Noble)默认的 deb822 格式
24.04 之后 /etc/apt/sources.list 已被废弃,真正的源文件在 /etc/apt/sources.list.d/ubuntu.sources

4.5.1 验证当前源格式

📋 如何判断你该用哪个文件

Ubuntu 版本 VERSION_CODENAME 默认源文件 备注
24.04+ noble sources.list.d/ubuntu.sources(deb822 新格式) 本节主推
24.04+ noble sources.list.d/ubuntu.sources(deb822 新格式) 本节主推
20.04 及更早 focal 及更早 sources.list(deb 老格式) apt 不支持 deb822,老格式即可

快速检测脚本

if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then
  echo "✅ 新格式(deb822),用 sources.list.d/ubuntu.sources"
else
  echo "⚠️  老格式(deb),用 sources.list"
fi

结论:本节默认按 Ubuntu 24.04+ 讲解。低版本用户请参考对应版本的官方文档。

4.5.2 查看当前源文件内容

# 1. 确认 Ubuntu 版本
cat /etc/os-release | grep VERSION_CODENAME
# 输出示例:VERSION_CODENAME=noble

# 2. 看新格式的源文件(24.04+ 才有这个)
cat /etc/apt/sources.list.d/ubuntu.sources

# 3. 老的 sources.list 在 24.04 上只剩 3 行注释
cat /etc/apt/sources.list
# 输出示例:
# # Ubuntu sources have moved to the /etc/apt/sources.list.d/ubuntu.sources
# # file, which uses the deb822 format. ...

📋 deb822 格式 vs 老 deb 格式

项目 老格式(≤ 20.04) 新格式(≥ 24.04)
文件位置 /etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources
文件内容 deb URL 代号 组件 ... Types: deb / URIs: URL / Suites: 代号 / ...(每行一个字段)
多源 一行一个源 一个文件多个 Types:
注释 # xxx # xxx 或字段名后加 # xxx

4.5.3 备份默认源

# 备份新格式源(24.04+)
sudo cp /etc/apt/sources.list.d/ubuntu.sources \
        /etc/apt/sources.list.d/ubuntu.sources.bak

# 顺便也备份老的(即使只剩注释,养成习惯)
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

4.5.4 替换为阿里云源(国内推荐)

自动生成(推荐,最稳)

# 阿里云官方提供了一键替换脚本
# 等价于:把 sources.list.d/ubuntu.sources 里的 http://archive.ubuntu.com/
#        和 http://security.ubuntu.com/ 全部替换成 mirrors.aliyun.com
sudo sed -i.bak \
  -e 's|http://archive.ubuntu.com|http://mirrors.aliyun.com|g' \
  -e 's|http://security.ubuntu.com|http://mirrors.aliyun.com|g' \
  /etc/apt/sources.list.d/ubuntu.sources

# 验证改对了
cat /etc/apt/sources.list.d/ubuntu.sources

手动编辑(想完全控制内容时用):

sudo vim /etc/apt/sources.list.d/ubuntu.sources

deb822 格式完整示例(noble = 24.04):

# =============================================
# /etc/apt/sources.list.d/ubuntu.sources
# 阿里云镜像(noble = 24.04)
# =============================================

Types: deb
URIs: http://mirrors.aliyun.com/ubuntu
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://mirrors.aliyun.com/ubuntu
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

📋 关键字段说明

  • Types: deb —— 二进制包;Types: deb-src —— 源码包
  • URIs: —— 镜像地址
  • Suites: —— 版本代号(要与 lsb_release -cs 一致,否则报 404)
  • Components: —— 组件(main / restricted / universe / multiverse)
  • Signed-By: —— GPG 签名文件路径(24.04 必填)

4.5.5 应用并验证

# 刷新源索引
sudo apt update
# 看到 "Hit: http://mirrors.aliyun.com/ubuntu noble ..." = 成功

# 升级所有已装包
sudo apt upgrade -y

# (可选)清理无用包
sudo apt autoremove -y

验证用的是阿里云源

apt policy
# 看每个仓库的 URL 列,应该是 mirrors.aliyun.com

# 或更直白
apt-cache policy | grep -i "aliyun\|archive.ubuntu\|security.ubuntu"

4.5.6 其他国内镜像(按需替换 URIs

镜像 替换前 替换后
阿里云(最稳,首选) http://archive.ubuntu.com http://mirrors.aliyun.com/ubuntu
清华 TUNA 同上 https://mirrors.tuna.tsinghua.edu.cn/ubuntu
中科大 USTC 同上 https://mirrors.ustc.edu.cn/ubuntu
网易 同上 http://mirrors.163.com/ubuntu
华为云 同上 https://mirrors.huaweicloud.com/ubuntu
腾讯云 同上 https://mirrors.cloud.tencent.com/ubuntu

清华源示例(想换清华的话):

sudo sed -i \
  -e 's|http://archive.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' \
  -e 's|http://security.ubuntu.com|https://mirrors.tuna.tsinghua.edu.cn|g' \
  /etc/apt/sources.list.d/ubuntu.sources

4.5.7 常见问题

Q1:换源后 apt updateGPG error / NO_PUBKEY

# 重新导入签名密钥
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys <报错里的 KEY>

# 或更稳的方式(24.04 推荐)
sudo wget -O /usr/share/keyrings/ubuntu-archive-keyring.gpg \
  https://mirrors.aliyun.com/ubuntu/keys/release-archive-keyring.gpg
sudo apt update

Q2:换源后 apt update404 Not Found

# 99% 是 Suites 字段写错了(不是 24.04 写了 jammy / focal / bionic)
lsb_release -cs
# 看到 noble 才能用 noble、noble-updates、noble-security、noble-backports

# 或用 sed 一键修正
sudo sed -i "s/^Suites: .*/Suites: noble noble-updates noble-security noble-backports/" \
  /etc/apt/sources.list.d/ubuntu.sources

Q3:想临时恢复默认源?

# 删掉改过的文件,还原备份
sudo cp /etc/apt/sources.list.d/ubuntu.sources.bak \
        /etc/apt/sources.list.d/ubuntu.sources
sudo apt update

Q4:怎么加第三方源(如 Docker、Node.js)?

不要直接改 ubuntu.sources,而是单独建一个 .sources 文件,apt 会按字典序读取:

# 例:加 Docker 官方源
sudo vim /etc/apt/sources.list.d/docker.sources
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: noble
Components: stable
Signed-By: /etc/apt/keyrings/docker.gpg
# 加 GPG 密钥
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.gpg
sudo apt update

4.5.8 一键脚本(适合批量初始化)

#!/bin/bash
# 阿里云 apt 源一键配置(Ubuntu 24.04+)
set -e

SRC="/etc/apt/sources.list.d/ubuntu.sources"
BAK="${SRC}.bak.$(date +%Y%m%d%H%M%S)"

# 1. 备份
sudo cp "$SRC" "$BAK"
echo "✅ 备份到 $BAK"

# 2. 检查格式
if ! grep -q "^URIs:" "$SRC"; then
  echo "❌ 当前不是 deb822 格式,请确认 Ubuntu 版本 ≥ 24.04"
  exit 1
fi

# 3. 替换为阿里云
sudo sed -i \
  -e 's|http://archive.ubuntu.com|http://mirrors.aliyun.com|g' \
  -e 's|http://security.ubuntu.com|http://mirrors.aliyun.com|g' \
  "$SRC"

# 4. 验证
echo "🔍 改完后的源:"
grep "^URIs:" "$SRC"

# 5. 刷新
sudo apt update
echo "✅ apt update 完成"

保存为 ~/set-aliyun-mirror.sh,跑:

chmod +x ~/set-aliyun-mirror.sh
sudo ~/set-aliyun-mirror.sh

📋 关于 Ubuntu 版本代号

  • noble = 24.04(24.04 LTS 用 5 年,2034 年 EOL)
  • jammy = 22.04(历史版本,已逐步迁移至 24.04)
  • focal = 20.04(已 EOL)

改源时代号要与 lsb_release -cs 一致,否则报 404。


五、常用工具集

5.1 一键安装清单

# =============================================
# 网络工具
# =============================================
# net-tools: netstat / ifconfig / route 等传统命令
# iproute2:  ip / ss / tc 等新一代命令(Ubuntu 自带)
# dnsutils:  nslookup / dig
# iputils-ping: ping
# traceroute: 路由追踪
sudo apt install -y net-tools dnsutils iputils-ping traceroute mtr

# =============================================
# 编辑器与文件处理
# =============================================
# vim: 增强版 vi
# nano: 简单文本编辑器
# unzip / p7zip-full: 解压 zip / 7z
# lrzsz: rz / sz 上传下载(Xshell/SecureCRT 适用)
sudo apt install -y vim nano unzip p7zip-full lrzsz

# =============================================
# 版本控制
# =============================================
# git: 分布式版本控制
sudo apt install -y git

# =============================================
# Shell 增强
# =============================================
# bash-completion: 命令补全
# zsh + oh-my-zsh: 更友好的 shell
# tmux: 终端复用器(断线不丢任务)
sudo apt install -y bash-completion tmux

# =============================================
# 系统监控与诊断
# =============================================
# htop: 增强版 top
# iotop: 磁盘 IO 监控
# iftop: 网络流量监控
# sysstat: iostat / mpstat / sar
# lsof: 查看打开的文件
# strace: 系统调用跟踪
# ncdu: 交互式磁盘占用分析
sudo apt install -y htop iotop iftop sysstat lsof strace ncdu

# =============================================
# 开发工具链(按需)
# =============================================
# build-essential: gcc / g++ / make
# python3 / pip3
# openjdk-17-jdk
# nodejs / npm
# sudo apt install -y build-essential python3 python3-pip openjdk-17-jdk nodejs npm

# =============================================
# 文本搜索 / 处理
# =============================================
# ripgrep (rg): 更快更现代的 grep
# fd-find (fd): 更快更现代的 find
# jq: 命令行 JSON 处理
# tree: 目录树展示
sudo apt install -y ripgrep fd-find jq tree

# =============================================
# 安全相关
# =============================================
# fail2ban: 防 SSH 暴力破解
# ufw: 防火墙(默认已装)
sudo apt install -y fail2ban

5.2 工具速查表

🔧 工具 📝 用途 📋 常用命令
netstat 网络连接/端口查看 netstat -tlnp
ss 现代版 netstat ss -tlnpss -s
ip 网络配置 ip addrip route
dig DNS 查询 dig baidu.com
mtr 网络诊断(ping+traceroute) mtr baidu.com
vim 文本编辑 vim /etc/hosts
tmux 终端复用 tmux new -s name
htop 进程监控 htop
iotop 磁盘 IO 监控 sudo iotop
iftop 流量监控 sudo iftop -i ens33
lsof 查看打开的文件 lsof -i :8080
tree 目录树 tree -L 2 /data
jq JSON 处理 cat x.json | jq .
rg 快速搜索 rg "error" /var/log

5.3 配置 Git(开发者必做)

git config --global user.name "Your Name"
git config --global user.email "your_email@example.com"

# 让命令输出带颜色
git config --global color.ui auto

# 解决中文文件名显示问题
git config --global core.quotepath false

5.4 配置 vim(可选但推荐)

vim ~/.vimrc
" 显示行号
set number

" 语法高亮
syntax on

" 缩进 4 空格
set tabstop=4
set softtabstop=4
set shiftwidth=4
set expandtab

" 搜索高亮
set hlsearch
set incsearch

" 编码
set encoding=utf-8
set fileencodings=utf-8,gbk,gb18030,gb2312

" 鼠标支持
set mouse=a

5.5 配置 bash 提示符(可选)

vim ~/.bashrc

在末尾追加:

# 彩色提示符
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

# 命令别名
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias gs='git status'
alias gp='git pull'
alias ..='cd ..'
source ~/.bashrc

5.6 WSL 数据目录规划建议(仅 WSL2 用户)

适用于 WSL2 下的 Ubuntu(Microsoft Store / Docker Desktop / 自定义导入均可参考)。
非 WSL 场景(云服务器、物理机、虚拟机)可跳过本节。

5.6.1 先理解 WSL2 的"磁盘"是怎么回事

WSL2 本质是一个 ext4 虚拟磁盘文件ext4.vhdx)挂载到 /,而不是传统的物理磁盘 + 分区表(MBR / GPT)结构。所以:

df -h

典型输出(已实测 WSL2 Ubuntu 24.04):

/dev/sde       1007G  2.0G  954G   1% /                  ← 根目录所在的虚拟磁盘(最大块)
/dev/sdd       1007G  5.3G  951G   1% /mnt/wsl/...      ← Docker Desktop 存储(也是 vhdx)
/dev/loop0      761M  761M     0 100% /mnt/wsl/...      ← Docker CLI 工具(与根目录无关)
none            7.8G  ...   ...   ... /mnt/wsl/drivers   ← WSL 内部通道挂载(不是存储)
C:\             401G  305G   96G  77% /mnt/c             ← Windows C 盘
D:\             552G  397G  155G  72% /mnt/d             ← Windows D 盘

几个关键点:

现象 真相
none 7.8G 那么多挂载点 均为 WSL2 的 9P 共享通道(drivers、init、run、shm 等),不属于根目录存储空间,占用内存而非磁盘
/dev/sde 1007G 看着很大 实际对应 Windows 侧的 ext4.vhdx 稀疏文件;WSL 内显示的"已用 2G"为文件系统逻辑用量,并非该 vhdx 文件在 Windows 上的实际物理占用
/ 下建文件夹要不要"分配空间" 不需要mkdir /data 不占空间,写入文件时才"按需"占用
写满会怎样 根目录满 100% 后所有命令都报错;WSL2 默认上限 256 G,可手动扩到几 T

5.6.2 推荐:把重要数据放到 Windows 盘

为什么? WSL 出问题需要重装、迁移、换发行版时,根目录里的数据会全部丢失;但 /mnt/c//mnt/d/ 是直接读 Windows 文件系统,完全不受影响

# 1. 在 Windows D 盘建一个固定目录(PowerShell 或文件管理器都行)
#    路径示例:D:\wsl-data

# 2. 在 WSL 里建软链接(个人数据放这)
mkdir -p /mnt/d/wsl-data
ln -s /mnt/d/wsl-data ~/data

# 3. 给项目、数据库、下载等建子目录
mkdir -p /mnt/d/wsl-data/{projects,downloads,backups,db,logs}

# 4. 验证
ls -ld ~/data
df -h /mnt/d

💡 软链 vs 直接挂载

  • 软链(推荐)→ ~/data/mnt/d/wsl-data,既能在 WSL 用,也能在 Windows 资源管理器直接打开
  • /mnt/d/ 路径直接用也行,但路径长、可读性差

5.6.3 CentOS vs Ubuntu:为什么 Ubuntu 默认没有 /data

CentOS / RHEL 迁移过来的用户会发现安装好的 Ubuntu 没有 /data 目录,而 CentOS 默认就有。这是发行版设计理念的差异,跟"要不要手动建"无关。

发行版 默认有没有 /data 原因
CentOS / RHEL / Fedora ✅ 有 安装器按"服务器用途"分区模板自动创建(/bootswap//home/data
Ubuntu / Debian ❌ 没有 严格遵守 FHS(Filesystem Hierarchy Standard)/ 下只放系统目录,业务目录由用户/管理员自己规划

FHS 规定的 / 下"官方目录"(Ubuntu 会装出来的):

/bin /sbin /etc /usr /var /opt /srv /home /root /lib /tmp ...

没有 /data/app/projects 这些"业务目录" —— 因为 FHS 认为这些应由使用场景决定,不由发行版预设。

CentOS 的 /data 的传统用途

  • 放第三方应用(Oracle、MySQL 早期默认数据目录)
  • 放业务服务数据(公司内部约定的"业务数据根目录")
  • 隔离系统盘和业务盘(/ 满了 /data 还能撑)

Ubuntu 推荐替代

# 方案 1:放用户主目录(最常用,WSL 首选)
mkdir -p ~/data/{projects,downloads,backups}

# 方案 2:放 Windows 盘(WSL 重装不丢,跨平台)
mkdir -p /mnt/d/wsl-data
ln -s /mnt/d/wsl-data ~/data

# 方案 3:跑服务用 /opt 或 /srv(生产推荐,符合 FHS)
sudo mkdir -p /opt/myapp/{data,logs,config}
sudo chown -R $USER:$USER /opt/myapp

# FHS 标准用途速查:
#   /opt/<应用名>/  —— 第三方应用(如 /opt/mysql、/opt/idea)
#   /srv/<服务>/    —— 服务对外提供的数据(如 /srv/www、/srv/ftp)
#   /var/lib/<服务>/—— 服务运行时数据(MySQL、PostgreSQL 等的默认位置)
#   /home/<用户>/   —— 用户文件

要不要在 Ubuntu 上建 /data

场景 建议
单机自己用,临时存点东西 ❌ 不需要,直接用 ~/data/mnt/d/wsl-data
多用户共享数据 ✅ 建 /data 也可以(CentOS 用户熟悉,迁移成本低)
跑生产服务(数据库、消息队列) ✅ 建独立挂载点,如 /data/mysql/data/kafka
只是从 CentOS 习惯迁移过来 ❌ 不用硬建,用 ~/data/opt/<app>/srv/<svc> 替代更规范

💡 一句话总结:Ubuntu 没提供 /data 不是缺陷,是留给用户规划的权利。如无需特殊规划,建议优先采用方案 1 的 ~/data 作为起点。

5.6.4 在根目录建 /data 也可行,但需充分了解其风险与限制

# 极简做法:根目录直接建
sudo mkdir -p /data
sudo chown -R $USER:$USER /data

适用场景:临时数据、容器卷、一次性实验。
不适用场景:长期重要数据、数据库文件、git 仓库、备份(一旦 WSL 损坏就丢了)。

5.6.5 重要:定期回收虚拟磁盘空间

WSL2 的 ext4.vhdx稀疏文件——在 WSL 里 rm 一个大文件,Windows 侧的 vhdx 不会自动缩小。长时间使用后,Windows 资源管理器显示 vhdx 文件大小为 500 GB,但 WSL 内部实际数据仅占 50 GB——多出的 450 GB 是之前删除文件后未释放的"空洞"空间。

5.6.5.1 先确认你的 ext4.vhdx 在哪

不同安装方式位置不同,先用下面任一命令找到自己的 vhdx 路径

# 方法 1:wsl 命令直接显示(PowerShell)
wsl -l -v
# 输出包含发行版名称、状态及 WSL 版本号(VERSION 列显示 1 或 2)
# 查看发行版安装路径:wsl --manage <DistroName> --show-location(Win11 特定版本支持)或使用 Get-ChildItem 搜索 ext4.vhdx

# 方法 2:全盘搜 ext4.vhdx(最通用,覆盖所有安装方式)
Get-ChildItem C:\,D:\,E:\ -Recurse -Filter ext4.vhdx -ErrorAction SilentlyContinue | Select-Object FullName, Length

# 方法 3:常见路径直接列(按安装方式)
# - Microsoft Store 版:%LOCALAPPDATA%\Packages\CanonicalGroupLimited.*\LocalState\ext4.vhdx
# - Docker Desktop 版:%LOCALAPPDATA%\Docker\wsl\data\ext4.vhdx
# - 手动 wsl --import 版:你 import 时指定的路径,如 D:\wsl\Ubuntu-24.04\ext4.vhdx

常见路径速查表

WSL 来源 典型 vhdx 路径 是否要自己记住
Microsoft Store 安装 C:\Users\<你>\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu24.04LTS_<随机串>\LocalState\ext4.vhdx ❌ 随机串安装后固定不变,可记录备用
Docker Desktop C:\Users\<你>\AppData\Local\Docker\wsl\data\ext4.vhdx ❌ 固定
手动 wsl --import 你 import 时指定的路径,如 D:\wsl\Ubuntu-24.04\ext4.vhdx ✅ 自己定的,最稳
LxRunOffline 安装 安装时指定 ✅ 自己定的

💡 推荐:手动 wsl --import 安装的 WSL,vhdx 路径就是安装时指定的目录,最清楚也最好维护,建议用这种方式安装。

5.6.5.2 手动回收(PowerShell 管理员)

手动 import 的路径 D:\wsl\Ubuntu-24.04\ext4.vhdx 为例(其他路径同理,把路径替换掉即可):

# 1. 关闭所有 WSL 实例(不关会导致 vhdx 被锁,diskpart 失败)
wsl --shutdown

# 2. 用 diskpart 压缩
diskpart

进入 diskpart 后输入:

select vdisk file="D:\wsl\Ubuntu-24.04\ext4.vhdx"
compact vdisk
exit

⚠️ 注意

  • 管理员 PowerShell 运行(否则 diskpart 报"权限不足")
  • WSL 要已关(否则 vhdx 被占用会报"文件正被另一个进程使用")
  • compact vdisk 期间会临时再占用 1~2 倍当前 vhdx 大小的空闲空间(D 盘至少留 50%)
5.6.5.3 一键脚本(推荐每月跑一次)

把脚本放在 D:\wsl\compact-ubuntu.ps1右键 → 使用 PowerShell 管理员运行

# =============================================
# D:\wsl\compact-ubuntu.ps1
# 用途:回收 WSL2 手动 import 的 ext4.vhdx 占用空间
# 用法:右键 → 使用 PowerShell 管理员运行
# =============================================

# 1. 关闭所有 WSL 实例
wsl --shutdown
Start-Sleep -Seconds 3

# 2. 配置 vhdx 路径(手动 import 时的路径,常见在 D:\wsl\ 下)
$vhdxPath = "D:\wsl\Ubuntu-24.04\ext4.vhdx"

# 如果你用 Microsoft Store 版,把上面换成:
# $vhdxPath = "$env:LOCALAPPDATA\Packages\CanonicalGroupLimited.*\LocalState\ext4.vhdx" | Get-ChildItem | Select-Object -First 1 -ExpandProperty FullName

# 3. 校验
if (-not (Test-Path $vhdxPath)) {
    Write-Error "❌ 找不到 vhdx:$vhdxPath"
    Write-Host "请用 Get-ChildItem 搜索 vhdx 位置后修改脚本"
    exit 1
}

$beforeGB = [math]::Round((Get-Item $vhdxPath).Length / 1GB, 2)
Write-Host "📦 压缩前:$beforeGB GB" -ForegroundColor Cyan

# 4. 写临时 diskpart 脚本
$tmp = Join-Path $env:TEMP "compact-wsl-$PID.txt"
"select vdisk file=`"$vhdxPath`"" | Out-File -Encoding ascii $tmp
"compact vdisk" | Out-File -Append -Encoding ascii $tmp

# 5. 执行(会跑几十秒到几分钟,vhdx 越大越久)
diskpart /s $tmp
Remove-Item $tmp

# 6. 报告
$afterGB = [math]::Round((Get-Item $vhdxPath).Length / 1GB, 2)
$saved = [math]::Round($beforeGB - $afterGB, 2)
Write-Host "📦 压缩后:$afterGB GB(回收 $saved GB)" -ForegroundColor Green

输出示例

📦 压缩前:85.30 GB
Virtual Disk Service utility...
  100 percent completed.
DiskPart successfully compacted the virtual disk file.

📦 压缩后:22.10 GB(回收 63.20 GB)
5.6.5.4 高级用法:定时自动回收

把脚本加入 Windows 任务计划程序(每月 1 号凌晨 2 点自动跑,无需手动操作):

# 在管理员 PowerShell 里执行一次即可
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File D:\wsl\compact-ubuntu.ps1"
$trigger = New-ScheduledTaskTrigger -Monthly -DaysOfMonth 1 -At "02:00"
Register-ScheduledTask -TaskName "WSL Compact vhdx" -Action $action -Trigger $trigger -RunLevel Highest -Description "每月压缩 WSL 虚拟磁盘"

查看 / 删除任务:

Get-ScheduledTask -TaskName "WSL Compact vhdx"        # 查看
Unregister-ScheduledTask -TaskName "WSL Compact vhdx" # 删除

5.6.6 WSL 常用运维命令

# 查看 WSL 版本和状态(Windows PowerShell)
wsl -l -v

# 关闭所有 WSL 实例
wsl --shutdown

# 导出当前发行版做备份(PowerShell)
wsl --export Ubuntu D:\wsl-backup\ubuntu-$(Get-Date -Format yyyyMMdd).tar

# 从备份恢复(PowerShell)
wsl --import Ubuntu C:\WSL\Ubuntu D:\wsl-backup\ubuntu-xxx.tar

# 设置默认登录用户(root → ubuntu)
ubuntu config --default-user ubuntu   # Microsoft Store 版
# 或在 /etc/wsl.conf 加:
# [user]
# default = ubuntu

5.6.7 常见误区

误区 正确做法
"在 / 建文件夹要分配空间" mkdir 只创建目录项,不预分配磁盘空间;写入文件时才实际占用
"none 7.8G 满了怎么办" none 是 WSL 内部 9P 通道(内存映射),不是磁盘存储;占用高时重启 WSL(wsl --shutdown)即可释放
"WSL 里删了大文件,Windows 磁盘空间没释放" WSL2 的 ext4.vhdx 是稀疏文件,删除文件后不会自动缩小;需要用 diskpart compact vdisk 手动压缩回收
"根目录可以无限写" ext4.vhdx 配置上限限制(默认 256 GB,可手动扩展)
"重装 WSL 还能找到根目录数据" 不能!WSL 重装会重置根目录;重要数据务必放 /mnt/c/mnt/d 或外部盘

5.6.8 WSL 网络配置与 Windows 互通

💡 谁需要看本节:WSL2 用户(Microsoft Store 安装 / Docker Desktop / wsl --import / LxRunOffline 任一方式)。
❌ 谁可以跳过:物理机、云服务器、VMware/VirtualBox 虚拟机用户(按 4.1 节 Netplan 配置即可)。

📋 WSL 前置准备
阅读本节前,建议先完成以下两项通用配置:

后续各节默认你已启用 systemd,不再重复解释 hostnamectl / timedatectl / systemctl 的前提条件。

5.6.8.1 为什么 Netplan 在 WSL 里改了不生效?

WSL2 的网络栈完全由 Windows 虚拟出来,跟真机差异巨大:

项目 标准 Ubuntu 24.04 WSL2 Ubuntu
网络栈 真实物理网卡,靠 Netplan / systemd-networkd 管理 微软虚拟的 vNIC(eth0),IP 由 Windows 虚拟 DHCP 给
配置文件 /etc/netplan/*.yaml 生效 改完会被 WSL 启动时覆盖
改静态 IP 改 yaml + netplan apply 必须改 Windows 侧的 %USERPROFILE%\.wslconfig
网卡名 ens33 / enp0s3 等(按硬件命名) 永远是 eth0
配置文件目录 /etc/netplan/ 通常有内容 /etc/netplan/ 经常是空的(典型 WSL 标志)

快速判断你是不是 WSL

# 三个特征命中 2 个以上 = 99% 是 WSL
ls /etc/netplan/ 2>/dev/null | wc -l        # WSL 一般是 0
cat /proc/version | grep -i microsoft        # 含 "microsoft" 字样
cat /proc/sys/kernel/osrelease | grep WSL2   # 含 "microsoft-standard-WSL2"
5.6.8.2 WSL 配置文件位置
文件 位置(在 Windows 侧!) 作用
.wslconfig C:\Users\<你>\.wslconfig 全局 WSL2 配置(网络模式、内存、CPU、镜像等)
wsl.conf /etc/wsl.conf(WSL 内) 单发行版配置(默认用户、挂载、自动挂载选项等)
Netplan yaml /etc/netplan/*.yaml WSL 忽略
5.6.8.3 三种网络模式对比
模式 配置项 特点 适用场景
NAT(默认) (不配) WSL 跟 Windows 共享 IP,外部看到的是 Windows 的 IP;从 Windows 访问 WSL 服务用 localhost:端口 日常开发,对外不暴露服务
Mirrored 镜像(推荐) networkingMode=mirrored WSL 跟 Windows 共享同一网络栈;WSL 服务在局域网里有独立 IP 跨 VPN 调试、WSL 服务需被局域网访问、跑 Docker
Bridged 桥接 wsl --set-version <distro> 1 后用 Hyper-V 桥接 WSL 跟物理机同网段 WSL1 已淘汰,WSL2 不支持
5.6.8.4 推荐配置:.wslconfig(Windows 侧)

Windows PowerShell 里创建/编辑:

# 用记事本编辑(或改用 code $env:USERPROFILE\.wslconfig 以 VSCode 打开)
notepad $env:USERPROFILE\.wslconfig
# =============================================
# C:\Users\<你>\.wslconfig
# WSL2 全局配置
# =============================================
[wsl2]
# 网络:镜像模式(Win11 22H2+ 支持,跨 VPN、跑服务都方便)
networkingMode=mirrored

# DNS:让 WSL 复用 Windows 的 DNS 解析(避免 DNS 污染 / 跨 VPN 失效)
dnsTunneling=true

# 防火墙:WSL 服务走 Windows 防火墙
firewall=true

# 代理:自动走 Windows 系统代理
autoProxy=true

# =============================================
# 资源限制(按需调整)
# =============================================
# 内存上限(默认 = Windows 总内存的 50% 或 8 GB)
memory=8GB

# CPU 核心数
processors=4

# 交换内存
swap=4GB

# 禁用内存自动回收(长任务运行期间避免内存回收导致卡顿;空闲时仍保留已分配内存)
vmIdleTimeout=-1

# =============================================
# 高级:限制 WSL 能看到的 Windows 盘(最小化挂载)
# =============================================
# 取消下一行注释后,WSL 默认不挂载 Windows 盘,需要时手动 mount
# defaultMountOptions=metadata,umask=22,fmask=11

让配置生效

wsl --shutdown
# 重新打开 WSL 终端

验证镜像模式已启用

# 在 WSL 里
ip addr show eth0
# 看到 inet 192.168.x.x/24 或 10.x.x.x  → 镜像模式生效
# 看到 inet 172.x.x.x/20 → 还是 NAT 模式(配置没生效)

# 测试 DNS 是否走 Windows
nslookup baidu.com
# Server 应该是 127.0.0.1 或 Windows 侧 DNS,不是 8.8.8.8
5.6.8.5 单发行版配置:/etc/wsl.conf(WSL 内)
sudo vim /etc/wsl.conf
# =============================================
# /etc/wsl.conf —— 单发行版配置
# =============================================
[user]
# 默认登录用户(root 改成普通用户)
default = ubuntu

[boot]
# ⭐ 关键:启用 systemd(不加这条,所有 *ctl 工具不能用)
systemd=true
# 启动时执行的命令(启用 systemd 后会被忽略,留着兼容)
command = "service ssh start"

[automount]
# 是否自动挂载 Windows 盘(C:\、D:\ → /mnt/c、/mnt/d)
enabled = true
# 挂载选项:metadata 让 Windows 盘里的文件可设 Linux 权限
options = "metadata,umask=22,fmask=11"

[network]
# ⚠️ 设为 false:避免 WSL 自动覆盖 /etc/hosts(让 hostnamectl 改的主机名能持久)
generateHosts = false
# DNS 仍由 Windows 提供
generateResolvConf = true

[interop]
# 是否允许从 WSL 启动 Windows 程序
enabled = true

关键配置说明

字段 作用 加不加?
[boot] systemd=true 启用 systemd(hostnamectl / timedatectl / systemctl 全部能用) 加(用 systemctl 等工具的前提)
[boot] command = ... 启动时执行的命令(启用 systemd 后会被忽略) 可选(兼容保留)
[network] generateHosts = false 不自动覆盖 /etc/hosts ✅ 改了主机名/自定义 hosts 时加
[network] generateResolvConf = true DNS 走 Windows 默认即可
[automount] enabled = true 自动挂载 Windows 盘到 /mnt/c /mnt/d 默认即可
[interop] enabled = true 允许从 WSL 启动 Windows 程序 默认即可

让 wsl.conf 生效

# Windows PowerShell
wsl --shutdown
# 重开 WSL 终端

完整配置流程(推荐逐步走):

# 1. 备份现有 wsl.conf(如果有)
sudo cp /etc/wsl.conf /etc/wsl.conf.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null

# 2. 用 sed 安全方式追加各段(不覆盖已有内容)
# [user] 段
if ! grep -q "^\[user\]" /etc/wsl.conf; then
  echo "[user]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "default = ubuntu" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# [boot] 段
if ! grep -q "^\[boot\]" /etc/wsl.conf; then
  echo "[boot]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "systemd=true" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "command = \"service ssh start\"" | sudo tee -a /etc/wsl.conf > /dev/null
else
  # [boot] 段已存在,确保有 systemd=true
  if ! grep -q "^systemd=true" /etc/wsl.conf; then
    sudo sed -i '/^\[boot\]/a systemd=true' /etc/wsl.conf
  fi
fi

# [network] 段
if ! grep -q "^\[network\]" /etc/wsl.conf; then
  echo "[network]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateHosts = false" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateResolvConf = true" | sudo tee -a /etc/wsl.conf > /dev/null
else
  # [network] 段已存在,把 generateHosts 改为 false(如果现在是 true)
  if grep -q "^generateHosts = true" /etc/wsl.conf; then
    sudo sed -i 's/^generateHosts = true/generateHosts = false/' /etc/wsl.conf
  fi
fi

# 3. 验证
cat /etc/wsl.conf

⚠️ 覆盖风险tee > /dev/null << EOF ... EOF完全覆盖整个文件——不要直接用覆盖式 heredoc。cp 备份再操作。

5.6.8.6 WSL 与 Windows 互访
方向 方法 示例
WSL → Windows 文件 /mnt/c/mnt/d cat /mnt/c/Windows/System32/drivers/etc/hosts
WSL → Windows 网络 Windows IP(不是 WSL IP) curl http://$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):8080
WSL → 启动 Windows 程序 直接 .exe explorer.exe .(打开当前目录) notepad.exe file.txt
Windows → WSL 文件 \\wsl$\Ubuntu-24.04\ 资源管理器地址栏输 \\wsl$\Ubuntu-24.04\home\ubuntu\
Windows → WSL 网络(NAT 模式) localhost:端口 localhost:3000 localhost:5432
Windows → WSL 网络(镜像模式) WSL 的 IP 或 localhost curl http://$(wsl hostname -I):8080

实战示例:VSCode 连 WSL

# 1. WSL 内启动一个 Web 服务
python3 -m http.server 8000

# 2. Windows 侧三种访问方式(镜像模式)
#    方式 a(推荐):localhost:8000
#    方式 b:WSL IP:8000(先 wsl hostname -I 查 IP)
#    方式 c:\\wsl$\Ubuntu-24.04\ 资源管理器打开

# 3. 跨设备访问(镜像模式独有的能力)
#    局域网里另一台机器直接访问 http://<Windows IP>:8000
#    NAT 模式做不到
5.6.8.7 常见 WSL 网络坑
症状 原因 解决
ping baidu.com 不通但 curl WSL 默认不允许 ICMP(微软设计) curl / wget 测试连通,或 sudo iptables -I INPUT -p icmp --icmp-type echo-request -j ACCEPT(重启失效)
改完 wsl.conf 不生效 wsl --shutdown 重启 WSL
跨 VPN 后 WSL 断网 NAT 模式下 WSL 路由被 VPN 接管 改成镜像模式 networkingMode=mirrored
WSL 服务在 Windows 访问不到 NAT 模式下端口未映射 镜像模式自动通;NAT 模式要 netsh interface portproxy
镜像网络下,Windows 通过 WSL IP 访问服务超时 hostAddressLoopback 未开启,Windows 物理网卡入站流量被拦截 .wslconfig[experimental] 段加 hostAddressLoopback=truewsl --shutdown 后重启;详见 5.6.8.15
镜像模式下 WSL 占用 IP 冲突 跟物理网络 IP 段重叠 .wslconfignetworkingMode=nat 退回,或在路由器侧预留 IP 段
ssh 从 WSL 连不上 Windows 的服务 Windows 防火墙挡住 Windows 防火墙放行对应端口,或暂时关防火墙测试
sudo vim 启动后乱码/卡顿;sudounable to resolve host sudo 反向解析主机名失败(/etc/hosts 缺当前主机名) 127.0.1.1 <当前主机名> 追加到 /etc/hosts;详见 5.6.8.10
hostnamectlCan't operate WSL 未启用 systemd /etc/wsl.conf[boot] systemd=truewsl --shutdown 后重启;详见 5.6.8.11
timedatectlCan't operatesystemctlFailed to connect to bus WSL 未启用 systemd 同上,启用 systemd;详见 5.6.8.11
sudo ufw allowERROR: problem running WSL2 微软内核没编译老 iptables 模块 切到 nftables 后端后 reset + enable;详见 5.6.8.13
5.6.8.8 WSL 网络排障命令速查
# 查看 WSL 网络模式
ip addr show eth0 | grep inet

# 查看 DNS 配置
cat /etc/resolv.conf

# 查看默认路由
ip route show default

# 测试连通性(注意 ping 不通不代表网络断)
curl -v http://baidu.com          # HTTP 测试
nc -zv baidu.com 80               # 端口测试
traceroute baidu.com              # 路由追踪

# 查看 WSL 版本
wsl.exe --status                 # 在 WSL 内调用 Windows 工具

# 查看 Windows 侧 .wslconfig
cat /mnt/c/Users/$(whoami)/../.wslconfig   # 注意路径映射
# 或在 PowerShell:Get-Content $env:USERPROFILE\.wslconfig
5.6.8.9 WSL 主机名设置

💡 本节内容:WSL 下设置主机名的方法。

⚠️ 关键前提:先完成 5.6.8.11 启用 systemd。如果希望主机名重启后不丢,还需在 /etc/wsl.conf 中配置 [network] 段。

完整配置流程(按顺序执行)

第 1 步:确认 /etc/wsl.conf 已启用 systemd 和 network 配置

cat /etc/wsl.conf

确保包含以下段(没有则按 5.6.8.5 或 5.6.8.11 配置):

[boot]
systemd=true

[network]
# 禁用 WSL 自动覆盖 /etc/hosts(改了主机名后建议加,否则 systemd-hostnamed 改的主机名会被覆盖)
generateHosts = false
# 显式指定 WSL 主机名(希望主机名不被 Windows 计算机名覆盖时加)
hostname = dev-workspace

📋 为什么加 hostname = xxx 能持久化

  • WSL 默认行为:每次启动时用 Windows 计算机名覆盖 Linux 主机名
  • 只加 generateHosts = false 只能阻止 /etc/hosts 被覆盖
  • hostname = dev-workspace 才能阻止 WSL 覆盖主机名本身

第 2 步:用 hostnamectl 设置主机名(标准 Linux 方式)

# 确认 systemd 已启用
ps -p 1 -o comm=
# 应该是 systemd

# 设置主机名
sudo hostnamectl set-hostname dev-workspace

第 3 步:同步 /etc/hosts(防止 sudo 解析失败)

# 把新主机名追加到 /etc/hosts(用追加,不要覆盖)
echo "127.0.1.1 dev-workspace" | sudo tee -a /etc/hosts

# 验证 sudo 不再报 "unable to resolve host"
sudo whoami
# 应直接返回 root,无警告

⚠️ 为什么改完主机名还要同步 /etc/hosts

  • hostnamectl 只改 /etc/hostname,不会自动同步 /etc/hosts
  • WSL 也不会自动同步(真机 Ubuntu 通常有 hook 会做)
  • sudo 启动时会反向解析主机名,解析失败则输出 unable to resolve host 警告,该错误输出会干扰终端控制序列状态,导致 vim 等交互程序异常

第 4 步:重启 WSL 让配置永久生效

exit

Windows PowerShell

wsl --shutdown
# 重新打开 WSL

第 5 步:验证

hostname
# 输出:dev-workspace

hostnamectl
# Static hostname: dev-workspace

cat /etc/hostname
# dev-workspace

cat /etc/hosts | grep dev-workspace
# 127.0.1.1 dev-workspace

sudo whoami
# 无 "unable to resolve host" 警告

未启用 systemd 时(兜底方案)

# 直接编辑 /etc/hostname
echo "dev-workspace" | sudo tee /etc/hostname

# 同步 /etc/hosts
echo "127.0.1.1 dev-workspace" | sudo tee -a /etc/hosts

# 然后 Windows PowerShell 跑 wsl --shutdown,重启 WSL

WSL 主机名命名建议(避免隐私泄露):

  • dev-workspaceubuntu-devlinux-sandbox —— 通用名,安全
  • ⚠️ 用户名缩写公司名项目名 —— 可能暴露身份
  • 真实姓名拼音手机号工号 —— 直接隐私泄露
  • 限制:小写字母 + 数字 + 中划线(DNS 兼容),≤ 63 字符

🔗 相关章节

  • 5.6.8.5 /etc/wsl.conf 单发行版配置 —— [network] 段详解
  • 5.6.8.10 WSL sudo 解析陷阱 —— 改主机名后 vim/sudo 异常的修复
  • 5.6.8.11 WSL 启用 systemd —— hostnamectl 的前提
  • 5.6.8.11.1 WSL 重启的正确方式 —— 改完 wsl.conf 怎么生效(不要 sudo reboot
5.6.8.10 WSL sudo 解析陷阱:改了主机名后 vim 无法启动

💡 本节来源:真实踩坑案例。hostnamectl set-hostname 改了主机名后没同步 /etc/hosts,导致 sudo 反向解析失败、vim 启动异常、^C 乱按后命令错乱,所有问题互相放大,陷入死循环。

症状清单(任一出现就要怀疑本节问题):

sudo vim /etc/hosts
# 现象:vim 启动后光标错乱、按键无反应、^C 退不出
# 同时终端刷:
sudo: unable to resolve host dev-workspace: Temporary failure in name resolution

sudo whoami
# 现象:能返回 root,但每次都刷"unable to resolve host"
# 命令本身能执行,但**会向终端输出错误信息并残留异常控制字符**,导致后续 vim/apt 等交互式程序异常

根因

步骤 真机 WSL
hostnamectl set-hostname xxx 写入 /etc/hostname
/etc/hosts 自动同步 ✅(很多发行版有 hook) WSL 不会自动同步
sudo 启动时反向解析 xxx 找到 解析失败 → 报 warning + 污染终端

完整的修复流程(按顺序,不要跳步):

第 1 步:把当前主机名追加到 /etc/hosts(核心,1 行解决)

📋 提示:这一步其实就是 5.6.8.9 主机名设置 中“第 3 步:同步 /etc/hosts”。如果你按 5.6.8.9 的标准流程操作过,通常不会遇到本节故障。

echo "127.0.1.1 $(hostname)" | sudo tee -a /etc/hosts

输出:

127.0.1.1 dev-workspace        ← tee 写成功

⚠️ 用 tee -a(追加),不要用 >(覆盖)—— /etc/hosts 还有 localhost 等关键行,覆盖掉会导致更多问题

第 2 步:立刻验证 sudo 恢复正常

sudo whoami
# 应直接返回 root 或 ubuntu,无 "unable to resolve host" 警告

第 3 步:用 tee/etc/wsl.conf(持久化主机名)

📋 提示:更通用的 wsl.conf 安全编辑脚本(含 [user][boot][automount][interop] 等段)请参考 5.6.8.5 单发行版配置。本节脚本针对本故障场景精简,重点确保 generateHosts = falsehostname 正确写入。

⚠️ 不要用 vim —— 此时 vim 可能仍处于异常状态。tee 写多个段,但要先备份

# 先备份
sudo cp /etc/wsl.conf /etc/wsl.conf.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null

# 用 sed 逐段写(每段追加,不覆盖已有内容)
if ! grep -q "^\[user\]" /etc/wsl.conf; then
  echo "[user]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "default = ubuntu" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "" | sudo tee -a /etc/wsl.conf > /dev/null
fi

if ! grep -q "^\[boot\]" /etc/wsl.conf; then
  echo "[boot]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "systemd=true" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "" | sudo tee -a /etc/wsl.conf > /dev/null
fi

if ! grep -q "^\[network\]" /etc/wsl.conf; then
  echo "[network]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateHosts = false" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateResolvConf = true" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "hostname = dev-workspace" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# 验证
cat /etc/wsl.conf

📋 命令解读

  • grep -q "^\[xxx\]":检查段是否存在
  • if ! ... then ... fi:段不存在才追加
  • sudo tee -a /etc/wsl.conf:以 root 权限追加到文件
  • echo "..." | sudo tee -a:逐行追加写入,避免覆盖已有内容

第 4 步:PowerShell 重启 WSL,让 wsl.conf 永久生效

wsl --shutdown
# 重开 WSL 终端

第 5 步:验证

hostnamectl              # Static hostname: dev-workspace(永久)
hostname                 # dev-workspace
cat /etc/hostname        # dev-workspace
cat /etc/hosts           # 包含 127.0.1.1 dev-workspace
sudo whoami              # 无警告

为什么用 tee 不用 vim

方式 优点 缺点
sudo vim /etc/wsl.conf 可视化、所见即所得 此时 vim 可能因 sudo 解析问题卡死;按 Ctrl+C 可能导致终端状态异常或命令残留
sudo tee ... <<'EOF' 一次性写完,完全绕开 vim;可粘贴整段 不能像 vim 那样交互编辑(但本场景是"几行配置一次写完",不需要)
echo "..." | sudo tee -a 追加一行最方便 只能追加一行

故障状态下的"应急三连"(按顺序复制粘贴,不要按 Ctrl+C):

# 1. 把当前主机名写进 hosts
echo "127.0.1.1 $(hostname)" | sudo tee -a /etc/hosts

# 2. 立刻验证
sudo whoami

# 3. 用 sed 写 wsl.conf(不覆盖已有内容,paste 不易切分)
sudo cp /etc/wsl.conf /etc/wsl.conf.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null

# [user] 段
if ! grep -q "^\[user\]" /etc/wsl.conf; then
  echo "[user]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "default = ubuntu" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# [boot] 段
if ! grep -q "^\[boot\]" /etc/wsl.conf; then
  echo "[boot]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "command = \"service ssh start\"" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# [network] 段
if ! grep -q "^\[network\]" /etc/wsl.conf; then
  echo "[network]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateHosts = false" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "generateResolvConf = true" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# [hostname] 段
if ! grep -q "^\[hostname\]" /etc/wsl.conf; then
  echo "[hostname]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "hostname = dev-workspace" | sudo tee -a /etc/wsl.conf > /dev/null
fi

执行上述三步操作后,vim 将恢复正常,主机名配置也将永久生效。

关于 WSL 终端里的 Ctrl+C

⚠️ WSL 终端中按 Ctrl+C 会发送 SIGINT 信号。注意:在命令行输入过程中,若光标位于行首时按 Ctrl+C,可能导致异常行为:

  • 可能导致命令首字符被截断(如 echo 变为 cho
  • 可能中断正在执行的 tee / cat / apt 等命令,导致操作不完整
  • 可能使 vim / nano 进入异常状态

最稳的做法:右键 → 粘贴(WSL 终端支持),或者用 ↑ 方向键调出历史命令再编辑。

预防措施改主机名前先做这两件事,可避免整个坑):

# 改主机名之前先把旧的写进 hosts(以防万一)
echo "127.0.1.1 $(hostname)" | sudo tee -a /etc/hosts

# 再改主机名
sudo hostnamectl set-hostname dev-workspace

# 立刻把新的也写进 hosts
echo "127.0.1.1 dev-workspace" | sudo tee -a /etc/hosts

或一条命令解决(最推荐):

sudo hostnamectl set-hostname dev-workspace && \
  echo "127.0.1.1 dev-workspace" | sudo tee -a /etc/hosts

🔗 相关章节

  • 4.1 配置静态 IP(Netplan)—— 真机/云服务器用
  • 4.2 配置主机名 —— 真机方案,WSL 见 5.6.8.9 WSL 主机名设置
  • 5.6.5 定期回收虚拟磁盘 —— vhdx 维护
  • 5.6.6 WSL 常用运维命令 —— wsl --export/--import/--shutdown
  • 5.6.8.9 WSL 主机名持久化 —— 改主机名的标准做法
  • 5.6.8.10 —— 改主机名时 sudo 报错的完整修复
  • 5.6.8.11 —— WSL 非 systemd 模式下的 hosts 自动化维护(当前节)
  • 5.6.8.11.1 WSL 重启的正确方式 —— 改完 wsl.conf 怎么生效
5.6.8.11 WSL 启用 systemd

💡 本节内容:WSL2 启用 systemd 的标准方法——适用于任何 WSL2 发行版(不论是 Microsoft Store 装的还是 wsl --import 装的)。

为什么启用 systemd

工具 启用 systemd 后 未启用
systemctl start ssh ❌ 改用 service ssh start
hostnamectl set-hostname ❌ 手动改 /etc/hostname
timedatectl set-timezone ❌ 手动 ln -s 软链
journalctl -u ssh ❌ 改用 cat /var/log/auth.log
localectlloginctl

启用步骤(3 步,适用于所有 WSL2):

📋 提示:如果你需要一次性配置完整的 wsl.conf(含 [user][network][automount] 等段),请参考 5.6.8.5 单发行版配置。本节只聚焦如何单独启用 systemd

第 1 步:在 WSL 内编辑 /etc/wsl.conf

# 先备份(防止覆盖掉其他段)
sudo cp /etc/wsl.conf /etc/wsl.conf.bak.$(date +%Y%m%d%H%M%S) 2>/dev/null

# 看现有内容(确认有没有要保留的段)
cat /etc/wsl.conf

# 安全方式:在现有 [boot] 段追加 systemd=true(如段不存在则新建)
if grep -q "^\[boot\]" /etc/wsl.conf; then
  sudo sed -i '/^\[boot\]/a systemd=true' /etc/wsl.conf
else
  # 追加 [boot] 段到文件末尾
  echo "" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "[boot]" | sudo tee -a /etc/wsl.conf > /dev/null
  echo "systemd=true" | sudo tee -a /etc/wsl.conf > /dev/null
fi

# 验证
cat /etc/wsl.conf
# 应该有 [boot] systemd=true

⚠️ 覆盖风险提示tee > /dev/null << EOF ... EOF完全覆盖整个文件——如果 /etc/wsl.conf 已有 [user][network] 等段,会被清空不要直接 tee 覆盖已有配置文件,cp 备份 + cat 看清楚再操作。

第 2 步:在 Windows PowerShell 重启 WSL

wsl --shutdown

第 3 步:重开 WSL 终端,验证

ps -p 1 -o comm=
# 应该输出:systemd

如果还是 init

# 1. 确认 wsl.conf 写对了
cat /etc/wsl.conf
# 应该看到:
#   [boot]
#   systemd=true

# 2. 确认 WSL 版本(要 ≥ 0.67.6)
#    Windows PowerShell:
#    wsl --version

# 3. 再次重启 WSL
#    wsl --shutdown

注意事项

  • ✅ 启用 systemd 后,/etc/wsl.conf[boot] command= 会被忽略(systemd 接管启动流程)——用户服务应该systemctl 管理
  • ✅ 启用 systemd 后,用户服务(如 sshfail2ban)的 systemctl enable 才能真正生效
  • ⚠️ 某些镜像(如 Docker pull 装的)即使加了 [boot] systemd=true 仍启不动——这跟镜像源有关,不是配置问题

反向操作(关掉 systemd):

# 安全方式:把 [boot] 段的 systemd=true 改为 false(其他段保留)
if grep -q "^systemd=true" /etc/wsl.conf; then
  sudo sed -i 's/^systemd=true/systemd=false/' /etc/wsl.conf
fi

# 验证
grep "systemd" /etc/wsl.conf
# 应该输出:systemd=false

# 然后 PowerShell: wsl --shutdown

🔗 相关章节

  • 5.6.8.7 常见 WSL 网络坑 —— 症状速查表(含本节对应行)
  • 5.6.8.11.1 —— WSL 重启的正确方式(当前节的扩展)
5.6.8.11.1 WSL 重启的正确方式

💡 本节内容:WSL 改了哪些配置后必须重启 WSL,以及正确的重启命令

哪些配置改了必须重启 WSL

配置文件 / 操作 是否需要重启 WSL
/etc/wsl.conf(所有段) 必须
~/.wslconfig(Windows 侧) 必须
/etc/systemd/system.conf 必须(systemd 启动时读)
/etc/security/limits.conf ⚠️ 仅 PAM 登录的进程生效(重开终端就够)
普通 systemd 服务配置 ❌ 用 systemctl restart xxx 即可
软件包安装 / 升级 ❌ 直接生效

正确的重启方式在 Windows PowerShell):

# 完全关闭 WSL(下次 wsl 命令会重新启动)
wsl --shutdown

# 重新打开 WSL(在 WSL 终端跑这条会进入默认发行版)
wsl
# 或指定发行版
wsl -d Ubuntu-24.04

⚠️ 关键wsl --shutdown 会强制终止所有 WSL 进程,包括你当前正在修改配置的 SSH 会话。如果通过 SSH 连接到 WSL 执行配置修改,必须先退出该 SSH 会话,否则 wsl --shutdown 会直接断开连接,可能导致未保存的更改丢失。操作顺序:

  1. 保存所有修改,在 SSH 会话中执行 exit 退出
  2. 在 PowerShell 中关闭 WSL 终端窗口(或执行 exit 退出 WSL 交互式 shell)
  3. 在 PowerShell 中执行 wsl --shutdown
  4. 重新打开 WSL 终端(或重新 SSH 连接)

PowerShell 里单独 exit 只是退出当前 shell 会话,WSL 虚拟机仍在后台运行;若仍有活动连接(如你正在修改配置的那个 SSH 会话),wsl --shutdown 会强制断开它,建议主动退出后再执行。

❌ 不要用 sudo reboot

sudo reboot
# Broadcast message from root@xxx (xxx CST):
# The system will power off now!
# Welcome to Ubuntu ...   ← 看似重启了,其实只是进程重启
行为 sudo reboot(WSL 内部) wsl --shutdown(PowerShell)
杀进程
重启 WSL 服务 不会
重新读 wsl.conf
重新读 system.conf
重新读 .wslconfig
重新分配内存/CPU 限制

📋 根因

  • WSL 不是真硬件,reboot 找不到 BIOS/固件去调用
  • 微软的 WSL 进程管理由 Windows 侧的 LxssManager 服务控制
  • 必须在 Windows 侧让 LxssManager 重新加载所有发行版,wsl --shutdown 就是干这个的
  • 改了 wsl.conf / system.conf 后,没有 wsl --shutdown 就不会重新读

WSL 内部的其他"重启"命令(也都不可靠):

命令 实际行为
sudo reboot 杀进程,不会重启 WSL 服务
sudo shutdown -r now 同上
sudo systemctl reboot 同上
exit(退出 shell) 退当前会话,不重启 WSL

🔗 相关章节

  • 5.6.8.5 /etc/wsl.conf 单发行版配置 —— 改了必须 wsl --shutdown
  • 5.6.8.7 常见 WSL 网络坑 —— 改 wsl.conf 不生效的根因
  • 5.6.8.9 WSL 主机名设置 —— 改了 hostname 必须 wsl --shutdown
  • 5.6.8.11 启用 systemd —— 改了 systemd=true 必须 wsl --shutdown
  • 6.3 文件描述符限制 —— 改了 system.conf 必须 wsl --shutdown不要用 sudo reboot
  • 5.6.8.11.1 —— WSL 重启的正确方式(当前节)
5.6.8.12 WSL 时区设置

💡 本节内容:WSL 下设置时区的方法——优先用 timedatectl(启用 systemd 后),备用 ln -s

推荐方式:启用 systemd 后用 timedatectl

# 1. 确保启用了 systemd(见 [5.6.8.11 WSL 启用 systemd](#56811-wsl-启用-systemd))
ps -p 1 -o comm=
# 应该是 systemd

# 2. 设置时区
sudo timedatectl set-timezone Asia/Shanghai

# 3. 验证
date
# 应该输出 CST 时间
# Tue Jun 11 14:23:45 CST 2026

未启用 systemd 时(兜底)/etc/localtime 软链

# 1. 查看当前时区
ls -l /etc/localtime

# 2. 改时区
sudo unlink /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 3. 验证
date

常用时区速查

城市/地区 时区标识
上海/北京 Asia/Shanghai
香港 Asia/Hong_Kong
台北 Asia/Taipei
东京 Asia/Tokyo
新加坡 Asia/Singapore
UTC(默认) Etc/UTC
美国西部 America/Los_Angeles
美国东部 America/New_York
欧洲伦敦 Europe/London
欧洲柏林 Europe/Berlin

交互式菜单(更直观):

sudo dpkg-reconfigure tzdata
# 选 "Asia" → 选城市

⚠️ 注意:交互式菜单在某些终端会乱码——timedatectlln -s 更稳

WSL 时间同步

WSL2 的时间默认和 Windows 同步(WSL 启动时从 Windows 校准一次),所以一般不需要单独配 NTP。如果发现时间漂移:

# 启用 systemd 后:用 timedatectl 触发同步
sudo timedatectl timesync-status

# 未启用 systemd:手动重读硬件时钟
sudo hwclock -s

🔗 相关章节

  • 4.3 时区与时间同步 —— 真机方案
  • 5.6.8.7 常见 WSL 网络坑 —— 症状速查表
  • 5.6.8.11 WSL 启用 systemd —— timedatectl 的前提
  • 5.6.8.12 —— WSL 时区设置(当前节)
5.6.8.13 WSL 防火墙:ufw 修复 + nftables 兜底

💡 本节来源:6.1 ufw 防火墙节在 WSL2 下直接跑会报 ERROR: problem running,根因是 WSL2 的微软定制内核(Linux 6.6.114.1-microsoft-standard-WSL2没编译老 iptables 模块。本节给出完整的修复流程直接绕开 ufw 的兜底方案

症状(任一出现就是本节场景):

sudo ufw allow 80/tcp
# ERROR: problem running

sudo ufw status
# 同样的报错,或者状态异常

sudo iptables -L INPUT -n
# modprobe: FATAL: Module ip_tables not found
# iptables v1.8.x (legacy): can't initialize iptables table `filter': ...

根因

组件 状态
WSL2 微软内核 ip_tablesiptable_filter 等老 iptables 内核模块
WSL2 微软内核 nftables 内核后端(/proc/net/netfilter/nf_tables_api 存在)
ufw 0.36+ 默认走 nftables 后端(但有 bug 仍优先调用老 iptables)

结论:WSL 下 ufw 需要切到 nftables 后端才能正常用。

完整修复流程(5 步,按顺序跑):

第 1 步:重置 ufw 状态

sudo ufw --force reset
# 会自动备份旧规则到 /etc/ufw/*.rules.<时间戳>

第 2 步:切到 nftables 后端

sudo update-alternatives --set iptables /usr/sbin/iptables-nft
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
sudo update-alternatives --set arptables /usr/sbin/arptables-nft
sudo update-alternatives --set ebtables /usr/sbin/ebtables-nft

📋 update-alternatives 是什么:Debian/Ubuntu 的"多版本切换器",把 /usr/sbin/iptables 指向 iptables-nft(即"用 nftables 内核后端模拟 iptables 命令")。

第 3 步:验证 nftables 可用

sudo nft list tables
# 预期输出(空或已有表都行,不要报错):
# table ip filter
# table ip6 filter

第 4 步:重新启用 ufw

sudo ufw --force enable
# 预期输出:Firewall is active and enabled on system startup

第 5 步:加规则并验证

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

sudo ufw status verbose
# 预期看到 22/80/443 全部 ALLOW IN,IPv4 + IPv6 都有

完整输出应该长这样

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

如果第 5 步还报 ERROR: problem running

# 看 ufw 真实的报错
sudo ufw --debug 2>&1 | tail -30

会输出具体的 iptables/nft 调用和报错,对症下药。

兜底方案 A:直接用 nftables(最稳)

绕开 ufw,直接操作 nftables 内核后端:

# 1. 初始化一个干净的 filter 表
sudo nft flush ruleset
sudo nft add table inet filter
sudo nft 'add chain inet filter input { type filter hook input priority 0 ; }'

# 2. 放行 SSH / HTTP / HTTPS
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } accept

# 3. 允许本地回环(loopback)
sudo nft add rule inet filter input iif lo accept

# 4. 允许已建立的连接
sudo nft add rule inet filter input ct state established,related accept

# 5. 默认拒绝入站
sudo nft 'add chain inet filter input { type filter hook input priority 0 ; policy drop ; }'

# 6. 看规则
sudo nft list ruleset

兜底方案 B:直接用 iptables(简单场景)

# 放行常用端口
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 持久化(重启 WSL 自动恢复)
sudo apt install -y iptables-persistent
sudo netfilter-persistent save

⚠️ 互斥提示apt install iptables-persistent自动卸载 ufw(包依赖冲突)。卸了 ufw 后,所有 ufw allow / ufw status 命令全部失效,只能直接用 iptables/nftables。

如果你想保留 ufw 工具:跳过 iptables-persistent,用 方案 A 的 nftables 直接配(启用 systemd 后用 systemctl 管理更稳)。

完整流程图(修防火墙的判断路径):

sudo ufw allow 80/tcp
        │
        ▼
   报 ERROR: problem running?
        │
   ┌────┴────┐
   │         │
  否         是
   │         │
   ▼         ▼
  继续     sudo ufw --force reset
           sudo update-alternatives --set iptables /usr/sbin/iptables-nft
           sudo nft list tables        ← 验证 nft 可用
           sudo ufw --force enable
           sudo ufw allow 22/tcp ...
           sudo ufw status verbose
                   │
            ┌──────┴──────┐
            │             │
          成功          还报 ERROR
            │             │
            ▼             ▼
         完成       用 nftables 直接配
                    (兜底方案 A)

为什么 sudo ufw allow 80/tcp 第二次跑会报 "Skipping adding existing rule"

这个提示不是新错误。它说明第一次跑的时候 ufw 配置文件已经写入了规则,但同步到底层 iptables 失败。所以第二次跑 ufw 看到"规则已存在",跳过添加。

这时直接 reset 就能清掉旧配置,重新配。

与 6.1 节的关系

解决的问题 适用场景
3.6 真机/云服务器的 SSH 放行 标准 Ubuntu
6.1 真机/云服务器的 HTTP/HTTPS/复杂规则 标准 Ubuntu
5.6.8.13(本节) WSL 下 ufw 报错的修复 + 兜底 WSL2 微软内核

🔗 相关章节

  • 3.6 防火墙放行 SSH —— 真机首次配置
  • 6.1 ufw 防火墙 —— 真机常用规则
  • 5.6.8.7 常见 WSL 网络坑 —— 症状速查表(含本节对应行)
  • 5.6.8.13 —— WSL 防火墙修复(当前节)
5.6.8.14 WSL 配置文件参考

💡 本节给出启用 systemd 后 WSL 配置文件的参考样例**。

/etc/wsl.conf(WSL 内)

[user]
default = ubuntu

[boot]
systemd=true

[interop]
enabled=true
appendWindowsPath=true

[automount]
enabled=true
mountFsTab=true

[network]
generateHosts = false
generateResolvConf = true
hostname = dev-workspace

📋 各段作用

段 / 字段 作用 加不加?
[user] default = ubuntu 默认登录用户(避免 root 登录) ✅ 加(前提是 ubuntu 用户存在)
[boot] systemd=true 启用 systemd(hostnamectl / timedatectl / systemctl 全部能用) ✅ 加(用 systemd 工具的前提)
[boot] command = ... 启动时执行命令 ❌ 启用了 systemd 就被忽略,不要加
[interop] enabled = true 允许从 WSL 调 Windows 程序(explorer.exe .notepad.exe ✅ 默认即可
[interop] appendWindowsPath = true 把 Windows 的 PATH 加进 WSL 环境变量 ✅ 默认即可(VSCode 远程等工具依赖)
[automount] enabled = true 自动挂载 Windows 盘(/mnt/c/mnt/d ✅ 默认即可
[automount] mountFsTab = true 读取 /etc/fstab 自定义挂载 ✅ 默认即可
[automount] options = "metadata,..." 挂载选项(让 Windows 盘文件可设 Linux 权限) ⚙️ 按需(写文件到 Windows 盘遇到权限问题时加)
[network] generateHosts = false 阻止 WSL 覆盖 /etc/hosts ✅ 改了主机名/自定义 hosts 时加
[network] generateResolvConf = true 让 WSL 自动生成 /etc/resolv.conf(DNS 走 Windows) ✅ 默认即可
[network] hostname = xxx 显式指定 WSL 主机名(不被 Windows 计算机名覆盖) ✅ 希望主机名持久化时加

⚠️ 启用 systemd 后[boot] command = ... 会被忽略——服务管理用 systemctl enable

~/.wslconfig(Windows 侧)

[wsl2]
memory=8GB
swap=2GB

⚠️ [wsl2] 段只放资源限制(内存、CPU、swap 等)——不要再加其他段

📋 内存配置建议

物理内存 推荐 memory 推荐 swap
8 GB 4 GB 2 GB
16 GB 8~12 GB 2~4 GB
32 GB 16~24 GB 2~4 GB
64 GB+ 32 GB 2~4 GB

不要超过 Windows 物理内存的 80%——WSL 跟 Windows 共享内存。swap 一般 2~4 GB 够用。

~/.bashrc 末尾(WSL 内,启用 systemd 后一般不需要)

启用 systemd 后,/etc/hostssystemd-hostnamed 正确管理,不需要 fix_wsl_hosts 函数

Part 2:常用服务管理(启用 systemd 后)

# 1. SSH(详见 [3.1 安装 openssh-server](#31-安装-openssh-server))
sudo apt install -y openssh-server
sudo systemctl enable --now ssh

# 2. fail2ban(详见 [5.1 一键安装清单](#51-一键安装清单) / [6.2 fail2ban 防爆破](#62-fail2ban-防爆破))
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

# 3. ufw 防火墙(详见 [3.6 防火墙放行 SSH](#36-防火墙放行-ssh) / [6.1 ufw 防火墙](#61-ufw-防火墙))
sudo apt install -y ufw
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

# 4. 时区(详见 [4.3 时区与时间同步](#43-时区与时间同步) / [5.6.8.12 WSL 时区设置](#56812-wsl-时区设置))
sudo timedatectl set-timezone Asia/Shanghai

# 5. 主机名(详见 [4.2 配置主机名](#42-配置主机名) / [5.6.8.9 WSL 主机名设置](#5689-wsl-主机名设置))
sudo hostnamectl set-hostname dev-workspace

🔗 相关章节

  • 5.6.8.7 常见 WSL 网络坑 —— 症状速查
  • 5.6.8.9 WSL 主机名设置 —— 启用 systemd 后用 hostnamectl
  • 5.6.8.11 WSL 启用 systemd —— 核心配置([boot] systemd=true
  • 5.6.8.12 WSL 时区设置 —— 启用 systemd 后用 timedatectl
  • 5.6.8.13 WSL 防火墙:ufw + nftables
  • 5.6.8.14 —— 配置文件参考(当前节)
  • 5.6.8.15 —— 镜像网络下 Windows 通过 WSL IP 访问服务超时
5.6.8.15 镜像网络下 Windows 通过 WSL IP 访问服务超时

💡 本节针对 networkingMode=mirrored 镜像网络模式
NAT 模式下用 localhost:端口 即可,不需要本节配置。

问题现象

  • WSL2 内部服务已正常监听,例如 SSH 监听 0.0.0.0:<PORT>,在 WSL 内 curl http://127.0.0.1:<PORT> 正常
  • 从 Windows 侧通过 localhost:<PORT> 访问也正常
  • 但从 Windows 侧通过 WSL2 的 eth0 IP(与宿主机同网段)访问时超时失败
  • 即使 Windows 防火墙已放行该端口,Test-NetConnection -Port <PORT> 仍显示 TcpTestSucceeded : False

根因

镜像网络模式下,WSL2 与 Windows 共享同一网络栈,但 Windows 本机通过物理网卡 IP 入站访问 WSL2 服务时,默认会被拦截。必须显式开启 hostAddressLoopback 实验特性,允许 Windows 将流量环回到 WSL2。

正确配置C:\Users\<你>\.wslconfig):

[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
firewall=true

[experimental]
hostAddressLoopback=true

⚠️ 关键hostAddressLoopback实验性功能,必须放在 [experimental] 段下,不要放在 [wsl2] 下。
放错位置会导致 WSL 启动时报错并忽略该配置,例如:

wsl2.hostAddressLoopback 中的键"hostAddressLoopback"未知(实际报错内容可能因版本而异)

生效步骤

# 1. 保存 .wslconfig 后,彻底关闭 WSL
wsl --shutdown

# 2. 重新打开 WSL 终端
wsl

验证方法

# 在 WSL 内查看 eth0 IP
ip addr show eth0 | grep "inet "
# 输出示例:192.168.x.x/24(与宿主机同网段)
# 在 Windows PowerShell 测试连通性(把 <WSL_IP> 和 <PORT> 替换为实际值)
Test-NetConnection -ComputerName <WSL_IP> -Port <PORT>
# 期望输出:TcpTestSucceeded : True

常见误区

误区 说明
hostAddressLoopback=true[wsl2] ❌ 错误,WSL 会报错并忽略
只放行 Windows 防火墙就够了 ❌ 不够,流量还没到达防火墙就被拦截
localhost:<PORT> 能通就说明没问题 localhost 走本地回环,不受 hostAddressLoopback 限制;只有走 WSL IP 才需要它
改完 .wslconfigwsl --shutdown ❌ 配置不会生效,必须完全重启 WSL

适用场景

  • 第三方 SSH 客户端(如 Termius、PuTTY、Xshell)配置 WSL IP 连接
  • 局域网内其他设备/虚拟机通过宿主机 IP 访问 WSL 服务
  • 需要在 Windows 侧模拟“外部访问”WSL 服务的调试场景

六、安全与优化

6.1 ufw 防火墙

详见 3.6 防火墙放行 SSH,补充常用规则:

# 放行 HTTP/HTTPS
sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"

# 放行指定 IP 段访问 SSH(更安全)
sudo ufw allow from 192.168.1.0/24 to any port 22

# 拒绝特定 IP
sudo ufw deny from 10.0.0.5

# 删除规则
sudo ufw status numbered
sudo ufw delete <编号>

# 关闭防火墙
sudo ufw disable

⚠️ WSL 用户注意:ufw 在 WSL2 下经常报 ERROR: problem running,根因是 WSL2 微软内核没编译老 iptables 模块,需要切到 nftables 后端才能用。完整的修复 + 兜底方案5.6.8.13 WSL 防火墙先看 5.6.8.13 再操作本节)。

6.2 fail2ban 防爆破

sudo apt install -y fail2ban
sudo vim /etc/fail2ban/jail.local
[DEFAULT]
# 封禁时间(1 小时)
bantime  = 1h

# 监测时间窗口(10 分钟)
findtime = 10m

# 最大重试次数
maxretry = 5

# 封禁动作(ufw)
banaction = ufw

[sshd]
enabled = true
port    = ssh
filter  = sshd
logpath = /var/log/auth.log
maxretry = 3
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

# 查看封禁列表
sudo fail2ban-client status sshd
# 手动解封某 IP
sudo fail2ban-client set sshd unbanip 1.2.3.4

6.3 文件描述符限制

大并发服务(Tomcat、Nginx 等)经常遇到 too many open files 错误。

# 查看当前限制
ulimit -n
# 临时修改(当前会话)
ulimit -n 65535

永久修改:

sudo vim /etc/security/limits.conf
*       soft    nofile  65535
*       hard    nofile  65535
root    soft    nofile  65535
root    hard    nofile  65535

📋 说明

  • * 匹配所有非 root 用户,root 要单独写(limits.conf 规则:通配符不作用于 root)
  • 两组值看起来一样,但不能合并——这是 limits.conf 的限制
  • 没加 nproc:进程数 65535 没意义,默认就够用;除非跑大并发服务(如 MySQL、Kafka)才需要
sudo vim /etc/systemd/system.conf

找到 #DefaultLimitNOFILE=1024:524288 这一行,取消注释并改为 65535

DefaultLimitNOFILE=65535

📋 为什么需要改

  • systemd 默认soft=1024hard=524288
  • 所有用 systemctl 启动的服务(fail2bansshnginxmysql 等)都受这个限制
  • 默认 1024 对大并发服务不够:nginx 一个连接 2~3 个 FD,1024 / 3 ≈ 340 并发就报 too many open files
  • soft 到 65535 是生产/开发环境的标配
# 重启后生效
sudo reboot

⚠️ WSL 用户注意:在 WSL2 下不要用 sudo reboot——WSL 不是真硬件,reboot 只会杀进程、不会重读 /etc/systemd/system.conf改完 system.conf 后必须在 Windows PowerShell 跑 wsl --shutdown。详见 5.6.8.11.1 WSL 重启的正确方式

6.4 内核参数调优

sudo vim /etc/sysctl.d/99-tuning.conf
# =============================================
# 网络优化
# =============================================
# 允许端口复用(TIME_WAIT 快速回收)
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_fin_timeout = 15

# 提升 TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# SYN 队列长度(防 SYN 洪水)
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 8192

# 启用 SYN Cookie
net.ipv4.tcp_syncookies = 1

# =============================================
# 安全加固
# =============================================
# 禁用 IP 转发(单机部署不需要)
net.ipv4.ip_forward = 0

# 忽略 ICMP 重定向(防中间人)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0

# 忽略源路由
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0

# 开启反向路径过滤
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# 记录可疑包
net.ipv4.conf.all.log_martians = 1
sudo sysctl -p /etc/sysctl.d/99-tuning.conf

6.5 配置 Swap(如内存较小)

# 查看当前 swap
free -h
swapon --show

# 创建 4G swap 文件
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# 调整 swappiness(值越小越倾向用物理内存,推荐 10-30)
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-tuning.conf
sudo sysctl -p

七、验证检查清单

完成所有配置后,建议逐项验证。

7.1 通用检查(真机 / 云服务器 / WSL 通用)

✅ 检查项 🔧 命令 🎯 预期
SSH 远程可连 ssh ubuntu@IP 成功登录(最好密钥免密)
密码登录已关闭 ssh -o PasswordAuthentication=no ubuntu@IP 仍可登录 = OK
SSH 服务自启 sudo systemctl is-enabled ssh enabled
防火墙已启用 sudo ufw status Status: active
网络连通 ping -c 3 baidu.comcurl -v http://baidu.com 有响应(注意:WSL 默认禁 ICMP,ping 可能不通
DNS 解析 dig baidu.com 返回 IP
时区正确 timedatectl Asia/Shanghai
时间同步 timedatectl show NTPSynchronized=yes
系统已更新 apt list --upgradable 无输出 = 已最新
FD 限制 ulimit -n 65535(已配置时)
工具齐全 which htop tmux jq tree vim 全部有路径
fail2ban 运行 sudo systemctl status fail2ban active (running)

7.2 真机 / 云服务器额外检查(WSL 跳过)

✅ 检查项 🔧 命令 🎯 预期
静态 IP 生效 ip addr show <网卡名> IP 与配置一致(网卡名因硬件/虚拟化平台而异:常见如 ens33ens160enp0s3 等,需按实际填写)
默认路由 ip route show default 显示网关 IP
远程可 ping 通 ping <服务器IP>(从另一台机器) 有响应(服务器防火墙可能挡 ICMP)

📋 怎么知道自己的网卡名

# 列所有网卡(找带 inet IP 的那个)
ip -br addr
# 输出示例:
# lo               UNKNOWN        127.0.0.1/8
# ens33            UP             192.168.1.100/24   ← 这就是
# docker0          DOWN           172.17.0.1/16

7.3 WSL2 用户额外检查

✅ 检查项 🔧 命令 🎯 预期
WSL 发行版 wsl -l -v(PowerShell 跑) 看到自己的发行版,版本是 2
systemd 已启用 ps -p 1 -o comm= systemd(不是 init
WSL 主机名 hostname 你设的名字(如 dev-workspace
主机名持久化 cat /etc/wsl.conf [network] hostname = xxx
hosts 同步 cat /etc/hosts | grep $(hostname) 127.0.1.1 <主机名>
sudo 无警告 sudo whoami 直接返回 root,无 "unable to resolve host"
根目录所在虚拟磁盘 df -h / 容量正常(默认 256G,可手动扩)
根目录使用率 df -h / | tail -1 | awk '{print $5}' < 80%
Windows 盘已挂载 ls /mnt/c /mnt/d 能列出文件
数据软链就绪 ls -ld ~/data 指向 /mnt/d/wsl-data(如已建)
防火墙工具存在 which ufwwhich iptables 至少有一个(WSL 防火墙见 5.6.8.13 WSL 防火墙修复
WSL 发行版 cat /etc/os-release Ubuntu 24.04
WSL 重启生效 wsl --shutdownwsl(PowerShell 跑) 配置变更生效
WSL 镜像模式(按需) ip addr show eth0 inet 是 192.168.x 或 10.x(不是 172.x)

7.4 一键自检脚本(通用 + WSL)

保存为 ~/check-env.shchmod +x ~/check-env.sh 后跑:

#!/bin/bash
# =============================================
# Ubuntu 初始环境一键自检脚本
# =============================================
echo "================================"
echo "Ubuntu 初始环境自检"
echo "================================"

echo -e "\n[1] 系统信息"
echo "版本:$(grep PRETTY_NAME /etc/os-release | cut -d= -f2- | tr -d '"')"
echo "内核:$(uname -r)"
echo "当前用户:$(whoami)"

echo -e "\n[2] SSH 服务"
systemctl is-enabled ssh && echo "✅ SSH 自启" || echo "❌ SSH 未自启"
systemctl is-active ssh && echo "✅ SSH 运行中" || echo "❌ SSH 未运行"

echo -e "\n[3] 防火墙"
if command -v ufw &> /dev/null; then
  ufw status | head -3
else
  echo "⚠️ ufw 未装(WSL 下可能未启用,见 [5.6.8.13 WSL 防火墙修复](#56813-wsl-防火墙ufw-修复--nftables-兜底))"
fi

echo -e "\n[4] 时区与时间"
timedatectl | grep -E "Time zone|System clock"

echo -e "\n[5] 网络"
ip -br addr | grep -v "DOWN" | head -5

echo -e "\n[6] DNS"
cat /etc/resolv.conf 2>/dev/null | grep nameserver | head -2

echo -e "\n[7] 资源限制"
echo "ulimit -n: $(ulimit -n)"
echo "ulimit -u: $(ulimit -u)"

echo -e "\n[8] 工具检查"
for tool in htop tmux jq tree vim git curl wget; do
  if command -v $tool &> /dev/null; then
    echo "✅ $tool"
  else
    echo "❌ $tool 缺失"
  fi
done

echo -e "\n[9] systemd 状态(WSL 关注)"
ps -p 1 -o comm= | grep -q systemd && echo "✅ systemd 已启用" || echo "❌ PID 1 不是 systemd(WSL 需配置 wsl.conf)"

echo -e "\n[10] 主机名"
echo "当前:$(hostname)"
grep -q "^127.0.1.1 $(hostname)" /etc/hosts && echo "✅ /etc/hosts 同步" || echo "⚠️ /etc/hosts 未同步(sudo 可能报 unable to resolve host)"

echo -e "\n[11] WSL 特定(如适用)"
if grep -qi "microsoft" /proc/version 2>/dev/null; then
  echo "✅ WSL 环境"
  grep -q "^\[network\]" /etc/wsl.conf && echo "✅ wsl.conf 有 [network] 段" || echo "⚠️ wsl.conf 缺 [network] 段(主机名可能不持久)"
else
  echo "非 WSL 环境(真机/云服务器)"
fi

echo -e "\n================================"
echo "自检完成"
echo "================================"

八、常用命令速查

8.1 服务管理

🔧 操作 🔧 CentOS 7 🔧 Ubuntu 24.04
启动 systemctl start sshd sudo systemctl start ssh
停止 systemctl stop sshd sudo systemctl stop ssh
状态 systemctl status sshd sudo systemctl status ssh
开机自启 systemctl enable sshd sudo systemctl enable ssh
重载配置 systemctl reload sshd sudo systemctl reload ssh
服务名 sshd ssh
配置文件 /etc/ssh/sshd_config /etc/ssh/sshd_config(路径相同)

📋 关键差异:Ubuntu 把 SSH 服务名从 CentOS 的 sshd 改成了 ssh,其他都一致。

8.2 包管理对照

🔧 操作 🔧 CentOS 7 (yum) 🔧 Ubuntu 24.04 (apt)
更新源索引 yum check-update sudo apt update
安装包 yum install -y pkg sudo apt install -y pkg
删除包 yum remove pkg sudo apt remove pkg
搜索包 yum search keyword apt search keyword
包信息 yum info pkg apt show pkg
列出已装 yum list installed apt list --installed
升级所有 yum update -y sudo apt upgrade -y

8.3 网络命令对照

🔧 用途 🔧 CentOS 7 🔧 Ubuntu 24.04
查看 IP ip addr / ifconfig ip addrifconfig 需装 net-tools
查看端口 netstat -tlnp netstat -tlnp(需装 net-tools) / ss -tlnp
测试连通 ping / traceroute ping / traceroute(需装)
DNS 查询 nslookup / dig dig(需装 dnsutils
防火墙 firewalld / firewall-cmd ufw
网络配置 /etc/sysconfig/network-scripts/ifcfg-ens33 /etc/netplan/*.yaml
主机名 hostnamectl set-hostname x hostnamectl set-hostname x(相同)
SELinux setenforce 0 无(Ubuntu 用 AppArmor)

8.4 时间与日志对照

🔧 用途 🔧 CentOS 7 🔧 Ubuntu 24.04
时区设置 timedatectl set-timezone ... 相同
时间同步 chrony systemd-timesyncd(默认) / chrony
系统日志 /var/log/messages /var/log/syslog
认证日志 /var/log/secure /var/log/auth.log
查看日志 journalctl -u sshd journalctl -u ssh

8.5 防火墙命令对照

🔧 操作 🟢 ufw(Ubuntu 默认) 🟡 iptables(底层通用) 🔵 nftables(现代替代) 🔴 firewalld(CentOS 默认)
查看状态 sudo ufw status verbose sudo iptables -L -n -v sudo nft list ruleset sudo firewall-cmd --list-all
启动/启用 sudo ufw enable 开机自启需 iptables-persistent 开机自启需 nftables.service sudo systemctl enable --now firewalld
放行 22 端口 sudo ufw allow 22/tcp sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT sudo nft add rule inet filter input tcp dport 22 accept sudo firewall-cmd --permanent --add-port=22/tcp
放行服务名 sudo ufw allow ssh sudo firewall-cmd --permanent --add-service=ssh
放行 IP 段 sudo ufw allow from 192.168.1.0/24 sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT sudo nft add rule inet filter input ip saddr 192.168.1.0/24 accept sudo firewall-cmd --permanent --add-source=192.168.1.0/24
拒绝某 IP sudo ufw deny from 10.0.0.5 sudo iptables -A INPUT -s 10.0.0.5 -j DROP sudo nft add rule inet filter input ip saddr 10.0.0.5 drop sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.5 drop'
重新加载 自动 sudo iptables-restore < /etc/iptables/rules.v4 sudo nft -f /etc/nftables.conf sudo firewall-cmd --reload
关闭防火墙 sudo ufw disable sudo iptables -F(清空规则,慎用) sudo nft flush ruleset sudo systemctl stop firewalld
命令缺失 sudo apt install -y ufw Ubuntu 自带 sudo apt install -y nftables sudo yum install -y firewalld

📋 选择建议

  • 标准 Ubuntu 优先用 ufw(本教程主推),最简单。
  • 需要复杂规则(端口转发、NAT、限速)用 iptables / nftables
  • 跨平台脚本或 CentOS 兼容场景用 firewalld

8.6 一键脚本(新建服务器跑一次)

📋 脚本定位

  • 本脚本对应本文档 第二章(初始环境检查)、3.1-3.3(SSH 服务)、4.3(时区)、5.1(常用工具)、6.1-6.5(安全与优化)的最小可用集
  • 不包含的内容:4.1(Netplan 静态 IP,按网络环境差异较大)、4.2(主机名,个性化)、4.5(apt 换源,建议手动换源跑此脚本)、5.3-5.5(Git/vim/bashrc 偏好设置)、3.5(密钥免密,建议手动执行以免覆盖既有密钥)。
  • 默认按"真机 / 云服务器"编写,脚本会自动识别 WSL2 环境并跳过不适用项(systemctlufwreboot 等)。
#!/bin/bash
# =============================================
# Ubuntu 24.04 初始环境一键配置脚本
# 对应文档:Ubuntu与WSL2初始环境配置与常用工具安装教程.md 第 8.6 节
# 用法:sudo bash init-ubuntu.sh
# 前置:建议先按 4.5 节换 apt 源,再跑本脚本
# 幂等:重复运行不会破坏既有配置(已存在配置会跳过)
# =============================================
set -euo pipefail

# ---------- 颜色输出 ----------
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
log()  { echo -e "${GREEN}[✓]${NC} $*"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
err()  { echo -e "${RED}[✗]${NC} $*"; }

# ---------- 0. 权限与环境探测 ----------
if [[ $EUID -ne 0 ]]; then
  err "请使用 root 或 sudo 运行本脚本"
  exit 1
fi

# WSL2 探测:/proc/version 含 "microsoft" 或 "WSL"
IS_WSL=0
grep -qiE 'microsoft|wsl' /proc/version 2>/dev/null && IS_WSL=1

# 当前登录用户(sudo 场景下 SUDO_USER 非空;root 直登时退到默认 ubuntu)
REAL_USER="${SUDO_USER:-${USER:-ubuntu}}"
[[ "$REAL_USER" == "root" ]] && REAL_USER="ubuntu"

log "运行环境:$( [[ $IS_WSL -eq 1 ]] && echo 'WSL2' || echo '真机/云服务器' )"
log "操作用户:$REAL_USER"

# ---------- 1. 更新源(对应 4.5 / 5.1) ----------
log "[1/9] 更新 apt 源与软件包"
apt update
# upgrade 升级所有包;如不希望升级可注释掉下一行
apt upgrade -y

# ---------- 2. 常用工具(对应 5.1 一键安装清单) ----------
log "[2/9] 安装常用工具集"
apt install -y \
  openssh-server openssh-client \
  vim nano curl wget git \
  net-tools dnsutils iputils-ping traceroute mtr \
  unzip p7zip-full lrzsz \
  bash-completion tmux \
  htop iotop iftop sysstat lsof strace ncdu \
  ripgrep fd-find jq tree \
  fail2ban ufw

# ---------- 3. SSH 服务(对应 3.1 / 3.3) ----------
log "[3/9] 配置 SSH 服务"
# 备份原配置(仅首次备份)
[[ -f /etc/ssh/sshd_config ]] && [[ ! -f /etc/ssh/sshd_config.bak ]] && \
  cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

# 用 sed 调整关键项(保留其它已有配置)
# 注意:PasswordAuthentication 默认保持 yes,确保首次也能密码登录;
# 验证密钥可用后,再按"完成提示"改为 no
SSHD_CFG=/etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/'             "$SSHD_CFG"
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication yes/' "$SSHD_CFG"
sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/'   "$SSHD_CFG"
sed -i 's/^#\?X11Forwarding.*/X11Forwarding no/'                   "$SSHD_CFG"
sed -i 's/^#\?MaxAuthTries.*/MaxAuthTries 3/'                      "$SSHD_CFG"

# 启用并启动 SSH(WSL2 启用 systemd 后 systemctl 才会生效;未启用时为 no-op)
if [[ $IS_WSL -eq 0 ]]; then
  systemctl enable --now ssh >/dev/null 2>&1 || warn "ssh 服务启动失败,请检查 systemd"
else
  warn "WSL2 环境:未启用 systemd 时 systemctl 不可用,请按 5.6.8.11 节启用后再重启"
fi

# 校验配置(错误则不重启,避免失联)
if command -v sshd >/dev/null 2>&1; then
  sshd -t && log "sshd_config 语法校验通过" || err "sshd_config 语法错误,请检查 $SSHD_CFG"
fi

# ---------- 4. 防火墙(对应 6.1) ----------
log "[4/9] 配置 ufw 防火墙"
if [[ $IS_WSL -eq 0 ]]; then
  ufw default deny incoming  >/dev/null
  ufw default allow outgoing >/dev/null
  ufw allow 22/tcp comment "SSH" >/dev/null
  # 用 yes 自动应答交互
  echo "y" | ufw enable >/dev/null 2>&1 || true
  log "ufw 已启用(仅放行 22/tcp)"
else
  warn "WSL2 环境:ufw 需先切 nftables 后端才能用,详见 5.6.8.13 节"
fi

# ---------- 5. fail2ban(对应 6.2) ----------
log "[5/9] 配置 fail2ban"
JAIL_LOCAL=/etc/fail2ban/jail.local
if [[ ! -f $JAIL_LOCAL ]]; then
  cat > "$JAIL_LOCAL" <<'EOF'
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
banaction = ufw

[sshd]
enabled = true
port    = ssh
filter  = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF
  log "已生成 $JAIL_LOCAL"
else
  warn "$JAIL_LOCAL 已存在,跳过覆盖(手动调整请编辑该文件)"
fi

if [[ $IS_WSL -eq 0 ]]; then
  systemctl enable --now fail2ban >/dev/null 2>&1 || warn "fail2ban 启动失败"
else
  warn "WSL2 环境:未启用 systemd 时 fail2ban 无法后台常驻"
fi

# ---------- 6. 时区与时间同步(对应 4.3) ----------
log "[6/9] 配置时区与时间同步"
timedatectl set-timezone Asia/Shanghai
if [[ $IS_WSL -eq 0 ]]; then
  systemctl enable --now systemd-timesyncd >/dev/null 2>&1 || true
fi
log "当前时区:$(timedatectl | grep 'Time zone' | awk '{print $3}')"

# ---------- 7. 文件描述符限制(对应 6.3) ----------
log "[7/9] 配置文件描述符限制"
LIMITS_CONF=/etc/security/limits.conf
# 幂等:仅当 nofile 65535 不存在时追加
if ! grep -qE '^\*\s+soft\s+nofile\s+65535' "$LIMITS_CONF" 2>/dev/null; then
  cat >> "$LIMITS_CONF" <<'EOF'

# === Added by init-ubuntu.sh ===
*   soft    nofile  65535
*   hard    nofile  65535
root soft    nofile  65535
root hard    nofile  65535
EOF
  log "已追加 nofile 限制到 $LIMITS_CONF"
else
  warn "$LIMITS_CONF 已包含 nofile 65535,跳过"
fi

# systemd 服务级 FD 限制
SYSTEMD_CONF=/etc/systemd/system.conf
if ! grep -qE '^DefaultLimitNOFILE=65535' "$SYSTEMD_CONF" 2>/dev/null; then
  sed -i 's/^#\?DefaultLimitNOFILE=.*/DefaultLimitNOFILE=65535/' "$SYSTEMD_CONF" || \
    echo "DefaultLimitNOFILE=65535" >> "$SYSTEMD_CONF"
  log "已设置 DefaultLimitNOFILE=65535"
else
  warn "$SYSTEMD_CONF 已包含 DefaultLimitNOFILE=65535,跳过"
fi

# ---------- 8. 内核参数调优(对应 6.4) ----------
log "[8/9] 配置内核参数调优"
SYSCTL_FILE=/etc/sysctl.d/99-tuning.conf
if [[ ! -f $SYSCTL_FILE ]]; then
  cat > "$SYSCTL_FILE" <<'EOF'
# === Added by init-ubuntu.sh ===
# 网络优化
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_fin_timeout = 15
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 8192
net.ipv4.tcp_syncookies = 1

# 安全加固
net.ipv4.ip_forward = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.log_martians = 1

# Swap 使用倾向(值越小越倾向用物理内存)
vm.swappiness = 10
EOF
  log "已生成 $SYSCTL_FILE"
else
  warn "$SYSCTL_FILE 已存在,跳过覆盖(如需重置请手动删除)"
fi

# 应用 sysctl(非 WSL 立即生效;WSL 大部分参数会被宿主内核忽略)
if [[ $IS_WSL -eq 0 ]]; then
  sysctl -p "$SYSCTL_FILE" >/dev/null 2>&1 || warn "sysctl 部分参数应用失败(多因模块未加载,可忽略)"
else
  warn "WSL2 环境:sysctl 大部分参数由 Windows 宿主内核控制,配置仅作记录"
fi

# ---------- 9. 完成提示 ----------
echo
log "初始化完成"
echo "------------------------------------------------"
echo "  下一步:"
echo "  1) 在本机执行:ssh-copy-id ${REAL_USER}@\$(hostname -I | awk '{print \$1}')"
echo "  2) 验证密钥登录成功后,再把 PasswordAuthentication 设为 no 永久生效"
echo "  3) 真机/云服务器需 reboot;WSL2 在 Windows PowerShell 执行 wsl --shutdown"
echo "------------------------------------------------"

💡 文档维护提示

  • 上述所有配置均在 Ubuntu 24.04 LTS 实测通过。
  • Ubuntu 20.04 大部分兼容,仅 Netplan 语法、nmtui 行为略有差异。
  • Ubuntu 24.04 发布后请关注 systemd 变更,可能影响部分服务配置。
posted @ 2026-07-07 18:19  RK5123153  阅读(52)  评论(0)    收藏  举报