01 / 本文
鍵は正しいのに Connection closed
修正をコミットしたのに、1か月半たっても本番に反映されていなかった。ワークフローは毎回失敗していた。
ログに出ていたのは認証エラーではなく、接続そのものが切られる行だった。
鍵を疑って入れ直しても結果は変わらない。鍵の問題ではなかった。
02 / 本文
どこまで届いているかを切り分ける
SSHは、接続・鍵交換・認証の順に進む。どこで止まったかでメッセージが変わる。
Connection closed 接続した直後に切られた(IPで弾かれている)
Permission denied (publickey) 接続は成立。鍵が合っていない
Connection timed out そもそも届いていない03 / 本文
Permission denied が出るなら、接続自体は通っている
Permission denied は悪い知らせに見えるが、接続は成功している証拠。 相手に届いていなければ、その前の段階で切れる。
手元のPCから同じサーバーに繋ぐと普通に入れた。ランナーからだけ切られる。つまり送り元のIPで判断されている。
レンタルサーバー側に海外からの接続を遮断する設定があり、GitHub Actions のランナーはそこに当たっていた。ランナーのIPは固定できないので、許可リストに入れる方法は使えない。
04 / 本文
SSHできる別のサーバーを踏み台にする
別のレンタルサーバーには、同じランナーから問題なく入れた。そこを経由させる。
OpenSSH の ProxyJump を使うと、~/.ssh/config を書くだけで済む。コマンド側は何も変えなくてよい。
Host jumpbox
HostName <踏み台のホスト>
User <踏み台のユーザー>
Port 10022
IdentityFile ~/.ssh/jump
Host target
HostName <本来の宛先>
User <宛先のユーザー>
Port 10022
IdentityFile ~/.ssh/target
ProxyJump jumpbox05 / 本文
鍵は2本いる
踏み台用と宛先用で別の鍵が要る。どちらもランナーの中だけに書き出し、ファイルには残さない。
install -m 700 -d ~/.ssh
printf '%s' "$JUMP_KEY" > ~/.ssh/jump
printf '%s' "$TARGET_KEY" > ~/.ssh/target
chmod 600 ~/.ssh/jump ~/.ssh/target
rsync -a -e "ssh -o BatchMode=yes" ./ "target:$DEST/"06 / 本文
リモートで環境変数が展開されない
踏み台越しにコマンドを流すとき、ヒアドキュメントの中の変数はローカルで展開されないことがある。値を明示的に渡す。
ssh target "DEST='$DEST' bash -s" <<'REMOTE'
cd "$DEST"
php artisan view:clear
REMOTE07 / 本文
届いたことを本番で確かめる
転送が成功しても、本番の中身が変わったとは限らない。ワークフローの最後に、本番を叩いて確かめるステップを足した。
この1行があれば、同じ問題が再発したときにワークフローが赤くなる。赤くならない壊れ方がいちばん長引く。 今回も、失敗に気づくまで1か月半かかっていた。
08 / 本文
まとめ
- Connection closed は鍵ではなく、送り元のIPで弾かれている合図
- Permission denied (publickey) が出るなら接続は通っている
- ランナーのIPは固定できない。許可リストでは解けない
- SSHできる別サーバーがあるなら ProxyJump で踏ませる
- 最後に本番を叩いて確かめるステップを入れる
コメント
この記事へのコメント
お名前だけで投稿できます。アカウント登録やログインは不要です。 いただいたコメントは確認のうえ公開します。