- サイバーセキュリティ 🛡️
- ネットワーク
- 技術 💻
ssh コマンドの使い方まとめ|鍵・ポート指定・config・接続エラー対処
ssh コマンドは ssh ユーザー名@サーバー名 でリモートのサーバーにログインするコマンドで、ポートは -p、秘密鍵は -i で指定します。 一度 ~/.ssh/config に書いておけば ssh 別名 だけで接続でき、つながらないときは -v を付けて「どの鍵を試して、どこで止まったか」を読むのが解決への最短ルートです。
この記事では、ローカルに sshd を2台(接続先と踏み台)立てて、基本の接続から鍵の作成・配置、ポートフォワード、踏み台経由、config、そして Permission denied (publickey) や REMOTE HOST IDENTIFICATION HAS CHANGED などの接続エラーまで、すべて実際に実行した結果つきで解説します。上位の解説記事はオプションの一覧や構文の説明が中心で「打ったら何が表示されるか」「エラーが出たらどう読むか」が載っていないため、この記事はそこを主役にしています。冒頭の早見表だけでも日常の用は足りるように作りました。
ssh コマンドの早見表(やりたいこと → コマンド)
| やりたいこと | コマンド | 補足 |
|---|---|---|
| 接続する | ssh user@host |
初回は「yes」でホスト鍵を登録 |
| ユーザーを指定する | ssh -l user host |
user@host と同じ意味 |
| ポートを指定する | ssh -p 2222 user@host |
大文字 -P は scp 側の指定 |
| 秘密鍵を指定する | ssh -i ~/.ssh/id_ed25519 user@host |
指定した鍵以外を試させないなら -o IdentitiesOnly=yes |
| リモートでコマンドだけ実行する | ssh user@host 'uname -a; uptime' |
複数コマンドはクォートで囲む |
| 対話的なコマンドを実行する | ssh -t user@host top |
top・vim・sudo など端末が要るもの |
| ファイルを送る・取る | scp -P 2222 file user@host:/tmp/ |
対話型なら sftp -P 2222 user@host |
| 手元のポートをサーバー側に転送(ローカル転送) | ssh -L 8080:localhost:80 user@host |
手元の 8080 → サーバーの 80 |
| サーバーのポートを手元に転送(リモート転送) | ssh -R 9000:localhost:3000 user@host |
サーバーの 9000 → 手元の 3000 |
| SOCKS プロキシにする(動的転送) | ssh -D 1080 user@host |
curl --socks5-hostname localhost:1080 ... |
| 踏み台を経由する | ssh -J bastion user@host |
config なら ProxyJump bastion |
| 転送だけ張ってバックグラウンドに | ssh -N -f -L 8080:localhost:80 user@host |
止めるときは kill PID |
| つながらない原因を調べる | ssh -v user@host |
-vvv まで増やせる |
| 鍵を作る | ssh-keygen -t ed25519 -C "コメント" |
既定で ~/.ssh/id_ed25519 と .pub ができる |
| 公開鍵をサーバーに登録する | ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host |
使えない場合は authorized_keys に追記 |
| パスフレーズ入力を1回にする | eval "$(ssh-agent -s)"; ssh-add ~/.ssh/id_ed25519 |
登録済みの確認は ssh-add -l |
| 鍵のパスフレーズを変える | ssh-keygen -p -f ~/.ssh/id_ed25519 |
鍵本体は変わらない |
| 鍵のフィンガープリントを見る | ssh-keygen -lf ~/.ssh/id_ed25519.pub |
ホスト鍵の確認にも使う |
| 接続先を別名で登録する | ~/.ssh/config に Host 別名 ブロック |
ssh -G 別名 で解決結果を確認 |
| 鍵ファイルの権限を直す | chmod 700 ~/.ssh; chmod 600 ~/.ssh/id_ed25519 ~/.ssh/authorized_keys |
権限が広いと鍵が無視される |
| ホスト鍵が変わったサーバーの登録を消す | ssh-keygen -R '[host]:2222' |
消したあと再接続で再登録 |
| 固まった接続を切る | Enter のあと ~. |
~? で一覧表示 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ssh コマンドの使い方まとめ|鍵・ポート指定・config・接続エラー対処」
ssh とは:この記事の検証環境
ssh(Secure Shell)は、ネットワーク越しのサーバーに暗号化された経路でログインし、コマンドを実行したりファイルを転送したりするための仕組みとコマンドです。 通信はすべて暗号化され、サーバーの本人確認(ホスト鍵)と利用者の本人確認(パスワードまたは公開鍵)を組み合わせて安全性を保ちます。Linux・Mac・Windows 11 のいずれにも OpenSSH というクライアントが入っており、ターミナルで ssh と打てば使えます。
この記事の実行結果は、次の環境で取りました。
| 項目 | 内容 |
|---|---|
| クライアント/サーバー | OpenSSH 9.6p1(Ubuntu 24.04)。最新版は OpenSSH 10.5(2026-08-11 公開、公式リリースノートで確認) |
| 接続先(サーバー役) | 手元の localhost でポート 7682 に sshd を起動(公開鍵認証のみ、パスワード認証は無効) |
| 踏み台(bastion 役) | 同じく localhost のポート 7683 に 2台目の sshd を起動 |
| 接続先ユーザー | 検証用に作った Linux ユーザー sshdemo(踏み台は sshjump) |
| クライアント側の設定 | 共有の ~/.ssh を汚さないよう、作業フォルダ内の ./config(中身は UserKnownHostsFile ./known_hosts の1行)を -F ./config で指定 |
手元では localhost のポート 7682 で sshd を起動して試しています。実際の運用では ssh ユーザー名@サーバー名 のように書きます。 以降の実行例に出てくる -F ./config は検証用の指定なので、みなさんの環境では省いて読んでください(既定で ~/.ssh/config と ~/.ssh/known_hosts が使われます)。
# 検証用 sshd の設定ファイル(sshd_a.conf。パスは絶対パスで指定)
Port 7682
ListenAddress 127.0.0.1
HostKey /作業フォルダ/hostkey_a
PidFile /作業フォルダ/sshd_a.pid
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthorizedKeysFile .ssh/authorized_keys
UsePAM no
AllowTcpForwarding yes
LogLevel VERBOSE
# ホスト鍵を作って起動し、待ち受けを確認
ssh-keygen -t ed25519 -f hostkey_a -N ""
/usr/sbin/sshd -f $PWD/sshd_a.conf -E $PWD/sshd_a.log
ss -tlnp | grep -E '768[23]'
LISTEN 0 128 127.0.0.1:7682 0.0.0.0:* users:(("sshd",pid=1186,fd=4))
LISTEN 0 128 127.0.0.1:7683 0.0.0.0:* users:(("sshd",pid=1188,fd=4))
基本の接続:初回の確認プロンプトからログアウトまで
初めてのサーバーに接続すると「can't be established」と聞かれる
初めて接続するサーバーでは、ssh は「このサーバーのホスト鍵はまだ知らない。本当につなぐか」を確認してきます。 yes と答えると、そのホスト鍵が known_hosts に記録され、2回目以降は自動で照合されます。
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost
The authenticity of host '[localhost]:7682 ([127.0.0.1]:7682)' can't be established.
ED25519 key fingerprint is SHA256:MkSwfTWwARSFkQNVbOhhzKXhGcGpNKAkhgGLXnGE0Vk.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:7682' (ED25519) to the list of known hosts.
sshdemo@vm:~$ whoami; hostname; pwd
sshdemo
vm
/home/sshdemo
sshdemo@vm:~$ exit
logout
Connection to localhost closed.
このプロンプトの意味を表にまとめます。
| 表示 | 意味 |
|---|---|
The authenticity of host ... can't be established. |
まだ known_hosts に無いサーバー(=初回接続) |
ED25519 key fingerprint is SHA256:... |
サーバーのホスト鍵の指紋。本物かどうかはこれで確かめる |
This key is not known by any other names. |
同じ鍵が別のホスト名で登録されてもいない |
(yes/no/[fingerprint]) |
yes で登録して続行、no で中止。指紋の文字列を貼り付けると一致確認つきで登録 |
Warning: Permanently added ... |
known_hosts に追記された(警告ではなく通知) |
yes と答える前に指紋を確かめるのが本来の手順です。 サーバー側で ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub を実行すると同じ指紋が表示されるので、画面の値と一致していれば本物のサーバーです。今回の検証では、サーバー役のホスト鍵に対して実行した結果が、プロンプトの指紋と一致していました。
# サーバー側で(今回は検証用ホスト鍵 hostkey_a.pub に対して実行)
ssh-keygen -lf hostkey_a.pub
256 SHA256:MkSwfTWwARSFkQNVbOhhzKXhGcGpNKAkhgGLXnGE0Vk hostkey_a (ED25519)
登録後の known_hosts には、ホスト名(ポートが 22 以外なら [host]:port の形)と公開鍵が1行で記録されます。
[localhost]:7682 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPqjsoqeN8Co53YZ3W8PI0bNCBrtRqpg3cHJ+JCGZl6r
自動化で確認プロンプトを出したくないとき:StrictHostKeyChecking=accept-new
スクリプトや CI から初回接続するときは、確認プロンプトで止まらないように -o StrictHostKeyChecking=accept-new を付けます。「新しいホストは自動登録するが、登録済みの鍵が変わっていたら拒否する」という動きで、no よりも安全です。
ssh -F ./config -o UserKnownHostsFile=./kh_acceptnew -o StrictHostKeyChecking=accept-new \
-i ./id_ed25519 -p 7682 sshdemo@localhost 'echo connected as $(whoami)'
Warning: Permanently added '[localhost]:7682' (ED25519) to the list of known hosts.
connected as sshdemo
| 値 | 新しいホスト | 鍵が変わったホスト | 使いどころ |
|---|---|---|---|
ask(既定) |
確認プロンプト | 拒否 | 手で接続するとき |
accept-new |
自動登録 | 拒否 | 自動化・CI |
yes |
拒否(手動で登録が必要) | 拒否 | 登録済みのサーバーにしかつながせたくないとき |
no(off) |
自動登録 | 警告だけ出して接続 | 使い捨ての検証環境のみ(通常は避ける) |
値の挙動は ssh_config(5) のマニュアルで確認しました。
ユーザー指定:user@host と -l user は同じ意味
ssh -F ./config -i ./id_ed25519 -p 7682 -l sshdemo localhost whoami
sshdemo
sshdemo@localhost と -l sshdemo localhost は同じ意味です。 ユーザー名を省略すると手元のログインユーザー名が使われるので、サーバー側のユーザー名が違うときだけ指定します。ユーザー名にハイフンなどが入って読みにくい場合や、スクリプトで変数展開するときは -l が見やすいこともあります。
ポート指定:-p(小文字)
ポートは -p 番号 で指定します。 既定は 22 です。scp と sftp では大文字の -P になる点だけ覚えておくと、毎回の検索が減ります。
| コマンド | ポート指定 |
|---|---|
ssh |
-p 7682 |
scp |
-P 7682 |
sftp |
-P 7682 |
ssh-copy-id |
-p 7682 |
リモートでコマンドだけ実行して戻ってくる
ホストの後ろにコマンドを書くと、ログインシェルに入らずにそのコマンドだけを実行して、結果を手元に表示して終了します。 複数のコマンドは ; でつないで全体をクォートで囲みます。
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost 'uname -a; uptime'
Linux vm 6.18.44-fc-v51 #1 SMP PREEMPT_DYNAMIC @0 x86_64 x86_64 x86_64 GNU/Linux
15:28:52 up 19 min, 0 user, load average: 0.12, 0.45, 0.36
クォートの違いは次のとおりです。$(...) や変数をサーバー側で展開したいときはシングルクォートにします。
| 書き方 | 展開される場所 | 例 |
|---|---|---|
ssh host 'echo $HOME' |
サーバー側 | サーバーのホームが表示される |
ssh host "echo $HOME" |
手元 | 手元のホームが文字列として送られる |
対話的なコマンドには -t が要る
リモートコマンド実行では、既定で擬似端末(pty)が割り当てられません。top・vim・less・パスワードを聞く sudo のように端末が必要なコマンドは -t を付けます。
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost tty
ssh -F ./config -i ./id_ed25519 -p 7682 -t sshdemo@localhost tty
not a tty
/dev/pts/1
Connection to localhost closed.
-t なしでは「端末ではない」、-t ありでは /dev/pts/1 という端末が割り当てられています。逆に -T は端末を割り当てない指定で、ssh -T git@github.com のような接続確認でよく見かけます。
ログアウトと、固まった接続を切る ~.
通常のログアウトは exit(または Ctrl+D)です。サーバーが応答しなくなって exit も効かないときは、Enter を押してから ~. と入力すると、クライアント側で接続を切れます。 実際に sleep 1000 で戻ってこない状態を作って試しました。
sshdemo@vm:~$ sleep 1000
Connection to localhost closed.
~? を入力すると使えるエスケープの一覧が表示されます(改行直後にだけ認識されます)。
sshdemo@vm:~$ ~?
Supported escape sequences:
~. - terminate connection (and any multiplexed sessions)
~B - send a BREAK to the remote system
~R - request rekey
~V/v - decrease/increase verbosity (LogLevel)
~^Z - suspend ssh
~# - list forwarded connections
~& - background ssh (when waiting for connections to terminate)
~? - this message
~~ - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)
鍵認証の一連の流れ:ssh-keygen から接続まで
公開鍵認証は「手元で鍵ペアを作る → 公開鍵(.pub)をサーバーの ~/.ssh/authorized_keys に登録する → -i で秘密鍵を指定して接続する」の3ステップです。 パスワードをネットワークに流さず、秘密鍵は手元から出ないので、サーバー側でパスワード認証を無効にできます。
flowchart LR
A["ssh-keygen -t ed25519<br>秘密鍵 id_ed25519 と<br>公開鍵 id_ed25519.pub"] --> B["公開鍵をサーバーの<br>~/.ssh/authorized_keys に登録<br>(ssh-copy-id か手動)"]
B --> C["ssh -i ~/.ssh/id_ed25519 user@host<br>秘密鍵で署名 → サーバーが公開鍵で検証"]
1. 鍵を作る:ssh-keygen -t ed25519 -C "コメント"
ssh-keygen -t ed25519 -C "demo@my-pc"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/root/.ssh/id_ed25519): ← そのまま Enter(検証では ./id_ed25519 と入力)
Enter passphrase (empty for no passphrase): ← パスフレーズ(検証では空)
Enter same passphrase again:
Your identification has been saved in ./id_ed25519
Your public key has been saved in ./id_ed25519.pub
The key fingerprint is:
SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s demo@my-pc
The key's randomart image is:
+--[ED25519 256]--+
|..ooo. . ..=o |
…(省略)…
+----[SHA256]-----+
| 質問 | 答え方 |
|---|---|
Enter file in which to save the key |
Enter で既定の ~/.ssh/id_ed25519。用途別に分けるなら ~/.ssh/id_ed25519_work のように名前を変える |
Enter passphrase |
秘密鍵ファイルを暗号化する合言葉。付けておくと鍵ファイルが流出しても即座には使われない。毎回の入力は ssh-agent で1回にできる(後述) |
-C "コメント" |
公開鍵の末尾に付く目印。既定は ユーザー名@ホスト名。どの PC の鍵か分かる文字列にしておくと authorized_keys の整理が楽 |
生成されたファイルと権限を確認します。秘密鍵は 600(自分だけ読み書き)、公開鍵は 644 で作られます。 秘密鍵の権限が広いと ssh が鍵を無視するので(後述のエラー再現を参照)、コピーした後は必ず ls -l で確かめます。
ls -l id_ed25519 id_ed25519.pub
cat id_ed25519.pub
-rw------- 1 root root 399 Oct 2 15:27 id_ed25519
-rw-r--r-- 1 root root 92 Oct 2 15:27 id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKgjezghTwpgb8xj0/Mic7WKyGYl3qZd9sE1jASfKANG demo@my-pc
公開鍵は「鍵の種類・鍵本体(Base64)・コメント」の1行です。サーバーに登録するのはこの1行だけで、-----BEGIN OPENSSH PRIVATE KEY----- で始まる秘密鍵は決して渡しません。
鍵の種類は ed25519 を選びます。 -t を省略した場合も ed25519 が作られることを確かめました(ssh-keygen(1) のマニュアルでも既定は ed25519 です)。
ssh-keygen -f ./id_default_demo -N "" -C "default" # -t を省略
ssh-keygen -lf ./id_default_demo.pub
Generating public/private ed25519 key pair.
256 SHA256:3C3WHI8vYaBnILUuBhXwhrTqnDJ9OhniyqCLKJoDcRo default (ED25519)
接続先が ed25519 に対応していないなど RSA が必要な場合は -b 4096 でビット数を指定します(既定は 3072 ビット。マニュアルで確認)。手元では生成に約 1.4 秒かかり、公開鍵は 734 バイト(ed25519 は 92 バイト)になりました。
ssh-keygen -t rsa -b 4096 -f ./id_rsa_demo -N "" -C "rsa-demo"
ssh-keygen -lf ./id_rsa_demo.pub
4096 SHA256:gUyxePrf0+gCuLGG5Ic3et0NDt7ME9/m0adH/lZYIJw rsa-demo (RSA)
| 鍵種別 | 指定 | 特徴 |
|---|---|---|
| ed25519 | -t ed25519 |
短く速く、現在の既定。迷ったらこれ |
| rsa | -t rsa -b 4096 |
対応範囲が最も広い。ed25519 に対応していない機器向けの選択肢 |
| ecdsa | -t ecdsa -b 256/384/521 |
一部の環境が要求する場合に |
| ed25519-sk / ecdsa-sk | -t ed25519-sk |
FIDO セキュリティキー(物理キー)に鍵を入れる |
2. 公開鍵をサーバーに登録する:ssh-copy-id または手動
ssh-copy-id は「公開鍵を相手の ~/.ssh/authorized_keys に追記し、ディレクトリと権限も整える」コマンドです。 登録に使う認証(パスワードや既存の鍵)で一度ログインできることが前提です。今回のサーバーはパスワード認証を無効にしているので、まず登録済みの鍵で認証して2本目の鍵を追加する形で実行しました。
ssh-copy-id -f -i ./id_ed25519_pass.pub -p 7682 -o IdentityFile=./id_ed25519 \
-o UserKnownHostsFile=./known_hosts sshdemo@localhost
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "./id_ed25519_pass.pub"
Number of key(s) added: 1
Now try logging into the machine, with: "ssh -p 7682 -o 'IdentityFile=./id_ed25519' -o 'UserKnownHostsFile=./known_hosts' 'sshdemo@localhost'"
and check to make sure that only the key(s) you wanted were added.
サーバー側の authorized_keys は、1行1鍵で追記されています。
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKgjezghTwpgb8xj0/Mic7WKyGYl3qZd9sE1jASfKANG demo@my-pc
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILOaVtKAERkk2YeRKZtwBqK7O5HnaaHaDsfmgHOZaAjT demo-with-passphrase
まだ何も登録されていないサーバーに対して、パスワード認証が無効のまま ssh-copy-id を実行すると次のようになります(実際の出力)。この場合は次の「手動で登録」に進みます。
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
sshdemo@localhost: Permission denied (publickey).
手動で登録する場合は、サーバー側で次の3点をそろえます:~/.ssh は 700、authorized_keys は 600、所有者はログインするユーザー本人。 今回は root でサーバー側に直接置きました。
# サーバー側(root で実行。sshdemo は接続先ユーザー)
install -d -m 700 -o sshdemo -g sshdemo /home/sshdemo/.ssh
cat id_ed25519.pub >> /home/sshdemo/.ssh/authorized_keys
chown sshdemo:sshdemo /home/sshdemo/.ssh/authorized_keys
chmod 600 /home/sshdemo/.ssh/authorized_keys
ls -la /home/sshdemo/.ssh
drwx------ 2 sshdemo sshdemo 4096 Oct 2 15:28 .
drwxr-x--- 3 sshdemo sshdemo 4096 Oct 2 15:28 ..
-rw------- 1 sshdemo sshdemo 92 Oct 2 15:28 authorized_keys
すでに別の方法でログインできるなら、手元から1行で登録することもできます。
cat ~/.ssh/id_ed25519.pub | ssh user@host 'umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys'
3. パスフレーズ付きの鍵を ssh-agent で楽に使う
パスフレーズを付けた鍵で接続すると、毎回パスフレーズを聞かれます。
ssh -F ./config -i ./id_ed25519_pass -p 7682 sshdemo@localhost whoami
Enter passphrase for key './id_ed25519_pass':
sshdemo
ssh-agent に秘密鍵を預けておくと、パスフレーズの入力はログインセッション中1回で済みます。 ssh-add -l で預けた鍵の一覧を確認でき、以降は -i を省いても agent の鍵が使われます。
eval "$(ssh-agent -s)" # agent を起動して環境変数を設定
ssh-add -l # 預けた鍵の一覧(まだ無い)
ssh-add ./id_ed25519_pass # 鍵を預ける(パスフレーズを1回入力)
ssh-add -l
ssh -F ./config -p 7682 sshdemo@localhost whoami # -i なしで接続
Agent pid 2658
The agent has no identities.
Enter passphrase for ./id_ed25519_pass:
Identity added: ./id_ed25519_pass (demo-with-passphrase)
256 SHA256:oGqH/UucgpFU0hnQmPy3srOgfELsXaR5OoQbpIkpOjs demo-with-passphrase (ED25519)
sshdemo
| コマンド | 役割 |
|---|---|
eval "$(ssh-agent -s)" |
agent を起動し、SSH_AUTH_SOCK などの環境変数を現在のシェルに設定 |
ssh-add 鍵ファイル |
鍵を預ける。-t 3600 で有効期限(秒)を付けられる |
ssh-add -l |
預けた鍵の一覧(-L で公開鍵そのものを表示) |
ssh-add -d 鍵ファイル / ssh-add -D |
1本削除/全部削除 |
ssh-agent -k |
agent を終了(SSH_AGENT_PID を見て止める) |
Mac では Keychain、Windows では ssh-agent サービス、多くの Linux デスクトップではログイン時に agent が自動で起動するので、ssh-add -l で「既に動いているか」をまず確かめると早いです。
4. パスフレーズの変更とフィンガープリントの確認
パスフレーズは ssh-keygen -p で変えられ、鍵本体(公開鍵)は変わらないのでサーバー側の再登録は不要です。 空にして外すこともできます。
ssh-keygen -p -f ./id_ed25519_pass
Enter old passphrase:
Key has comment 'demo-with-passphrase'
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.
フィンガープリント(指紋)は鍵を短い文字列で識別するもので、「どの鍵が登録されているか」「GitHub などに登録した鍵と手元の鍵が同じか」を見比べるときに使います。公開鍵・秘密鍵のどちらに対して実行しても同じ値になります。
ssh-keygen -lf id_ed25519.pub
ssh-keygen -lf id_ed25519
ssh-keygen -lf id_ed25519.pub -E md5 # 旧形式(MD5)で表示したいとき
256 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s demo@my-pc (ED25519)
256 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s demo@my-pc (ED25519)
256 MD5:71:86:aa:70:db:64:ac:b9:a7:45:8f:49:58:7d:7e:b7 demo@my-pc (ED25519)
| やりたいこと | コマンド |
|---|---|
| 鍵の指紋を見る | ssh-keygen -lf 鍵ファイル |
| 秘密鍵から公開鍵を作り直す(.pub を消してしまった) | ssh-keygen -y -f ~/.ssh/id_ed25519 > ~/.ssh/id_ed25519.pub |
| コメントを変える | ssh-keygen -c -C "新コメント" -f ~/.ssh/id_ed25519 |
| known_hosts からホストを消す | ssh-keygen -R '[host]:port' |
| known_hosts にホストがあるか探す | ssh-keygen -F '[host]:port' |
ポートフォワードと踏み台:-L / -R / -D / -N -f / -J
ポートフォワードは「ssh の暗号化された経路の中に、別の TCP 通信を通す」機能です。 サーバー内でしか開いていない Web 管理画面や DB のポートに手元から届かせたり(-L)、逆に手元の開発サーバーをリモートから見せたり(-R)、ブラウザの通信をまとめてサーバー経由にしたり(-D)できます。検証では、作業フォルダで python3 -m http.server 7684 を起動し、それを「サーバー内でしか見えないサービス」に見立てています。
| オプション | 書き方 | 待ち受ける側 | 向き |
|---|---|---|---|
-L ローカル転送 |
-L 手元ポート:宛先ホスト:宛先ポート |
手元の ssh | 手元 → サーバー側の宛先 |
-R リモート転送 |
-R サーバー側ポート:宛先ホスト:宛先ポート |
サーバーの sshd | サーバー → 手元側の宛先 |
-D 動的転送 |
-D 手元ポート |
手元の ssh(SOCKS5) | 手元のアプリ → 任意の宛先 |
宛先ホスト は「ssh の相手側から見た」名前です。-L 7685:localhost:7684 の localhost はサーバー自身を指し、サーバーから見える別のホスト(-L 5432:db.internal:5432 など)も指定できます。
-L:手元のポートをサーバー側に転送する
ssh -F ./config -i ./id_ed25519 -p 7682 -N -f -L 7685:localhost:7684 sshdemo@localhost
ss -tlnp | grep 7685
curl -s http://localhost:7685/
LISTEN 0 128 127.0.0.1:7685 0.0.0.0:* users:(("ssh",pid=3036,fd=4))
<h1>hello from port 7684</h1>
手元の 7685 で待ち受けているのは ssh 自身で、そこへの接続がサーバー側の 7684 に届いています。 -N は「リモートコマンドを実行しない(転送だけ)」、-f は「認証が終わったらバックグラウンドへ」の指定で、この2つを組み合わせるとトンネルだけを張りっぱなしにできます。
バックグラウンドにした ssh は、ss -tlnp に出る PID(上の例では 3036)を kill して止めます。
kill 3036
ss -tlnp | grep 7685 # 停止後は何も表示されない
curl -s http://localhost:7685/; echo "exit=$?"
exit=7
停止後は curl が「接続できない」(終了コード 7)になり、トンネルが閉じたことが確認できます。
-R:サーバーのポートを手元に転送する(逆向き)
ssh -F ./config -i ./id_ed25519 -p 7682 -N -f -R 7686:localhost:7684 sshdemo@localhost
ss -tlnp | grep 7686
curl -s http://localhost:7686/
LISTEN 0 128 127.0.0.1:7686 0.0.0.0:* users:(("sshd",pid=3063,fd=7))
<h1>hello from port 7684</h1>
今度は 7686 で待ち受けているのが sshd(サーバー側)です。 サーバーに来た接続が ssh の経路を逆向きに通って、手元の 7684 に届きます。手元の開発中の Web アプリを、サーバーに来た相手に見せたいときの形です。既定ではサーバーの 127.0.0.1 でだけ待ち受け、外部にも公開するには sshd 側の GatewayPorts 設定が必要です(今回は未実行)。
止めるときは、-R の ssh は手元で待ち受けないので ss には出ません。pgrep -a -x ssh で ssh プロセスだけを一覧して PID を確かめます。
pgrep -a -x ssh
kill 3061
3061 ssh -F ./config -i ./id_ed25519 -p 7682 -N -f -R 7686:localhost:7684 sshdemo@localhost
-D:SOCKS プロキシとして使う(動的転送)
ssh -F ./config -i ./id_ed25519 -p 7682 -N -f -D 7687 sshdemo@localhost
ss -tlnp | grep 7687
curl -s --noproxy '' --socks5-hostname localhost:7687 http://localhost:7684/
curl -v --noproxy '' --socks5-hostname localhost:7687 http://localhost:7684/ 2>&1 | grep -i socks
LISTEN 0 128 127.0.0.1:7687 0.0.0.0:* users:(("ssh",pid=3219,fd=4))
<h1>hello from port 7684</h1>
* SOCKS5 connect to localhost:7684 (remotely resolved)
* SOCKS5 request granted.
-D は宛先を決め打ちしない転送で、手元の 7687 が SOCKS5 プロキシになります。 ブラウザや curl にこのプロキシを設定すると、どの宛先への通信もサーバー経由になります。--socks5-hostname(ブラウザなら「プロキシで DNS を解決」)にすると、名前解決もサーバー側で行われ、サーバー内でしか引けない名前も使えます。
検証環境では NO_PROXY=localhost,... という環境変数が設定されていたため、curl が SOCKS 指定を無視して直接つないでしまいました。--noproxy '' を付けると SOCKS 経由が強制されます。同じ環境変数がある方は注意してください。ssh を止めた後に同じ curl を実行すると、SOCKS 経由だったことがはっきりします。
curl: (7) Failed to connect to localhost port 7687 after 0 ms: Couldn't connect to server
-J:踏み台(bastion)を経由して接続する
-J 踏み台 を付けると、ssh は「踏み台に ssh 接続 → その中から目的のサーバーに ssh 接続」を一度にやってくれます。 内部では ssh -W を使った ProxyCommand が自動で組み立てられます(-J は ProxyJump 設定の省略形だと ssh(1) のマニュアルに書かれています)。検証では 2台目の sshd(ポート 7683、ユーザー sshjump)を踏み台にしました。
まず、つまずきやすい結果から。-i で指定した鍵は踏み台への接続には引き継がれません。 鍵を -i だけで指定して -J を使うと、踏み台側で認証が通りません。
ssh -F ./config -i ./id_ed25519 -J sshjump@localhost:7683 -p 7682 sshdemo@localhost 'hostname; whoami'
sshjump@localhost: Permission denied (publickey).
Connection closed by UNKNOWN port 65535
直し方は2つあります。1つ目は ssh-agent に鍵を預けておくこと(踏み台側の ssh も agent の鍵を使えます)。
ssh-add ./id_ed25519
ssh -F ./config -J sshjump@localhost:7683 -p 7682 sshdemo@localhost 'hostname; whoami; echo $SSH_CONNECTION'
Identity added: ./id_ed25519 (demo@my-pc)
vm
sshdemo
127.0.0.1 60652 127.0.0.1 7682
踏み台側 sshd のログ(-E でファイルに出力)にも、踏み台ユーザーでの認証成功が記録されています。
Accepted publickey for sshjump from 127.0.0.1 port 57260 ssh2: ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s
2つ目は、踏み台を ~/.ssh/config に書いておくこと(鍵・ユーザー・ポートが踏み台側にも適用されます)。次の設定を用意すると、-J bastion・-o ProxyJump=bastion・config の ProxyJump bastion の3通りすべてで接続できました。
# ~/.ssh/config(検証では ./config を -F で指定)
Host server-a
HostName localhost
Port 7682
User sshdemo
IdentityFile ./id_ed25519
IdentitiesOnly yes
ProxyJump bastion
Host bastion
HostName localhost
Port 7683
User sshjump
IdentityFile ./id_ed25519
IdentitiesOnly yes
ssh -F ./config -J bastion -i ./id_ed25519 -p 7682 sshdemo@localhost whoami # コマンドラインで -J
ssh -F ./config -o ProxyJump=bastion server-direct whoami # -o で指定
ssh -F ./config server-a 'hostname; whoami; echo $SSH_CONNECTION' # config の ProxyJump
sshdemo
sshdemo
vm
sshdemo
127.0.0.1 32788 127.0.0.1 7682
-v を付けると、2段階の認証が順に行われている様子が読めます。
ssh -F ./config -v server-a true 2>&1 | grep -iE "proxy|Authenticating|Authenticated|Offering"
debug1: Setting implicit ProxyCommand from ProxyJump: ssh -F ./config -v -W '[%h]:%p' bastion
debug1: Executing proxy command: exec ssh -F ./config -v -W '[localhost]:7682' bastion
debug1: Authenticating to localhost:7683 as 'sshjump'
debug1: Offering public key: ./id_ed25519 ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s explicit
Authenticated to localhost ([127.0.0.1]:7683) using "publickey".
debug1: Authenticating to localhost:7682 as 'sshdemo'
debug1: Offering public key: ./id_ed25519 ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s explicit
Authenticated to localhost (via proxy) using "publickey".
| 書き方 | 使いどころ |
|---|---|
ssh -J user@bastion:port user@target |
一時的に経由したいとき(鍵は agent か既定の場所に) |
ssh -J bastion target(config に両方を定義) |
踏み台の鍵・ユーザー・ポートを config に任せる |
ssh -o ProxyJump=bastion target |
スクリプトで切り替えたいとき |
config の ProxyJump bastion |
毎回同じ経路なら最もシンプル。ssh server-a だけで済む |
-J b1,b2(カンマ区切り) |
多段の踏み台 |
踏み台を経由しても、目的サーバーへの認証は手元の鍵で行われます。 踏み台に秘密鍵を置く必要はなく、-A(agent 転送)も不要です。
~/.ssh/config で接続を短く書く:-F と -G
毎回 -p -i -J を打つ代わりに、~/.ssh/config に接続先ごとの設定を書いておくと ssh 別名 だけで接続できます。 ファイルは chmod 600 ~/.ssh/config にしておきます(権限が広いと Bad owner or permissions で読み込まれません)。書き方の詳細は別記事「ssh config の書き方」に譲り、ここでは今回使ったテンプレートと、-F・-G で確認する方法に絞ります。
# ~/.ssh/config のテンプレート(検証で実際に使ったもの。パスは環境に合わせて変更)
# 接続先サーバー(踏み台 bastion を経由)
Host server-a
HostName localhost
Port 7682
User sshdemo
IdentityFile ./id_ed25519
IdentitiesOnly yes
ProxyJump bastion
# 踏み台
Host bastion
HostName localhost
Port 7683
User sshjump
IdentityFile ./id_ed25519
IdentitiesOnly yes
# 同じサーバーに直接つなぐ版(踏み台なし)
Host server-direct
HostName localhost
Port 7682
User sshdemo
IdentityFile ./id_ed25519
IdentitiesOnly yes
# 全ホスト共通(最初に一致した値が優先されるので末尾に置く)
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
UserKnownHostsFile ./known_hosts
| 項目 | 意味 | 書く目安 |
|---|---|---|
Host |
コマンドで使う別名(ワイルドカード可) | 覚えやすい短い名前 |
HostName |
実際のホスト名/IP | 必須 |
User |
ログインユーザー | 手元と違うとき |
Port |
ポート | 22 以外のとき |
IdentityFile |
秘密鍵 | 既定の場所以外に置いたとき |
IdentitiesOnly yes |
指定した鍵以外を試さない | 鍵を複数持っているなら常に |
ProxyJump |
踏み台 | 経由が必要なとき |
ServerAliveInterval / ServerAliveCountMax |
無通信時に生存確認を送る間隔(秒)と回数 | 60 / 3(= 約3分無応答で切断) |
ForwardAgent yes |
agent を相手に転送 | 必要なホストにだけ(後述) |
ssh_config(5) のマニュアルどおり、同じ項目が複数回現れたときは「最初に書いた値」が使われます。 個別のホストを上に、Host * の共通設定を下に書くのはそのためです。ServerAliveInterval の既定は 0(送らない)、ServerAliveCountMax の既定は 3 です。
-F で設定ファイルを指定して接続する
ssh -F ./config server-a 'hostname; whoami; echo $SSH_CONNECTION'
ssh -F ./config server-direct whoami
vm
sshdemo
127.0.0.1 32788 127.0.0.1 7682
sshdemo
-F を付けると、そのファイルだけが読まれ、~/.ssh/config と /etc/ssh/ssh_config は読まれません。検証用の設定を切り替えて試すときに便利です。
-G で「結局どの設定で接続するのか」を確認する
ssh -G 別名 は、config を評価した結果(実際に使われる値)をすべて表示して終了します。 接続はしないので、鍵やポートの指定が効いているかを安全に確かめられます。今回の環境では 82 行が出力されたので、知りたい項目だけ grep しました。
ssh -G -F ./config server-a | grep -iE '^(hostname|user|port|identityfile|identitiesonly|proxyjump|serveraliveinterval|serveralivecountmax|userknownhostsfile|stricthostkeychecking|forwardagent) '
user sshdemo
hostname localhost
port 7682
identitiesonly yes
stricthostkeychecking ask
serveralivecountmax 3
serveraliveinterval 60
identityfile ./id_ed25519
userknownhostsfile ./known_hosts
forwardagent no
proxyjump bastion
config に無いホスト名を指定すると既定値が見えます。IdentityFile を書かなかったときに ssh が順に試す鍵の一覧も、ここで確認できます。
ssh -G -F ./config unknown-host | grep -iE '^(hostname|user|port|identityfile) '
user root
hostname unknown-host
port 22
identityfile ~/.ssh/id_rsa
identityfile ~/.ssh/id_ecdsa
identityfile ~/.ssh/id_ecdsa_sk
identityfile ~/.ssh/id_ed25519
identityfile ~/.ssh/id_ed25519_sk
identityfile ~/.ssh/id_xmss
identityfile ~/.ssh/id_dsa
| 確認したいこと | コマンド |
|---|---|
| 別名がどのホスト・ポート・ユーザーに解決されるか | ssh -G 別名 | grep -E '^(hostname|port|user) ' |
| どの鍵を使うか | ssh -G 別名 | grep identityfile |
| 踏み台が効いているか | ssh -G 別名 | grep proxyjump |
| 設定ファイルの文法ミス | ssh -G 別名 が Bad configuration option を出す |
接続エラーを実際に再現:メッセージ/原因/対処の一覧表
ssh がつながらないときは、最後に表示された1行(メッセージ)で原因の候補がほぼ絞れます。 代表的なエラーを検証環境で実際に起こし、出たメッセージをそのまま載せました。まず一覧表で当たりを付け、各項目で実際の出力と直し方を確認してください。
| メッセージ(実際に出たもの) | 主な原因 | 対処 |
|---|---|---|
sshdemo@localhost: Permission denied (publickey). |
公開鍵が authorized_keys に無い/-i の付け忘れ/ユーザー名違い/サーバー側 ~/.ssh の権限が広い |
-v で差し出した鍵を確認し、その公開鍵を正しいユーザーの authorized_keys に登録(権限は 700/600) |
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! |
サーバーのホスト鍵が変わった(再インストール・IP の付け替えなど) | 指紋を確認し、ssh-keygen -R '[host]:port' で以前の登録を消して再接続 |
WARNING: UNPROTECTED PRIVATE KEY FILE! |
秘密鍵ファイルの権限が 644 などで他人から読める | chmod 600 秘密鍵 |
Host key verification failed. |
未登録ホストに StrictHostKeyChecking=yes/CI などで確認プロンプトに答えられない |
事前に ssh-keyscan で登録、または -o StrictHostKeyChecking=accept-new |
ssh: connect to host localhost port 7689: Connection refused |
そのポートで sshd が待ち受けていない(ポート違い・sshd 停止) | -p を見直す。サーバー側で ss -tlnp |
ssh: connect to host 10.255.255.1 port 22: Connection timed out |
相手に届かない(IP 違い・遮断・VPN 未接続)。経路が無いと Network is unreachable |
IP・VPN・サーバー側の受け入れ設定を確認 |
ssh: Could not resolve hostname localhsot: Name or service not known |
ホスト名の打ち間違い/名前解決できない(VPN 外・社内 DNS) | つづりと ssh -G 別名 | grep hostname を確認 |
Received disconnect from 127.0.0.1 port 7682:2: Too many authentication failures |
agent などの鍵が多く、正しい鍵の前に上限(既定 6 回)に達した | -o IdentitiesOnly=yes -i 正しい鍵 |
kex_exchange_identification: Connection closed by remote host |
ssh 以外のサービス(Web サーバーなど)のポートにつないだ | -p を見直す |
Permission denied (publickey):鍵が「登録されていない」か「使われていない」
最も多いエラーで、意味は「公開鍵認証を試したが、サーバーに受け入れられる鍵が1本も無かった」です。 authorized_keys に登録していない鍵(id_rsa_demo)で接続すると、次のようになります。
ssh -F ./config -i ./id_rsa_demo -o IdentitiesOnly=yes -p 7682 sshdemo@localhost whoami
sshdemo@localhost: Permission denied (publickey).
原因を切り分けるには -v を付けて「どの鍵を差し出したか(Offering)」を見ます。 下は -i を付け忘れて接続したときの抜粋で、既定の場所の鍵 ~/.ssh/id_ed25519(検証は root で実行したので /root/.ssh/。サーバーには未登録)が試されて拒否されています。
debug1: Offering public key: /root/.ssh/id_ed25519 ED25519 SHA256:Ct1XqBHmE7IApF6SHlJPHCzPq4pcwKXOi8Tk7v2w16Y
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
sshdemo@localhost: Permission denied (publickey).
「Offering public key: の直後に Authentications that can continue: publickey が返ってきた」のが、その鍵がサーバーに拒否された合図です(受け入れられたときは Server accepts key:)。表示された指紋を ssh-keygen -lf 公開鍵 の値と見比べれば、登録した鍵と差し出した鍵が同じか分かります。
直し方は、Offering の鍵が未登録ならその公開鍵(.pub の1行)を ~/.ssh/authorized_keys に追記し、既定の鍵が並んでいるなら -i 鍵 か config の IdentityFile を指定します。メッセージ先頭のユーザー名(検証では root@localhost: と出ました)が想定と違うときは user@host を直します。
サーバー側の権限が原因のケースは、クライアントからは区別がつきません。検証で ~sshdemo/.ssh を 777 にして接続すると、クライアントには同じ Permission denied (publickey). が出て、理由(Authentication refused: bad ownership or modes for directory /home/sshdemo/.ssh)はサーバーのログ(/var/log/auth.log や journalctl -u ssh)にだけ記録されました。 sshd の StrictModes(既定で有効)が権限を確認してから受け入れるためです(sshd_config(5) のマニュアルで確認)。
REMOTE HOST IDENTIFICATION HAS CHANGED:サーバーのホスト鍵が変わった
known_hosts に登録してある鍵と、サーバーが今名乗っている鍵が一致しないときの警告です。 サーバーの再インストールや、同じホスト名・IP への別サーバーの割り当てで起きることが多い一方、通信を横取りされている場合も同じ表示になるため、ssh は接続を止めます。検証では、ホスト鍵を作り直して sshd を再起動し、それまでの known_hosts のまま接続しました。
ssh-keygen -t ed25519 -f hostkey_a -N "" -C "hostkey_a-regenerated" # サーバー側で作り直し
kill $(cat sshd_a.pid); /usr/sbin/sshd -f $PWD/sshd_a.conf # 再起動
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost whoami # 以前の known_hosts のまま
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
…(省略)…
The fingerprint for the ED25519 key sent by the remote host is
SHA256:BSqWyDsWSqLBdVbtgZnqDdziKLvnaAe2IjJ5Dq78emA.
…(省略)…
Offending ED25519 key in ./known_hosts:1
remove with:
ssh-keygen -f './known_hosts' -R '[localhost]:7682'
Host key for [localhost]:7682 has changed and you have requested strict checking.
Host key verification failed.
読むのは3か所です。The fingerprint ... がサーバーが今名乗っている鍵の指紋(管理者に聞いた新しい指紋と一致するか確かめます)、Offending ...:1 が食い違う登録の行番号、remove with: の下がそれを消すコマンドです。直し方は、指紋が正しいことを確認したうえで ssh-keygen -R で以前の登録を消し、再接続して新しい鍵を登録することです。 既定の ~/.ssh/known_hosts なら -f を省いて ssh-keygen -R '[host]:port' と打ちます。
ssh-keygen -f './known_hosts' -R '[localhost]:7682'
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost whoami
# Host [localhost]:7682 found: line 1
./known_hosts updated.
Original contents retained as ./known_hosts.old
The authenticity of host '[localhost]:7682 ([127.0.0.1]:7682)' can't be established.
ED25519 key fingerprint is SHA256:BSqWyDsWSqLBdVbtgZnqDdziKLvnaAe2IjJ5Dq78emA.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:7682' (ED25519) to the list of known hosts.
sshdemo
初回接続と同じプロンプトに戻り、yes で新しい鍵が登録されて接続できました(known_hosts を丸ごと消すと他のサーバーの登録まで消えるので、-R で該当ホストだけ消します)。ここから先の実行例では、ホスト鍵がこの作り直したもの(指紋 BSqW...)になっているため、冒頭の指紋 MkSw... とは値が違います。
UNPROTECTED PRIVATE KEY FILE:秘密鍵の権限が広い
秘密鍵ファイルが他のユーザーから読める権限(644 など)だと、ssh はその鍵を無視します。 鍵を別の PC からコピーしたときに起きやすく、検証では id_ed25519 のコピーを chmod 644 にして接続しました。
chmod 644 ./id_ed25519_loose
ssh -F ./config -i ./id_ed25519_loose -o IdentitiesOnly=yes -p 7682 sshdemo@localhost whoami
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for './id_ed25519_loose' are too open.
This private key will be ignored.
sshdemo@localhost: Permission denied (publickey).
This private key will be ignored. のとおり鍵が無視され、結果として Permission denied (publickey). になります。直し方は chmod 600 ./id_ed25519_loose だけで、同じコマンドを再実行すると sshdemo が表示されました。
Host key verification failed:確認プロンプトに答えられなかった
「ホスト鍵を確認できなかったので中止した」というメッセージで、未知のホストに厳格モードで接続したときや、CI などで確認プロンプトに答えられないときに出ます。 検証では、空の known_hosts に対して StrictHostKeyChecking=yes で接続しました。
ssh -F ./config -o UserKnownHostsFile=./kh_empty -o StrictHostKeyChecking=yes -i ./id_ed25519 -p 7682 sshdemo@localhost whoami
No ED25519 host key is known for [localhost]:7682 and you have requested strict checking.
Host key verification failed.
「手元では動くのに CI では止まる」場合もこの形が多く、端末が無いので (yes/no) に答えられず Host key verification failed. の1行で止まります(検証では標準入力を /dev/null にして再現。-o BatchMode=yes でも同じ)。直し方は「事前にホスト鍵を登録しておく」か「新規ホストだけ自動登録する(accept-new)」のどちらかです。 前者は ssh-keyscan -t ed25519 -p 7682 localhost >> ~/.ssh/known_hosts のように出力を追記します。検証では別ファイルに保存して ssh-keygen -lf で指紋(BSqW...)を確かめ、StrictHostKeyChecking=yes のまま接続できました。
Connection refused:そのポートで誰も待ち受けていない
ssh -F ./config -i ./id_ed25519 -p 7689 sshdemo@localhost whoami
ssh: connect to host localhost port 7689: Connection refused
「相手のマシンには届いたが、そのポートを開いているプロセスが無い」状態で、認証の手前(TCP 接続)で止まっています。 -p の値と config の Port(ssh -G 別名 | grep port)、サーバー側で sshd が動いているか(ss -tlnp | grep sshd)、ファイアウォールの受け入れ設定を順に確認します。
ポート番号を取り違えて ssh 以外のサービス(検証では 7684 の Web サーバー)につないだ場合は、接続直後に切られて kex_exchange_identification: Connection closed by remote host が出ました(-v なら相手の応答が banner line として見えます)。
Connection timed out:相手に届かない
ssh -F ./config -o ConnectTimeout=3 -i ./id_ed25519 sshdemo@10.255.255.1 whoami
ssh: connect to host 10.255.255.1 port 22: Connection timed out
「届かない」ので、宛先 IP の間違い・VPN の未接続・途中の機器での遮断・サーバー側で受け入れていない、のいずれかです。 切り分け中は -o ConnectTimeout=3 のように待ち時間を短くすると速く返ります(検証では 3 秒)。経路そのものが無い場合は Network is unreachable という別のメッセージになりますが、手元では再現できませんでした(未実行)。
Could not resolve hostname:名前が引けない
ssh: Could not resolve hostname localhsot: Name or service not known
ホスト名を IP に変換できなかった、というメッセージで、原因の大半はつづりの間違いです(上は localhost を localhsot と打った例)。 社内 DNS でしか引けない名前を VPN 外から使った場合や、config の HostName の誤りでも出ます。別名を使っているなら ssh -G 別名 | grep hostname で、どの名前に解決されているかを先に確認します。
Too many authentication failures:試した鍵が多すぎた
ssh-agent に鍵をたくさん預けていると、ssh は agent の鍵を順に差し出し、正しい鍵の番が来る前にサーバー側の上限(MaxAuthTries、既定 6)に達して切断されます。 検証では agent に 7 本の鍵を預け、-i で正しい鍵を指定して接続しました。
ssh -F ./config -i ./id_ed25519 -p 7682 sshdemo@localhost whoami # agent には 7 本の鍵
Received disconnect from 127.0.0.1 port 7682:2: Too many authentication failures
Disconnected from 127.0.0.1 port 7682
-v を見ると、-i で指定した鍵(行末 explicit)より先に agent の鍵(行末 agent)が差し出され、6 本目の直後に切られていました。直し方は IdentitiesOnly=yes で「指定した鍵だけを使う」ことです。 同じ agent の状態のまま、オプションを1つ足すだけで接続できました。恒久的には config に IdentitiesOnly yes と IdentityFile を書き、agent の鍵は ssh-add -l で確認して ssh-add -d で減らします。
ssh -F ./config -o IdentitiesOnly=yes -i ./id_ed25519 -p 7682 sshdemo@localhost whoami
sshdemo
OpenSSH 10.5 のリリースノートには、試される鍵を順番どおりに表示する ssh -Z user@host の追加が書かれています(手元の 9.6 には無いため未実行)。
-v のログの読み方:どの鍵を試して、どこで止まったか
-v のログは「設定読み込み → TCP 接続 → バージョン交換 → ホスト鍵の確認 → 認証 → セッション」の順に流れるので、最後がどの段階かを見れば原因の層が分かります。 成功時のログ(62 行)から要点を抜粋します。
ssh -v -F ./config -o IdentitiesOnly=yes -i ./id_ed25519 -p 7682 sshdemo@localhost whoami
debug1: Reading configuration data ./config
debug1: Connecting to localhost [127.0.0.1] port 7682.
debug1: Connection established.
debug1: Remote protocol version 2.0, remote software version OpenSSH_9.6p1 Ubuntu-3ubuntu13.19
debug1: Server host key: ssh-ed25519 SHA256:BSqWyDsWSqLBdVbtgZnqDdziKLvnaAe2IjJ5Dq78emA
debug1: Host '[localhost]:7682' is known and matches the ED25519 host key.
debug1: Will attempt key: ./id_ed25519 ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s explicit
debug1: Offering public key: ./id_ed25519 ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s explicit
debug1: Server accepts key: ./id_ed25519 ED25519 SHA256:6k4TDUhqBfDU1r3/yAxP8Wf83QYlBNczTOz5+whe+3s explicit
Authenticated to localhost ([127.0.0.1]:7682) using "publickey".
debug1: Sending command: whoami
sshdemo
debug1: Exit status 0
| 段階 | 目印になる行 | ここで止まったら疑うこと |
|---|---|---|
| 1. 設定読み込み・TCP 接続 | Connecting to ... → Connection established. |
Connection refused/timed out/Could not resolve ならネットワークかポート |
| 2. バージョン交換 | Remote protocol version 2.0, remote software version ... |
出ないなら ssh 以外のサービスにつないでいる(banner line を見る) |
| 3. ホスト鍵の確認 | Server host key: ... → Host '...' is known and matches |
HAS CHANGED や Host key verification failed は known_hosts の問題 |
| 4. 認証 | Will attempt key: → Offering public key: → Server accepts key: |
Offering の後に Authentications that can continue が返るなら未登録。Will attempt に目的の鍵が無いなら -i 忘れ |
| 5. セッション | Authenticated to ... → Sending command: → Exit status 0 |
ここまで来ていれば ssh は成功。以降はリモート側の問題 |
Authentications that can continue: にはサーバーが許可している認証方式が並びます(publickey,password ならパスワード認証も残っています)。さらに詳しくは -vv、-vvv、ログの保存は -E ファイル です。
ssh コマンドのオプション一覧表(意味と使いどころ)
よく使うオプションを「意味/使いどころ」でまとめます。 意味は ssh(1) のマニュアルで確認し、-4 -C -q -E -T -A も検証環境で実行しました(-6 は手元が IPv6 非対応のため名前解決で止まりました。-X は未実行)。
| オプション | 意味 | 使いどころ |
|---|---|---|
-p ポート |
接続先ポート(既定 22) | 22 以外で待ち受けるサーバー。scp/sftp は -P |
-i 鍵ファイル |
使う秘密鍵 | 既定の場所以外の鍵 |
-l ユーザー |
ログインユーザー | user@host と同じ意味 |
-t |
擬似端末を強制的に割り当てる | ssh host top、ssh host sudo ... など対話的なコマンド |
-T |
擬似端末を割り当てない | ssh -T git@github.com のような接続確認、パイプ処理 |
-v / -vv / -vvv |
デバッグ出力(段階的に詳しく) | つながらないときの第一手 |
-q |
警告や診断メッセージを抑える | スクリプトで出力をすっきりさせたいとき |
-C |
通信を圧縮する | 回線が細いとき(検証では compression: zlib@openssh.com になった) |
-N |
リモートコマンドを実行しない | ポートフォワードだけ張るとき |
-f |
認証後にバックグラウンドへ | -N と組み合わせてトンネルを常駐 |
-L 手元:宛先:ポート |
ローカル転送 | サーバー内のサービスを手元のポートで使う |
-R サーバー側:宛先:ポート |
リモート転送 | 手元のサービスをサーバー側に見せる |
-D ポート |
動的転送(SOCKS5) | ブラウザや curl の通信をサーバー経由に |
-J 踏み台 |
ProxyJump(踏み台経由) | 直接届かないサーバーへ。カンマで多段 |
-A |
agent 転送 | 接続先からさらに別のサーバーへ鍵認証するときだけ |
-X |
X11 転送 | GUI アプリを手元に表示(未実行) |
-o 設定=値 |
config の項目をその場で指定 | -o StrictHostKeyChecking=accept-new など |
-F ファイル |
設定ファイルを指定 | 検証用・用途別の config を切り替える |
-G |
設定を評価して表示し、接続しない | どの設定で接続するかの確認 |
-4 / -6 |
IPv4/IPv6 のみを使う | 名前が両方に解決され、片方が通らないとき |
-E ログファイル |
デバッグ出力をファイルに追記 | -v のログを残して共有するとき |
Windows 11・Mac・WSL での違い(いずれも未実行)
この記事のコマンド(-p -i -J -L など)は、Windows 11・Mac・WSL のどれでもそのまま使えます。 違うのはファイルの場所と agent の起動方法です。以下は検証環境(Linux)では動かしていない未実行の情報です(Windows の鍵・agent は Microsoft Learn の「OpenSSH のキー管理」ページで確認)。
| 項目 | Windows 11(PowerShell の ssh.exe) |
Mac(ターミナル) | WSL(Ubuntu など) |
|---|---|---|---|
| config・鍵の場所 | C:\Users\名前\.ssh\config、C:\Users\名前\.ssh\id_ed25519 |
~/.ssh/config、~/.ssh/id_ed25519 |
WSL 内の ~/.ssh/(Windows 側とは別) |
| 鍵の権限 | NTFS のアクセス権で他ユーザーの読み取りを外す | chmod 600 |
chmod 600(/mnt/c 上では権限を保てないので WSL 内に置く) |
| ssh-agent | Windows サービス。PowerShell で Start-Service ssh-agent(自動起動は Set-Service -StartupType Automatic)→ ssh-add $env:USERPROFILE\.ssh\id_ed25519 |
ssh-add --apple-use-keychain ~/.ssh/id_ed25519 で Keychain に保存(一般に知られた仕様) |
eval "$(ssh-agent -s)" → ssh-add(Linux と同じ) |
安全に使うための設定(鍵・パスフレーズ・config)
安全に使うコツは「ed25519 の鍵にパスフレーズを付け、パスワード認証を使わず、config で鍵と転送の範囲を明示する」ことです。 この記事で確認した挙動と合わせて理由をまとめます。
| 設定 | 書き方 | 理由(この記事で確認したこと) |
|---|---|---|
| 鍵は ed25519 | ssh-keygen -t ed25519 -C "用途" |
短く速く、ssh-keygen の既定。RSA が必要なら -t rsa -b 4096 |
| 鍵にパスフレーズ | ssh-keygen のプロンプトで入力。後から ssh-keygen -p で変更 |
鍵ファイルが流出してもそのままでは使えない。入力は ssh-agent で1回に |
| パスワード認証を使わない | サーバーの sshd_config で PasswordAuthentication no(鍵でログインできることを確認してから) |
鍵が無い接続は Permission denied (publickey) で止まる |
| 鍵を指定して他を試さない | config に IdentityFile と IdentitiesOnly yes |
Too many authentication failures を防ぐ |
| 切断を早く検知する | ServerAliveInterval 60、ServerAliveCountMax 3 |
無応答のセッションを約3分で切る |
| agent 転送は必要なときだけ | 既定の ForwardAgent no のまま。必要なホストにだけ -A |
接続先の管理者権限を持つ人が手元の agent を使えてしまう(ssh_config(5) に注意書きあり) |
| 権限を正しく | chmod 700 ~/.ssh; chmod 600 ~/.ssh/id_ed25519 ~/.ssh/config ~/.ssh/authorized_keys |
広いと鍵が無視され(UNPROTECTED PRIVATE KEY FILE)、サーバー側でも拒否される |
よくある質問
Q. ssh user@host でパスワードを聞かれます。鍵認証にするには?
A. サーバーがパスワード認証を許可していて、かつ鍵が受け入れられなかった状態です。ssh -v で Offering public key: の鍵を確認し、その公開鍵をサーバーの ~/.ssh/authorized_keys に登録します(ssh-copy-id が最短)。登録後も聞かれるなら -i の指定と権限(~/.ssh 700・authorized_keys 600)を確認します。
Q. 鍵を複数持っていると、どの鍵が使われますか?
A. -i や config の IdentityFile で指定した鍵と、ssh-agent に預けた鍵が順に試されます(ssh -v の Will attempt key: の並びが実際の順番)。サーバーごとに IdentityFile と IdentitiesOnly yes を config に書くと、指定した鍵だけが差し出されます。
Q. 接続がしばらく放置すると切れます。
A. 途中の機器が無通信の接続を閉じていることが多いので、config の Host * に ServerAliveInterval 60 を書いて定期的に生存確認を送ります。固まったら Enter のあと ~. で切れます。
まとめ
- 基本は
ssh ユーザー名@サーバー名。ポートは-p、鍵は-i、リモートコマンドは末尾に書く(対話的なものは-t) - 鍵認証は「
ssh-keygen -t ed25519→ 公開鍵をauthorized_keysに登録 →-iで接続」の3ステップ -L/-R/-Dのポートフォワードと-Jの踏み台は、-N -fで張りっぱなしにして PID で止める~/.ssh/configに書けばssh 別名だけで接続でき、-Gで解決結果、-vで「どの鍵を差し出してどこで止まったか」が読めるPermission deniedは鍵の未登録か未指定、HAS CHANGEDはssh-keygen -R、UNPROTECTEDはchmod 600、Too manyはIdentitiesOnly=yes- 安全に使うには ed25519+パスフレーズ、パスワード認証オフ、
IdentitiesOnly、ForwardAgentは必要時のみ
参考(出典)
- OpenSSH Release Notes(10.5 の公開日、
ssh -Z): https://www.openssh.org/releasenotes.html - ssh(1) マニュアル(オプション、エスケープ文字、終了コード): https://man.openbsd.org/ssh
- ssh_config(5) マニュアル(StrictHostKeyChecking、IdentitiesOnly、ServerAliveInterval、ForwardAgent): https://man.openbsd.org/ssh_config
- ssh-keygen(1) マニュアル(既定の鍵種別、RSA の既定ビット数、-p/-l/-R): https://man.openbsd.org/ssh-keygen
- sshd_config(5) マニュアル(MaxAuthTries、StrictModes、GatewayPorts): https://man.openbsd.org/sshd_config
- Microsoft Learn「OpenSSH のキー管理」(Windows の鍵の場所、ssh-agent サービス): https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement
- 上位記事(内容の比較のため確認): https://www.sooota.com/ssh-コマンド/ 、https://popinsight.jp/blog/?p=50500
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「ssh コマンドの使い方まとめ|鍵・ポート指定・config・接続エラー対処」
株式会社RJCでは、ssh コマンドの使い方や接続エラーの切り分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。