ByteScope

22

ポート 22 · SSH

TCPIANA 割り当てありリモート接続

sshd が待ち受けるポート。その裏には `scp`、`rsync`、SSH 越しの `git`、トンネル、そして SFTP がぶら下がっていて、ここが 1 つ拒否されるだけで別々の 5 つが同時に壊れます。

ポート 22 を使っているプロセスを特定する

自分の環境の行をそのまま実行してください。ポートを掴んでいるプロセス名と、バインドしているアドレスが出ます。たいていはそれだけで答えが分かります。

外側から確かめる

`nmap -Pn -p 22 host.example.com` は、マシンの外から見たそのポートの姿を報告します。`-Pn` は対象をオンライン扱いするので、ping を落とすホストでもスキャンできます。nmap の定義は厳密です。`open` はそこでアプリケーションが実際に接続を受け付けているということ。`closed` は到達できて応答も返ったが待ち受けているものがないということで、これは sshd が止まっているときの姿です。`filtered` はパケットフィルタがプローブをポートまで届かせなかったということで、nmap には open か closed かの区別が付きません——そしてそれこそが、あなたのクライアントを即座に失敗させずに固まらせていたファイアウォールです。`--reason` は実際に返ってきたもの、open なら `syn-ack`、closed なら `conn-refused` を出します。`-sV` はバージョンバナーを読みますが、SSH の場合それは暗号化が始まる前にプロトコルが平文で送る識別文字列、たとえば `SSH-2.0-OpenSSH_9.6` です。この文字列は全世界スキャナーが集めているものそのものなので、中身は公開情報だと思って扱ってください。スキャンは自分が責任を持つホストにだけ。

22 につながらないときの読み方

出ているもの意味
ssh: connect to host host.example.com port 22: Connection refusedホストは生きていて応答しました——22 番を持つプロセスがないので、カーネルがリセットを返しています。sshd が止まっているか起動に失敗したか、あなたが叩いたアドレスを含まない場所にバインドしているか、設定変更後に別のポートで待ち受けているかです。この失敗は即座に返ってきます。その速さ自体が有益な手がかりで、ネットワークの経路は通っていて足りないのはサービスだけだと分かります。コンソールか別の経路でそのマシンに入り、自分の環境のコマンドを実行してください。
ssh: connect to host host.example.com port 22: Connection timed out診断としては真逆で、だからこそ 2 つを区別する価値があります。何一つ返ってきていません。ファイアウォール、クラウドのセキュリティグループ、あるいはネットワーク ACL が SYN を黙って捨てているか、そのマシンのものではなくなったアドレスを叩いています。macOS は同じことを `Operation timed out` と言います。数十秒待たされたことが目印です。拒否なら即座に返り、破棄なら接続タイムアウトを最後まで座って待つことになります。`nmap --reason` で確認してください。`filtered` が破棄です。
Permission denied (publickey).TCP もポートもデーモンも正常です——認証まで到達して失敗しただけで、しかもこのメッセージはサーバーが試す気のあった唯一の方式を名指ししています。順番に潰してください。まず `ssh -v` を実行して `Offering public key` の行を読み、クライアントが実際にどの鍵を出したか見ます。鍵をたくさん抱えたエージェントは、正しい鍵に辿り着く前にサーバー側の試行回数の上限を使い切ることがあるので、`-i` と `IdentitiesOnly=yes` で 1 本に固定します。次にサーバー側で、その鍵が当該アカウントの `~/.ssh/authorized_keys` に入っているかを確認します。OpenSSH の `StrictModes` の既定値は yes なので、ホームディレクトリ、`.ssh`、`authorized_keys` のいずれかがグループや他人から書き込める状態だと、sshd はクライアントに何も告げずにそのファイルを無視します。`~/.ssh` は 700、`authorized_keys` は 600、所有者はそのユーザー。本当の理由はサーバーのログが 1 行で書いてくれます。クライアント側には一生出てきません。
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! ... Host key verification failed.サーバーが提示した鍵が、`known_hosts` にその名前で記録されている鍵と違います。そしてこれは、反射的に出てくる対処が間違っている数少ないエラーです。`ssh-keygen -R` から始めないでください。そのホストが以前どうだったかを示す唯一の記録を消してしまいます。無害な原因はいくつもあります。マシンを作り直した、クラウドのアドレスが解放されて誰か別の人のインスタンスに割り当てられた、名前の解決先が別のバックエンドに変わった、転送されたポート越しに別のホストへ届いている。そして無害でない原因が一つ、あなたとサーバーの間に誰かが座っている場合です。まずどちらかを確定させてください。ssh が表示したフィンガープリントを、コンソールで `ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key` を実行して得たものや、インスタンスのブートログに出ているものと突き合わせます。`ssh-keygen -F host` は保存されているエントリとその在り処を教えてくれます。新しいフィンガープリントが確認できて初めて、`ssh-keygen -R host` が正しいコマンドになります。
error: Bind to port 22 on 0.0.0.0 failed: Address already in use.既に何かがソケットを持っているので sshd が起動できません。たいていは古い sshd がまだ動いている場合で、停止と競走した restart か、パッケージのサービスと張り合っている手元ビルドのどちらかです。socket ユニットが 22 番を持っているところに service ユニットも起動している、というパターンもあります。当てずっぽうではなく上のコマンドで持ち主を特定してください。そして、そのセッション自身が依存している sshd を、コンソールか 2 つ目の入口を確保しないまま止めないこと。
ssh_exchange_identification: Connection closed by remote hostTCP の接続は成功していて、sshd がプロトコルのバナーを出す前に切っています。つまりポートも経路もファイアウォールもすべて正常です。よくある原因は、fail2ban か同種のものによる送信元アドレスの ban、負荷やファイルディスクリプタ枯渇で `MaxStartups` が接続を間引いている状態、そして `AllowUsers`・`DenyUsers`・TCP wrappers のようなアクセス規則です。これはネットワークの障害ではなく、サーバーがあなたについて下した判断で、どれなのかはサーバーのログに書いてあります。

