Setup on WSL

This runbook sets up the dev environment in an Arch distribution on a Windows host.

The distribution

  1. Create the distribution from PowerShell.

    wsl --install archlinux --no-launch
    

    --no-launch prevents an account setup at the first start.

  2. Start the distribution as root.

    wsl -d archlinux -u root
    

The keyring

The official image does not contain sudo or a user account. It also does not contain an initialised pacman keyring. Without the keyring, pacman -Syu stops with keyring is not writable.

  1. Initialise the keyring as root.

    pacman-key --init
    pacman-key --populate archlinux      # ~182 keys
    pacman -Syu --noconfirm
    

The user account

  1. Create the locale.

    sed -i 's/^#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen
    locale-gen
    echo 'LANG=en_US.UTF-8' > /etc/locale.conf
    
  2. Create the user and the sudo rule.

    useradd -m -G wheel -s /bin/bash jdoe
    echo '%wheel ALL=(ALL:ALL) ALL' > /etc/sudoers.d/10-wheel
    chmod 0440 /etc/sudoers.d/10-wheel
    
  3. Check the sudo rule.

    visudo -c -f /etc/sudoers.d/10-wheel
    
  4. Set the password from PowerShell.

    wsl -d archlinux -u root passwd jdoe
    

    Until you set the password, sudo stops with a password is required. WSL lets you in because it trusts the Windows session.

/etc/wsl.conf

  1. Add these lines to /etc/wsl.conf.

    [boot]
    systemd=true
    
    [interop]
    enabled=true
    appendWindowsPath=false
    
    [automount]
    enabled=true
    options="metadata,umask=22,fmask=11"
    
    [user]
    default=jdoe
    
  2. Restart the distribution from PowerShell.

    wsl --shutdown
    

    Do not use --terminate, because that command does not register the WSLInterop handler. Each Windows executable then stops with exec format error.

  3. Start the distribution again.

  4. Check the systemd state and the interop handler.

    id                                              # your user and group IDs
    systemctl is-system-running                     # running
    [ -f /proc/sys/fs/binfmt_misc/WSLInterop ] && echo interop-ok
    

    The output names your user, for example uid=1000(jdoe), and shows running and interop-ok.

    appendWindowsPath=false removes each Windows directory from PATH. Command completion then does not examine the 9p mount. To use a Windows tool, write the full path, or use the pwsh wrapper in ~/.local/bin.

Packages

  1. Install the packages as root.

    pacman -S --needed sudo git openssh chezmoi
    

    The image does not contain sudo yet. chezmoi apply installs all other packages. WSL has no AUR helper and no Wayland stack, so the installation uses the official repositories only.

Linger

  1. Enable linger for your user.

    sudo loginctl enable-linger $USER
    

    XDG_RUNTIME_DIR is the directory for your session’s runtime files. systemd-logind creates it at login, and sets the variable for your session. The path is /run/user/ plus your user ID, such as /run/user/1000 for the first user.

    WSL sets the variable even when no logind session exists, so the directory can be missing. Linger makes logind create it at boot and keep it after you log out. Without linger, chezmoi update stops with an error like mkdir /run/user/1000: permission denied, although SSH operates correctly.

The SSH key

WSL has no service account token. 1Password therefore cannot load the key into the agent. The key is on disk, and ~/.bashrc loads it one time for each session.

  1. Create the .ssh directory.

    mkdir -p ~/.ssh && chmod 700 ~/.ssh
    
  2. Paste the private key from the Devices/jdoe_id item.

    ( umask 077; cat > ~/.ssh/jdoe_id )
    

    Press Ctrl-D after the last line of the key. The public half is already registered with GitHub and with the server. You need only the private key.

  3. Set the file mode to 0600.

    chmod 600 ~/.ssh/jdoe_id
    

    The subshell prevents a change to umask in the parent shell. If you set umask without a subshell, the next git pull writes each file that it changes as 0600.

  4. Start the agent socket.

    systemctl --user start ssh-agent.socket
    
  5. Export the socket path.

    export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
    
  6. Add the key to the agent.

    ssh-add ~/.ssh/jdoe_id
    

    The command prompts for the passphrase.

  7. Check the key with GitHub.

    ssh -T git@github.com
    

    The output contains Hi <user>!.

    After you apply the dotfiles, ~/.bashrc runs the ssh-add command for each interactive shell with an empty agent. It does not run in a non-interactive shell. If no prompt appears, check whether the shell is interactive.

Apply the dotfiles

  1. Run the chezmoi init command.

    chezmoi init --apply ssh://git@git.jdoe-site.com:2222/home/git/dotfiles.git
    

    The URL contains the port number and the user name. This form does not need ~/.ssh/config. The command prompts for your name, your email, and the font size. The answers are kept for this machine. For an unattended installation, add --promptString.

    The command also writes the Windows Alacritty configuration through /mnt/c. The terminal then uses the shared template and the font. A second copy on Windows is not necessary.

tmux and Neovim

tmux runs every shell. ~/.bashrc contains exec tmux new-session. tmux opens session 0 for the first terminal and session 1 for the second. A session continues after you close its terminal.

  1. Start Neovim to install the treesitter parsers.

    nvim
    
  2. Quit Neovim.

    Type :q and press Enter.

Neovim is the editor for vi and vim. Its keys are in neovim. The shell keys are in terminal and workflow.

Editing the dotfiles

chezmoi manages each file in your home directory. chezmoi shows the commands to edit a file and to check for changes that are not applied.

Verification

  1. Open a file in the editor.

    nvim ~/.bashrc
    

    Neovim shows the file.

  2. Quit Neovim.

    Type :q and press Enter.

  3. List the tmux sessions.

    tmux ls
    

    The output shows session 0 and each session that you did not close.

  4. Check the key with GitHub.

    ssh -T git@github.com
    

    The output contains Hi <user>!.