OpenSSH

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

OpenSSH (OpenBSD Secure Shell) は、Secure Shell (SSH) プロトコルを用いてコンピュータネットワーク経由の暗号化された通信セッションを提供するコンピュータプログラム群です。OpenSSH は、SSH Communications Security によって提供されているプロプライエタリな Secure Shell ソフトウェアスイートのオープンソースな代替として作成されました。OpenSSH は OpenBSD プロジェクトの一部として開発されており、Theo de Raadt によって率いられています。

OpenSSH は、似た名前の OpenSSL と混同されることがあります。しかし、これらのプロジェクトの目的は異なり、開発チームも異なります。この似たような名前は、ただ単にゴールが似ているからです。

目次

インストール

openssh パッケージをインストールしてください。

クライアントの使用

サーバに接続するには、以下を実行してください:

$ ssh -p ポート ユーザ@サーバアドレス

サーバが公開鍵認証のみを許可している場合、SSH 鍵 の記事に従ってください。

設定

クライアントは、共通のオプションとホストを保存するように設定することができます。全プションは、グローバルに、あるいは特定のホストに制限して宣言することができます。例えば:

~/.ssh/config
# グローバルなオプション
User user

# 特定のホストのオプション
Host myserver
    Hostname server-address
    Port     port

このような設定を用いると、以下の2つのコマンドは等価になります:

$ ssh -p port user@server-address
$ ssh myserver

詳細は ssh_config(5) を見てください。

一部のオプションには等価なコマンドラインスイッチがありません。しかし、コマンドラインで -o フラグを用いることで設定オプションを指定できます。例えば: -oKexAlgorithms=+diffie-hellman-group1-sha1

サーバの使用

sshd は OpenSSH サーバのデーモンです。/etc/ssh/sshd_config で設定され、sshd.service によって管理されます。設定を変更する際は、サーバを再起動する前に sshd をテストモードで使用し、サーバが正しく起動できることを確認してください。設定が有効である場合は、何も出力されません。

# sshd -t

設定

一部のユーザにのみアクセスを許可するには、以下の行を追加してください:

AllowUsers    user1 user2

一部のグループにのみアクセスを許可するには:

AllowGroups   group1 group2

素晴らしいウェルカムメッセージを (/etc/issue ファイルなどから) 追加するには、Banner オプションを設定してください:

Banner /etc/issue

公開ホスト鍵と秘密ホスト鍵は、sshdgenkeys サービスによって /etc/ssh 内に自動で生成されます。sshd_config 内の HostKeyAlgorithms オプションによって一部の署名アルゴリズムしか許可されていない場合でも、鍵が存在しない場合、再生成されます。dsa、rsa、ecdsa、そして ed25519 アルゴリズムに基づく4組の鍵のペアが提供されます。sshd に特定の鍵を使用させるには、以下のオプションを指定してください:

HostKey /etc/ssh/ssh_host_rsa_key

サーバを WAN に公開するつもりであるならば、以下のようにデフォルトのポートを 22 から別のランダムで大きい値に変更することが推奨されます:

Port 39901
ヒント:
  • 一般的なサービスにまだ割り当てられていない代替ポートを探すには、TCP と UDP のポート番号一覧を見てください。また、/etc/services にあるローカルのポート番号情報を見ることもできます。デフォルトのポート 22 番からポートを変更すると、自動化された認証試行によるログエントリ数が減るでしょう。しかし、そのような攻撃を排除することはできません。関連する情報は ポートノッキング を参照してください。
  • パスワードログインを完全に無効化することが推奨されます。そうすることで、セキュリティが格段に向上します。詳細は #公開鍵認証を強制する を参照してください。他の推奨されるセキュリティ手法については #保護 を参照してください。
  • 設定ファイル内に複数の Port port_number 行を記述することにより、OpenSSH に複数のポートをリッスンさせることができます。
  • 新しい (或いは存在しない) ホスト鍵ペアは、置き換えたいペアを /etc/ssh から削除し ssh-keygen -A を root として実行することで、生成することができます。

デーモンの管理

sshd.service起動/有効化してください。これは、SSH デーモンを永続的にアクティブ状態に保ち、各着信接続に対してフォークします。[1]

ノート: Systemd のソケットアクティベーションを使用する sshd.socket は、DOS (サービス拒否) の影響を受けやすいため、openssh 8.0p1-3 で削除されました。詳細は FS#62248 を参照してください。openssh 8.0p1-3 に更新する時に sshd.socket が有効化されていた場合、sshd.socketsshd@.service ユニットは /etc/systemd/system/ にコピーされ、再有効化されます。これは、既存のセットアップを破壊しないためだけに行われるのであって、ユーザは依然として sshd.service に移行することが推奨されます。
警告: sshd.socket の使用を継続するならば、このユニットの問題に注意してください:
  • sshd.socket ユニットは (例えばメモリ不足の状況などにより) 失敗する場合があり、Restart=always はソケットユニットに対しては指定できません。systemd issue 11553 を参照。
  • ソケットアクティベーションの使用は、接続が多すぎるとサービスのアクティブ化が拒否される可能性があるため、サービス拒否を引き起こす可能性があります。FS#62248 を参照。
ノート: sshd.socket を使用すると ListenAddress の設定が無効化され、任意のアドレスを介して接続できるようになってしまいます。ListenAddress の設定に効力を持たせるには、sshd.socket編集して、ポートと IP の両方ListenStream で設定しなければなりません (例: ListenStream=192.168.1.100:22)。また、[Socket] セクションに FreeBind=true も追加しなければなりません。さもないと、IP アドレスを設定した時に ListenAddress を指定した時と同じ欠点が生じます: ネットワークが時間内に立ち上がっていない場合、ソケットは起動に失敗します。
ヒント: ソケットアクティベーションを使用すると、各接続に対して sshd@.service の一時的なインスタンスが (異なるインスタンス名で) 開始されます。ゆえに、sshd.socket もデーモンの通常の sshd.service も、接続試行をログでモニタできません。ソケットアクティベートされた SSH インスタンスのログは、journalctl -u "sshd@*" を root として実行するか、journalctl /usr/bin/sshd を root として実行することで、確認することができます。

保護

SSH によるリモートログインを許可することは管理業務においては良いことですが、サーバーのセキュリティに脅威を及ぼすことにもなりえます。総当り攻撃の標的になりやすいので、SSH のアクセスは制限して、第三者がサーバーにアクセスできないようにする必要があります。

ssh-audit は、サーバとクライアントの設定の自動化された解析を提供します。このトピックに関して、いくつか他のガイドやツールが利用できます。例えば:

公開鍵認証を強制する

デフォルトでは、クライアントが公開鍵で認証できない場合、SSH サーバはパスワード認証にフォールバックします。なので、悪意のあるユーザがパスワードのブルートフォースによるアクセスを試みることができてしまいます。このような攻撃から保護する最も効果的な方法の1つが、パスワードログインを完全に無効化し、SSH 鍵の使用を強制することです。これは、デーモンの設定ファイルで以下のオプションを設定することで可能です:

/etc/ssh/sshd_config
PasswordAuthentication no
AuthenticationMethods publickey
警告: これを設定に追加する前に、SSH アクセスを必要とする全アカウントが、対応する authorized_keys ファイルで公開鍵認証をセットアップしていることを確認してください。詳細は SSH 鍵#リモートサーバーに公開鍵をコピー を参照してください。

