ポート

ネットワーク通信でプロセスを識別する番号で、TCP/UDP の接続先を指定する

ネットワーク基礎

ポートとは

ポートは、ネットワーク通信でプロセスを識別する 0〜65535 の番号で、IP アドレスと組み合わせて通信先を特定する。IP アドレスが「建物の住所」なら、ポートは「部屋番号」。上限が 65535 なのは番号が 16 ビットで表されるためで、この数はプロトコルの仕様として固定されている。

0 は実際の宛先としては使わない番号で、プログラムが bind に 0 を指定した場合は「空いている番号を OS に選ばせる」という意味になる。クライアント側が送信元ポートを明示しないのはこの動きを使っているためで、通信は「送信元 IP・送信元ポート・宛先 IP・宛先ポート」の組で区別される。同じサーバーの 443 番に何千台がつないでも取り違えが起きないのは、相手側の送信元ポートが違うからである。

ポート番号の分類

番号の区分は IANA が管理し、区分の境界と呼び名は RFC 6335 で定められている。

範囲名称 (RFC 6335)割り当て
0〜1023ウェルノウンポート (システムポート)IANA が割り当て・新規登録の審査が最も厳しい80 (HTTP), 443 (HTTPS)
1024〜49151登録済みポート (ユーザーポート)IANA が割り当て3306 (MySQL), 5432 (PostgreSQL)
49152〜65535動的ポート (プライベート・エフェメラルポート)割り当てを行わない・一時利用専用クライアント側の送信元ポート

この表で実務上つまずきやすいのは、下 2 つの区分の読み方である。まず登録は台帳への記載であって番号の占有権ではない。開発サーバーでよく使う 3000 番も、登録簿の上では別のサービス名で登録済みである。つまり「登録が無いから空いている」「登録があるから他の用途で使ってはいけない」という読み方はどちらも成り立たず、実際にその番号を使っているプロセスを見る以外に確かめる方法はない。

もう一つは、OS が自動割り当てに使う範囲が規格の 49152〜65535 と一致しないことである。Linux の既定値は 32768〜60999 (net.ipv4.ip_local_port_range) で、登録済みポートの範囲に食い込んでいる。自分で選んだ 40000 番台のポートが、たまたま OS の一時割り当てとぶつかって起動に失敗することがあるのはこのためで、戻り通信を通すファイアウォールの設計やポート枯渇の見積りでは、規格の区分ではなく実機の設定値を見る。

主要なポート番号

番号と用途の対応は IANA の登録簿に TCP / UDP それぞれの行として載っている。下表は登録簿にある代表例で、ファイアウォールの許可を判断する場面で繰り返し出てくるものである。

ポートプロトコル用途
22SSHリモートログイン
53DNS名前解決
80HTTPWeb (非暗号化)
443HTTPSWeb (暗号化)
3306MySQLデータベース
5432PostgreSQLデータベース
6379Redisキャッシュ
8080HTTP (代替)開発サーバー

Lambda とポート

Lambda では、関数のコードがリクエストを待ち受けるポートを自分で開かない。外から見える窓口は API Gateway 側の HTTPS (443) で、そこで受けた内容が Lambda の呼び出しとして関数へ渡される。ポートの概念が消えるのではなく、待ち受けの位置がマネージドサービス側へ移っている。

クライアント → API Gateway (:443) → Lambda 呼び出し (関数は listen しない)

実行環境の内側では、ランタイムが環境変数 AWS_LAMBDA_RUNTIME_API に入ったエンドポイントへ HTTP でイベントを取りに行く仕組みになっている。関数から外部の API やデータベースへつなぐときも、相手のポートと自分の送信元ポートを使う通常の通信である。したがって「サーバーレスならポートを気にしなくてよい」のは受け口の設定に限った話で、接続先のポート番号やセキュリティグループの許可は通常のサーバーと同じように設計する必要がある。

ポートの確認

つながらないときに最初に見るのは、狙った番号で実際に待ち受けているプロセスがいるかどうかである。

# 使用中のポートを確認
lsof -i :3000
# COMMAND  PID USER FD TYPE DEVICE NODE NAME
# node    1234 user 22u IPv6 TCP *:3000 (LISTEN)

# ポートが開いているか確認
nc -zv localhost 3000

ポートフォワーディング

相手側のポートへ直接届かない場合は、SSH の転送で手元のポートを相手側のポートにつなぐと、ローカルのブラウザやクライアントからそのまま触れる。踏み台越しにデータベースへつなぐときの定番手段である。

# ローカルの 8080 をリモートの 80 に転送
ssh -L 8080:localhost:80 user@remote-server
# localhost:8080 でリモートの Web サーバーにアクセス

よくある問題

起きる問題は数が限られており、症状から原因を絞れる。

問題対策
ポートが既に使用中lsof -i :PORT で使用中のプロセスを特定して停止する。前回の起動が残っているだけのことが多い
ファイアウォールでブロックセキュリティグループのインバウンドルールを確認する。応答が全く返らない (拒否ではなく無反応) ならまずこれを疑う
権限エラー (1024 未満)Linux では 1024 未満へ待ち受けるのに root か CAP_NET_BIND_SERVICE が必要。アプリは 8080 等で待ち受け、80 / 443 はロードバランサーやリバースプロキシで受けるのが定石

つまずいたときの見方

ポート絡みの不通は、待ち受け側・経路の許可・接続先の指定という 3 か所のどこかで食い違っている。順番としてはまず待ち受け側で、目的の番号が開いているか、そして 127.0.0.1 だけに bind していないかを確認する。ローカルでは動くのに他のマシンから届かないという症状の大半はこれで、待ち受けアドレスを 0.0.0.0 にするか、経路上のプロキシから内向きに繋ぐ形へ直す。ここが正しければ次にファイアウォールやセキュリティグループの許可、最後にクライアント側が指定している番号を疑う。

番号を変えて動いた場合も、元の番号で駄目だった理由を残しておくとよい。OS の一時割り当て範囲との衝突なのか、権限なのか、別プロセスの残骸なのかで、別の環境へ同じ設定を持っていったときの再現性が変わる。

この記事は役に立ちましたか?

関連用語

関連する記事