何
WSLでは、開いたターミナルからwindows側のVSCodeをcode .で開くことができる。
これをSSH接続先のubuntuからでもできるようにしたかったので、やった。
今回は、ubuntuマシンFMVAにSSH接続し、vscode .でwindowsのVSCodeを起動できるようにしたのでそのケースを書く。
code --remoteでwindowsからリモートに接続してVSCodeを開けるので、
Windows側でHTTPリスナーを起動しておき、UbuntuからはSSHのポートフォワード経由でhostとpathを送る。リスナーは受け取った情報を使って、Windows上で次のようなコマンドを実行する。
code --remote ssh-remote+FMVA /home/user/projects/test
処理の流れは次のとおり。
- Ubuntuで
vscode .を実行する。 - シェル関数が現在の絶対パスとSSHホスト名をHTTPで送る。
-
RemoteForwardが、そのHTTPリクエストをWindowsのローカルポートへ転送する。 - WindowsのPowerShellスクリプトが
code --remoteを実行する。 - VSCodeがRemote SSH経由でUbuntu上のフォルダを開く。
下準備
- WindowsにVSCodeと拡張機能Remote-SSHを入れる
- Windowsから
ssh FMVAでUbuntuへ接続できるようにする - WindowsのPowerShellで
code --versionが実行できることを確認する - Ubuntuに
curlをインストールする
(この記事の設定は、最初に書いた通りWindowsからUbuntuへSSH接続する場合のもの。FMVAはWindowsのSSH設定で使っているホスト別名なので、各自の名前に置き換える。ubuntuやwindowsのユーザー名も同様。)
1.WindowsのSSH設定にRemoteForwardを追加する
Windowsの~/.ssh/configを開き、対象ホストの設定へRemoteForwardを追加する。
Host FMVA
HostName 192.168.x.x
User user
RemoteForward 54321 localhost:54321
この設定で、Ubuntu側のlocalhost:54321へ接続すると、SSHトンネルを通ってWindows側の localhost:54321へ届く。
設定を反映するには、いったんSSH接続を切断して接続し直す。
2. Windows側でVS Codeを起動するリスナーを作る
Windows側に、HTTPリクエストを受け取ってVS Codeを起動するPowerShellスクリプトを作成する。ここではvscode-listener.ps1という名前にする。
param(
[int]$Port = 54321
)
$listener = [System.Net.HttpListener]::new()
$listener.Prefixes.Add("http://localhost:$Port/")
$listener.Start()
Write-Host "VS Code listener started: http://localhost:$Port/"
Write-Host "Stop with Ctrl+C"
try {
while ($listener.IsListening) {
$context = $listener.GetContext()
$request = $context.Request
$response = $context.Response
try {
$hostName = $request.QueryString["host"]
$path = $request.QueryString["path"]
if ([string]::IsNullOrWhiteSpace($hostName) -or
[string]::IsNullOrWhiteSpace($path)) {
throw "host または path が指定されていません。"
}
# 意図しない起動を防ぐため、許可するSSHホストを限定する。
if ($hostName -ne "FMVA") {
throw "許可されていない host です: $hostName"
}
# Ubuntuのホーム配下だけを開けるようにする。
if (-not $path.StartsWith("/home/user/")) {
throw "許可されていない path です: $path"
}
$code = (Get-Command code -ErrorAction Stop).Source
Start-Process -FilePath $code -ArgumentList @(
"--remote",
"ssh-remote+$hostName",
$path
)
Write-Host "Opened: $hostName $path"
$response.StatusCode = 204
}
catch {
Write-Warning $_
$response.StatusCode = 400
}
finally {
$response.Close()
}
}
}
finally {
$listener.Stop()
$listener.Close()
}
hostとpathを検証しているのは、受け取った値をそのままVS Codeの起動に使わないため。自分だけが使う構成でも、ホスト名と開けるパスを絞っておくと安心。
PowerShellでスクリプトを起動する。
Set-Location "C:\Users\<ユーザー名>\Scripts"
.\vscode-listener.ps1
次の表示が出れば、リスナーの起動は完了。
VS Code listener started: http://localhost:54321/
このPowerShellのウィンドウは、Ubuntuからvscodeを使っている間は開いたままにしておく。
3. Ubuntuに vscode 関数を追加する
Ubuntuの~/.bashrcまたは~/.bash_aliasesに次の関数を追加する。
vscode() {
local path
path="$(realpath "${1:-.}")" || return
echo "Opening: $path"
curl --fail --silent --show-error -G \
--data-urlencode "host=FMVA" \
--data-urlencode "path=$path" \
http://localhost:54321/
}
source ~/.bashrcまたはsource ~/.bash_aliasesで反映する。
この関数では、引数がなければ現在のディレクトリを使う。realpathで絶対パスにしてから、curl --data-urlencodeで安全に送信しているため、パスに空白や日本語が含まれていても扱える。
これで、SSH先のUbuntuで次のように使える。
vscode .
vscode ~/projects/my-app
動作確認
まず、Windows側のリスナーを直接叩いて、VSCodeが起動するか確認する。
Invoke-WebRequest `
-Uri "http://localhost:54321/?host=FMVA&path=%2Fhome%2Fuser" `
-Method Get
HTTPステータスが204で、VSCodeが開けばリスナーは正常。
次にWindowsからssh FMVAで接続し直し、Ubuntuで確認する。
curl -v -G \
--data-urlencode "host=FMVA" \
--data-urlencode "path=$HOME" \
http://localhost:54321/
このリクエストでVSCodeが開けば、RemoteForwardも正常に動いている。最後にvscode .を実行して確認する。
うまく動かないとき
Ubuntuで接続エラーになる
curl: (7) Failed to connectのようなエラーが出る場合は、次を確認する。
- Windows側で
vscode-listener.ps1を起動しているか - SSH接続を、RemoteForwardを追加したあとに張り直したか
- Windowsの
~/.ssh/configの対象が、実際に接続しているHost FMVAか
Ubuntu側でcurl -v http://localhost:54321/を実行すると、どこで止まっているか確認しやすい。
HTTPは204だがVSCodeが開かない
WindowsのPowerShellで、次を単体で実行してみる。
code --remote ssh-remote+FMVA /home/user
これで開かない場合は、リスナーではなくVSCode CLIまたはRemote SSH側の問題。code --version が実行できるか、VSCodeのRemote SSH設定にFMVAが見えているかを確認する。
以前は動いたのに急に動かなくなった
この構成ではWindows側のリスナーが常駐している必要がある。まずPowerShellのリスナー画面が閉じていないかを確認する。
VSCodeは開けるがSSH接続はエラーになる
まずこれが躓くところだと思う。すごく苦労した。
RemoteForwardをターミナルとVSCode内で奪い合ってしまうのが原因。
ターミナルで接続するSSHをこのように迂回する。
Host FMVA
HostName FMVA
User user
IdentityFile ~/.ssh/id_ed25519
Host FMVA-shell
HostName FMVA
User user
IdentityFile ~/.ssh/id_ed25519
RemoteForward 54321 localhost:54321
ExitOnForwardFailure yes
ターミナルでSSH接続するときはFMVA-shellを使い、VSCodeではFMVAを使う。
PowerShellに打ち込む文字列をもっと短くしたい
Set-Location "C:\Users\<ユーザー名>\Scripts"
.\vscode-listener.ps1
長い。なのでバッチファイルを作る。
@powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%USERPROFILE%\bin\vscode-listener.ps1"
%USERPROFILE%\binにvscode-listener.ps1があれば、これで起動する。
%USERPROFILE%\binにパスを通しておくといいだろう。
これで使用感をWSLと同じようにできる。