WebVMは、ブラウザ上で完全にクライアントサイドで動作する仮想Linux環境です。
CheerpX(WebAssemblyによるx86仮想化技術)をベースにしています。強力なJITリコンパイルエンジンとext2ブロックベースのファイルシステムにより、大規模なユースケースの実行が可能です: GCC / Clang / Python / Node.js / Rubyやその他多くのものがすぐにサポートされます。
しかし、重要なことが欠けていました。
ネットワーキングはWebVMで最も要望の多かった機能で、それには理由があった。ネットワーキングがないと、ターミナル経由でしかデータを入出力できず、OSイメージに含まれているものしか使えないからだ。
この機能を追加する際の主な難点は、ブラウザがUDPやTCPのような低レベルのプロトコルへのアクセスを公開しないことです。できるのはHTTP(S)だけで、それもCORSポリシーによって厳しく制限される。
では、WebSocketはどうだろう?WebSocket接続は、"Upgrade "ヘッダーを持つHTTP接続から始まる。その後、アップグレードが承認されると、WebSocketプロトコルが引き継がれます。WebSocketパケットにも独自のヘッダーがあります。そのため、通常のTCPソケットに透過的に接続することはできません。
任意のソケットに接続するためには、プロトコルのアップグレードを実行し、宛先に送信する前にWebSocketパケットをアンラップする(逆方向にはその逆を行う)プロキシサーバーが必要です。
このプロキシサーバーをホストすると、新たな問題が発生する:
・私たちはサーバー側のインフラにお金を払い、維持する必要があり、それはユーザー数に応じて拡張することが必要です。
・私たちのサーバーはユーザーの代わりにネットワークリクエストを実行するので、私たちはトラフィックに対して法的責任を負うことになる。このサービスは悪意のある行為者によって悪用される可能性がある。
2つ目の問題を解決するためには、ユーザーに認証を求め、ネットワークの使用状況を把握し、事実上VPNプロバイダーになる必要がある。
では、この"VPNプロバイダー"業務を、もっと適任の人間に任せることができるとしたらどうだろう?
ブラウザーから直接利用できるVPNサービスが見つかれば、1つ目の問題も解決し、サーバー・インフラを自分たちで用意する必要もなくなる。
Tailscaleの紹介
TailscaleはWireGuardプロトコルに基づくVPNサービスである。ネットワーク内のすべてのマシンのWireGuardキーを管理し、ユーザーの認証を行うコントロール・プレーンが含まれている。
TailscardはWireGuardの上に構築されており、WireGuardは通信にUDPを使用するため、振り出しに戻ったと思うだろう。
しかし、Tailscaleの特徴のひとつは、メッシュ・ネットワークでマシン同士を直接接続できることだ。これは、NATトラバーサルのためのSTUNサーバーを提供することで実現している。
STUNサーバーでさえNATを突破できないことがあるため、Tailscaleは代替メカニズムとしてDERPサーバーを提供している。
DERP(Detoured Encrypted Routing Protocol)サーバーは、2つのピアが直接接続できない場合にトラフィックを中継するために使用されます。最も厄介なファイアウォールをも回避できるように設計されているため、通常のHTTPSとウェブソケットを使用して通信します。
これがまさに必要なものだ!
あとは、Tailscaleのコントロール・プレーン・プロトコル、DERPプロトコル、WireGuardプロトコルをブラウザで再実装すれば完了だ。
ほんの冗談だ!幸運なことに、Tailscaleの公式クライアント(Goで書かれている)はWasmにコンパイルされている。
ブラウザのsshクライアント(tsconnect)を少し修正し、カスタムTunデバイスを実装することで、JavaScriptのMessageChannelでIPパケットを送受信するだけで、Tailscaleネットワークとの通信に成功した!
GoとWasmについて
GoのコードをWasmにコンパイルするのがとても簡単なことに驚きました。
環境変数GOOS=js GOARCH=wasmを設定し、$(go env GOROOT)/misc/wasm/wasm_exec.jsをwasmモジュールと一緒に出荷するだけだ。
もちろん、依存関係はwasmターゲットをサポートする必要がある(私の場合、Tailscaleの人々が全ての作業をしてくれた)。
欠点はコンパイルされたwasmモジュールのサイズだ: 16MBだ!
wasm-optもあまり役に立たず、わずか1MBしか削減できなかった。比較のため、CheerpX VM全体は6MB以下に収まっている。
このため、ネットワーキング・コードは、Tailscaleにログインしようとしたときだけロードされるようになっている。
TCP/IPスタック
驚くほど少しの作業で、ブラウザからIPパケットを交換できるようになりました。残念ながら、ほとんどのアプリケーションは生のIPパケットを送信せず、TCPやUDPを使って通信を行う。
TCP/IPスタックをゼロから作ることもできるが、できれば既存のものを見つけたい。
Lwip(Cで書かれている)は組み込みの世界では一般的な選択肢のようだ。Cheerpを使ってWasmにコンパイルし、MessageChannelネットワーク・インターフェース用の "ドライバー "を追加するのはとても簡単だった。
あとはCheerpXでlwipを使ってネットワーク関連のシステムコールを実装すればOKだ。
Demos
理論はもういい、これで何ができる?
SSH
ネットワーク対応WebVMの最も簡単な使い方は、sshクライアントとして使うことです:
Tailscaleネットワーク内の他のマシン(出口ノードがあればその先も)に、どのブラウザからでもプライバシーを保護した方法でアクセスできます。あなたのキー入力は暗号化されるだけでなく、Tailscaleのサーバには一切触れません。
また、ssh を使って WebVM の内外にファイルを簡単に移動することもできます。コードやデータをインポートして実行したり、作業結果をエクスポートしたりできるようになったので、WebVMで実質的にできることの範囲が広がります。
Full stack webの開発
より野心的な目標は、WebVMをfull-stack開発プラットフォームとして使うことだ。
確かに、私たちはまだそこに到達していないが、ネットワーキングはその目標に向けた重要な一歩だ。
次のデモのGIFでは、私を見てもらうことができる:
・github.comからPythonのgitリポジトリをダウンロードしているところ。
・pipを使った依存関係のインストール!
・Sqliteデータベースを永続ストレージとして含むFlask webアプリケーションを実行し、2つ目のブラウザタブからアクセスする。
・別の WebVMタブからlynxでアクセスする。
・アプリケーションを編集し、gitにコミットし、githubにプッシュバックする。
pipの依存関係をインストールするのは確かに速くはない(セットアップスクリプトの中には、そこでネイティブコードをコンパイルしているものもある!)が、我々のIndexedDBにバックアップされたファイルシステムのおかげで、その作業は一度だけで済む。
もちろん、他にも多くの制限がある。例えば、npmはまだ動いていないし、aptも動いていない。しかし、これらの問題を解決するのは特に複雑なことではありませんし、私たちのシスコール・エミュレーション・レイヤーは常に改善されています(ネットワーク・サポートで実行できるアプリケーションのセットを拡張したおかげでもあります)。
自分で試す
自分で試してみたい方は、以下の手順でWebVMのネットワーク・アクセスを有効にしてください:
・webvm.ioにアクセスし、右上の "Tailscale Login "をクリックします。
・ネットワークの速度によっては、Tailscale Wasmモジュールがダウンロードされるまでしばらく待つ必要があります。
・Tailscaleの認証情報を使ってログインします。
・公共のインターネットにアクセスしたい場合は、Exit Nodeが必要です。設定方法はこちらを参照してください。Tailscaleネットワーク内のマシンにアクセスするだけなら、必要ありません。
・WebVMタブに戻ります。右上に自分のIPアドレスが表示されます。
WebVMの短命な性質を考慮して、私たちはエフェメラル・ノードとしてTailscaleにログインします。これは、一定期間操作が行われないと、ノードがTailscaleネットワークから消えてしまうことを意味します。また、タブを再読み込みすると、再度ログインする必要があります。2回目以降は速くなるはずです。
次は何ですか?
私たちは、ネットワークのサポートがWebVMの可能性を広げることにとても興奮しています。
そして、次に何をするか(ヒント:X11)についてのアイデアを持っていますが、WebVMを何に使いたいかについても聞きたいと思っています。
メールやTwitterで連絡をとることもできますし、私たちのDiscordチャンネルでチャットすることもできます。
もし何か試してみてうまくいかなかったら、遠慮なくGitHubでissueを出してください。
Redditでの議論: https://www.reddit.com/r/programming/comments/xx3r83/webvm_linux_virtualization_in_webassembly_with/
Hacker News での議論: https://news.ycombinator.com/item?id=33116245