Install ArchLinux insides Hyper-V

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

Overview

This is a tutorial to guide you to install ArchLinux inside Hyper-V on Windows 11 Pro, and solve the problems like:

  • System-wide transparent proxy
  • File sharing between guest and host
Tips

This guide is based on Windows 11 Pro English edition.

What’s the problem?

The biggest problems while installing ArchLinux inside Hyper-V are:

  • System-wide transparent proxy

    Previously, we installed ArchLinux insides a VirtualBox machine, and it’s easy to configure proxy for the guest machines, by setting it to use NAT network, because NAT network is processed in process-level, which could be proxied by some system softwares like Proxifier.

    However, it’s impossible to do the same thing in Hyper-V, even if you put your guest behind a NAT network,

    The solution is to use tun2socks to redirect all the traffic to a proxy server.

  • Sharing files between guest and host

    In VirtualBox, it’s easy to share a folder between guest and host, by using VirtualBox’s system components. But in Hyper-V, you have to use CIFS to do that, and you have to solve the problem of Windows account password.

By the way, to improved the time of startup, we use UEFI boot mode.

Enabling Hyper-V

Download Archlinux LiveCD

Go to Archlinux Official Site, and choose a nearby mirror site, download the file archlinux-20**.**.**-x86_64.iso.

Create Hyper-V Virtual Network

All operations below should use PowerShell with Administrator privilege.

  1. Create an internal switch network

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

    If it’s successful, you will see:

    1Name         SwitchType NetAdapterInterfaceDescription
    2----         ---------- ------------------------------
    3MyArchSwitch Internal
    
  2. Open the system settings, choose “Network & Internet / Advanced network settings”

    Find the network you are using, click to expand, and choose Edit in “More adapter options”.

    Tips
    It should be easier in Windows 10, you can find the traditional network management panel, right-click the network connection you are using, and choose "Properties" to open this UI.
    

    In the new opened interface, switch to the Sharing tab, check the first checkbox “Allow other user connect through this computer’s internet connection”, and choose the Internal Switch you created above in the dropdown list, then click Save.

    Tips
    Don't enable the second checkbox, because it will enable NAT, and we don't need it.
    
  3. Run Get-NetIPAddress -InterfaceAlias "vEthernet (MyArchSwitch)", you will see the IPv4 address of the host, it should be `

    Tips
    I choose `192.168.137.1/24` as the network segment.
    
  4. Configure Windows Firewall rules, press Win+S, search Windows Defender Firewall with Advanced Security, in the opened console, choose Inbound Policy in the left pane, then choose New Rule in the right pane, and follow the steps:

    1. Rule Type: Choose Custom, and click Next
    2. Program: Keep All Program, and click Next
    3. Protocol And Ports: Keep it, and click Next
    4. Scope: Add the local IP address 192.168.137.1·, and the remote IP address 192.168.173.2`, and click Next
    5. Action: Keep it, and click Next
    6. Profile: Keep all three checked, and click Next
    7. Name: Give it a name, like “Allowed Archlinux in Hyper-V”, and click Finish

Create Hyper-V Virtual Machine

  1. Press Win+S, search and open Hyper-V Manager (Enable it if not found)
  2. Click menu Action / New / Virtual Machine, to start the virtual machine creation wizard
  3. Specify Name And Location: Set the name and storage path of the virtual machine
  4. Specify Generation: Choose Generation 2
  5. Assign Memory: At least 4GiB
  6. Configure Networking: Choose the Virtual Network Switch you created above, like MyArchSwitch
  7. Connect Virtual Hard Disk: Choose to create a new virtual hard disk, and adjust the size, it should be no less than 40GiB
  8. Install Options: Choose “Install an operating system from a bootable CD/DVD-ROM”, and choose the Archlinux LiveCD file you downloaded before.
  9. Finish the creation, and continue to configure it.

Configure Hyper-V Virtual Machine

  1. Find the virtual machine you created in Hyper-V Manager.

  2. Right-click on it and choose Settings

  3. Go to the Security tab, and disable Enable Secure Boot (You can enable TPM if needed)

  4. Go to the Processor tab, add 3 hard driver, with names:

    • Home: For /home, size as you need
    • Docker: For /var/lib/docker, size as you need
    • Swap: For swap partition, size as the same as the memory
    • Add more if needed.

    Remember, the order of the hard drivers should be: 0, 1, 2, 3. And the DVD Drive should be 4.

  5. Go to the Firmware tab, make sure DVD Drive is the first boot order, and move Network Adapter to the last.

  6. Go to the Checkpoint tab, disable Enable checkpoints

  7. Click Apply, and then close