二要素認証と公開鍵

SSH は、認証に複数の方法を要求するようにセットアップすることができます。AuthenticationMethods オプションを使うことで、どの認証方法を要求するかを指定することができます。これにより、公開鍵と2要素認証を使用することができます。

認証プロバイダ

Google Authenticator をセットアップする方法については Google Authenticator を参照してください。

Duo の場合、pam_duo.so モジュールを提供する duo_unixAURインストールしてください。必須の Duo 認証情報 (Integration Key、Secret Key、API Hostname) をセットアップする方法に関するインストラクションは Duo Unix ドキュメント を参照してください。

PAM セットアップ

PAM を OpenSSH で使用するには、以下のファイルを編集してください:

/etc/ssh/sshd_config
KbdInteractiveAuthentication yes
AuthenticationMethods publickey keyboard-interactive:pam

これで、PAM セットアップによって要求されるユーザ認証か公開鍵のどちらか一方でログインできます。

一方、PAM セットアップによって要求されるユーザ認証と公開鍵の両方でユーザを認証したい場合、AuthenticationMethods の分割にスペースではなくコンマを使用してください:

/etc/ssh/sshd_config
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive:pam

要求される公開鍵と pam 認証の両方を用いて、パスワード要件を無効化すると良いでしょう:

/etc/pam.d/sshd
auth      required  pam_securetty.so     #disable remote root
#Require google authenticator
auth      required  pam_google_authenticator.so
#But not password
#auth      include   system-remote-login
account   include   system-remote-login
password  include   system-remote-login
session   include   system-remote-login

ブルートフォース攻撃に対する保護

ブルートフォース (総当り) は単純なコンセプトです: 大量のランダムなユーザ名とパスワードの組み合わせを用いて、あるウェブページやサーバの SSH のようなログインプロンプトに絶え間なくログインを試みるのです。

iptables については ufw#ufw によるレート制限シンプルなステートフルファイアウォール#ブルートフォース攻撃 を参照してください。

あるいは、fail2bansshguard などの自動スクリプトを使うことで攻撃者をブロックすることでブルートフォース攻撃から身を守ることができます。

  • 信頼された場所からの着信 SSH 接続のみを許可する。
  • fail2bansshguard を使用して、パスワード認証に失敗しすぎた IP アドレスを自動的にブロックする。
  • pam_shield を使用して、特定の時間内に多くのログイン試行を行った IP アドレスをブロックする。fail2bansshguard とは対照的に、このプログラムはアカウントへのログイン成功や失敗を考慮しません。

root ログインの制限

この記事またはセクションは情報が古くなっています。
理由: 現在のバージョンでは、root ログインは上流でデフォルトで無効化されています。 (Discuss)

一般的に、root ユーザが制限無しで SSH を介してログインできることはバッドプラクティスだと考えられています。セキュリティを向上させるために SSH の root アクセスを制限する方法は2つあります。

拒否

Sudo を使うことで、root アカウントの認証を行うことなく、必要に応じて root 権限を選択的に付与することができます。このため SSH による root ログインを拒否して、攻撃者にパスワードに加えて (root でない) ユーザー名も推測させる必要を生じさせることで、ブルートフォース攻撃を困難にすることが可能です。

デーモンの設定ファイルで "Authentication" セクションを編集することで SSH からの root ユーザのログインを拒否するように設定できます。PermitRootLoginno に設定してください:

/etc/ssh/sshd_config
PermitRootLogin no

次に、SSH デーモンを再起動してください。

これで、SSH を使って root でログインすることはできなくなります。ただし、通常ユーザーでログインしてから susudo を使ってシステム管理を行うことは依然として可能です。

制限

自動的な作業の中にも、リモートによるフルシステムバックアップなど、root 権限を必要とするものがあります。セキュアな方法で root を許可したい場合、SSH による root ログインを無効化する代わりに、特定のコマンドだけ root ログインを許可することができます。~root/.ssh/authorized_keys を編集して、以下のように特定のキーの前にコマンドを記述します:

command="/usr/lib/rsync/rrsync -ro /" ssh-rsa …

上記の設定で、特定の鍵を使ってログインした場合はクォートで囲ったコマンドを実行できるようになります。

ログイン時に root ユーザーの名前を出すことで攻撃する対象が増えてしまうことに対しては sshd_config に以下を追加することで埋め合わせができます:

PermitRootLogin forced-commands-only

上記の設定は root が SSH で実行できるコマンドを制限するだけでなく、パスワードの使用も無効化して、root アカウントでは強制的に公開鍵認証を使うようになります。

root で使えるコマンドは制限しないで公開鍵認証の強制だけをするという手もあり、それでもブルートフォース攻撃はほぼ不可能です。その場合、以下を設定:

PermitRootLogin prohibit-password

authorized_keys ファイルのロック

警告: このファイルをロックしても、ユーザの間違いや特定の単純な対人攻撃からの保護しかできません。この方法は、悪意のあるプログラムや侵入に対するあらゆる保護も提供しません。多要素認証、ファイアウォール、そして縦深防御を用いて、侵入を未然に防いでください。

何らかの理由により、疑いのあるユーザに既存の鍵を追加/変更させるべきではないと思われる場合、そのファイルを操作できないようにできます。

サーバでは、ユーザの authorized_keys ファイルを読み取り専用にして、他の全パーミッションを禁止してください:

$ chmod 400 ~/.ssh/authorized_keys

ユーザがパーミッションを元に戻せないようにするには、authorized_keys ファイルに変更不可のビットを設定してください。ユーザが ~/.ssh ディレクトリをリネームして新しい ~/.ssh ディレクトリと authorized_keys ファイルを作成できないようにするには、~/.ssh ディレクトリにも変更不可のビットを設定してください。鍵を追加/削除するには、authorized_keys から変更不可のビットを削除して一時的に書き込み可能にする必要があります。

ヒント: auditd などを用いて、authorized_keys ファイルの変更を記録することが推奨されます。

SSH 証明書

一般的な SSH 鍵と手動でのフィンガープリントの検証は、一人の管理者によって管理されている少数のホストにおいては簡単でしょうが、この認証方法は拡張性が全くありません。一定数のサーバをいくつかのユーザが SSH を通してアクセスする必要がある場合、全てのホストの SSH 公開鍵フィンガープリントを手動でセキュアかつ確実に検証するのは、ほぼ不可能です。

これに対する解決策は、SSH 証明書を使うことです。SSH 証明書を使えば、SSH のデフォルトの Trust On First Use アプローチよりも拡張性の高い信用の鎖によって、公開鍵の正当性を自動で検証できます。SSH 証明書は、基本的には通常の SSH 公開鍵ですが、信頼されている認証局からの署名が付け加えられおり、これにより鍵の正当性を検証します。

インフラストラクチャ用のホスト認証局の鍵を作成する
$ ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C 'Host certificate authority for *.example.com'

認証局の秘密鍵はセキュアに保存されているべきです。鍵の抽出を防止する機構が備わっている NitrokeyYubiKey といったスマートカードやハードウェアトークン上に保存するのが理想です。

サーバの SSH ホスト公開鍵を署名する

サーバの公開鍵を、認証局の秘密鍵が保存されているローカルのシステムにコピーし、サーバの公開鍵を署名してください:

$ ssh-keygen -h -s ~/.ssh/ca_key -I certLabel -n server01.example.com ./ssh_host_ed25519_key.pub
新しい証明書を移動し、sshd にそれを使わせる

生成された証明書 ssh_host_ed25519_key-cert.pub は、サーバの /etc/ssh/ にコピーする必要があります。

/etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
認証局を信頼するように全てのクライアントを設定する
~/.ssh/known_hosts
@cert-authority  *.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKL8gB/pjuff005YNazwMCqJpgsXAbQ3r4VStd/CRKwU Host certificate authority for *.example.com
警告: サーバが識別用の証明書を提供しないと、デフォルトで公開鍵認証がフォールバックとして使用されてしまいます。
SSH ユーザ証明書

ユーザの数やデプロイ方法にもよりますが、SSH ユーザ鍵を証明書と共に使用することもできます。多くの ssh ユーザが存在する組織では、この方法でユーザ鍵のデプロイをセキュアに管理することが強く推奨されます。

ユーザ証明書のデプロイは、基本的にはサーバの ID と同じように機能します。詳細と方法については Wikibooks:OpenSSH/Cookbook/Certificate-based Authentication で見られます。

証明書のデプロイを自動化する

多くのオープンソースなツールによって、SSH 証明書のデプロイを自動化する方法が提供されています。人気なものとしては例えば以下があります:

ヒントとテクニック

暗号化 SOCKS トンネル

暗号化トンネルは、安全でない様々なワイヤレス接続を使用するノートパソコンユーザにとって非常に有用です。必要なのは SSH サーバーが安全な場所 (家や仕事場など) で動作していることだけです。DynDNS などのダイナミック DNS サービスを利用すれば IP アドレスを覚える必要もありません。

手順 1: 接続の開始

以下のコマンドを実行するだけで接続を開始できます:

$ ssh -TND 4711 user@host

user はユーザー名に、host は SSH サーバーが動作しているホストに置き換えてください。パスワードを入力すると接続が行われます。N フラグはインタラクティブプロンプトを無効化し、D フラグは listen するローカルポートを指定します (ポート番号は何でもかまいません)。T フラグは疑似 tty アロケーションを無効化します。

verbose (-v) フラグを追加することで、接続が成功していることを出力から確認することができます。

手順 2 (やり方 A): ブラウザ (或いはその他のプログラム) の設定

新しく作成した SOCKS トンネルを使用するようにウェブブラウザ (や他のプログラム) を設定しないと上記の作業は無意味です。SSH は現在 SOCKS v4 と SOCKS v5 の両方をサポートしているため、使用するのはどちらでも構いません。

  • Firefox の場合: 設定 > 一般 を開き、ページ下部に移動し、ネットワーク設定の右にある 接続設定... をクリックしてください。次に、セミウィンドウ内で、手動でプロキシを設定する オプションにチェックを入れ、SOCKS ホスト テキストフィールドに localhost と入力し、ポート テキストフィールドには SSH のポート番号 (上記の例では 4711) を入力してください。
Firefox は自動的に SOCKS トンネルを介して DNS リクエストを行いません。この潜在的なプライバシーの問題は、インターネット接続の設定画面を更にスクロールし、SOCKS v5 を使用するときは DNS もプロキシーを使用する にチェックを入れることで、軽減することができます。明らかに、この方法は SOCKS v4 ではなく SOCKS v5 を選んだ場合にしか適用できません。
これらの設定をアクティブ化するために Firefox を再起動してください。
  • Chromium の場合: SOCKS の設定を環境変数かコマンドラインオプションとして設定できます。以下の関数のうち1つを .bashrc に追加することをおすすめします:
function secure_chromium {
    port=4711
    export SOCKS_SERVER=localhost:$port
    export SOCKS_VERSION=5
    chromium &
    exit
}

あるいは

function secure_chromium {
    port=4711
    chromium --proxy-server="socks://localhost:$port" &
    exit
}

そして、ターミナルを開いて、以下を実行してください:

$ secure_chromium

セキュアトンネルを楽しみましょう!

手順 2 (やり方 B): ローカルの TUN インターフェイスをセットアップする

このやり方は若干複雑ですが、SOCKS プロキシを使用するためにアプリケーションを1つずつ手動で設定する必要が無くなります。この方法には、ローカル TUN インターフェイスのセットアップと、そのインターフェイスを介したトラフィックのルーティングが含まれます。

VPN over SSH#badvpn とトンネルインターフェイスをセットアップする を見てください。

X11 フォワーディング

X11 フォワーディングは、リモートシステムで X11 プログラムを動作させて、グラフィカルインターフェイスをローカルのクライアントマシンで表示させるメカニズムです。X11 フォワーディングではリモートホストに X11 システムを完全にインストールさせる必要はなく、xauth をインストールするだけで十分です。xauth は、X11 セッションの認証を行うために必要なサーバーとクライアントによって使用される Xauthority の設定を管理するユーティリティです (ソース)。

警告: X11 フォワーディングにはセキュリティ的に重要な問題があります。sshsshd_config、そして ssh_config のマニュアルページの該当するセクションを読んで最低限の知識をつけてください。この StackExchange の質問 も参照。

セットアップ

リモート側
  • xorg-xauth パッケージをインストールしてください
  • /etc/ssh/sshd_config 内で:
    • X11Forwardingyes に設定してください
    • AllowTcpForwardingX11UseLocalhost オプションが yes に設定されおり、X11DisplayOffset10 に設定されていることを確認してください (これらの設定は、何も変更していなければ、デフォルト値です。sshd_config(5) を参照)。
  • そして、sshd デーモンを再起動してください。
クライアント側
  • xorg-xauth パッケージをインストールしてください。
  • コマンドラインで日和見的な接続を行うための -X スイッチを指定するか、或いはクライアントの設定ForwardX11yes に設定して、ForwardX11 オプションを有効化してください。
ヒント: GUI の描画がおかしい場合やエラーが表示されるときは ForwardX11Trusted オプションを有効にできます (コマンドラインでは -Y スイッチ)。X11 フォワーディングが X11 SECURITY 拡張 の制御から外れるようになります。使用するときはセクション冒頭の警告を読んでください。

使用方法

通常通りリモートマシンにログオンしてください。クライアントの設定ファイルで ForwardX11 が有効化されていない場合は -X スイッチを指定してください:

$ ssh -X user@host

グラフィカルアプリケーションを実行しようとしてエラーが発生する場合は、代わりに ForwardX11Trusted を試してください:

$ ssh -Y user@host

X11 forwarding request failed と出力される場合、リモートマシンでセットアップをやり直してください。X11 フォワーディングのリクエストが成功したら、リモートサーバ上の任意の X プログラムを実行でき、プログラムがローカルセッションにフォワーディングされます:

$ xclock

Can't open display という内容が含まれるエラーが出力される場合は、DISPLAY が適切に設定されていないことを意味します。

一部のアプリケーションは、実行中のインスタンスのチェックをローカルのマシンで行うため、注意してください。Firefox がその例です: すでに実行中の Firefox を閉じるか、以下の起動パラメータを使用してリモートインスタンスをローカルマシン上で起動してください:

$ firefox --no-remote

