在 Hyper-V 下安装 ArchLinux

该文章根据 CC-BY-4.0 协议发表,转载请遵循该协议。
本文地址:https://fenying.net/post/2023/10/17/install-archlinux-in-hyper-v/

Overview

本教程指导在 Windows 11 Pro 中,使用系统自带的 Hyper-V 虚拟机安装 ArchLinux,并解决代理和宿主机文件共享问题。

Tips

本文操作环境为 Windows 11 Pro 英文版系统,部分系统文案请自行转换为中文理解。

目标与难点

本文的目标是在 Windows 11 Pro + Hyper-V 环境安装 Archlinux,并保证 Archlinux 可以全面使用代理,并与主机进行文件共享。

此外,本次安装不使用 grub 等引导管理器,直接使用 UEFI 引导。

  • 问题1:代理

    此前在 VirtualBox 下安装客户机系统后,由于采用的是 NAT 网络,可以通过对 VirtualBox 所有进程挂代理(使用 Proxifier 软件),给客户机配置系统级透明代理。换成 Hyper-V 后,这一套行不通了,须配合 tun2socks 来实现。

  • 问题2:共享目录

    VirtualBox 下,通过 VirtualBox 的系统组件很容易实现共享目录的挂载。而在 Hyper-V 下则必须用 CIFS 来实现,而且还须解决 Windows 账户口令的问题。

配置开启 Hyper-V

下载安装 Archlinux LiveCD

前往 Archlinux 官网,选择一个合适的下载源,我这里选择 aliyun,下载其中的 archlinux-20**.**.**-x86_64.iso 文件。

创建 Hyper-V 虚拟网络

启动管理员 PowerShell 命令行终端,执行如下步骤:

  1. 创建一个内部交换网络

    1New-VMSwitch -SwitchName "MyArchSwitch" -SwitchType Internal
    

    执行成功后,显示应该如下:

    1Name         SwitchType NetAdapterInterfaceDescription
    2----         ---------- ------------------------------
    3MyArchSwitch Internal
    
  2. 以 Win11 为例,进入系统设置,选择“Network & Internet / Advanced network settings”

    找到你当前使用的网络,点击展开,在“More adapter options”那一栏选择 Edit。

    Tips

    Windows 10 应该更简单,可以直接找到传统的网络管理面板,找到当前使用的网络连接,右键“属性”就能打开这个 UI。

    在弹出的框里切换到 Sharing 栏,勾选第一个 Allow other user connect throught this computer’s internet connection,并在下面的下拉框里选择你上面创建的 Internal Switch,然后点击保存。

    Tips

    第二个复选框不用勾选。

  3. 执行 Get-NetIPAddress -InterfaceAlias "vEthernet (MyArchSwitch)" 就可以看到主机的 IPv4 地址,一般情况下应该都是 192.168.137.1

    Tips

    下面都以 192.168.137.1/24 为例,如果你的不一样请自行调整。

  4. 配置 Windows 防火墙放行规则,按下 Win+S,搜索 Windows Defender Firewall with Advanced Security,在打开的控制台界面,左侧选择 Inbound Policy,再选择右侧栏的 New Rule,在 New Inbound Rule Wizard 导航里,按如下操作:

    1. Rule Type:选择 Custom 类型的规则,下一步;
    2. Program:不做修改,保存选择 All Program,下一步;
    3. Protocol And Ports:不做修改,下一步;
    4. Scope:添加本地 IP 地址 192.168.137.1,添加远程 IP 地址 192.168.137.2,下一步;
    5. Action:不做修改,保持 Allow the connections,下一步;
    6. Profile:不做修改,保持三个全选,下一步;
    7. Name:取个名字,比如“Allowed Archlinux in Hyper-V",完成。

创建 Hyper-V 虚拟机

  1. 按下 Win+S,查找并打开 Hyper-V Manager (如果没有,请通过操作系统设置启用 Hyper-V)
  2. 选择菜单“Action / New / Virtual Machine”,启动虚拟机创建导航
  3. Specify Name And Location:设置虚拟机名称和存储路径
  4. Specify Generation:选择第二代虚拟机(Generation 2)
  5. Assign Memory:配置内存至少 4GiB
  6. Configure Networking:网络选择上面创建的 Virtual Network Switch,如 MyArchSwitch
  7. Connect Virtual Hard Disk:选择创建新的主硬盘,自己调节大小,不应小于 40GiB
  8. Install Options:选择“Install an operating system from a bootable CD/DVD-ROM”,选择上面下载的 Archlinux LiveCD 文件
  9. 创建完成,继续配置