Install ArchLinux

  1. Right-click the virtual machine, and choose Connect

  2. Click Start in the new opened window, and wait for the LiveCD to start

  3. Execute the command ip addr to check the IP address of the virtual machine, it should be 192.168.137.xxx, remember it.

  4. Execute curl https://www.google.com, to make sure the network is working

  5. Start the OpenSSH server by executing systemctl start sshd, so that you can connect to the virtual machine via SSH for further operations, which is convenient for copy-paste and so on.

  6. Execute passwd to set the password of the root user in the LiveCD system, so that you can connect to the virtual machine via SSH.

  7. Execute ssh -p 22 [email protected] to connect to the virtual machine via SSH, in your host machine.

  8. Initialize the disks:

     1fdisk /dev/sda # Initialize the main disk
     2
     3o           # Create a DOS partition table
     4
     5n           # Create a partition
     6p           # Create a new primary partition
     71           # The first partition
     8Enter       # Just press Enter
     9+512M       # Create a EFI partition
    10
    11n           # Create a partition
    12p           # Create a new primary partition
    132           # The second partition
    14Enter       # Just press Enter
    15Enter       # The rest of the disk
    16
    17w           # Write the partition table and exit
    18
    19mkfs.fat /dev/sda1      # The EFI partition must be FAT format
    20mkfs.ext4 /dev/sda2     # The root partition
    21mkfs.ext4 /dev/sdb      # The whole Home disk for `/home`
    22mkfs.ext4 /dev/sdc      # The whole Docker disk for `/var/lib/docker`
    23mkswap /dev/sdd         # The whole Swap disk for 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. Configure Pacman mirror (Optional)

    Edit the file /etc/pacman.d/mirrorlist with vim, and add your preferred mirror at the top:

    Usually unnecessary, because the default mirror is fast enough.

    However, if you are in some region with network control, you may need to setup a custom mirror to speed up the download.

  10. Start the installation

1pacstrap /mnt base linux linux-firmware dhcpcd openssh vim wget sudo unzip
2
3genfstab -U /mnt >> /mnt/etc/fstab
4arch-chroot /mnt
  1. Initialize the system
 1ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime  # Set the timezone
 2echo 'MyXXXXX' > /etc/hostname            # Set the hostname
 3hwclock --systohc       # Set the hardware clock
 4
 5ln -s /usr/bin/vim /usr/bin/vi
 6
 7vi /etc/locale.gen  # Uncomment line of en_US.UTF-8 UTF-8
 8
 9locale-gen  #      Generate the locale
10echo 'LANG=en_US.UTF-8' > vi /etc/locale.conf  #  Set the locale
11
12passwd   # Set the password for root
  1. Create a normal user
 1systemctl enable sshd    # Enable SSH server and make it start on boot
 2
 3YOUR_USER=xxxxx  # Set the username
 4useradd -m $YOUR_USER # Create a normal user (the UID and GID will be 1000 by default)
 5
 6visudo # Uncomment line of %sudo  ALL=(ALL:ALL) ALL
 7groupadd sudo
 8
 9usermod -aG sudo $YOUR_USER  # Add the normal user to the sudo group
10passwd $YOUR_USER # Set the password for the normal user
11
12mkdir /home/$YOUR_USER/.ssh
13echo 'YOUR-SSH-Pubkey' > /home/$YOUR_USER/.ssh/authorized_keys # Set the SSH public key for the normal user
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. Configure the network

    This solution will set a fixed IP for easy access, here we use 192.168.137.2/32

    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
    

    By the way, you can also set a fixed DNS server, like using Cloudflare’s DNS:

    However if you wanna enable DoT/DoH, please skip this configuration.

    1echo 'static domain_name_servers=1.1.1.1' >> /etc/dhcpcd.conf
    
  2. DoH/DoT (Optional)

    1pacman -S dnscrypt-proxy
    2systemctl enable dnscrypt-proxy
    3echo 'static domain_name_servers=127.0.0.1' >> /etc/dhcpcd.conf
    

    Edit /etc/dnscrypt-proxy/dnscrypt-proxy.toml, uncomment line of server_names = [...], and add your preferred DoH/DoT server, like:

    Tips
    If your network does not allow access these DoT/DoH servers, you can use a proxy server to access them.
    
    ```toml
    proxy = 'socks5://192.168.137.1:11111' # Your proxy server
    ```
    
  3. Setup EFI

     1exit   #  Go back to the LiveCD
     2
     3blkid /dev/sda2 # Find and copy the content of 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'  # Replace xxxxxxxx-xx with the PARTUUID you copied
    13
    14poweroff  # Shutdown, and then start again, you will enter the system.
    