接続時に "X11 forwarding request failed on channel 0" と表示される場合 (サーバーの /var/log/errors.log に "Failed to allocate internet-domain X11 display socket" と出力される場合)、xorg-xauth パッケージがインストールされていることを確認してください。上手く機能しない場合、以下の設定を試してみてください:

  • サーバsshd_configAddressFamily any オプションを有効にする。
  • 或いは、サーバsshd_configAddressFamily オプションを inet に設定する。

IPv4 で Ubuntu クライアントを使っている場合は inet に設定することで問題が解決する場合があります。

SSH サーバーの他のユーザーで X アプリケーションを実行するには SSH でログインしているユーザーの xauth list の認証行を xauth add する必要があります。

ヒント: X11 Forwarding の問題をトラブルシューティングする有用なリンクをいくつか挙げます: [2][3][4]

他のポートのフォワーディング

SSH の X11 の組み込みサポートに加えて、SSH には任意の TCP 接続をセキュアにトンネル化することもできます。ローカルフォワーディングとリモートフォワーディングの両方が使えます。

ローカルフォワーディングはローカルマシンのポートを開き、ローカルマシンに対する接続はリモートホストにフォワーディングされ、リモートホストから指定された宛先に転送されます。転送先をリモートホストと同じにすることで、同一マシンに対してセキュアシェルやセキュアな VNC 接続を提供します。ローカルフォワーディングは -L スイッチで利用することができ <トンネルポート>:<宛先アドレス>:<宛先ポート> という形式で転送先を指定します。

ゆえに:

$ ssh -L 1000:mail.google.com:25 192.168.0.100

上記のコマンドは SSH で 192.168.0.100 にログインしてシェルを開き、ローカルマシンの TCP ポート 1000 から mail.google.com のポート 25 へのトンネルが作成されます。接続が確立すると localhost:1000 への通信は Gmail の SMTP ポートに接続されます。Google から見ると、192.168.0.100 から接続が来ているように見えます (必ずしも接続と一緒にデータが運ばれるとは限りません)。データはローカルマシンと 192.168.0.100 との間でセキュアに運ばれますが、192.168.0.100 と Google との間はセキュアではありません (他の方法を取らない限り)。

似たように:

$ ssh -L 2000:192.168.0.100:6001 192.168.0.100

このコマンドは、localhost:2000 に接続することができ、リモートホストのポート 6001 へ透過的に送信されます。前者の例は、vncserver ユーティリティ (tightvnc パッケージの一部) を使用して VNC 接続を行う際に便利です。便利とはいえ、セキュリティの問題があります。

リモートフォワーディングは SSH トンネルとローカルマシンを通してリモートホストから任意のホストに接続できるようにします。ローカルフォワーディングとは逆の機能であり、ファイアウォールによってリモートホストの接続が限られている場合などに有用です。リモートフォワーディングは -R スイッチで使うことができ <トンネルポート>:<宛先アドレス>:<宛先ポート> という形式で転送先を指定します。

ゆえに:

$ ssh -R 3000:irc.libera.chat:6667 192.168.0.200

上記のコマンドは 192.168.0.200 にシェルを立ち上げて、192.168.0.200 からローカルホストの 3000 番ポートへの接続をトンネルを通して送信し、それから irc.freenode.net のポート 6667 に転送します。ポート 6667 がブロックされている場合でもリモートホストから IRC プログラムを利用することができるようになります。

ローカルフォワーディングとリモートフォワーディングはどちらもセキュアなゲートウェイとして使用することができます。<tunnel address>:<tunnel port>:<destination address>:<destination port> のようにバインドアドレスをつかうことで、SSH や SSH デーモンを動かしていなくても他のコンピュータが SSH トンネルを利用することが可能です。<tunnel address> はトンネルの入り口となるマシンのアドレスです: localhost, * (あるいは空)。特定のアドレス経由の接続、ループバックインターフェイス経由の接続、全てのインターフェイス経由の接続を許可します。デフォルトでは、フォワーディングはトンネルの入り口のマシンからの接続だけに制限されており <tunnel address>localhost に設定されています。ローカルフォワーディングは特に設定が必要ありませんが、リモートフォワーディングはリモートサーバーの SSH デーモンの設定によって制限を受けます。詳しくは sshd_config(5)GatewayPorts オプションを見てください。

踏み台ホスト

場合によっては、接続先の SSH デーモンに直接接続できず、踏み台サーバー (ジャンプサーバー) を使わざるを得ないことがあります。2つ以上の SSH トンネルを接続して、それぞれのサーバーに対してローカルの鍵で認証します。SSH エージェントの転送 (-A) と疑似端末の割当 (-t) を使って以下のようにローカルの鍵を転送します:

$ ssh -A -t -l user1 bastion1 \
  ssh -A -t -l user2 intermediate2 \
  ssh -A -t -l user3 target

ProxyCommand オプションを使えばこれを自動化することができます:

$ ssh -o ProxyCommand="ssh -W %h:%p bastion.example.org" targetserver.example.org

-J フラグで ProxyJump オプションを使用すれば、これをより簡単かつセキュアに行うことができます:

$ ssh -J user1@bastion1,user2@intermediate2 user3@target

-J ディレクティブで指定するホストはカンマで区切り、指定された順番で接続されます。user...@ の部分は必須ではありません。-J で指定したホストは ssh の設定ファイルを使うため、必要であればホスト毎にオプションを設定することが可能です。

ProxyCommand オプションと ProxyJump オプションの主な違いは、後者は踏み台ホスト上のシェルを必要としないところにあります。その結果、ユーザのログイン認証情報への踏み台サーバでのアクセスや SSH エージェントフォワーディングが必要なくなります。ProxyJump オプションでは、ssh クライアントは踏み台サーバを通して直接ターゲットのサーバへ接続し、エンドツーエンドの暗号化されたチャネルをクライアントとターゲットサーバとの間で確立します。

設定ファイルにも、-J フラグと等価なものとして ProxyJump オプションがあります。詳細は ssh_config(5) を見てください。

リレーを介したリバース SSH

アイデアとしては、クライアントは別のリレーを使ってサーバに接続し、サーバはリバース SSH トンネルを使って同じリレーに接続します。これは、サーバが NAT 内にあり、リレーが、ユーザがアクセス可能なプロキシとして使用されている、パブリックにアクセス可能な SSH サーバである場合に便利です。ゆえに、クライアントの鍵がリレーとサーバの両方に対して認可されていることが前提条件であり、サーバはリレーに対してもリバース SSH 接続に対しても認可されている必要があります。

以下の設定例では、user1 が client 上で使用されているユーザアカウントであり、user2 は relay 上のアカウント、user3 が server 上のアカウントであるとします。まず、以下のコマンドでサーバとリバーストンネルとの接続が確立している必要があります:

ssh -R 2222:localhost:22 -N user2@relay

これは、スタートアップスクリプトや systemd サービス、autossh を使って自動化することもできます。

クライアント側では、以下のコマンドで接続を確立させます:

ssh -t user2@relay ssh user3@localhost -p 2222

リバーストンネルとの接続を確立させるためのリモートのコマンドは、relay の ~/.ssh/authorized_keys に以下のような command フィールドを含めることで、定義できます:

command="ssh user3@localhost -p 2222" ssh-rsa KEY2 user1@client

この場合、接続は以下のコマンドで確立できます:

ssh user2@relay

