$ echo -n "" > /dev/tcp/1.2.3.4/56
(AWS のネットワーク疎通確認、/dev/tcp が telnet や nc よりも便利な理由)
EC2 から RDS や ElastiCache、外部エンドポイントに繋がらない時、多くのエンジニアは telnet や nc、curl を使います。
ただし、最小構成の AMI(Amazon Linux 2023、Ubuntu Minimal、Bottlerocket など)ではこれらが標準でインストールされていないことがあります。
そんな時は、Bash 組み込みのこれを使ってください。インストール不要、Bash がある場所ならどこでも動きます。
echo -n "" > /dev/tcp/{ホスト名 or IP}/{ポート番号}
返り方は3パターンあり、それぞれ「どこで詰まっているか」を一発で示してくれます。
- 何も出力されず終了(exit code 0) → 疎通成功
- タイムアウトする → VPC、Security Group、NACL、ルーティングを疑え
-
変な文字列や
Connection refusedが返る → ポートは開いているが、ミドルウェア側で何か起きている
なぜ AWS でこれが効くのか
AWS のネットワークトラブルシューティングが難しいのは、ツールが悪いからではなく、問題が起きているレイヤーが分かりづらいからです。
EC2 から RDS への疎通失敗ひとつとっても、原因はこれだけあります。
- VPC ルートテーブルの設定ミス
- EC2 側 Security Group の egress
- RDS 側 Security Group の ingress
- サブネットの Network ACL
- VPC エンドポイントや PrivateLink の設定漏れ
- DNS の名前解決
- アプリケーション側がそもそも想定ポートで Listen していない
- アプリ設定ファイルのポート番号間違い
従来の手順は「診断ツールを入れる → 実行する → 出力を読み解く」ですが、Amazon Linux 2023 のクリーンなインスタンスには telnet も nc も入っていません。dnf install する必要があります。本番環境ではパッケージ追加権限がないこともよくあります。
/dev/tcp は Bash 専用の特殊デバイスで、Bash がある環境ならいつでも使える。AWS の標準的な Linux インスタンスは基本的に Bash が入っているため、ほぼどこでも動きます。
/dev/tcp の仕組み
/dev/tcp/<host>/<port> は実在のファイルではありません。Bash が「このパスへのリダイレクトは TCP ソケットを開く操作」として解釈する特別なパスです。リダイレクトすることで Bash が裏で TCP ハンドシェイクを実行してくれます。
# TCP コネクションを開くのと等価
echo -n "" > /dev/tcp/example.com/443
echo -n "" は空文字列を送るだけ。実データを送りたいわけではなく、ソケットを開けるかどうかだけを見たいためです。
注意: これは Bash 限定の機能です。
sh、dash、その他 POSIX 厳密モードのシェルでは動きません。Amazon Linux 2023 のec2-userのデフォルトシェルは Bash なので問題ないですが、Alpine ベースのコンテナ(ash採用)では別の手段が必要です。
3つの結果の読み解き方
パターン1: 何も出力されず正常終了 → 疎通 OK
$ echo -n "" > /dev/tcp/google.com/443
$ echo $?
0
ソケットが正常に開けた = ホストに到達でき、ポートが開いており、TCP ハンドシェイクが成立。ネットワーク経路は問題なし。
あなたが直面しているトラブルは、これより上(アプリ設定、認証情報、リクエスト形式など)にあります。
パターン2: タイムアウトする → ネットワーク層の問題
$ echo -n "" > /dev/tcp/10.0.5.42/3306
# ... 30 秒以上待たされて ...
-bash: connect: 接続がタイムアウトしました
-bash: /dev/tcp/10.0.5.42/3306: 接続がタイムアウトしました
TCP ハンドシェイクが完了していません。典型的なネットワーク層の問題です。AWS なら、以下の順で確認します。
- 送信元(EC2)の Security Group: 宛先ポートへの outbound が許可されているか
- 宛先(RDS や EC2 など)の Security Group: 送信元の SG または CIDR からの inbound が許可されているか
- 両側のサブネット Network ACL
- 送信元サブネットのルートテーブル: 宛先へのルートがあるか
-
DNS:
<hostname>が想定の IP に解決されているか(dig <hostname>またはgetent hosts <hostname>で確認)
30 秒も待ちたくない場合は timeout を併用します。
timeout 3 bash -c 'echo -n "" > /dev/tcp/10.0.5.42/3306'
timeout が exit code 124 で抜けた場合、タイムアウト確定 = ネットワーク層の問題と判定できます。
パターン3: 変な文字列や Connection refused → ミドルウェア層の問題
$ echo -n "" > /dev/tcp/10.0.5.42/3306
# 出力なし、または:
$ echo -n "GET / HTTP/1.0\r\n\r\n" > /dev/tcp/10.0.5.42/3306
J
5.7.42-log...wG)/SAdLM]wFa\Vu7yG/BlQwmysql_native_password
TCP コネクション自体は成立しているが、応答が想定外の文字列。ネットワークは正常で、問題はアプリ/ミドルウェア層です。よくある原因:
- 正しいホストに繋がっているが、ポート番号が想定と違う(HTTP のつもりが MySQL の 3306 を叩いている、など)
- ミドルウェアの設定ミス(リスナーの違い、プロトコルの違い)
- プロキシやサイドカーが間に入って通信を奪っている
または Connection refused が返るパターン:
$ echo -n "" > /dev/tcp/10.0.5.42/3306
-bash: connect: 接続を拒否されました
-bash: /dev/tcp/10.0.5.42/3306: 接続を拒否されました
Connection refused は、ホストには到達しているがそのポートで Listen しているプロセスがない状態です。アプリケーションが落ちているか、想定と違うポートで起動している可能性が高いです。
本番 AWS 環境でなぜこれを選ぶのか
VPC のネットワークトラブルを十分にデバッグしてきた経験から確信していることがあります。
問題が起きているレイヤーを特定できれば、原因の 90% は見えます。
/dev/tcp の強みは、TCP レイヤーだけを切り出して検証できることにあります。curl だと HTTP・TLS・DNS のノイズが入り込みます。telnet は対話式でスクリプト化しづらい。nc は便利ですが、いつもインストールされているわけではない。
echo > /dev/tcp は、ただひとつの問いに答えます: このアドレスに TCP ソケットを開けるか?
AWS で何かが動かない時、99% これが知りたい問いです。
実用デバッグレシピ
EC2 から RDS に繋がらない時、私は実際にこの手順で動きます。
# Step 1: DNS 解決できるか
getent hosts mydb.cluster-xxx.ap-northeast-1.rds.amazonaws.com
# Step 2: TCP ソケットを開けるか
timeout 3 bash -c 'echo -n "" > /dev/tcp/mydb.cluster-xxx.ap-northeast-1.rds.amazonaws.com/3306'
echo "Exit code: $?"
# Step 3: Step 2 でタイムアウトした場合、インスタンスから SG/NACL の状態を取得
curl -s http://169.254.169.254/latest/meta-data/security-groups
curl -s http://169.254.169.254/latest/meta-data/mac
# AWS Console や CLI で SG ルールをクロスチェック
# Step 4: 同じ VPC 内の正常に動いているインスタンスから Step 2 を再実行
# そこでも疎通できなければ宛先側の問題
# そこからは疎通できるなら送信元側の問題(SG egress または NACL の可能性が高い)
この 4 ステップで、私が現場で見てきた AWS 疎通トラブルの体感 9 割は片付いてきました。本番障害含めて。
/dev/tcp を使わない方がいい場面
念のため、ハマる前に知っておくべき制約を共有しておきます。
-
Alpine / BusyBox では使えない —
ashは/dev/tcp非対応。ncを入れるか Bash を入れるか -
UDP には使えない —
/dev/tcpは TCP 専用。/dev/udpは存在するがハンドシェイクがない分、宛先に届いたかの判別が難しい -
HTTPS のハンドシェイク確認には使えない — TCP が成立しても TLS が成立するかは別問題。これは
openssl s_client -connect host:443かcurl -vの出番 -
本番スクリプトでは必ず
timeoutをかける — つけないとカーネルのデフォルトタイムアウト(60 秒以上)まで止まる
関連する AWS のサービス
/dev/tcp で「ネットワークが詰まっている」と分かった後の深掘りには、AWS 側のツールも併用します。
- VPC Reachability Analyzer — 2 つのエンドポイント間の経路を可視化。どの SG / NACL / ルートで止まっているかを Console で特定できる
- VPC Flow Logs — ENI レベルで accepted / rejected パケットを記録
- AWS Network Manager — マルチアカウント、マルチリージョンのネットワーク全体図
- AWS X-Ray — アプリ層のトレースが必要な場合
ただし、これらは設定に数分かかります。/dev/tcp は 1 秒で答えが出ます。まずはここから。
締め
このネタは X で 4,000+ ビューを獲得しました。意外と知られていなかったようです。
多くの AWS エンジニアが長年 telnet や nc を使ってきた中、Bash 組み込みでどこでも動く代替手段の存在は驚きを呼んだようです。
しかしこの Tip の本質は /dev/tcp そのものではなく、「インストール済みのツールに頼りすぎる前に、OS が標準で持っている機能を見直す」という姿勢だと思っています。
私が信頼するエンジニアは、クラウドの一段下のレイヤーを理解している人です。AWS はそのレイヤーの上に成り立っているのですから。
アプリとインフラの両方の気持ちがわかるエンジニア。 それが、トラブルシューティングを速くする視座です。
関連スライド
このネタの詳細解説と AWS デバッグの実践テクニックは、JAWS-UG 彩の国埼玉支部で登壇したスライドにもまとめてあります。
彩の国で始めよう おっさんエンジニアから共有したい当たり前のことを当たり前にする技術
せっかくなので 英語の勉強もトライしています(英語版はこちら)
https://qiita.com/plustick/items/7fa40eba8ec41b2d24d6
著者
大槻 剛(Tsuyoshi Otsuki / @plustick)
AWS Ambassador(2025年)× AWS Japan Top Engineer(2023年〜) × AWS Solutions Architect Professional / DevOps Engineer Professional。
クラウド食堂 創設者。
アプリとインフラの両方を、現場で 25 年動かしてきました。
Speaker Deck · LinkedIn ·
この Tip でデバッグ時間が短縮できたら、👍 か X でシェアしてもらえると嬉しいです。