[PR] 本記事にはプロモーションが含まれています。

【番外編】VS Code の Remote-SSH で、自宅サーバーを直接開発する

TypeScript

はじめに

このシリーズの開発は、すべて自宅サーバーの上で行っています。手元の Windows PC で VS Code を開き、Remote-SSH という拡張機能でサーバーに接続して、サーバー上のファイルを直接編集し、サーバー上のターミナルでコマンドを実行しています。

これまでの回では当たり前のように「VS Code のターミナルで」と書いてきましたが、その前提になっている接続の方法は紹介していませんでした。この番外編では、Remote-SSH の仕組みと設定の手順、そして実際につまずいたことをまとめます。

ほかの方法との違い

手元の PC で Linux の環境を使う方法には、Windows の WSL もあります。私の使い方では、次のような違いで Remote-SSH を選んでいます。

WSLRemote-SSH(自宅サーバー)
Linux が動く場所手元の PC の中別のマシン(自宅サーバー)
作ったものの公開PC を閉じると止まるので、公開には向かないサーバーは常時動いているので、そのまま公開できる
開発と本番の環境別々(開発後にサーバーへ持っていく必要がある)同じマシン。開発したその場で、本番と同じ構成で確かめられる
必要なものPC だけ常時動いている Linux サーバー

組み込みでいえば、Remote-SSH は、手元の PC のエディタとデバッガから、ケーブル越しにターゲットボードを直接触っている状態です。ソースもビルドも実行もターゲット側にあり、手元にあるのは画面と操作だけ、という形になります。

仕組み:画面は手元、それ以外はサーバー

Remote-SSH で接続すると、VS Code は2つに分かれて動きます。

手元の PC の VS Code とブラウザが、SSH の1本の接続を通して、自宅サーバーの VS Code Server、ファイル、ターミナルにつながっている様子を示した図
場所動いているもの役割
手元の PCVS Code 本体画面の表示と、キーボード・マウスの操作だけ
自宅サーバーVS Code Serverファイルの読み書き、ターミナル、拡張機能の多く、ポート転送の受け口

VS Code Server は、初めて接続したときに、VS Code が自動でサーバーの ~/.vscode-server に入れてくれます。自分でインストールする必要はありません。

ファイルはサーバー上にしかないので、編集した内容は、保存した瞬間にサーバーのディスクに書き込まれます。ターミナルもサーバー上で動いているので、npm run build や git push は、そのままサーバーの上で実行されます。

手元とサーバーの間は、SSH(暗号化された遠隔ログインの仕組み)の1本の接続だけでつながっています。画面の操作も、ファイルの中身も、ターミナルの入出力も、ポート転送も、すべてこの1本の中を通ります。サーバーの側で開けておく必要があるのは、SSH の 22 番ポートだけです。

準備:鍵を作り、サーバーに登録し、接続先を設定する

ここからは、手元の Windows PC から自宅サーバーへ、パスワードではなく鍵でログインできるようにする手順です。自宅の LAN の中から接続するので、ルーターでポートを開ける必要はありません。

この記事では、サーバーの IP アドレスを 192.168.0.10、サーバーのユーザー名を devuser、接続先に付ける呼び名を myserver としています。ご自分の環境に合わせて読み替えてください。

① SSH のクライアントがあるか確かめる

Windows 10 / 11 には、SSH のクライアントが標準で入っています。PowerShell で確かめます。

PowerShell
PS> ssh -V

OpenSSH_for_Windows_… のようにバージョンが表示されれば使えます。

② 鍵を作る

PowerShell
PS> ssh-keygen -t ed25519

保存場所を聞かれたら、そのまま Enter で既定の場所(C:\Users\<ユーザー名>\.ssh\id_ed25519)に保存します。パスフレーズ(鍵そのものにかける合言葉)は、設定しておくのがおすすめです。

2つのファイルができます。

ファイル中身扱い
id_ed25519秘密鍵手元の PC から外に出さない
id_ed25519.pub公開鍵ログインしたいサーバーに登録する

