3秒でわかる
あるポートに届いた通信を別のホストやポートへ中継する仕組み。コンテナや踏み台の向こう側にあるサービスへ手元から届かせるために使います。
もう少し詳しく
どういうものか
ポート転送は、あるホストの特定のポートに届いた通信を、別のホストや別のポートへ横流しする仕組みです。手元の端末から直接は見えない場所にあるサービスに、あたかもローカルで動いているかのようにアクセスできるようになります。
実務でよく出てくるのは Docker と SSH の2つです。Docker はコンテナの内側のポートをホスト側のポートに結びつけ、SSH は暗号化されたトンネルを通して遠くのポートを手元に持ってきます。
なぜ必要か
コンテナの中で動くアプリは、既定ではコンテナ専用のネットワークにいるため、ホストのブラウザから開けません。同じように、本番のデータベースはインターネットから直接つながらない場所に置くのが基本で、公開してしまうと総当たり攻撃の的になります。それでも開発者は手元の GUI ツールからつなぎたい、という要求があります。ポート転送は、公開範囲を広げずに必要な経路だけを一時的に通す方法です。
具体例
# Dockerでホストの8080をコンテナの80へつなぐ
docker run -d -p 8080:80 nginx
# ブラウザで http://localhost:8080 を開くとコンテナのnginxが応答する
# 手元の15432を、踏み台サーバー経由でDBの5432へ転送する
ssh -N -L 15432:db.internal:5432 user@bastion.example.com
# 別のターミナルから手元の15432につなぐとDBに届く
psql -h 127.0.0.1 -p 15432 -U appuser appdb
# 逆向き。手元で動く3000番を、リモートの8000番として公開する
ssh -N -R 8000:localhost:3000 user@remote.example.comローカル転送 (-L) の経路
[手元 127.0.0.1:15432]
| SSHの暗号化トンネル
v
[踏み台<a href="/glossary/server" class="text-primary font-medium underline underline-offset-2 hover:text-primary-dark">サーバー</a>] --- 社内ネットワーク ---> [db.internal:5432]
手元のアプリはローカルにつないでいるつもりで、実際はDBに届いているつまずきやすいところ
Docker の -p は左がホスト側、右がコンテナ側です。ここを逆に書くと、起動はするのにブラウザからつながりません。またコンテナ内のアプリが 127.0.0.1 だけを待ち受けていると、転送してもコンテナの外からは届きません。0.0.0.0 で待ち受ける設定に変えます。
SSH のローカル転送では、転送先のホスト名は踏み台サーバーから見た名前です。手元の hosts ファイルに書いた名前を指定しても解決されません。-N を付けないとシェルまで開いてしまい、うっかり exit してトンネルごと切れる事故が起きます。
すでに使われているポートを指定すると Address already in use で失敗します。5432 のようによく使う番号は避け、15432 のようにずらしておくと衝突しにくくなります。
似た用語との違い
| 語 | 内容 |
|---|---|
| ローカル転送 (-L) | 手元のポートを、遠くのサービスへつなぐ |
| リモート転送 (-R) | 遠くのポートを、手元のサービスへつなぐ |
| ダイナミック転送 (-D) | SOCKS プロキシとして動き、宛先を固定しない |
| NAT のポート開放 | ルーターが外からの通信を内側の機器へ振り分ける設定 |