SSHの-Lで`localhost`と`127.0.0.1`を書き分ける意味、実はほぼない

  • SSH
  • macOS
  • Networking

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

macからSSHでリモートのポートを転送してブラウザで見る、というのはよくやる作業だけど、毎回微妙に迷うポイントがいくつかあるので整理した。

おさらい:基本の書き方

ローカル8080 → リモート3000に転送する場合。

ターミナル
ssh -L 8080:localhost:3000 user@server.example.com

SSH自体が22番以外のポートで動いてる場合は-pを足す。

ターミナル
ssh -p 2222 -L 8080:localhost:3000 user@server.example.com

逆方向(ローカルのサービスをリモート側から見る)なら-R。

ターミナル
ssh -R 8080:localhost:3000 user@server.example.com

ここまでは普通に使ってれば覚える。

localhostと127.0.0.1、どっちを書くべきか

-L 8080:localhost:3000のlocalhost部分、これは「SSH接続先のサーバから見た接続先ホスト」を指定してる。ここを127.0.0.1にすべきという情報をたまに見るけど、実際にはサーバ上でこの2つはほぼ同じ意味(ループバックアドレス)になるので、書き分けても動作は変わらない。

差が出るとしたら、サーバ側の名前解決がIPv6の::1を優先していて、かつ転送先のアプリがIPv4の127.0.0.1でしかリッスンしていない、みたいな特殊なケースくらい。普通の環境ならlocalhostのままで問題ない。

転送してもブラウザが真っ白になるとき

原因は主に2パターンあって、切り分けが必要。

パターン1:アプリのリッスンアドレスの問題

転送先のアプリがDockerコンテナ内などで動いていて、コンテナ内部のアドレスでしかリッスンしていない場合。0.0.0.0でリッスンしてないと、SSH側からは繋がらない。

パターン2:フォワード自体が拒否されている

こっちはchannel 2: open failedみたいなエラーが出るパターン。サーバ側の/etc/ssh/sshd_configで

AllowTcpForwarding no

になっていると、そもそもポートフォワード自体が拒否される。これは「アプリがどこでリッスンしてるか」とは全く別のレイヤーの話なので、真っ白になった原因を探すときは分けて考えたほうがいい。

HTTPSのポートを転送したとき

リモートの443を8443とかに転送してhttps://localhost:8443で見ると、証明書のCN/SANはサーバの本来のドメイン名(server.example.comとか)で発行されているせいで、ブラウザ側でホスト名不一致の警告が出る。

動作自体は問題ないので、警告を無視して進めば普通に繋がる。ただし初見だと「壊れてる?」と焦るので、先に知っておくと落ち着ける。

まとめると

  • localhostと127.0.0.1はサーバ上でほぼ同じ、書き分ける必要は基本ない
  • 真っ白になったら「アプリのリッスンアドレス」か「AllowTcpForwardingの設定」かを分けて疑う
  • HTTPS転送時の証明書警告は仕様なので気にしなくていい