ポート 22 で動いているもの

IANA は 22 番を `ssh`、Secure Shell プロトコルに、TCP・UDP・SCTP で割り当てています。実際に使われるのは TCP だけです。このポートの 1 つのリスナーが運んでいるのは対話的なシェルだけではありません。`scp`、SSH の上で走る `rsync`、`git clone git@host:repo`、`ssh -L` や `-D` のトンネル、`ProxyJump` の踏み台経由、そして SFTP のサブシステム——SFTP と呼ばれているものの正体はこれで、21 番の FTP とは縁もゆかりもありません。OpenSSH が文書化している既定値は `sshd_config` の `Port 22` で、どのインターフェイスにバインドするかは `ListenAddress` が決めます。どちらも複数書けるので、1 台のサーバーが 22 番と別のポートの両方で正しく応答することもあります。プロセスを探しに行く前に一つ。いくつかのディストリビューションは SSH の systemd socket ユニットを同梱するようになりました。`ssh.socket` が有効なホストでは、22 番を持っているのは `systemd` で、`sshd` は接続が来て初めて存在します。これは正常で、他の何かがポートを奪った証拠ではありません。SSH を 22 番から動かすのも 1 行では済みません。`sshd_config` の `Port` を変え、ホストのファイアウォールで新しいポートを開け、SELinux のシステムならさらに `semanage port -a -t ssh_port_t -p tcp 2222` で登録します。この最後の一手を飛ばすと、sshd は起動してバインド失敗をログに書き、他のどこから見ても健康そのものに見えるマシンから締め出されます。新しいポートの確認は、必ず今つながっているセッションを開いたまま、もう 1 つのセッションから行ってください。

ポート 22 を外部に開けてよいか