Appendixes

Automatically start ssh-agent when the user logs in

This must be run as a normal user, not as root, because the ssh-agent must be separated for each user.

 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 # Login again to make it work

Remember the SSH keys in ssh-agent

Only works with ssh-agent.

When a SSH key is used in ssh/scp commands, you may want to remember it in ssh-agent, avoiding retype the password every time.

Prepend the following lines to ~/.ssh/config:

1AddKeysToAgent  yes

Optimize the effect of Ctrl key in the command line

Must be executed as root.

Edit the file /etc/inputrc, add two lines in the middle:

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

Now you can use Ctrl + Delete and Ctrl + Backspace to delete nearby words.

Tips

Take effect after you restart the terminal.

Switch to LTS version of Linux kernel

Must be executed as root.

If you prefer use a stable version of Linux kernel, you can switch to LTS version.

 1pacman -S linux-lts efibootmgr
 2
 3blkid /dev/sda2 # Find and copy the content of 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' # Replace xxxxxxxx-xx with the PARTUUID you copied
13
14poweroff  # Shutdown, and then start again, you will enter the system using LTS kernel.

If it works well, you can remove the old kernel:

1pacman -R linux

Enable access to host directories by CIFS

Must be executed as root.

  1. Create a normal user in Windows

    Go to Windows system settings, create a normal user (like arch-guest), set the password login (do not set reset password and password expiration).

  2. Right-click on the directory you want to share (like D:/VMShared), choose “Properties”, go to “Sharing”, choose “Advanced Sharing”, go to “Permissions”.

  3. Remove all permissions of “Everyone”, then click “Add”, add the user you created, grant all permissions, and save.

  4. Go to your virtual machine, execute the following command:

     1pacman -S cifs
     2
     3mkdir /mnt/vmshared # where to mount the shared directory in the guest machine
     4
     5id $YOUR_USER # Check the UID and GID of the normal user
     6
     7echo 'username=xxxxxxxxxxxx' > ~/.windows_credentials # The username in Windows
     8echo 'password=xxxxxxxxxxxx' >> ~/.windows_credentials # The password in 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  # Check if the shared directory is mounted successfully, or check dmesg for errors
    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  # Set it to mount automatically on boot
    

Setup system-wide transparent proxy (Optional)

Must be executed as root.

Tips

Download the latest stable version of tun2socks in https://github.com/xjasonlyu/tun2socks/releases/.

And you should replace the version v2.5.1 with the new version you downloaded.

Don’t forget change the line proxy: socks5://192.168.137.1:11111 to your proxy server.

 1sudo su # Switch to 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

Map ports to host (Optional)

The guest machine is behind the NAT network, so you will need to map the ports to the host.

The netsh command can be used to achieve port mapping. Here is how to use it, and don’t forget to execute it in an administrator PowerShell terminal:

  • Add a port mapping

    To map port 22 of the guest machine to port 2222 of the host machine, execute the following command:

    1netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=22 connectaddress=192.168.137.2
    
  • Check the existing port mappings

    1netsh interface portproxy show all
    

    An example output:

    1Listen on ipv4:             Connect to ipv4:
    2
    3Address         Port        Address         Port
    4--------------- ----------  --------------- ----------
    50.0.0.0         2222        192.168.137.2   22
    
  • Delete a port mapping

    Delete a port mapping by executing the following command:

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

FAQ

What if network is not working after reboot?

  • If tun2socks is enabled, please check if the proxy server is working.

  • If the network of host machine is changed, please turn off sharing of previous NIC, and share the current NIC to the virtual switch.

comments powered by Disqus

Translations: