SSHサーバーを構築する
連載ナビ
この連載は「Linuxを使えるようになる」ではなく、「Linuxがどう動いているのか」を理解するための実践シリーズです。
今回は Linuxを理解する 〜 LFSで学ぶLinux内部構造 〜 の Part 6 / 第3回として、仕組みのつながりを意識しながら学びます。
- 前回: ipコマンド入門
- 次回: nginxをソースからビルドする
—
SSHサーバーとは「TCP 22で待つ sshd デーモン + 鍵による認証」のこと
EC2やVPSに ssh で入るとき、接続先で何が動いているのか。結論から言うと、SSHサーバーの実体は次の組み合わせです。
sshd(OpenSSHサーバーのデーモン)が、TCPの22番ポートで接続を待ち受けている- クライアントと鍵交換を行って通信を暗号化し、ホスト鍵(
/etc/ssh/ssh_host_*_key)でサーバーの正当性を、公開鍵認証やパスワードでユーザーの正当性を確認する - 認証が通ると、そのユーザー権限でシェルセッションを起動する
設定はほぼすべて /etc/ssh/sshd_config という1つのファイルに集約されています。つまりSSHサーバーの構築とは、「sshd を起動して22番でLISTENさせ、認証方式を設定すること」に尽きます。今回はこれを最小構成で実際に立ち上げます。
デーモン・ポート・認証の3層が分かれば、接続トラブルを切り分けられるから
なぜ内部構造まで理解するのか。理由は、SSHの接続トラブルが「どの層で失敗したか」でエラーメッセージが明確に変わるため、構造を知っていれば原因をほぼ即断できるからです。
| クライアント側のエラー | 失敗した層 | 主な原因 |
Connection timed out |
ネットワーク層 | ファイアウォール、AWSのセキュリティグループ、経路なし |
Connection refused |
デーモン層 | sshd が起動していない、別ポートでLISTENしている |
Permission denied (publickey). |
認証層 | 公開鍵未登録、~/.ssh の権限不正、ユーザー名間違い |
たとえばEC2で Permission denied (publickey). が出たときに、セキュリティグループを疑って時間を溶かす必要はありません。このメッセージが返ってきた時点で、TCP接続とsshdへの到達は成功しているからです。残る容疑者は鍵とユーザー名だけ、と即座に絞れます。これが前回までの「経路 → ソケット → アプリ」という層の見方の、実践での使い方です。
最小構成でSSHサーバーを立ち上げる
Part 1で作ったLinux VM(Ubuntu想定)で実際に構築します。
# 1. OpenSSHサーバーをインストール
sudo apt update && sudo apt install -y openssh-server
# 2. サービスを起動し、自動起動も有効化
# (サービス名はUbuntuでは ssh、RHEL系では sshd)
sudo systemctl enable --now ssh 2>/dev/null || sudo systemctl enable --now sshd
# 3. 22番ポートでLISTENしているか確認
sudo ss -ltnp | grep :22
3のコマンドで次のような行が出れば、デーモン層まではできあがりです。
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=612,fd=3))
0.0.0.0:22 は「すべてのインターフェースの22番で待ち受け」という意味でした(第1回参照)。あとは接続してみます。
# 自分自身に接続してみる(初回は fingerprint の確認で yes と答える)
ssh localhost
# ホスト側のIP(ip addr で確認)に対して、Macなど別マシンから接続する場合
ssh ユーザー名@192.168.64.5
初回接続時の The authenticity of host ... can't be established. という確認は、サーバーのホスト鍵を初めて受け取る際のものです。ここで yes と答えると ~/.ssh/known_hosts に記録され、以後同じサーバーの鍵が変わっていないかを毎回検証してくれます。
sshd_config を触るなら、sshd -t と「セッション維持」が命綱
構築の次は設定です。実運用で最初に行う定番の変更は「パスワード認証を無効化し、公開鍵認証のみにする」ことです。
# 1. クライアント側(例: Mac)で鍵ペアを作り、公開鍵をサーバーへ登録
ssh-keygen -t ed25519
ssh-copy-id ユーザー名@192.168.64.5
# 2. 鍵でログインできることを確認してから、サーバー側の設定を変更
sudo vi /etc/ssh/sshd_config
sshd_config では次の行を設定します(# でコメントアウトされていたら外します)。
PasswordAuthentication no
PubkeyAuthentication yes
ここで重要な作法が2つあります。
1. 反映前に必ず sudo sshd -t を実行する。 これは設定ファイルの文法チェックで、問題なければ何も出力されません。誤りがあれば /etc/ssh/sshd_config: line 57: Bad configuration option: ... のように行番号つきで教えてくれます。文法エラーのまま再起動すると sshd が起動できなくなります
2. 反映(sudo systemctl restart ssh)後も、いまのSSHセッションは切らずに、別ターミナルから新規接続を試す。 既存セッションは再起動後も維持されるので、もし設定ミスで入れなくなっても、生かしておいたセッションから修正できます。リモートサーバーで自分を締め出す事故を防ぐ、実務の基本動作です
認証で失敗する場合は、クライアント側で ssh -v ユーザー名@ホスト と実行すると、どの鍵を試してどの段階で拒否されたかが逐一表示されます。サーバー側のログは sudo journalctl -u ssh -f(Part 5参照)で追えます。
SSHは「デーモン・ポート・認証」の3層で理解し、3層で切り分ける
SSHサーバーの実体は、TCP 22で待つ sshd デーモンと /etc/ssh/sshd_config による認証設定であり、トラブルは「timeout=ネットワーク層 / refused=デーモン層 / Permission denied=認証層」で即座に切り分けられる——これが今回の結論です。
これでリモートのLinuxを安全に操作する入り口ができました。次のPart 7では、このサーバー上でnginxをソースコードからビルドします。apt install が隠している「configure → make → make install」の世界に入り、LFSで学んだビルドの知識を実際のミドルウェアに適用します。
図解テキスト
client ssh
-> port 22 … timeout / refused はここまでの問題
-> sshd daemon … /etc/ssh/sshd_config が設定
-> 鍵交換 + 認証 … Permission denied はここの問題
-> shell session
この回で実行するコマンド
上から順番に実行すれば、この回の内容を体験できます。
まずはそのままコピペして実行し、次に1行ずつ意味を確認してください。
sudo apt update && sudo apt install -y openssh-server
sudo systemctl enable --now ssh 2>/dev/null || sudo systemctl enable --now sshd
sudo ss -ltnp | grep :22
sudo sshd -t
ssh localhost
ハンズオン手順
1. ターミナルを開いて、上のコマンドを1行ずつ実行する
2. ss -ltnp | grep :22 の出力から、bindアドレスとPIDをメモする
3. ssh localhost で初回に表示される fingerprint の確認メッセージを読んでから yes と答える
4. 余裕があれば ssh -v localhost を実行し、認証がどの方式で通ったかをログから探す
5. エラーが出たら、そのエラーメッセージをそのまま残す
チェックポイント
- コマンドが最後まで実行できた
Connection timed out/Connection refused/Permission deniedがそれぞれどの層の失敗かを言えるsshd -tが何のためのコマンドか説明できる- 次の回に進む前に、分からない単語を1つ調べた
今回理解できたこと
- SSHサーバーの実体は
sshdデーモン +/etc/ssh/sshd_config+ 鍵による認証 - 接続可否は「ネットワーク(port)/ デーモン(listen)/ 認証(auth)」の3層で切り分ける
- 設定変更時は
sshd -tで文法確認し、既存セッションを残したまま新規接続で検証する