注意点として、client の SCP の自動補完関数は機能せず、SCP 転送自体も特定の構成においては機能しません。

マルチプレクス

SSH デーモンは通常はポート 22 番をリッスンします。しかし、公共のインターネット・ホットスポットでは通常の HTTP/HTTPS のポート(80 と 443)以外のトラフィックをブロックしていることが一般的です。そのため SSH 接続がブロックされてしまいます。すぐできる解決策として、sshd に許可されているポートをリッスンさせるという方法があります:

/etc/ssh/sshd_config
Port 22
Port 443

しかしポート 443 番は HTTPS コンテンツを提供する Web サーバによってすでに使われていることが多いです。その場合は sslh のようなマルチプレクサを使います。これは複数のポートをリッスンし、そこに来るパケットを複数のサービスに賢く振り分けることができます。

SSH の高速化

接続をグローバル及び特定のホストに対して高速化させることのできるクライアント設定がいくつかあります。これらのオプションに関する完全な説明は ssh_config(5) を参照してください。

  • より高速な暗号を使う: AESNI 命令セットを持つ最近の CPU では、aes128-gcm@openssh.comaes256-gcm@openssh.com を使うことで openssh のデフォルトの優先暗号 (通常 chacha20-poly1305@openssh.com) よりも劇的に優れたパフォーマンスを得られるはずです。暗号は -c フラグで選択できます。永続的に設定するには、~/.ssh/config 内に Ciphers オプションを追加し、暗号を優先順に並べて設定してください (例:
    Ciphers aes128-gcm@openssh.com,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
    )。
  • 圧縮を有効化あるいは無効化する: 圧縮は低速な接続において速度を向上させることができます。Compression yes オプションか -C フラグで有効化できます。しかし、使用される圧縮アルゴリズムは比較的低速な gzip(1) であり、高速なネットワークにおいてはボトルネックになってしまいます。接続を高速化させるために、ローカルネットワークや高速なネットワークにおいては Compression no を使うべきでしょう。
  • 接続共有: 以下のオプションを使用することで、同一ホストに対するセッションをすべて単一の接続に共有させることができます:
    ControlMaster auto
    ControlPersist yes
    ControlPath ~/.ssh/sockets/socket-%r@%h:%p
    
~/.ssh/sockets の部分は、他のユーザによって書き込むことができないのであれば、どのディレクトリでも構いません。
  • ControlPersist は、初回のクライアント接続が閉じられてから、新しいクライアントのためにマスターがどれくらいバックグラウンドで待機すべきかを指定します。利用可能な値は:
    • no: 最後のクライアントが切断されたらすぐに接続を閉じます。
    • 秒単位の時間
    • yes: 永遠に待ちます。接続は自動的に閉じられなくなります。
  • AddressFamily inet オプションか -4 フラグを使用して IPv6 ルックアップをバイパスすることで、ログインに要する時間を短くすることができます。
  • 最後に、SSH を SFTP や SCP のために使用するつもりであれば、High Performance SSH/SCP は、SSH バッファサイズを動的に大きくすることで、スループットを劇的に増やすことができます。この改善のパッチが施されたバージョンの OpenSSH である openssh-hpn-gitAUR パッケージをインストールしてください。

SSHFS でリモートファイルシステムをマウントする

sshfs を使って (SSH でアクセスした) リモートのファイルシステムをローカルフォルダにマウントする方法は SSHFS の記事を参照してください。マウントしたファイルは様々なツールであらゆる操作することができます (コピー、名前の変更、vim で編集など)。基本的に shfs よりも sshfs を使用することを推奨します。sshfsshfs の新しいバージョンであり、元の shfs は2004年から更新されていません。

キープアライブ

デフォルトでは、SSH セッションが一定時間アイドルであった場合、自動的にログアウトします。一定時間データが受信されなかった場合にサーバにキープアライブシグナルを送信することで、セッションを開いたままにすることができます。あるいは対照的に、クライアントからデータが送られてこない場合にサーバが定期的にメッセージを送信することもできます。

  • サーバ側: ClientAliveInterval はタイムアウトを秒単位で設定します。クライアントからデータが受信されずにその時間経過すると、sshd が応答を促すリクエストを送信します。デフォルトは0であり、メッセージは送信されません。例えば、60秒毎にクライアントに対して応答を要求するには、サーバ側の設定ClientAliveInterval 60 オプションを設定してください。ClientAliveCountMaxTCPKeepAlive オプションも参照してください。
  • クライアント側: ServerAliveInterval は、クライアントからサーバに向けて送信されるリクエストの時間間隔を設定します。例えば、120秒毎にサーバに対して応答を要求するには、クライアント側の設定ServerAliveInterval 120 オプションを追加してください。ServerAliveCountMaxTCPKeepAlive オプションも参照してください。
ノート: セッションを開いたままにするためにキープアライブリクエストを送信する必要があるのは、クライアントかサーバの一方のみです。サーバとクライアントの両方を制御できるならば、セッションを永続的にする必要のあるクライアントに対してのみ ServerAliveInterval を正の値に設定し、その他のクライアントやサーバはデフォルトの設定するのが妥当な選択です。

systemd で SSH トンネルを自動的に再起動

systemd を使ってブート時/ログイン時に SSH 接続を自動的に開始して、さらに接続が失敗した時に再起動させることができます。SSH トンネルの管理に役立つツールとなります。

以下のサービスでは、ssh の設定に保存された接続設定を使って、ログイン時に SSH トンネルを開始します。接続が何らかの理由で閉じられた場合、10秒待機してから再起動します:

~/.config/systemd/user/tunnel.service
[Unit]
Description=SSH tunnel to myserver

[Service]
Type=simple
Restart=always
RestartSec=10
ExecStart=/usr/bin/ssh -F %h/.ssh/config -N myserver

上記の systemd/ユーザーサービスを有効化して起動してください。トンネルがタイムアウトするのを防ぐ方法は #キープアライブ を見て下さい。起動時にトンネルを開始したい場合、ユニットをシステムサービスとして書きなおして下さい

Autossh - SSH セッションとトンネルの自動再起動

ネットワークの状態が悪かったりしてクライアントが切断してしまい、セッションやトンネルの接続を維持できない場合、autossh を使って自動的にセッションとトンネルを再起動できます。

使用例:

$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" username@example.com

SSHFS と組み合わせる:

$ sshfs -o reconnect,compression=yes,transform_symlinks,ServerAliveInterval=45,ServerAliveCountMax=2,ssh_command='autossh -M 0' username@example.com: /mnt/example 

プロキシ設定で設定した SOCKS プロキシを使って接続:

$ autossh -M 0 -o "ServerAliveInterval 45" -o "ServerAliveCountMax 2" -NCD 8080 username@example.com 

-f オプションで autossh をバックグラウンドプロセスとして実行することができます。ただし対話式でパスフレーズを入力することができなくなります。

セッション中に exit と入力したり autossh プロセスに SIGTERM、SIGINT、SIGKILL シグナルが送られるとセッションは終了します。

systemd を使ってブート時に自動的に autossh を起動する

autossh を自動的に起動したい場合、以下の systemd ユニットファイルを作成します:

/etc/systemd/system/autossh.service
[Unit]
Description=AutoSSH service for port 2222
After=network.target