配置 Hyper-V 虚拟机

  1. 在 Hyper-V Manager 的 Virtual Machines 列表里找到你刚刚创建的虚拟机

  2. 右键选择 Settings

  3. 选择 Security 栏,把里面的 Enable Secure Boot 关掉(如有需要可以开启 TPM)

  4. 选择 SCSI Controller 栏,添加3个 Hard Drive,名称如下:(创建时,注意磁盘文件的存储位置)

    • Home:用于存储 /home 目录,大小自定
    • Docker:用于存储 /var/lib/docker 目录,大小自定
    • Swap:用于交换分区,大小和内存大小一致即可
    • 如有其他,请自行添加。

    确保 SCSI Controller 下每个硬盘的 Location 分别为 0, 1, 2, 3(如果还有请按序排列),而 DVD Drive 的 Location 为 4(反正在最后)

  5. 选择 Firmware 栏,确保 DVD Drive 在第一个启动顺序,把 Network Adapter 移到最后

  6. 选择 Checkpoint 栏,去掉 Enable checkpoints

  7. 点击 Apply,然后关闭

安装虚拟机操作系统

  1. 右键选择你的虚拟机,选择 Connect

  2. 在新打开的虚拟机操作窗口里,选择 Start,等待进入的 LiveCD

  3. 执行命令,查看当前系统的 IP 地址

    1ip addr
    

    看看 eth0 网卡下的 inet 后面的 IP 地址,也就是 192.168.137.xxx,记住这个 IP。

  4. 执行 curl https://www.baidu.com,确保网络畅通

  5. 执行 systemctl start sshd 启动 OpenSSH 服务端,以便后面使用 SSH 连接到虚拟机里操作,方便复制粘贴等操作。

  6. 执行 passwd 命令,设置 LiveCD 系统里的 root 用户的口令

  7. 从主机执行 ssh -p 22 [email protected] 通过 SSH 连接到虚拟机继续操作。

  8. 初始化磁盘:

     1fdisk /dev/sda # 初始化主磁盘
     2
     3o           # 创建 DOS 分区表
     4
     5n           # 创建分区
     6p           # 创建一个新的主分区
     71           # 第1个分区
     8回车         # 直接回车
     9+512M       # 创建 EFI 分区
    10
    11n           # 创建分区
    12p           # 创建一个新的主分区
    132           # 第2个分区
    14回车         # 直接回车
    15回车         # 剩余部分为一个分区
    16
    17w           # 写入分区表并推出
    18
    19mkfs.fat /dev/sda1      # EFI 系统分区必须是 FAT 格式
    20mkfs.ext4 /dev/sda2     # 根分区
    21mkfs.ext4 /dev/sdb      # 整个 Home 磁盘为一个分区,给 `/home` 使用
    22mkfs.ext4 /dev/sdc      # 整个 Docker 磁盘为一个分区,给 `/home` 使用
    23mkswap /dev/sdd         # 整个 Swap 磁盘为一个交换分区
    24
    25mount /dev/sda2 /mnt
    26
    27mkdir /mnt/boot
    28mkdir /mnt/home
    29mkdir /mnt/var/lib/docker -p
    30
    31mount /dev/sda1 /mnt/boot
    32mount /dev/sdb /mnt/home
    33mount /dev/sdc /mnt/var/lib/docker
    34
    35swapon /dev/sdd
    
  9. 配置 Pacman 镜像源

    使用 vim 命令打开 /etc/pacman.d/mirrorlist 文件,在最前面添加一行:

    1Server = https://mirrors.aliyun.com/archlinux/$repo/os/$arch
    
    Tips

    如果你有代理,也可以不配置这个,直接 export https_proxy=http://192.168.137.1:11111 设置你的代理加速即可。

  10. 开始安装系统