組み込みでいえば、秘密鍵はセキュアエレメントの中に閉じ込めた鍵、公開鍵は相手に渡して照合してもらう情報です。

③ 公開鍵をサーバーに登録する

公開鍵の中身を、サーバーの ~/.ssh/authorized_keys に書き足します。Windows には Linux の ssh-copy-id がないので、次の1行で行います。このときだけ、サーバーのパスワードを聞かれます。

PowerShell
PS> Get-Content $HOME\.ssh\id_ed25519.pub | ssh devuser@192.168.0.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
部分意味
Get-Content … |公開鍵の中身を読み出して、次のコマンドに渡す
ssh devuser@192.168.0.10 "…"サーバーにログインして、"…" の中のコマンドを実行する
cat >> ~/.ssh/authorized_keys受け取った公開鍵を、登録済みの鍵の一覧の末尾に書き足す
chmod 700 / chmod 600自分以外は読めないようにする。権限が緩いと、SSH は安全のため鍵を使ってくれない

④ 接続先に呼び名を付ける

毎回 devuser@192.168.0.10 と打たなくて済むように、設定ファイル C:\Users\<ユーザー名>\.ssh\config に呼び名を登録します。ファイルがなければ新しく作ります。

Plaintext
Host myserver
    HostName 192.168.0.10
    User devuser
    IdentityFile ~/.ssh/id_ed25519

⑤ 鍵でログインできるか確かめる

PowerShell
PS> ssh myserver

サーバーのパスワードを聞かれずに(パスフレーズを付けた場合は、パスフレーズだけを聞かれて)ログインできれば、準備は完了です。exit で抜けます。

初めて接続したときは、「この相手の指紋はこれですが、接続しますか?」と聞かれます。yes と文字で入力して Enter を押してください。Enter だけを押すと「拒否」として扱われます。

VS Code で接続する

鍵でログインできるようになれば、VS Code 側の作業は少しだけです。

  1. VS Code の拡張機能で「Remote – SSH」(Microsoft 製)を検索して、インストールします。
  2. F1 キーを押し、「Remote-SSH: Connect to Host…」を選びます。
  3. 一覧に、④ で設定した myserver が出てくるので選びます。
  4. 新しいウィンドウが開き、初回はサーバーに VS Code Server が自動で入ります(少し時間がかかります)。
  5. 「フォルダーを開く」で、サーバー上の作業フォルダ(たとえば /home/devuser/apps/unitconv)を選びます。
VS Code のコマンドパレットで「Remote-SSH: Connect to Host...」を選び、接続先の一覧から myserver を選ぶ画面のイメージ

接続できると、VS Code の左下に、SSH: myserver のような緑色の表示が出ます。これが出ている間は、エディタで開いたファイルもターミナルも、すべてサーバー上のものです。

サーバーに接続中の VS Code の画面のイメージ。左下に SSH: myserver の表示、左側にサーバー上のフォルダ、下側にサーバーのプロンプトのターミナルがある

接続を終えるときは、この左下の表示をクリックして「リモート接続を閉じる」を選びます。

日々の使い方

ターミナル