[Service]
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -NL 2222:localhost:2222 -o TCPKeepAlive=yes foo@bar.com

[Install]
WantedBy=multi-user.target

AUTOSSH_GATETIME=0 は接続が成功して ssh が立ち上がったと autossh が認識する秒数です。0に設定すると autossh は ssh の最初の起動失敗を無視します。起動時に autossh を実行する場合は設定するべきです。他の環境変数は man ページを見てください。必要であればもっと複雑に設定することもできますが、AUTOSSH_GATETIME=0 を含む -f は systemd では機能しません。

設定後はサービスを起動有効化してください。

以下のように ControlMaster を無効化する必要もあるかもしれません:

ExecStart=/usr/bin/autossh -M 0 -o ControlMaster=no -NL 2222:localhost:2222 -o TCPKeepAlive=yes foo@bar.com
ヒント: 複数のautosshプロセスを維持し、複数のトンネルを存続させることも簡単です。名前の異なる複数のサービスファイルを作成するだけです。

SSH デーモンが失敗した場合の代替サービス

SSH のみに依存するリモート或いはヘッドレスのサーバにおいて、(システムアップグレード後などに) SSH デーモンの起動に失敗すると、管理アクセスできなくなってしまう場合があります。systemd は、OnFailure によるシンプルなソリューションを提供しています。

サーバ上で sshd が実行されていて、telnet がフェイルセーフであるとしてます。以下のようにファイルを作成してください。ただし、telnet.socket有効化しないでください!

/etc/systemd/system/sshd.service.d/override.conf
[Unit]
OnFailure=telnet.socket

これだけです。sshd が実行中である場合、Telnet は実行されません。sshd が起動に失敗した場合、telnet セッションがリカバリとして開かれます。

ホストに基づいてターミナル背景色を設定する

異なるホストに接続していることを簡単に判別できるようにするために、ホストの種類に応じて異なる背景色を設定することができます。

このソリューションは一般には適用できません (ZSH 限定)。

ネットワーク固有の設定

Match exec を使うことで、接続先のネットワークに固有のホスト設定を使用することができます。

例えば、nmcli(1) を使用していて、接続が検索ドメインを使用するように (手動、あるいは DHCP で) 設定されている場合:

Match exec "nmcli | grep domains: | grep example.com"
  CanonicalDomains example.com
  # Should you use a different username on this network
  #User username
  # Use a different known_hosts file (for private network or synchronisation)
  #UserKnownHostsFile <network>_known_hosts

Match host ... exec "..." の例: VPN に接続していない限り、internal.example.com への接続に (ProxyJump を用いた) 踏み台/プロキシが必要であるとしましょう。フラグメント !exec "host internal.example.com" は、internal.example.com が DNS を介して見つけられない場合にのみ、適用されます。様々な代替案が [5] で議論されています。

Match host internal.example.com !exec "host internal.example.com"
  ProxyJump bastion.example.com
Host internal.example.com
  User foobar

プライベートネットワークのホスト鍵検証

あるネットワーク上のサーバとそれとは別のネットワーク上のサーバは、互いに同じプライベート IP アドレスを持つ可能性があるため、それらのサーバは異なる方法で処理する必要があるかもしれません。

