Install VCode on Windows through WSL2
irm https://v-code.dev/install.ps1 | iex in PowerShell sets up WSL2 and an
Ubuntu distro with systemd, then runs the Linux installer inside the distro.
When WSL2 is already there it uses it as it is and installs nothing on Windows;
it only sets back a WSL service something has disabled. You
get the same box the Linux command makes, and it keeps running while you are
logged in to Windows. The command from "Add a computer" on app.v-code.dev
carries a join code, so the box links and pairs with that browser in one step.
Why you would use it
Your spare machine or your desk PC runs Windows, and you want VCode on it without a Linux install of its own. Inside WSL it is a Linux box: the same signed release, the same updater (update-automatically).
How to use it
You need Windows 10 21H2 (build 19044) or newer, or Windows 11, on an x64 PC, with virtualization turned on in the BIOS/UEFI.
Open PowerShell. Not the x86 one: the 32-bit PowerShell cannot see
wsl.exe.Run:
irm https://v-code.dev/install.ps1 | iexThe account page on v-code.dev shows this command with its own Copy button (
#copy-install-windows).Or copy the Windows command from "Add a computer" on app.v-code.dev (add-a-computer). It sets the join code first:
$env:V_CODE_JOIN='<code>'; irm https://v-code.dev/install.ps1 | iexWith it, step 7 has no email prompt: the box links and pairs with that browser, and the browser opens it.
A WSL service is disabled. When the Hyper-V Host Compute Service (
vmcompute) or the WSL Service (WSLService) is set to Disabled, which tuning tools and "stop WSL for good" guides do, Windows asks for administrator rights to set it back to the Windows default withsc.exe. Choose Yes. The install goes on; no restart.The Virtual Machine Platform is off. When neither it nor Hyper-V is on, Windows asks for administrator rights to turn it on with
dism.exe. Choose Yes, restart Windows, and run the command again (a new one, with a join code).No WSL yet. Windows asks for administrator rights to run
wsl --install --no-distribution. Choose Yes. When it is done, restart Windows and run the command again. It does nothing else on this run. If you run it again before the restart, it asks for nothing and says to restart. A join code lasts 15 minutes, so it runs out while Windows restarts. After a restart, make a new command.No Ubuntu distro yet. It installs Ubuntu-24.04. Ubuntu asks you to create your Linux user: type a user name and a password. When you see the Linux prompt, type
exit. The install goes on.When it asks, type your v-code.dev email, then the code from the email. This is the Linux installer's link step, as in install-on-linux. With
V_CODE_JOINset it joins instead and printsv-code: linked to <email>andv-code: paired with <browser name>.Open the URL it prints,
http://127.0.0.1:<port>, in a browser on Windows. Sign in with theAUTH_TOKEN. To read it from PowerShell:wsl -d Ubuntu-24.04 cat ~/.config/v-code/envPut your distro's name after
-d;wsl -l -vlists them.
Install your agents inside the distro, not on Windows. The installer drops the
Windows PATH (/mnt/...) before it runs, so Windows-side claude or codex
shims are not taken for agents. After you install one, run
~/.local/share/v-code/current/install.sh install in the distro.
The installer has no screen of its own. It runs in the terminal only.
What you see
Every line from the Windows script starts with v-code:. A full run prints, in
order:
v-code: the Hyper-V Host Compute Service (vmcompute) is disabled, and WSL cannot start without it. Windows asks for administrator rights to set it back to the Windows default: sc.exe config vmcompute start= demand, thenv-code: set it back to the Windows default. Only when a WSL service is disabled; with both, the line names both and one prompt sets both.v-code: WSL is not installed. Windows asks for administrator rights to run: wsl --install --no-distribution, thenv-code: WSL is installed. Restart Windows, then run this command again.Only when WSL is missing; the run ends there.v-code: the Virtual Machine Platform feature is off, and WSL 2 needs it. Windows asks for administrator rights to run: dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart, thenv-code: the Virtual Machine Platform feature is on. Restart Windows, then run this command again.Only when neither that feature nor Hyper-V is on; the run ends there.
With V_CODE_JOIN set, every "Restart Windows" line ends with
The join code in this command lasts 15 minutes, so after the restart copy a new command from Add a computer.
v-code: WSL is installed, but Windows has not restarted since. Restart Windows, then run this command again. If you have restarted since, run wsl --install --no-distribution in an administrator PowerShell, then run this again.When WSL was installed on an earlier run and Windows still needs the restart; the run ends there.v-code: updating WSL: wsl --update, when WSL is the old one built into Windows. This may ask for administrator rights too.v-code: no Ubuntu distro yet: installing Ubuntu-24.04. Create your Linux user when it asks; when you see the Linux prompt, type exit.v-code: turning on systemd in <distro>, when systemd is off. Ubuntu 24.04 already has it on, so this line does not show there.v-code: running the Linux installer in <distro>, then the Linux installer's own lines (install-on-linux).v-code: wrote <Startup folder>\v-code.lnk, which keeps <distro> running after you log in to Windowsv-code: started the keep-alive for <distro>, or on a second runv-code: the keep-alive for <distro> is already running.v-code: VCode is running: http://127.0.0.1:<port>
The URL shows only when /health answers from Windows within 60 s. Otherwise
it asks /health from inside the distro. When that answers:
v-code: VCode is running in <distro>, but Windows cannot reach it on http://127.0.0.1:<port>. Check that %USERPROFILE%\.wslconfig does not set localhostForwarding=false or networkingMode=none, that no Windows program holds port <port> (netstat -ano | findstr :<port>), and that the port is outside the ranges Windows reserves (netsh int ipv4 show excludedportrange protocol=tcp). Then run wsl --shutdown and this command again.
When it does not:
v-code: VCode did not answer on port <port>. In <distro>, check: systemctl --user status v-code.
It reads the port from VCODE_PORT in ~/.config/v-code/env, or, when that
file is missing, from WORKBENCH_PORT in ~/.config/claude-portal/env, where a
release from before the rename to VCode keeps it. When neither can be read:
v-code: installed in <distro>, but VCODE_PORT in ~/.config/v-code/env could not be read. Check that file in <distro>.
The checks that stop the run before anything in the distro is written:
| Check | Message |
|---|---|
| x64 | v-code: VCode on Windows needs an x64 PC; this one is <arch>. |
| not ARM64, even from an x64 PowerShell | v-code: VCode on Windows needs an x64 PC; this one is ARM64 (Windows on ARM), and the VCode release is built for x64 Linux only. |
V_CODE_JOIN is 34 letters, digits, - and _ |
v-code: V_CODE_JOIN is not a join code; copy the command again |
| build 19044 | v-code: VCode needs Windows 10 21H2 (build 19044) or newer; this is build <build>. Run Windows Update, then run this again. |
| 32-bit PowerShell | v-code: this is the 32-bit PowerShell, which cannot see wsl.exe. Open the 64-bit PowerShell (Windows PowerShell, not x86) and run this again. |
wsl.exe |
v-code: wsl.exe is missing. Install the latest Windows updates, then run this again. |
V_CODE_DISTRO names a distro |
v-code: there is no WSL distro named <name> (V_CODE_DISTRO). wsl -l -v lists them. |
| WSL 2 | v-code: <distro> runs on WSL 1. Convert it with: wsl --set-version <distro> 2, then run this again. Only when no Ubuntu* distro runs on WSL 2, or V_CODE_DISTRO names one on WSL 1 |
| a plain name | v-code: the distro name '<name>' has characters other than letters, digits and ._- (or starts with one of .-), so VCode does not pass it to a command. Pick or rename one that does not. The same for the user name |
| virtualization in the firmware, before any distro starts | v-code: virtualization is off in this PC's firmware, and WSL 2 cannot run without it. Turn on virtualization in the BIOS/UEFI setup (Intel VT-x or AMD-V, sometimes named SVM), then run this again. If this Windows is itself a virtual machine, turn on nested virtualization for it on the host (Hyper-V: Set-VMProcessor -VMName NAME -ExposeVirtualizationExtensions $true). Judged only when Windows' hypervisor is not running: a running one hides the CPU's virtualization from Windows |
| the distro starts | One of the messages in When WSL cannot start the distro |
| a normal default user | v-code: the default user of <distro> is root. VCode runs as a normal user: create one in <distro> (sudo adduser NAME), set it under [user] as default=NAME in /etc/wsl.conf, run wsl --terminate <distro>, then run this again. |
curl in the distro |
v-code: curl is missing in <distro>. Run sudo apt install curl in <distro>, then run this again. |
| the distro reaches the internet | v-code: <distro> cannot download <url> (curl exit <n>): then the cause. Exit 6, it cannot look up the host: add dnsTunneling=true (Windows 11) or networkingMode=mirrored under [wsl2] in %USERPROFILE%\.wslconfig, or disconnect the VPN. Exit 7 or 28, it cannot connect: the VPN, a firewall or a proxy (https_proxy). Exit 35, 51, 58, 60, 77 or 83, the certificate: the distro's clock, or a company proxy's CA to copy into the distro with update-ca-certificates. Any other exit gives curl's own error. curl gives up connecting after 15 s |
When WSL cannot start the distro
Every wsl -d call the script captures reads WSL's error code. A code it knows
gives a message that starts v-code: WSL could not start <distro> and names the
fix:
| WSL's code | The cause the message names | The fix it gives |
|---|---|---|
HCS_E_SERVICE_NOT_AVAILABLE, 0x80370114 |
the Hyper-V Host Compute Service could not start | Set-Service vmcompute -StartupType Manual and dism.exe for the Virtual Machine Platform, a restart; then the Exploit protection override for vmcompute.exe |
HCS_E_HYPERV_NOT_INSTALLED, 0x80370102, with the feature on |
the Windows hypervisor is not running | bcdedit /set hypervisorlaunchtype auto, a restart |
| the same, with the feature off | the Virtual Machine Platform feature is off | the same dism.exe, a restart |
0x800701bc |
its Linux kernel needs an update | wsl --update |
0x80070422 |
a service it needs is disabled | sc.exe config for WSLService, vmcompute and hns |
0x8007019e, 0x8004032d |
the Windows Subsystem for Linux feature is off | wsl --install --no-distribution, a restart |
HCS_E_CONNECTION_TIMEOUT, 0x80370109 |
its VM did not answer in time | wsl --shutdown; then a restart and wsl --update |
E_UNEXPECTED, 0x8000ffff, 0x8000000d |
WSL is in a bad state | wsl --shutdown; then a restart |
0x8007273d |
a network filter broke Windows sockets | netsh winsock reset, a restart |
0x80070070 |
the disk is full | free space on the distro's drive |
0x800704ec, a policy message |
a policy on this PC blocks WSL | whoever manages the PC allows AllowWSL |
Any other failure gives WSL's own text:
v-code: wsl -d <distro> did not start (exit code <code>): <what WSL printed>.
WSL's warnings on stderr, such as
wsl: Failed to translate 'D:\...' for a Windows PATH entry it cannot map,
show in these messages but never stop the run.
Later failures:
v-code: Windows did not run 'wsl.exe --install --no-distribution' as administrator (<reason>). If you declined the prompt, run this again and choose Yes. If Windows asked for an administrator's password you do not have, ask an administrator to run: wsl.exe --install --no-distributionThe same for thesc.exeanddism.exeprompts, with their commands.v-code: the <service> is still disabled (exit code <code>). In an administrator PowerShell run: sc.exe config <service> start= <mode> -- then run this again. If it is disabled again after that, a policy or a tuning tool is turning it off.v-code: dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart stopped with exit code <code>. Run it in an administrator PowerShell, restart Windows, then run this again.v-code: wsl --install --no-distribution stopped with exit code <code>. Run it in an administrator PowerShell, restart Windows, then run this again.v-code: wsl --update stopped with exit code <code>. Run it yourself, then run this again.v-code: wsl --install -d Ubuntu-24.04 stopped with exit code <code>, and Ubuntu-24.04 is not in WSL. Run it yourself, then run this again. If you installed WSL and have not restarted Windows since, restart first.A non-zero exit code alone does not stop the run: it is the exit code of the first Linux shell, so the run goes on when Ubuntu-24.04 is there.v-code: systemd did not come up in <distro> within 90 s. Run wsl --update, then run this again.The same withsystemctl --userfor the user manager.v-code: the Linux installer stopped with exit code <code>. Its messages above say why; fix that and run this again.
Options and settings
Set these in the same PowerShell window before the command, for example
$env:V_CODE_DISTRO = 'Debian'.
| Option | Default | What it changes |
|---|---|---|
V_CODE_DISTRO |
the default distro when its name starts with Ubuntu and it runs on WSL 2, else the first Ubuntu* on WSL 2, else a new Ubuntu-24.04 |
The distro to install into. It must exist, run on WSL 2 and have curl |
V_CODE_INSTALL_URL |
https://app.v-code.dev/install.sh |
The Linux installer it runs. For tests and staging. Letters, digits and ._:/- only |
V_CODE_JOIN |
unset | The join code from "Add a computer". The Linux installer joins with it instead of asking for the email |
To pass --port to the Linux installer, run the Linux command inside the
distro instead.
Limits and known gaps
- Beta. The script is tested with
wsl.exeand Windows replaced by stubs. A full install with a join code has run on one real PC (Windows 11 build 26200, WSL 2.7.14, Hyper-V on,vmcomputedisabled until the script set it back, an existingUbuntudistro). - x64 only. No Windows on ARM.
- On a PC with no distro, the first VM start is inside
wsl --install -d, whose output the script does not read. The firmware and Virtual Machine Platform checks run before it, but a failure they do not catch shows only WSL's own error above the script'swsl --install -d Ubuntu-24.04 stoppedline. - A PC whose Microsoft Store is blocked cannot run
wsl --installorwsl --updatethis way. Run them yourself with--web-download, then run the command again. - Constrained Language Mode (AppLocker, WDAC) refuses the Startup shortcut, so the install finishes without the keep-alive.
- The Windows script does not report whether the join worked; the Linux installer's lines above say so.
- The box runs while you are logged in to Windows. WSL stops a distro soon
after its last
wsl.exeprocess exits, and systemd units do not count. The keep-alive is a hiddenwsl.exerunningsleep infinity, started byv-code.lnkin your Startup folder each time you log in. wsl --shutdown, or a WSL update, stops the keep-alive and the box with it. It stays stopped until your next login, or until you runv-code.lnkfrom the Startup folder yourself.- Sleep and hibernate stop it too, like any program on the PC.
- The Windows script does not install agents. Install them inside the distro.
- A join code lives 15 minutes and works once. An install that stops for a
Windows restart outlives it. After a restart, make a new command. The Windows
note under the command on "Add a computer" (
#rs-add-windows) says so: "If this PC already has WSL2, it uses it and installs nothing on Windows. If not, it installs WSL2, asks for administrator rights and a restart; after the restart, make a new command."
Remove it
- Delete
v-code.lnkfrom the Startup folder. Press Win+R, typeshell:startup, and delete the file. - In the distro, run
~/.local/share/v-code/current/install.sh uninstall. It removes the units and the release; the env file and the state stay (install-on-linux lists what it removes). - Run
wsl --terminate <distro>to stop the keep-alive now, or log out.
Related
- install-on-linux — the installer this runs inside the distro
- update-automatically — how the box keeps itself up to date
- add-a-computer — the command with the join code
- link-this-box — the link the installer runs at the end
- log-in-with-the-token — where the
AUTH_TOKENgoes