Automated setup for a fresh Arch Linux WSL2 instance.
One command (after a quick user-setup step) takes you from a bare root environment to a fully configured development machine: system packages, AUR helper, Python/Node/Go/Rust toolchains, and dotfiles symlinked via GNU Stow — with SSH authentication handled by 1Password.
| Category | Tools |
|---|---|
| Shell | zsh + zinit, starship prompt |
| Editor | Neovim + lazy.nvim (LSP, Treesitter, Telescope) |
| CLI | ripgrep, fd, fzf, bat, eza, htop, tmux |
| Dev toolchains | pyenv (Python), fnm (Node), rustup (Rust), go |
| AUR | yay, 1password-cli, wslu, npiperelay |
| Fonts | JetBrains Mono Nerd Font, Noto Fonts (for WSLg) |
Complete these steps on Windows before touching WSL.
Download the latest Arch Linux bootstrap tarball from https://archlinux.org/download and import it as a WSL2 distro:
# In PowerShell (as Administrator)
wsl --install --no-distribution # Enable WSL2 if not already done
# Reboot if prompted
# Import Arch (adjust paths as needed)
New-Item -ItemType Directory -Path C:\WSL\Arch
wsl --import Arch C:\WSL\Arch C:\Downloads\archlinux-bootstrap-x86_64.tar.zst --version 2In the 1Password desktop app on Windows:
- Go to Settings → Developer
- Enable "Use the SSH agent"
This exposes your SSH keys to WSL2 without ever writing key files to disk.
npiperelay.exe bridges the 1Password SSH agent (a Windows named pipe) into WSL2.
It must be accessible from inside WSL — not just on the Windows PATH.
# Option A: WinGet
winget install albertony.npiperelay
# Option B: Scoop
scoop install npiperelayThen confirm the path from inside WSL (you will need this later):
# WinGet example
ls /mnt/c/Users/<WindowsUser>/AppData/Local/Microsoft/WinGet/Links/npiperelay.exewsl -d ArchYou land as root in a minimal Arch environment.
Run these commands as root inside the new distro. Replace gio with your preferred username.
# Create the user with a home directory and wheel group membership
useradd -m -G wheel -s /bin/bash gio
# Set a password
passwd gioecho "%wheel ALL=(ALL:ALL) ALL" > /etc/sudoers.d/wheel
chmod 0440 /etc/sudoers.d/wheelThis file tells WSL2 to start systemd, auto-login as your user, and mount Windows drives with proper metadata (needed for SSH key permissions).
cat > /etc/wsl.conf << 'EOF'
[boot]
systemd=true
[user]
default=gio
[automount]
enabled=true
options = "metadata,umask=22,fmask=11"
[interop]
enabled=true
appendWindowsPath=true
[network]
generateHosts=true
generateResolvConf=true
EOFWhy
metadatain automount options? Without it, Windows-mounted files always appear as755/644and SSH refuses private keys because they look world-readable.
Why
systemd=true? The 1Password SSH agent bridge relies on asystemdsocket unit. Without it, the bridge must be started manually every session.
From PowerShell or CMD (not from inside WSL):
wsl --shutdownThen relaunch:
wsl -d ArchYou are now logged in as gio (or whichever user you created). Verify:
whoami # should print your username, not rootsudo pacman -Sy git --noconfirmgit clone https://github.com/gio1612/arch-bootstrap.git ~/arch-bootstrap
cd ~/arch-bootstrapsudo bash bootstrap.sh --user "$USER" --dotfiles https://github.com/gio1612/dotfiles.gitThe bootstrap will:
- Run pre-flight checks — validates Arch Linux, WSL, internet, disk space, and arguments. Exits immediately with a clear error if anything is wrong.
- Configure
/etc/wsl.conf(idempotent — skipped if already written) - Set locale and timezone
- Ensure your user exists with wheel/sudo access
- Init the pacman keyring and run a full system upgrade
- Install all packages from
config/packages.txt - Build and install
yay, then install all AUR packages fromconfig/aur-packages.txt - Verify every package and key command — reports missing items before continuing
- Install dev toolchains: pyenv, fnm, rustup, Go workspace
- Sign in to 1Password CLI, clone your dotfiles, and stow all configs
- Set default shell to zsh and bootstrap zinit
- Fix ownership, clean up, print next steps
Phase 10 will print an
ACTION REQUIREDreminder to restart WSL again so that the new default shell and systemd changes take full effect.
After the bootstrap completes, 1Password CLI is installed and your dotfiles are stowed. Now configure SSH authentication.
op signinThe .zshrc from your dotfiles starts a socat bridge from the 1Password Windows named pipe
to a local socket. Test it:
ssh -T git@github.com
# Hi gio1612! You've successfully authenticated...If it fails, check:
npiperelay.exeis reachable:ls /mnt/c/Users/<WindowsUser>/.../npiperelay.exe- The path in
.zshrcmatches where it was installed (WinGet, Scoop, or manual) - 1Password SSH agent is enabled and unlocked (Settings → Developer → Use the SSH agent)
- The socat bridge started:
ls ~/.ssh/agent.sock - Restart the bridge manually:
pkill socat; exec zsh
The dotfiles .gitconfig intentionally omits machine-specific settings.
Create ~/.gitconfig.local on each machine:
[user]
signingkey = <your SSH public key from 1Password>
[gpg "ssh"]
program = /mnt/c/Users/<WindowsUser>/AppData/Local/1Password/app/8/op-ssh-sign-wsl.exeTo get the public key from 1Password CLI:
op read "op://Personal/GitHub SSH Key/public key"The bootstrap is idempotent — safe to re-run at any time. Already-completed phases are skipped automatically.
# Re-run everything from scratch
sudo bash bootstrap.sh --user "$USER" --dotfiles https://github.com/gio1612/dotfiles.git --force
# Re-run a single phase
sudo bash phases/05-packages.shLogs are written to /var/log/arch-bootstrap.log.
| File | Purpose |
|---|---|
config/packages.txt |
pacman packages to install (one per line, # comments ok) |
config/aur-packages.txt |
AUR packages installed via yay |
config/wsl.conf.template |
Template for /etc/wsl.conf ({{USER}} is substituted by phase 01) |
| Phase | What it does |
|---|---|
| 01 | Render config/wsl.conf.template → /etc/wsl.conf (only writes if changed) |
| 02 | Generate locale (en_US.UTF-8), detect and set timezone |
| 03 | Create user, add to wheel group, configure sudo, set password |
| 04 | Init pacman keyring, install sudo if missing, full system upgrade |
| 05 | Install packages from config/packages.txt |
| 06 | Build yay from source (avoids libalpm ABI mismatch), install AUR packages |
| 06b | Verify every package and key command; warns on failures, does not block |
| 07 | Install pyenv, fnm, rustup; create Go workspace |
| 08 | Sign in to 1Password CLI → clone dotfiles → stow all packages → shred temp key |
| 09 | Set default shell to zsh, bootstrap zinit |
| 10 | Fix home-dir ownership, clean up temp files, print summary and next steps |