この記事またはセクションの正確性には問題があります。
理由: 「最適な」ソリューションに、本番環境では別のものを使うべきという警告があるはずがない。 (議論: トーク:OpenSSH#)

最適なソリューションは、#ネットワーク固有の設定 を使用し、接続しているネットワークに応じて異なる UserKnownHostsFile を使うことです。2つめのソリューションは、プライベートネットワークのホスト鍵を単に無視することです (新しい/プロトタイプのネットワークで作業する際にデフォルトで使用するのが最適です):

Host 10.* 192.168.*.* 172.31.* 172.30.* 172.2?.* 172.1?.*
    # Disable HostKey verification
    # Trust HostKey automatically
    StrictHostKeyChecking no
    # Do not save the HostKey
    UserKnownHostsFile=/dev/null
    # Do not display: "Warning: Permanently Added ..."
    LogLevel Error
この記事またはセクションの正確性には問題があります。
理由: known_hosts ファイルは、サーバにアクセスするためにホスト名を使用したとしても、IP アドレスを記録します。 (議論: トーク:OpenSSH#)
警告: 本番環境では、ホスト名を使用してホストにアクセスしたり、ネットワーク固有の known_hosts ファイルを使用するようにしてください。

ログイン時にコマンドを実行

インタラクティブセッションを使用している場合、ログイン時にコマンドを実行する方法は複数存在します:

  • リモートホスト上の authorized_keys ファイルを使用する (sshd(8)AUTHORIZED_KEYS FILE FORMAT セクションを参照)
  • サーバで PermitUserRC オプションが有効化されている場合、リモートホスト上の ~/.ssh/rc を使用する
  • リモートホスト上のシェル設定ファイルを使用する (例: .bashrc)

エージェントフォワーディング

SSH エージェントのフォワーディングにより、サーバに接続している状態でローカルの鍵を使用することができます。選択したホストのみに対してエージェントフォワーディングを許可することが推奨されます。

~/.ssh/config
Host myserver.com
    ForwardAgent yes

次に、SSH エージェントを構成し、ssh-add を使ってローカル鍵を追加してください。

これで、リモートサーバに接続する場合、あなたのローカル鍵を使用して他のサービスに接続できるようになりました。

新しい鍵の生成

新しいサーバの秘密鍵は以下で生成できます:

  1. すべての鍵を削除する。例えば:
    # rm /etc/ssh/ssh_host_*_key*
  2. sshdgenkeys.service再起動するか、ssh-keygen -A を root として実行する。

sshd を非特権ユーザとして実行

sshd をコンテナ内で (或いはテスト目的などで) 非特権ユーザとして実行したい場合もあるでしょう。

非特権ユーザは /etc/ssh 内のホスト鍵を読むことができないため、新しいホスト鍵を生成しなければなりません:

$ ssh-keygen -q -N "" -t rsa -b 4096 -f /path/to/host/keys/ssh_host_rsa_key
$ ssh-keygen -q -N "" -t ecdsa -f /path/to/host/keys/ssh_host_ecdsa_key
$ ssh-keygen -q -N "" -t ed25519 -f /path/to/host/keys/ssh_host_ed25519_key

sshd_config を作成してください。以下の例では、1024 より大きい値のポート番号を使用し、ホスト鍵への新しいパスを提供し、PAM を無効化します:

/path/to/sshd_config
Port 2022
HostKey /path/to/host/keys/ssh_host_rsa_key
HostKey /path/to/host/keys/ssh_host_ecdsa_key
HostKey /path/to/host/keys/ssh/ssh_host_ed25519_key
UsePAM no

新しく作成した設定で sshd を実行します。-D フラグはデーモンモードを無効化し、-e は出力を標準エラー出力にリダイレクトしてモニタしやすくします:

$ sshd -f /path/to/sshd_config -D -e

トラブルシューティング

チェックリスト

まずは以下の単純な問題をチェックしましょう。

  1. 設定ディレクトリ ~/.ssh のコンテンツが対象ユーザによってのみアクセス可能である必要があります (クライアントとサーバの両方で確認してください)。かつ、対象ユーザのホームディレクトリがそのユーザによってのみ書き込み可能である必要があります:
    $ chmod go-w ~
    $ chmod 700 ~/.ssh
    $ chmod 600 ~/.ssh/*
    $ chown -R $USER ~/.ssh
    
  2. クライアントの公開鍵 (例: id_rsa.pub) がサーバ上の ~/.ssh/authorized_keys 内に記述されていることを確認する。
  3. サーバの設定AllowUsersAllowGroups によって SSH のアクセスが制限されていないことを確認する。
  4. ユーザがパスワードを設定しているかを確認する。サーバにログインしたことのない新しいユーザは、パスワードを持っていないことがあります。
  5. /etc/ssh/sshd_configLogLevel DEBUG追加してみる。
  6. journalctl -xe を root として実行して、(エラー) メッセージの取得を試みる。
  7. sshd再起動し、クライアントとサーバの両方でログアウト/ログインする。

接続の拒否やタイムアウトの問題

ポートフォワーディング

NAT モードやルータを使っている場合 (VPS を使っていたりパブリックにアドレッシングされたホストを使用していない限り、あり得ます)、ルータが ssh の着信接続をマシンにフォワーディングしていることを確認してください。$ ip addr を使ってサーバの内部 IP アドレスを見つけ、SSH ポートの TCP 接続をその IP にフォワーディングするようにルータを設定してください。portforward.com が役に立ちます。

SSH が動作していて、リッスンしているか?

ss ユーティリティは、以下のコマンドラインを使うことで、TCP ポートをリッスンしている全プロセスを表示します:

$ ss --tcp --listening

このコマンドの出力を見て、システムが ssh ポートをリッスンしていないことが判明した場合、SSH が実行されていないことを意味します。Journal でエラーなどが出力されていないか確認してください。

接続をブロックするようなファイアウォールのルールが存在しないか?

iptables によってポート 22 の接続がブロックされている可能性があります。次のコマンドで確認してください:

# iptables -nvL

INPUT チェインのパケットを拒否するようなルールがないか見て下さい。そして、必要であれば、次のようなコマンドでポートのブロックを解除します:

# iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT

ファイアウォールの設定に関する詳細はファイアウォールを見て下さい。

トラフィックがコンピュータにまで到達しているか?

以下のように問題のコンピュータのトラフィックを収集してみてください:

# tcpdump -lnn -i any port ssh and tcp-syn

上記は基本的な情報を表示します。トラフィックが表示されるまで待ってください。その後、接続を試行してみてください。何も出力がされない場合、コンピュータの外側にある何かがトラフィックを妨害しています (例: ハードウェアファイアウォールや NAT ルーターなど)。

ISP またはサードパーティによってデフォルトのポートがブロックされてないか?

ノート: このステップは次のことを確認した後で実行してください。ファイアーウォールを何も起動していないこと。DMZ へのルーターを正しく設定している、またはコンピュータへポートを転送していること。それでもまだ動かない場合、ここで診断のステップと解決法が見つかるでしょう。

ときどき ISP が SSH のデフォルトポート (22番) をブロックしている場合があります。この場合はあなたが何をしても (ポートを開ける、スタックを強化する、フラッドアタックを防御する、など) 無意味になります。ブロックされているかどうか確認するために、全てのインターフェイス (0.0.0.0) をリッスンするサーバを立ち上げ、リモートから接続してみてください。

このようなエラーメッセージが出る場合:

ssh: connect to host www.inet.hr port 22: Connection refused

これはそのポートが ISP にブロックされていないが、そのポートでサーバーの SSH が起動していないことを意味します (security through obscurity を参照)。

しかし、次のようなエラーメッセージが出る場合:

ssh: connect to host 111.222.333.444 port 22: Operation timed out 

これは何かがポート 22 での TCP トラフィックを拒否していることを意味します。そのポートはあなたのサーバー上のファイアーウォールか第三者 (ISP など) のどちらかによってステルスされています。自分のサーバーでファイアーウォールが起動していないことが確かなら、また、ルーターやスイッチの中でグレムリンが育っていないことが確かなら、ISP がトラフィックをブロックしています。

ダブルチェックのために、サーバ上で Wireshark を起動してポート 22 でのトラフィックをリッスンしてみましょう。Wireshark はレイヤ 2 のパケット・スニファリング・ユーティリティであり、TCP/UDP はレイヤ 3 以上なので (IP ネットワークスタックを参照)、もしリモートから接続するときに何も受け取っていなければ、十中八九、第三者がブロックしています。

問題診断

tcpdump または wireshark-cli パッケージで Wireshark をインストールしてください。

tcpdump の場合:

# tcpdump -ni interface "port 22"

Wireshark の場合:

$ tshark -f "tcp port 22" -i interface

interface は WAN 接続に使っているネットワークインターフェイスに置き換えてください (確認したいときは ip a を実行)。リモートで接続を試行してもパケットが全く受け取れない場合、ISP によってポート 22 のトラフィックがブロックされている可能性があります。

解決方法

解決方法は、単に ISP がブロックしていない他のポートを使うことです。/etc/ssh/sshd_config を編集して他のポートを使うようにしましょう。例えば次を追加します:

Port 22
Port 1234

そしてこのファイル中の他の Port 設定をコメントアウトします。「Port 22」をコメントにして「Port 1234」を追加するだけでは、sshd がポート 1234 しかリッスンしなくなるので、この問題は解決しません。この 2 行どちらも使用し、sshd が両方のポートをリッスンするようにします。

sshd.service サーバを再起動すれば、あともう少しです。次に、デフォルトのポートではなくもう一つのポートを使用するようにクライアントを設定しなければなりません。その問題に対するソリューションは数多く存在しますが、ここではそれらのうち2つを扱っています。

Read from socket failed: connection reset by peer

最近のバージョンの openssh は時々、古い ssh サーバに接続する際に上記のエラーメッセージで失敗することがあります。これは、そのホストに対する様々なクライアントオプションを設定することにより、回避可能です。以下のオプションに関する詳細は ssh_config(5) を見てください。

ecdsa-sha2-nistp*-cert-v01@openssh 楕円曲線ホスト鍵アルゴリズムが原因である可能性があります。このようなアルゴリズムは、HostKeyAlgorithms にそれらのアルゴリズムを除いたリストを設定することにより、無効化できます。

これでうまく行かない場合、暗号のリストが長過ぎる可能性があります。Ciphers オプションのリストを短くしてください (80 文字未満であれば十分でしょう)。同じように、MACs のリストも短くしてみてください。

openssh のバグフォーラムにおける議論も参照してください。

"[シェル]: No such file or directory" / ssh_exchange_identification problem

シェルのバイナリが $PATH に登録されているディレクトリ内にあったとしても、特定の SSH クライアントは $SHELL に絶対パスを設定する必要があります (パスは whereis -b [あなたのシェル] で確認できます)。

"Terminal unknown" や "Error opening terminal" エラーメッセージ

ログイン時に上記のようなエラーが表示される場合、サーバがターミナルを認識できていないことを意味します。また、nano などの ncurses アプリケーションを実行すると "Error opening terminal" というメッセージが表示されることがあります。

クライアントで使用しているターミナルの terminfo ファイルをサーバーにインストールするのが正しい解決方法です。これによってサーバーのコンソールプログラムがターミナルを正しく扱えるようになります。infocmp を実行してからパッケージを確認することで terminfo に関する情報を取得できます。

通常の方法でインストールできない場合、サーバーのホームディレクトリに terminfo をコピーしてください:

$ ssh myserver mkdir -p  ~/.terminfo/${TERM:0:1}
$ scp /usr/share/terminfo/${TERM:0:1}/$TERM myserver:~/.terminfo/${TERM:0:1}/

サーバーから一度ログアウトしてからログインしなおすと問題が解決しているはずです。

TERM ハック

ノート: これは最後の手段にするべきです。

あるいは、TERM=xterm 環境変数をサーバ側で (例えば .bash_profile で) 設定してしまうという方法もあります。これでエラーは出なくなり、ncurses アプリケーションを実行できるようになります。しかし、ターミナルの制御シーケンスが xterm のそれと正確に一致しない限り、奇妙な挙動やグラフィックのバグが発生する場合があります。

Connection closed by x.x.x.x [preauth]

sshd のログでこのエラーが確認できる場合、HostKey が正しく設定されているか確認してください:

HostKey /etc/ssh/ssh_host_rsa_key

サブシステム要求の失敗

OpenSSH 8.8 以降、scp はデータ転送のデフォルトプロトコルとして SFTP を使用し、sftp というサブシステムを要求するようになりました。もし scp を冗長モード scp -v で実行すれば、クライアントがどのサブシステムを使っているかがわかります (例: Sending subsystem: <subsystem-name>)。subsystem request failed on channel 0 のようなエラーは、サーバのサブシステムを設定することで修正できるかもしれません。sshd_config(5) § Subsystem のように設定します。サーバの設定は、以下の例のようにする必要があります:

/etc/ssh/sshd_config
...
Subsystem subsystem-name /path/to/subsystem-executable
...

OpenSSH 7.0 によって id_dsa が拒否される

OpenSSH 7.0 ではセキュリティ上の理由から DSA 公開鍵が非推奨になっています。どうしても有効にする必要がある場合、設定オプション PubkeyAcceptedKeyTypes +ssh-dss を設定してください (https://www.openssh.com/legacy.html はこれには言及していません)。

OpenSSH 7.0 で No matching key exchange method found

OpenSSH 7.0 では、Logjam 攻撃からの理論上の脆弱性を理由に diffie-hellman-group1-sha1 鍵アルゴリズムが非推奨になっています (https://www.openssh.com/legacy.html を参照)。特定のホストで鍵アルゴリズムが必要な場合、ssh は以下のようなエラーメッセージを吐きます:

Unable to negotiate with 127.0.0.1: no matching key exchange method found.
Their offer: diffie-hellman-group1-sha1

古いアルゴリズムを使用しないようにサーバーをアップグレード/設定することで上記のエラーは解決します。サーバー側の設定を変更できない場合、クライアント設定KexAlgorithms +diffie-hellman-group1-sha1 オプションを使うことでアルゴリズムを有効化できます。

SSH から切断したときに tmux/screen セッションがキルされる

セッションの終了時にプロセスがキルされる場合、ソケットアクティベーションを使っているために SSH セッションプロセスが終了したときに systemd によって終了されている可能性があります。ssh.socket の代わりに ssh.service を使用してソケットアクティベーションを使わないことで解決できます。もしくは ssh@.service の Service セクションで KillMode=process を設定してください。

KillMode=process は古典的な ssh.service でも役に立つことがあります。サーバーが停止したり再起動したときに SSH セッションプロセスや screentmux のプロセスが終了されることを防ぐことができます。

SSH セッションが応答しなくなる

SSH は Software flow control XONXOFF に反応します。Ctrl+s を押すとフリーズ/ハングアップ/応答停止します。セッションを再開するには Ctrl+q を使ってください。

Broken pipe

接続を作ろうとして packet_write_wait のレスポンスが Broken pipe になる場合、デバッグモードで接続を再試行し、出力がエラーで終わるかどうか確認する必要があります:

debug3: send packet: type 1
packet_write_wait: Connection to A.B.C.D port 22: Broken pipe

上記の send packet の行は、応答パケットが受信されなかったことを示しています。つまり、これは QoS の問題であることがわかります。パケットを落とす可能性を減らすには、IPQoS を設定してください:

/etc/ssh/ssh_config
Host *
    IPQoS reliability

サービスタイプ reliability (0x04) は、0x00throughput (0x08) と同様に、このコマンドを解決するはずです。

再起動後デーモンの起動が遅い

特にヘッドレスサーバや仮想化サーバにおいて、再起動後のデーモン起動時間が過度に長くなる場合 (例: デーモンが接続を受け付け始めるまでに数分かかる)、エントロピー不足が原因かもしれません。[6] これは、あなたのシステムに適した Rng-toolsHaveged をインストールすれば改善することが可能です。ただし、それぞれのパッケージの wiki ページで説明されている、関連するセキュリティ上の影響に注意してください。

応答のない SSH 接続を終了する

クライアントセッションが応答しなくなり、実行中のプログラム (例えば シェル) に終了を指示しても終了しない場合、Enter~、そして . をこの順番で次々に押すと、セッションを終了させることが可能です。

この ~ は疑似端末エスケープ文字 (ssh(1) § ESCAPE CHARACTERS 参照) であり、終了させるクライアントセッションに応じて複数回付加することが可能です。例えば、A から B へ接続し、B から C へ接続したときに B から C へのセッションがフリーズした場合、Enter を押して ~~. と入力すれば、B の作業セッションを残して B から C へのセッションを終了させることができます。

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!

ssh サーバの鍵が変更されたことをクライアントが警告した場合、新しく提供された鍵が本当にサーバオペレータのものであるかどうかを確認する必要があります。確認したら、known_hosts ファイルから古い鍵を ssh-keygen -R $SSH_HOST で削除し、まるで新しく追加されたサーバであるかのように新しい鍵を追加してください。

適切な terminfo エントリがないリモートに接続する場合

あなたのターミナルの terminfo エントリが無いホストに接続する場合 (例えば、ncurses に同梱されていない terminfo エントリのターミナルを使用している場合) や、terminfo データベースが限られているホストに接続する場合 (例えば、OpenWrt を実行しているシステム)、terminfo(5) に依存しているソフトウェアで様々な問題が発生します。

適切な解決策は、適切な terminfo エントリをホストに設置することです。それが不可能な場合は、リモートホストがサポートし、かつ端末と互換性のある値を TERM に設定することで解決できます。

OpenSSH 8.7 以降、カスタムの TERM 環境変数をリモートホストに渡すには、簡単な設定スニペットを使用してください:

~/.ssh/config
Host example.com
  SetEnv TERM=xterm-256color

踏み台ホストを介する接続が "bash: No such file or directory" で失敗する

(踏み台のサーバで) SHELL 環境変数に有効な完全パスを設定していない場合、以下に似たエラーメッセージで接続は失敗します:

bash: No such file or directory
kex_exchange_identification: Connection closed by remote host
Connection closed by UNKNOWN port 65535

踏み台サーバにおいて有効なシェルの完全パスを SHELL に設定するか、~/.ssh/config で各サーバに対して特定の SHELL を設定することで、この問題を解決できます。

参照

翻訳ステータス: このページは en:OpenSSH の翻訳バージョンです。最後の翻訳日は 2023-06-24 です。もし英語版に 変更 があれば、翻訳の同期を手伝うことができます。