Ctrl + Shift + `(バッククォート。日本語キーボードでは @ のキー)で、ターミナルが開きます。このターミナルはサーバーの上で動いているので、行頭はサーバーのプロンプト([devuser@myserver unitconv]$ など)になります。シリーズの記事で「VS Code のターミナルで」と書いているのは、すべてこのターミナルのことです。

ポート転送:サーバーで動かした画面を、手元のブラウザで見る

サーバーで動かした開発用のサーバー(たとえば 第4回の Vite の開発サーバー)は、外から勝手につながらないよう、サーバー自身(127.0.0.1)からの接続だけを受け付けるようにしています。そのままでは、手元の PC のブラウザから見られません。

そこで使うのが、VS Code のポート転送です。

  1. VS Code の下部パネルの「ポート」タブを開きます。
  2. 一覧に、サーバーで待ち受けているポート(たとえば 5173)があれば、そのまま使います。サーバーでプログラムを起動すると、自動で追加されることもあります。
  3. なければ「ポートの転送」を押して、ポート番号を入力します。
  4. 手元の PC のブラウザで、http://localhost:5173/… を開きます。
VS Code の下部パネルのポートタブで、サーバーの 5173 番が localhost:5173 に転送され、手元のブラウザでその URL を開いている様子のイメージ

SSH の接続の中を通して、サーバーの 5173 番を、手元の PC の 5173 番につないでいる状態です。インターネットには一切公開されません。組み込みでいえば、デバッガのケーブルの中に、もう1本の信号線を通してもらうようなものです。

シリーズでは、開発中の画面の確認(第4回)や、ビルドしたサーバーの単体確認(第7回)で、この方法を使っています。

GitHub への push は VS Code に任せる

サーバー上で書いたソースは、GitHub の非公開リポジトリに送って保管しています。ここで、「サーバーから GitHub に、どうやって認証するか」という問題が出てきます。

最初に考えた方法:SSH 鍵

最初は、GitHub にも SSH 鍵で接続しようとしました。ただ、サーバーに秘密鍵を置くと、サーバーが乗っ取られたときに、その鍵で入れる GitHub のリポジトリまで危険になります。そこで、手元の PC の鍵をサーバーから借りて使うエージェント転送という方法も試しました。秘密鍵は PC から出さず、サーバーからの署名の依頼だけを、SSH の接続の中で PC に中継してもらう仕組みです。

ところが、PowerShell から ssh -A で入ったときは転送が効いたのに、VS Code のターミナルでは、転送の目印になる SSH_AUTH_SOCK が空のままで、うまくいきませんでした。

落ち着いた方法:HTTPS + VS Code のサインイン

実は、VS Code には、手元でサインインしている GitHub のアカウントを使って、サーバー上の git の認証に答える仕組みがあります。普段から VS Code の「ソース管理」の画面で push していたのは、この仕組みのおかげでした。

サーバーの git が push するときに、VS Code が用意した認証の窓口に問い合わせ、SSH の接続の中を通って手元の VS Code がサインイン済みの GitHub アカウントで答え、その認証の情報を付けて GitHub に送る流れの図

この仕組みが使えるのは、送り先が HTTPS 形式(https://github.com/…)のときだけです。SSH 形式(git@github.com:…)で登録していると、SSH 鍵で接続しようとして失敗します。送り先の形式は、次のコマンドで確かめて、必要なら書き換えます。

PowerShell
$ git remote -v
$ git remote set-url origin https://github.com/example-user/apps-hello.git
$ git push -u origin main

行頭の $ は、一般ユーザーで実行するコマンドであることを示す記号(プロンプト)です。実際に入力するのは $ の後ろからです。

この方法なら、サーバーには SSH 鍵もパスワードも置きません。手元の VS Code でサインインしている間だけ push できる、という形になります。組み込みでいえば、鍵はセキュアエレメント(手元の PC)から一切出さず、必要なときだけ署名を代行してもらう形です。

方法秘密鍵・認証情報の場所結果
サーバーに SSH 鍵を置くサーバー採用しない(サーバーが乗っ取られると鍵も漏れる)
エージェント転送手元の PCVS Code のターミナルでは転送されず、うまくいかなかった
HTTPS + VS Code のサインイン手元の PC(VS Code)採用。VS Code のターミナルやソース管理から push できる

注意点は、VS Code を通さずに(たとえば PowerShell の ssh で)サーバーに入ったときは、この仕組みが使えないことです。push は、VS Code のターミナルかソース管理の画面から行います。

つまずいたこと

PowerShell では、外部のコマンドに ~ が通じない

エージェント転送を試したとき、PC の鍵を ssh-agent(鍵を預かって署名を代行する常駐プログラム)に読み込ませようとして、次のエラーになりました。

Plaintext
PS> ssh-add ~\.ssh\id_ed25519
~\.ssh\id_ed25519: No such file or directory

直前の ls ~\.ssh では、ファイルがちゃんと見えていたのにです。PowerShell では、~(ホームフォルダ)が展開されるのは、ls のような PowerShell 自身のコマンドのときだけで、ssh-add のような外部のプログラムには、~ という文字がそのまま渡されてしまいます。

PowerShell の変数 $HOME を使えば解決します。

PowerShell
PS> ssh-add $HOME\.ssh\id_ed25519

C でいえば、プリプロセッサが展開してくれると思っていたマクロが、展開されずに文字列のまま関数に渡ったような状態です。この記事の手順③で $HOME を使っているのも、このためです。

初めての接続先で、Enter だけを押すと拒否になる

初めて接続する相手には、SSH が「この相手の指紋はこれですが、本物と信じて接続しますか?」と聞いてきます。なりすましのサーバーにつながっていないかを確かめるための仕組みで、組み込みでいえば、初回のペアリングで相手のデバイス ID を確かめるのと同じです。

ここで Enter だけを押すと「拒否」として扱われ、Host key verification failed. で止まります。y だけでも受け付けられず、yes と文字で入力する必要がありました。

push が突然、認証エラーになる

それまで送れていた push が、ECONNREFUSED /run/user/…/vscode-git-….sock というエラーで失敗したことがあります。上の図の「認証の窓口」に、ターミナルがつながらなくなっていたのが原因で、ターミナルを開き直すと直りました。詳しくは、Git のつまずきをまとめた番外編で紹介しています。

VS Code の PATH が、サーバーの設定に紛れ込む

VS Code のターミナルには、VS Code 自身が使うフォルダ(~/.vscode-server/…)が、コマンドを探す場所の一覧(PATH)に追加されています。そのため、ターミナルの PATH をそのまま書き込むようなコマンドを実行すると、サーバーの設定に VS Code の都合が紛れ込みます。私の場合は、PM2 の自動起動の設定でこれが起きました。詳しくは、第2回で紹介しています。

設定を変えても、接続し直すだけでは反映されないことがある

SSH の設定ファイル(config)を書き換えた後、左下の表示から「リモート接続を閉じる」で接続し直しても、新しい設定が効かないことがあります。VS Code が、裏で前の接続を使い回すことがあるためです。

そのときは、F1 →「Remote-SSH: Kill VS Code Server on Host…」で接続先を選び、サーバー側の VS Code Server をいったん止めてから接続し直します。

まとめ

Remote-SSH を組み込みの言葉に置き換えると、次のようになります。

Remote-SSH の要素組み込みでいうと
手元の VS Code と、サーバーの VS Code Server手元のエディタ・デバッガと、ターゲット上のデバッグモニタ
SSH の1本の接続デバッガのケーブル(すべての信号がこの中を通る)
ポート転送ケーブルの中に通してもらう、もう1本の信号線
秘密鍵と公開鍵セキュアエレメントの中の鍵と、相手に渡して照合してもらう情報
初回接続の指紋の確認初回のペアリングで相手のデバイス ID を確かめる
VS Code による GitHub の認証鍵は手元から出さず、署名だけを代行してもらう

一度設定してしまえば、普段は VS Code を開いて接続先を選ぶだけで、サーバー上のファイルとターミナルを、手元のパソコンと同じ感覚で使えます。開発した場所がそのまま本番のサーバーなので、「手元では動いたのに、サーバーでは動かない」という問題が起きにくいのも、自宅サーバーで学ぶうえでの大きな利点だと感じています。

この記事は、シリーズ「組み込みエンジニアの Web 開発入門」の1本です。ほかの回は、シリーズの目次からどうぞ。

ほかの開発・プログラミングの記事は、開発・プログラミングメモの目次から、テーマ別に探せます。

このブログは、にほんブログ村と人気ブログランキングに参加しています。記事が役に立ったら、下のランキングのバナーのどれかを押して応援してもらえると励みになります。

ブログランキング・にほんブログ村へにほんブログ村

サーバー構築・運用ランキング プログラムランキング

TypeScript
watasoftdevをフォローする

コメント