1pacstrap /mnt base linux linux-firmware dhcpcd openssh vim wget sudo unzip
2
3genfstab -U /mnt >> /mnt/etc/fstab
4arch-chroot /mnt
  1. 系统基础配置
 1ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime          # 设置时区
 2echo 'MyXXXXX' > /etc/hostname            # 设置主机名
 3hwclock --systohc       # 写入系统时间
 4
 5ln -s /usr/bin/vim /usr/bin/vi
 6
 7vi /etc/locale.gen  # 去除注释 en_US.UTF-8 UTF-8,以及 zh_CN 开头的4个中文字符集。
 8
 9locale-gen  #      生成语言配置
10echo 'LANG=en_US.UTF-8' > vi /etc/locale.conf  #  设置默认语言
11
12passwd   # 设置新系统的 root 口令
  1. 创建普通用户并配置 SSH
 1systemctl enable sshd    # 设置 SSH 服务开机启动
 2
 3YOUR_USER=xxxxx  # 你想要的常规用户名,比如 admin?mick?sarah?
 4useradd -m $YOUR_USER # 创建常规用户,先创建用户,可以保证用户的 UID 和 GID 都是 1000 O(∩_∩)O
 5
 6visudo # 把 %sudo  ALL=(ALL:ALL) ALL 这行取消注释
 7groupadd sudo
 8
 9usermod -aG sudo $YOUR_USER  # 为常规用户设置 sudo 权限
10passwd $YOUR_USER # 为常规用户设置口令
11
12mkdir /home/$YOUR_USER/.ssh
13echo 'YOUR-SSH-Pubkey' > /home/$YOUR_USER/.ssh/authorized_keys # 设置常规用户的 SSH 登录公钥
14chmod 0700 /home/$YOUR_USER/.ssh
15chmod 0600 /home/$YOUR_USER/.ssh/authorized_keys
16chown -R $YOUR_USER:$YOUR_USER /home/$YOUR_USER/.ssh
  1. 网络配置

本方案将设置一个固定 IP 方便访问,此处使用 192.168.137.2

1pacman -S dhcpcd
2systemctl enable dhcpcd
3
4echo 'interface eth0' >> /etc/dhcpcd.conf
5echo 'static ip_address=192.168.137.2/24' >> /etc/dhcpcd.conf
6echo 'static routers=192.168.137.1' >> /etc/dhcpcd.conf

