2 日目の記事です。
node --inspect ./app.js
のようにして DevTools で Node.js アプリをデバッグできました。
手元のはそれで良いんですが、サーバーアプリを他のサーバーで実行している場合、そっちで --inspect
付けても手元からは見えません。それは当然だし本番サーバーでデバッグとか怖いんで避けたいんですが、まあそうじゃなくてもポート転送設定してない開発用仮想環境とかあるじゃないですか。
そんなときは ssh
でポート転送しましょう。
ポート転送して DevTools でサーバーで実行しているアプリをデバッグ
コマンドラインの SSH でやります。
-L
でローカルのポート 9229 番とリモートサーバーのポート 9229 番を繋げながら SSH 接続し、サーバー上でアプリを起動します。もちろん --inspect
を忘れずに。
$ ssh -L 9229:localhost:9229 [email protected] [[email protected] ~]$ node --inspect /path/to/app.js
これで繋がりました。SSH の接続が残っている間はリモートの 9229 番がローカルの 9229 番へ転送されてきます。
-L local_port:remote_host:remote_port
ポート転送の指定です。順にローカルのポート、サーバーのホスト名、サーバーのポート番号です。
サーバーの情報は外部からみたものではなく内部で認識する情報を指定します。デバッグ用の WebSocket は localhost
で起動するようなので、サーバーの IP アドレスじゃなくて localhost
のままにしておいてください。
user_name@host
SSH の接続先です。
通常の SSH で見るやつ。[email protected]
とか [email protected]
とか。~/.ssh/config
があるならそこで記述した設定名だけで良いです。
node --inspect /path/to/app.js
デバッグしたいアプリの実行コマンドです。
その他
-L
って?
いわゆる「SSH ポートフォワーディング」をするやつです。ローカルマシンのポートをサーバーマシンのポートへ接続します。
man ssh
より。
Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side.
ローカル(クライアント)ホスト上の与えられた TCP ポートか Unix ソケットへの接続が、リモート側の与えられたホストとポート、あるいは Unix ソケットへ転送されるよう指定します。
なんで “L” なんだろ?
なんか接続失敗のエラーが垂れ流される
延々とこういうのが出てくることがあります。(数字は場合によります。)
channel 3: open failed: connect failed: Connection refused
これは SSH が出してるエラーで、ポート転送を通して接続を確立しようとしたが失敗した、てなときに出ます。転送元のサーバーで誰もそのポートを利用していない可能性があります。
今回の話に限ると、以下の 3 点がありそう。
--inspect
を付け忘れた- 起動するより先に DevTools を開いた、あるいは終了後も開きっぱなし
-L
オプションのうちホスト名が誤っている
最後、-L
オプションに指定するのはサーバーに紐づいた外部から見えるホスト名とは限らない点にご注意ください。サーバー側で Node.js 実行した際のメッセージはたぶんこうです。
$ node --inspect tmp/app/server.js Debugger listening on ws://127.0.0.1:9229/0565bb7e-ed7c-470b-8556-d534f09afa14 For help, see: https://nodejs.org/en/docs/inspector Listening at 8000
注目するのは出力の一行目にある ws://127.0.0.1:9229/
の部分です。ここが 127.0.0.1:9229
なので、ローカル側で実行する SSH へ与える指示も -L 9229:127.0.0.1:9229
になります。
サーバー側で 127.0.0.1
=== localhost
となっている場合は置換しても大丈夫です。
- ✔ OK:
-L 9229:127.0.0.1:9229
- ✘ NG:
-L 9229:example.com:9229
アドレス使用済みエラー
Starting inspector on 127.0.0.1:9229 failed: address already in use
サーバーのどこかでアプリが起動しっぱなしになってる気がします。
$ lsof -i :9229 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME node 12345 ginpei 22u IPv4 36991283 0t0 TCP localhost:9229 (LISTEN)
PID を指定して強制終了。
$ kill 12345
ちなみにローカル側のポートが被っててもエラーにならないっぽい?
単発なら直接コマンド実行でも
-t
を加えると ssh
でシェルを開く代わりに直接コマンド実行させることもできるはできる。
$ ssh -t -L 9229:localhost:9229 [email protected] node --inspect /path/to/app.js
-t
を付けなくても動くんだけど、その場合は止めようと思って Ctrl+C
を押しても手元の ssh
が止まるだけでサーバー上で実行されている Node.js アプリは走ったままになってしまう。忘れずに付けよう。
おしまい
あんまり使う機会ないかも、というかこんなことしなくちゃいけない状況にはならないよう願いたいものではあります。
それはそれとして SSH ポートフォワーディングは便利なので使えるようになると良いですね。DevTools 関係ないけど。自分は IP アドレスで接続制限してるデータベースへの踏み台に使ってます。