22 番は、外に出すことを弁護できる数少ない管理用ポートです。通信は暗号化されていますし、クライアントは秘密を送る前にサーバーのホスト鍵を検証します。とはいえ、それは安全と同義ではありません。22 番のリスナーは数時間で見つかり、そこから `root`・`admin`・`ubuntu`・`git` をはじめ数百の名前に対する、退屈で切れ目のない総当たりを浴び続けます。結果を変える対策は次の 3 つです。1 つ目、鍵だけにして `PasswordAuthentication no`——このオプションの OpenSSH 自身の既定値は `yes` で、ディストリビューションが両方向に上書きしているので、思い込まずに動いている設定を読んでください。2 つ目、`PermitRootLogin` を緩くても文書化された既定値の `prohibit-password`、できれば `no` に。3 つ目、fail2ban のようなレート制限で、数回失敗した送信元アドレスを弾く——これで主に手に入るのは、読めるログです。デーモンを高い番号へ移すとノイズは劇的に減りますが、リスクはほとんど減りません。狙って掛けられたスキャンなら数秒で見つけます。効くのは、ファイアウォールで送信元アドレスを絞ること、`ProxyJump` で辿る踏み台を 1 台だけ立てて 22 番に答えるホストをそこに集約すること、あるいは先に VPN を必須にすることです。どれを選ぶにせよ、確認は既にログインしている 2 つ目のセッションから。締め出しはいつも、繋ぎ直すことでしか確認しなかった変更から始まります。

サービス
SSH
トランスポート
TCP
登録状況
IANA 割り当てあり
カテゴリ
リモート接続

このサイトのツール

どれもブラウザ内で完結します。アップロードは発生しません。

関連するポート

22 を調べているとき、ついでに確認することになりがちなポートです。

よくある質問

明らかに使用中なのに、コマンドが何も表示しないのはなぜ?

ほぼ権限の問題です。lsofss はソケット自体は出しますが、他ユーザーのプロセスは所有者の列を伏せるので、システムアカウントやコンテナランタイム、launchd が起動したサーバーは sudo を付け直すまで持ち主不明のリスナーに見えます。Windows は逆で、netstat には何も出ないのに bind だけ失敗します。これは Hyper-V や WSL2、Docker Desktop が起動時に予約したポート帯に当たっている状態です。

ポートを掴んでいるプロセスは kill してよい?

何なのかを先に見てください。取り残された開発サーバーなら問題ありませんが、書き込み中のデータベースは別ですし、他が依存しているシステムサービスも同様です。持ち主がコンテナならコンテナごと停止してください。ホストから見えるプロセスを kill してもランタイムが再起動するだけです。どうしても止められないものなら、自分のサービスを別のポートへ移すほうが早く片付きます。

ローカルからは届くのに、別のマシンからは届かないのはなぜ?

0.0.0.0 ではなく 127.0.0.1 にバインドしているからです。各ページのコマンドがプロセス名と並べてバインド先アドレスを出しているのはこのためで、ループバックにバインドしたものはファイアウォールの設定に関係なく自分のマシンからしか届きません。最近は意図的にそれを既定にしているフレームワークも多いので、たいていはバグではなくフラグの問題です。すでに 0.0.0.0 なのに届かないなら、次に疑うのはホストのファイアウォールかクラウドのセキュリティグループです。

珍しいポート番号に移すと安全になる?

ほとんどなりません。インターネット全体を舐めるスキャナーはポート範囲を丸ごと走査し続けているので、稼げるのは数時間であって安全ではなく、代わりに関係者全員がその番号を覚える羽目になります。既定ポートを狙う無差別スキャンのログが減るという効果は確かにありますが、それだけです。結果を変えるのは認証と、送信元アドレスを絞ったファイアウォールと、そもそも外に出さないことです。

ポート 22 でまだ詰まっていますか。ポート一覧をすべて見る。あるいは上に戻って、実際に出たエラー文から追ってください。