此时还可以配置一个固定的 DNS 服务器,比如使用阿里的 DNS:(但是,如果需要开启 DoT/DoH,请跳过这个配置

1echo 'static domain_name_servers=223.5.5.5 223.6.6.6' >> /etc/dhcpcd.conf
  1. DoH/DoT 设置(可选)
1pacman -S dnscrypt-proxy
2systemctl enable dnscrypt-proxy
3echo 'static domain_name_servers=127.0.0.1' >> /etc/dhcpcd.conf

然后编辑 /etc/dnscrypt-proxy/dnscrypt-proxy.toml 文件,移除 server_names = [...] 那行的注释,并选择你想要的 DoT/DoH 服务器。

Tips

由于 DoT/DoH 服务器大概率被 XX 了,可能需要配置代理,那么再加一行:

1proxy = 'socks5://192.168.137.1:11111' # 你的代理服务器
  1. 配置 EFI
 1exit   #  退出到 LiveCD
 2
 3blkid /dev/sda2 # 获取 PARTUUID="xxxxxxxx-xx",用于下一行命令
 4
 5efibootmgr \
 6  --disk /dev/sda \
 7  --part 1 \
 8  --create \
 9  --label "Linux Kernel" \
10  --loader /vmlinuz-linux \
11  --verbose \
12  --unicode 'root=PARTUUID=xxxxxxxx-xx rw initrd=\initramfs-linux.img'  # 替换其中的 xxxxxxxx-xx 为上一条命令里的值
13
14poweroff  # 关机,然后再启动即可正式进入系统

附录

配置用户在(开机后)第一次登录时自动启动 ssh-agent

只能以普通用户身份执行,不能以 root 身份执行。

 1mkdir -p ~/.config/systemd/user/
 2
 3cat > ~/.config/systemd/user/ssh-agent.service <<EOF
 4[Unit]
 5Description=SSH key agent
 6
 7[Service]
 8Type=simple
 9Environment=SSH_AUTH_SOCK=%h/.config/ssh-agent.socket
10ExecStart=/usr/bin/ssh-agent -D -a \$SSH_AUTH_SOCK
11
12[Install]
13WantedBy=default.target
14EOF
15
16echo 'export SSH_AUTH_SOCK=~/.config/ssh-agent.socket' >> ~/.bashrc
17
18systemctl --user enable --now ssh-agent.service # 重新登录即生效

记住本次开机后登录过的会话密钥,避免反复输入密钥

须结合上面的 ssh-agent 服务使用。

~/.ssh/config 文件的最前面加上一行:

1AddKeysToAgent  yes

优化命令行 Ctrl 键的效果

须以 root 身份执行。

编辑 /etc/inputrc 文件,在中间新增两行:

1"\C-h": backward-kill-word
2"\e[3;5~": kill-word

就可以使用 Ctrl + DeleteCtrl + Backspace 删除附近词了。

Tips

重新登录生效。

切换使用 LTS 版本的 Linux 内核

须以 root 身份执行。

如果不追求最新的内核版本,可以切换到 LTS 版本,以便获得更好的稳定性。

比如下面的 CIFS 挂载 Windows 宿主机共享目录,在 Linux 6.6.1 版本中就出了问题

 1pacman -S linux-lts efibootmgr
 2
 3blkid /dev/sda2 # 获取 PARTUUID="xxxxxxxx-xx",用于下一行命令
 4
 5efibootmgr \
 6  --disk /dev/sda \
 7  --part 1 \
 8  --create \
 9  --label "Linux Kernel LTS" \
10  --loader /vmlinuz-linux-lts \
11  --verbose \
12  --unicode 'root=PARTUUID=xxxxxxxx-xx rw initrd=\initramfs-linux-lts.img' # 替换 xxxxxxxx-xx 为上一条命令中读取的 PARTUUID
13
14poweroff  # 关机,然后再启动即可正式进入 LTS 版本的内核

确认无误后,可以删除掉旧的内核:

1pacman -R linux

开启 CIFS 访问主机目录

须以 root 身份执行。

  1. 先到 Windows 系统设置里创建一个普通用户(如 arch-guest),设置口令登录(不要设置重设口令和口令过期时间)
  2. 右键须分享的目录(如 D:/VMShared),选择“属性”,进入到“分享”,选择“高级分享(Advanced Sharing)”,进入“Permissions”。
  3. 将“Everyone”的权限全部去除,再点击“添加(Add)”,把你新建立的用户添加进来,授予所有权限,保存。
  4. 回到虚拟机里,执行如下命令:
 1pacman -S cifs
 2
 3mkdir /mnt/vmshared
 4
 5id $YOUR_USER # 查看你的常规用户的 UID 和 GID
 6
 7echo 'username=xxxxxxxxxxxx' > ~/.windows_credentials # Windows 的用户名
 8echo 'password=xxxxxxxxxxxx' > ~/.windows_credentials # Windows 的用户登录口令
 9
10mount -t cifs \
11   //HOST-PC-NAME/VMShared \
12   /mnt/vmshared \
13   -o credentials=/root/.windows_credentials,ip=192.168.137.1,iocharset=utf8,file_mode=0600,dir_mode=0700,uid=1000,gid=1000
14
15ls /mnt/vmshared  # 确定生效,如果没有,则根据 dmesg 日志进行排查。
16
17echo '//HOST-PC-NAME/VMShared  /mnt/vmshared cifs credentials=/root/.windows_credentials,ip=192.168.137.1,iocharset=utf8,file_mode=0600,dir_mode=0700,uid=1000,gid=1000,x-systemd.automount 0 0' >> /etc/fstab  # 写入到 fstab,使之在系统启动后自动挂载

配置系统级透明代理

须以 root 身份执行。

Tips

https://github.com/xjasonlyu/tun2socks/releases/ 找到最新稳定版,请按需替换如下 wget 命令中的 v2.5.1 版本号。

 1sudo su # 切换到root
 2cd ~
 3
 4wget https://github.com/xjasonlyu/tun2socks/releases/download/v2.5.1/tun2socks-linux-amd64-v3.zip
 5unzip tun2socks-linux-amd64-v3.zip
 6rm tun2socks-linux-amd64-v3.zip
 7mkdir /usr/local/tun2socks/bin -p
 8mv tun2socks-linux-amd64-v3 /usr/local/tun2socks/bin/tun2socks
 9
10cat > /usr/local/tun2socks/bin/init.sh <<EOF
11#!/usr/bin/env bash
12ip tuntap add mode tun dev tun0
13ip addr add 10.0.0.1/16 dev tun0
14ip link set dev tun0 up
15ip route add default via 10.0.0.1 dev tun0 metric 1
16EOF
17
18chmod 0700 /usr/local/tun2socks/bin/*
19
20cat > /usr/local/tun2socks/config.yml <<EOF
21# debug / info / warning / error / silent
22loglevel: warning
23
24# URL format: [protocol://]host[:port]
25proxy: socks5://192.168.137.1:11111
26
27# URL format: [driver://]name
28device: tun://tun0
29
30# Maximum transmission unit for each packet
31mtu: 1500
32
33# Network interface to bind, Linux/macOS only
34interface: eth0
35
36# Timeout for each UDP session, default value: 60 seconds
37udp-timeout: 60s
38
39# SO_MARK socket option, Linux only
40fwmark: 0
41EOF
42
43cat > /usr/lib/systemd/system/tun2socks.service <<EOF
44[Unit]
45Description=Tun2socks
46Documentation=https://github.com/xjasonlyu/tun2socks
47After=network.target network-online.target
48
49[Service]
50Type=simple
51ExecStart=/usr/local/tun2socks/bin/tun2socks -config /usr/local/tun2socks/config.yml
52Restart=always
53
54[Install]
55WantedBy=multi-user.target
56EOF
57
58cat > /usr/lib/systemd/system/init-tun2socks.service <<EOF
59[Unit]
60Description=Init Tun2socks
61Documentation=https://github.com/xjasonlyu/tun2socks
62After=network.target network-online.target
63
64[Service]
65Type=simple
66ExecStart=/usr/local/tun2socks/bin/init.sh
67
68[Install]
69WantedBy=multi-user.target
70EOF
71
72systemctl enable --now init-tun2socks.service
73systemctl enable --now tun2socks.service

映射虚拟机端口到主机上

由于使用的是内部网络,且通过网卡分享的方式,所以虚拟机的端口是无法通过 VM-NAT 网络映射到主机上的。

此时可以使用 netsh 命令来实现端口映射,下面是操作命令,应通过管理员 PowerShell 命令行终端执行:

  • 添加端口映射

    下面示例将虚拟机里的 22 端口映射到主机的 2222 端口上。(假定虚拟机的 IP 地址为 192.168.137.2

    1netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=22 connectaddress=192.168.137.2
    
  • 查看已经添加的端口映射

    1netsh interface portproxy show all
    

    这条命令的示例输出如下:

    1Listen on ipv4:             Connect to ipv4:
    2
    3Address         Port        Address         Port
    4--------------- ----------  --------------- ----------
    50.0.0.0         2222        192.168.137.2   22
    
  • 删除已经添加的端口映射

    通过指定主机端口和 IP 地址即可删除。

    1netsh interface portproxy delete v4tov4 listenport=2222 listenaddress=0.0.0.0
    

FAQ

CIFS 无法工作怎么办?

如果在滚动更新内核到 v6.6 以后,遇到 CIFS 无法工作,且 dmesg 报如下错误

1CIFS: VFS: cifs_mount failed w/return code = -4

那么,是因为内核更新导致的问题,可以将内核降级到 v6.6 之前的版本。(可以尝试切换到 linux-lts 内核,如果它还停留在 6.1 版本,详见附录)

虚拟机重启后突然网络不通了怎么办?

  1. 如果开启了 tun2socks 服务,请检查代理服务器是否正常工作。

  2. 检查宿主机的网卡,是否和你起初配置的网卡不一致了,如果是,请关掉此前的网卡,重新在当前网卡配置网络分享给虚拟交换机。

comments powered by Disqus