OpenSSH
OpenSSH (OpenBSD 安全 Shell) 是一组计算机程序,它使用 安全 Shell (SSH) 协议,在计算机网络上提供加密的通信会话。它被创建为 SSH Communications Security 提供的专有安全 Shell 软件套件的开源替代品。OpenSSH 是作为 OpenBSD 项目的一部分开发的,该项目由 Theo de Raadt 领导。
OpenSSH 有时会与名称相似的 OpenSSL 混淆;但是,这两个项目有不同的目的,由不同的团队开发,名称相似仅仅是因为目标相似。
安装
客户端使用
要连接到服务器,请运行
$ ssh -p port user@server-address
如果服务器仅允许公钥身份验证,请遵循 SSH 密钥。
配置
可以配置客户端以存储常用选项和主机。所有选项都可以全局声明或限制为特定主机。例如
~/.ssh/config
# global options User user # host-specific options Host myserver Hostname server-address Port port
使用这样的配置,以下命令是等效的
$ 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
选项仅允许某些算法,也会在丢失时重新生成。基于 ed25519、ecdsa 和 rsa 算法提供了三对密钥。要使 sshd 使用特定的密钥,请指定以下选项
HostKey /etc/ssh/ssh_host_ed25519_key
如果要将服务器暴露于 WAN,建议将默认端口从 22 更改为更高的随机端口,例如这样
Port 39901
- 为了帮助选择尚未分配给常用服务的备用端口,请查看 TCP 和 UDP 端口号列表。您还可以在本地
/etc/services
中找到端口信息。从默认端口 22 更改端口将减少由自动身份验证尝试引起的日志条目数量,但不会消除它们。有关相关信息,请参阅 端口敲门。 - 建议完全禁用密码登录。这将大大提高安全性,有关更多信息,请参阅 #强制公钥认证。有关更多建议的安全方法,请参阅 #保护。
- OpenSSH 可以通过在配置文件中包含多行
Port 端口号
来侦听多个端口。 - 可以通过删除要替换的密钥对从
/etc/ssh
中删除,并以 root 身份运行ssh-keygen -A
来生成新的(或丢失的)主机密钥对。
守护进程管理
启动/启用 sshd.service
。它将使 SSH 守护进程永久处于活动状态,并为每个传入连接 fork。
sshd.socket
,因为它容易受到拒绝服务攻击。 有关详细信息,请参阅 FS#62248。 如果在更新到 openssh 8.0p1-3 时启用了 sshd.socket
,则 sshd.socket
和 sshd@.service
单元将被复制到 /etc/systemd/system/
并 重新启用。 这只是为了不破坏现有设置而进行的;仍然建议用户迁移到 sshd.service
。sshd.socket
,请注意其问题sshd.socket
单元可能会失败(例如,由于内存不足的情况),并且无法在套接字单元上指定Restart=always
。 请参阅 systemd 问题 11553。- 使用套接字激活可能会导致拒绝服务,因为过多的连接可能会导致拒绝进一步激活服务。 请参阅 FS#62248。
sshd.socket
会否定 ListenAddress
设置,因此它将允许通过任何地址进行连接。 要实现设置 ListenAddress
的效果,您必须通过 编辑 sshd.socket
来指定 ListenStream
的端口和 IP(例如 ListenStream=192.168.1.100:22
)。 您还必须在 [Socket]
下添加 FreeBind=true
,否则设置 IP 地址将具有与设置 ListenAddress
相同的缺点:如果网络未及时启动,套接字将无法启动。sshd@.service
的瞬态实例(具有不同的实例名称)。 因此,sshd.socket
和守护进程的常规 sshd.service
都不允许监视日志中的连接尝试。 可以通过以 root 身份运行 journalctl -u "sshd@*"
或以 root 身份运行 journalctl /usr/bin/sshd
来查看套接字激活的 SSH 实例的日志。保护
允许通过 SSH 进行远程登录对于管理目的很有用,但可能会对服务器的安全性构成威胁。 SSH 访问通常是暴力破解攻击的目标,需要对其进行适当限制,以防止第三方获得对您服务器的访问权限。
ssh-audit 提供服务器和客户端配置的自动分析。 还有其他一些关于该主题的优秀指南和工具,例如
强制公钥认证
如果客户端无法通过公钥进行身份验证,则默认情况下,SSH 服务器会回退到密码身份验证,从而允许恶意用户尝试通过 暴力破解密码来获得访问权限。 防止此攻击最有效的方法之一是完全禁用密码登录,并强制使用 SSH 密钥。 这可以通过在守护进程配置文件中设置以下选项来实现
/etc/ssh/sshd_config.d/20-force_publickey_auth.conf
PasswordAuthentication no AuthenticationMethods publickey
authorized_keys
文件中设置了公钥身份验证。 有关更多信息,请参阅 SSH 密钥#将公钥复制到远程服务器。双因素认证和公钥
可以将 SSH 设置为需要多种身份验证方式;您可以使用 AuthenticationMethods
选项告诉需要哪些身份验证方法。 这使您可以使用公钥以及双因素授权。
认证提供程序
请参阅 Google Authenticator 以设置 Google Authenticator。
对于 Duo,安装 duo_unixAUR,它将提供 pam_duo.so
模块。 阅读 Duo Unix 文档,以获取有关如何设置必要的 Duo 凭据(集成密钥、密钥、API 主机名)的说明。
PAM 设置
要将 PAM 与 OpenSSH 一起使用,请编辑以下文件
/etc/ssh/sshd_config.d/20-pam.conf
KbdInteractiveAuthentication yes AuthenticationMethods publickey keyboard-interactive:pam
然后,您可以使用公钥或 PAM 设置要求的用户身份验证登录。
另一方面,如果您想同时验证公钥和 PAM 设置要求的用户身份验证,请使用逗号而不是空格来分隔 AuthenticationMethods
/etc/ssh/sshd_config.d/20-pam.conf
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 进行速率限制 或 简单状态防火墙#暴力破解攻击。
自 9.8 以来,实现了一种类似于 fail2ban 的基本保护:选项 PerSourcePenalties
设置为合理的默认值。针对客户端在其源地址上强制执行各种条件的惩罚,从而导致在一段时间内拒绝连接。
或者,您可以使用自动化脚本来保护自己免受暴力破解攻击,该脚本会阻止任何试图暴力破解进入的人。
- 仅允许来自受信任位置的传入 SSH 连接
- 使用 fail2ban 或 sshguard 自动阻止密码验证失败次数过多的 IP 地址。
- 使用 pam_shield 阻止在一定时间内执行过多登录尝试的 IP 地址。与 fail2ban 或 sshguard 相比,此程序不考虑登录成功或失败。
限制 root 登录
通常认为允许 root 用户不受限制地通过 SSH 登录是不好的做法。有两种方法可以限制 SSH root 访问权限以提高安全性。
拒绝
Sudo 有选择地为需要 root 权限的操作提供 root 权限,而无需针对 root 帐户进行身份验证。这允许锁定 root 帐户,以防止通过 SSH 访问,并可能充当针对暴力破解攻击的安全措施,因为现在攻击者除了密码之外还必须猜测帐户名。
可以通过编辑守护进程配置文件中的“身份验证”部分来配置 SSH 以拒绝使用 root 用户进行远程登录。只需将 PermitRootLogin
设置为 no
/etc/ssh/sshd_config.d/20-deny_root.conf
PermitRootLogin no
接下来,重启 SSH 守护进程。
现在您将无法通过 root 用户通过 SSH 登录,但仍然可以使用您的普通用户登录并使用 su 或 sudo 进行系统管理。
限制
某些自动化任务(例如远程全系统备份)需要完全 root 访问权限。为了以安全的方式允许这些操作,可以仅允许为选定的命令进行 root 登录,而不是禁用通过 SSH 进行 root 登录。这可以通过编辑 ~root/.ssh/authorized_keys
来实现,方法是在所需的密钥前加上前缀,例如,如下所示
command="rrsync -ro /" ssh-ed25519 ...
这将允许使用此特定密钥进行的任何登录仅执行引号之间指定的命令。
可以通过将以下内容添加到 sshd_config
来补偿在登录时暴露 root 用户名而增加的攻击面
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
中删除不可变位并使其暂时可写。
authorized_keys
文件的更改。SSH 证书
虽然常见的 SSH 密钥和手动指纹验证可能很容易用于由单个管理员管理的一些主机,但是这种身份验证方法根本无法扩展。当多个用户需要通过 SSH 访问大量服务器时,手动验证每个主机的 ssh 公钥指纹几乎不可能安全可靠地完成。
此问题的解决方案是使用 SSH 证书,该证书通过信任链提供公钥身份的自动验证,该信任链比 SSH 的默认首次使用时信任方法扩展性更好。SSH 证书基本上只是普通的公共 SSH 密钥,但带有来自受信任证书颁发机构的额外签名,用于验证密钥身份。
为您的基础设施创建主机证书颁发机构密钥
$ ssh-keygen -t ed25519 -f ~/.ssh/ca_host_key -C 'Host certificate authority for *.example.com'
私有证书颁发机构密钥应安全存储,最好存储在智能卡或硬件令牌上,以防止密钥提取,例如 Nitrokey 或 YubiKey。
签署服务器的公共 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.d/20-ed25519_key.conf
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 用户的组织,强烈建议使用证书来安全地管理用户密钥部署。
用户证书的部署基本上与服务器身份的部署相同。更多详细信息和说明可以在 Wikibooks:OpenSSH/Cookbook/基于证书的身份验证 中找到。
证书部署自动化
许多开源工具可以提供 SSH 证书的自动化部署。流行的例子有
SSHFP 记录
安全 Shell 指纹记录 (SSHFP) 是域名系统中的可选资源记录,它将 SSH 密钥与主机名关联。它可以通过使用 DNSSEC 而不是部署受信任的 CA 证书来验证公共服务器上的 SSH 指纹,这允许即使是未经管理的客户端也可以验证密钥指纹的有效性。
生成记录条目
要生成存储在 DNS 记录中所需的十六进制密钥指纹,请在目标服务器上创建哈希。
$ ssh-keygen -r host.example.com
这将读取指定域的所有可用 SSH 密钥,并输出有效的 SSHFP 记录,然后可以将其存储在受影响域的 DNS 条目中。
客户端配置
为了自动检索和信任存储为 SSHFP 记录的 SSH 密钥指纹,请将以下内容添加到您的 ssh 客户端配置文件中
~/.ssh/config
# global options Match all VerifyHostKeyDNS yes
如果目标主机具有有效的 SSHFP 记录,并且该记录已通过有效的 DNSSEC 签名验证,则指纹将自动被接受,而无需提示用户验证主机身份。如果 DNS 记录未通过 DNSSEC 验证,则会提示用户验证指纹。
生成 SSHFP 记录
要确定特定域的 SSH 指纹,请使用 ssh-keyscan 以有效的 DNS 记录格式检索 ssh 指纹。(请注意,默认情况下,每种可用密钥类型的指纹都以 SHA1 和 SHA256 形式提供。)
$ ssh-keyscan -D github.com
; github.com:22 SSH-2.0-babeld-57ca1323 ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 1 1 6f4c60375018bae0918e37d9162bc15ba40e6365 github.com IN SSHFP 1 2 b8d895ced92c0ac0e171cd2ef5ef01ba3417554a4a6480d331ccc2be3ded0f6b ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 3 1 3358ab5dd3e306c461c840f7487e93b697e30600 github.com IN SSHFP 3 2 a764003173480b54c96167883adb6b55cf7cfd1d415055aedff2e2c8a8147d03 ; github.com:22 SSH-2.0-babeld-57ca1323 github.com IN SSHFP 4 1 e9619e2ed56c2f2a71729db80bacc2ce9ccce8d4 github.com IN SSHFP 4 2 f83898df0bef57a4ee24985ba598ac17fccb0c0d333cc4af1dd92be14bc23aa5 ; github.com:22 SSH-2.0-babeld-57ca1323
由于 SSHFP 记录将密钥指纹存储为十六进制值,而 SSH 指纹的常见输出是公钥的 base64 编码 SHA256 哈希,因此有必要将记录转换回 base64 格式,以便将其与 known_hosts 文件或其他常用 SHA256 格式存储指纹的文档中的值进行比较。
$ echo "SSHFP-fingerprint" | xxd -r -p | base64
github.com 的示例,使用密钥类型 ed25519 的 sha256 指纹的十六进制值
$ echo "f83898df0bef57a4ee24985ba598ac17fccb0c0d333cc4af1dd92be14bc23aa5" | xxd -r -p | base64
+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU=
与 known_hosts 条目比较
$ ssh-keygen -l -f ~/.ssh/known_hosts
从 DNS 手动检索 SSHFP 记录
$ dig SSHFP targetdomain.tld +short
技巧与诀窍
加密 SOCKS 隧道
这对于连接到各种不安全无线连接的笔记本电脑用户非常有用。您唯一需要的是在某个安全位置(例如您的家或工作场所)运行的 SSH 服务器。使用像 DynDNS 这样的动态 DNS 服务可能很有用,这样您就不必记住您的 IP 地址。
步骤 1:启动连接
您只需执行此单个命令即可启动连接
$ ssh -TND 4711 user@host
其中 user
是您在 host
上运行的 SSH 服务器上的用户名。它会要求您输入密码,然后您就连接上了。N
标志禁用交互式提示,D
标志指定本地端口以进行侦听(您可以根据需要选择任何端口号)。T
标志禁用伪 tty 分配。
添加 verbose (-v
) 标志很好,因为这样您就可以从该输出中验证它是否真的已连接。
步骤 2(变体 A):配置您的浏览器(或其他程序)
上述步骤仅在与使用此新创建的 SOCKS 隧道的 Web 浏览器或其他程序结合使用时才有用。由于 SSH 当前同时支持 SOCKS v4 和 SOCKS v5,因此您可以使用其中任何一种。
- 对于 Firefox:在偏好设置 > 常规中,导航到页面底部,然后点击设置...,它位于网络设置标题的右侧。接下来,在新弹出的半窗口中,勾选手动代理配置选项,并在SOCKS 主机文本字段中输入
localhost
,以及在旁边的端口文本字段中输入端口号(在上面的示例中为4711
)。
- Firefox 不会自动通过 socks 隧道发出 DNS 请求。可以通过进一步向下滚动,勾选使用 SOCKS v5 时代理 DNS 来缓解这种潜在的隐私问题。显然,这仅在使用 SOCKS v5 而不是 v4 时才有效。
- 重启 Firefox 以激活这些设置。
- 对于 Chromium:您可以将 SOCKS 设置设置为环境变量或命令行选项。例如,将以下函数之一添加到您的
.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://127.0.0.1:$port" & exit }
现在打开终端并执行
$ secure_chromium
享受您的安全隧道吧!
步骤 2(变体 B):设置本地 TUN 接口
此变体前期稍微复杂一些,但最终您不必手动为每个应用程序逐个配置以使用 SOCKS 代理。它涉及设置本地 TUN 接口并通过它路由流量。
请参阅 VPN over SSH#设置 badvpn 和隧道接口。
X11 转发
X11 转发是一种机制,允许在远程系统上运行的 X11 程序的图形界面显示在本地客户端机器上。对于 X11 转发,远程主机不需要安装完整的 X11 系统;但是,它至少需要安装 xauth。xauth 是一个实用程序,用于维护服务器和客户端用于 X11 会话身份验证的 Xauthority
配置(来源)。
设置
远程
- 安装 xorg-xauth 软件包
- 在
/etc/ssh/sshd_config
中- 将
X11Forwarding
设置为 yes - 验证
AllowTcpForwarding
和X11UseLocalhost
选项是否设置为 yes,以及X11DisplayOffset
是否设置为 10(如果没有任何更改,这些是默认值,请参阅 sshd_config(5))
- 将
- 然后重启 sshd 守护进程。
客户端
- 安装 xorg-xauth 软件包
- 通过在命令行上指定
-X
开关进行机会性连接,或在客户端配置中将ForwardX11
设置为 yes,来启用ForwardX11
选项。
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_config
中启用AddressFamily any
选项,或者 - 在服务器上的
sshd_config
中将AddressFamily
选项设置为 inet。
将其设置为 inet 可能会修复 Ubuntu 客户端在 IPv4 上的问题。
为了以 SSH 服务器上的另一个用户身份运行 X 应用程序,您需要 xauth add
从 SSH 登录用户的 xauth list
中获取的身份验证行。
转发其他端口
除了 SSH 内置的 X11 支持外,它还可以通过本地转发或远程转发来安全地隧道任何 TCP 连接。
本地转发在本地机器上打开一个端口,连接到该端口的连接将被转发到远程主机,然后再转发到给定的目标。通常,转发目标将与远程主机相同,从而为同一台机器提供安全 shell 和,例如,安全 VNC 连接。本地转发通过 -L
开关及其随附的转发规范以 <隧道端口>:<目标地址>:<目标端口>
的形式完成。
因此
$ ssh -L 1000:mail.google.com:25 192.168.0.100
将使用 SSH 登录并在 192.168.0.100
上打开 shell,还将创建从本地机器的 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
上启动 shell,并且从 192.168.0.200
到自身端口 3000(远程主机的 localhost:3000
)的连接将通过隧道发送到本地机器,然后再发送到 irc.libera.chat 端口 6667,因此,在本例中,即使端口 6667 通常对其阻塞,也允许在远程主机上使用 IRC 程序。
本地和远程转发都可以用于提供安全“网关”,允许其他计算机利用 SSH 隧道,而无需实际运行 SSH 或 SSH 守护程序,方法是在转发规范中为隧道的起始端提供绑定地址,例如 <隧道地址>:<隧道端口>:<目标地址>:<目标端口>
。<隧道地址>
可以是隧道起始端机器上的任何地址。地址 localhost
允许通过 localhost
或环回接口进行连接,而空地址或 *
允许通过任何接口进行连接。默认情况下,转发仅限于来自隧道“开始”处的机器的连接,即 <隧道地址>
设置为 localhost
。本地转发不需要额外的配置;但是,远程转发受远程服务器的 SSH 守护程序配置的限制。有关远程转发和本地转发的更多信息,请参阅 sshd_config(5) 中的 GatewayPorts
选项和 ssh(1) 中的 -L address
选项。
跳转主机
在某些情况下,可能无法直接连接到您的目标 SSH 守护程序,并且需要使用跳转服务器(或 堡垒服务器)。因此,我们尝试将两个或多个 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 选项之间的主要区别在于,后者不需要跳转主机上的 shell。因此,这也意味着跳转服务器不需要访问用户的登录凭据或 SSH 代理转发。使用 ProxyJump 选项,ssh 客户端通过跳转服务器直接连接到目标服务器,从而在客户端和目标服务器之间建立端到端加密通道。
配置文件中 -J
标志的等效项是 ProxyJump
选项;有关详细信息,请参阅 ssh_config(5)。
通过中继的反向 SSH
其思想是客户端通过另一个中继连接到服务器,而服务器使用反向 SSH 隧道连接到同一个中继。当服务器位于 NAT 之后时,这很有用,而中继是用户可以访问的公共可访问的 SSH 服务器,用作代理。因此,先决条件是客户端的密钥已针对中继和服务器获得授权,并且服务器也需要针对中继进行授权以进行反向 SSH 连接。
以下配置示例假设 user1 是客户端上使用的用户帐户,user2 是中继上的用户帐户,user3 是服务器上的用户帐户。首先,假设我们将使用端口 2222,服务器需要建立反向隧道,使用
ssh -R 2222:localhost:22 -N user2@relay
这也可以通过启动脚本、systemd 服务、autossh 或 sidedoorAUR 自动完成。
在客户端,连接通过以下方式建立
ssh -t user2@relay ssh user3@localhost -p 2222
ssh user3@relay -p 2222
将要求您在中继服务器的防火墙中打开此端口,并允许来自其他地址的连接到此端口。在relay的 ~/.ssh/authorized_keys
中也可以通过包含 command
字段来定义建立反向隧道的远程命令,如下所示
command="ssh user3@localhost -p 2222" ssh-ed25519 KEY2 user1@client
在这种情况下,连接通过以下方式建立
ssh user2@relay
或者,您可以向 ssh 配置添加一个条目,该条目同时指定 RemoteCommand
和 RequestTTY
~/.ssh/config
Host jump-destination Hostname relay User user2 RemoteCommand ssh user3@localhost -p 2222 RequestTTY yes
这将减少连接到
ssh jump-destination
多路复用
SSH 守护程序通常在端口 22 上监听。但是,许多公共互联网热点通常会阻止所有不在常规 HTTP/S 端口(分别为 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.com
和aes256-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,高性能 SSH/SCP 可以通过动态增加 SSH 缓冲区大小来显着提高吞吐量。安装软件包 openssh-hpnAUR 以使用带有此增强功能的 OpenSSH 修补版本。
使用 SSHFS 挂载远程文件系统
请参阅 SSHFS 文章,将可通过 SSH 访问的远程系统挂载到本地目录,这样您就可以使用任何工具(复制、重命名、使用 vim 编辑等)对挂载的文件执行任何操作。通常首选 sshfs 而不是 shfs,后者自 2004 年以来未更新。
保持连接
默认情况下,如果 SSH 会话空闲一段时间,它会自动注销。为了保持会话连接,如果一段时间内未收到任何数据,客户端可以向服务器发送保持活动信号,或者服务器可以定期发送消息(如果它没有收到客户端的消息)。
- 在服务器端,
ClientAliveInterval
设置超时时间(以秒为单位),如果在超时时间后未收到来自客户端的任何数据,sshd 将发送响应请求。默认值为 0,不发送消息。例如,要每 60 秒向客户端请求一次响应,请在您的服务器配置中设置ClientAliveInterval 60
选项。另请参阅ClientAliveCountMax
和TCPKeepAlive
选项。 - 在客户端端,
ServerAliveInterval
控制从客户端发送到服务器的响应请求之间的间隔。例如,要每 120 秒向服务器请求一次响应,请将ServerAliveInterval 120
选项添加到您的客户端配置中。另请参阅ServerAliveCountMax
和TCPKeepAlive
选项。
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/User 服务。请参阅 #保持连接 了解如何防止隧道超时。如果您希望在启动时启动隧道,您可能需要将单元文件重写为系统服务。
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 时可能很有用。其他环境变量可在 autossh(1) 中找到。当然,如果需要,您可以使此单元更复杂(有关详细信息,请参阅 systemd 文档),并且显然您可以为 autossh 使用您自己的选项,但请注意,暗示 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
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 "..."
的另一个示例:考虑连接到 internal.example.com
需要堡垒/代理(通过 ProxyJump
),除非您已经通过 VPN 连接。片段 !exec "host internal.example.com"
仅在无法通过 DNS 查找 internal.example.com
时应用。在 [3] 中讨论了各种替代方案。
Match host internal.example.com !exec "host internal.example.com" ProxyJump bastion.example.com Host internal.example.com User foobar
私有网络主机密钥验证
由于不同网络上的不同服务器可能共享一个通用的私有 IP 地址,因此您可能希望以不同的方式处理它们。
最好的解决方案是使用#特定于网络的配置来使用不同的 UserKnownHostsFile
,具体取决于您所在的网络。第二种解决方案,最好在您处理新的/原型网络时用作默认设置,是简单地忽略私有网络的主机密钥
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
登录时运行命令
如果您正在使用交互式会话,则有多种方法可以在登录时执行命令
- 使用远程主机上的
authorized_keys
文件(请参阅 sshd(8) § AUTHORIZED_KEYS FILE FORMAT) - 如果服务器已启用
PermitUserRC
选项,则使用远程主机上的~/.ssh/rc
- 使用远程主机上的 shell 配置文件,例如
.bashrc
代理转发
SSH 代理转发允许您在连接到服务器时使用本地密钥。建议仅为选定的主机启用代理转发。
~/.ssh/config
Host myserver.com ForwardAgent yes
接下来,配置 SSH 代理 并使用 ssh-add 添加您的本地密钥。
如果您现在连接到远程服务器,您将能够使用您的本地密钥连接到其他服务。
生成新密钥
可以通过以下方式生成新的服务器私钥
- 删除所有密钥,例如
# rm /etc/ssh/ssh_host_*_key*
- 重启
sshdgenkeys.service
或以 root 身份运行ssh-keygen -A
。
以非特权用户身份运行 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
将输出重定向到 stderr 以方便监控。
$ sshd -f /path/to/sshd_config -D -e
故障排除
检查清单
在您深入了解之前,请检查这些简单的问题。
- 配置目录
~/.ssh
及其内容应仅可由用户访问(在客户端和服务器上都检查这一点),并且用户的主目录应仅可由用户写入$ chmod go-w ~ $ chmod 700 ~/.ssh $ chmod 600 ~/.ssh/* $ chown -R $USER ~/.ssh
- 检查客户端的公钥(例如
id_ed25519.pub
)是否在服务器上的~/.ssh/authorized_keys
中。 - 检查您是否在服务器配置中使用
AllowUsers
或AllowGroups
限制了 SSH 访问。 - 检查用户是否设置了密码。有时尚未登录到服务器的新用户没有密码。
- 附加
LogLevel DEBUG
到/etc/ssh/sshd_config
。 - 以 root 身份运行
journalctl -xe
以获取可能的(错误)消息。 - 重启
sshd
并在客户端和服务器上注销/登录。
连接被拒绝或超时问题
端口转发
如果您位于 NAT 模式/路由器之后(除非您在 VPS 或公共寻址的主机上,否则很可能如此),请确保您的路由器正在将传入的 ssh 连接转发到您的机器。使用 $ ip addr
找到服务器的内部 IP 地址,并将您的路由器设置为将 SSH 端口上的 TCP 转发到该 IP。portforward.com 可以提供帮助。
SSH 是否正在运行并监听?
ss 实用程序使用以下命令行显示所有正在监听 TCP 端口的进程
$ ss --tcp --listening
如果以上命令未显示系统正在监听端口 ssh
,则 SSH 未运行:检查日志中是否有错误等。
是否有防火墙规则阻止连接?
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 或第三方阻止默认端口?
在某些情况下,您的 ISP 可能会阻止默认端口(SSH 端口 22),因此无论您尝试什么(打开端口、强化堆栈、防御洪水攻击等)最终都将无济于事。为了确认这一点,请在所有接口 (0.0.0.0) 上创建一个服务器并远程连接。
如果您收到类似于此的错误消息
ssh: connect to host www.inet.hr port 22: Connection refused
这意味着端口未被 ISP 阻止,而是服务器未在该端口上运行 SSH(请参阅 隐蔽式安全)。
但是,如果您收到类似于此的错误消息
ssh: connect to host 111.222.333.444 port 22: Operation timed out
这意味着某些东西正在端口 22 上拒绝您的 TCP 流量。基本上,该端口是隐形的,可能是由于您的防火墙或第三方干预(例如 ISP 阻止和/或拒绝端口 22 上的传入流量)。如果您知道您没有在计算机上运行任何防火墙,并且您知道 Gremlins 没有在您的路由器和交换机中生长,那么您的 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。同时使用这两行可以在两个端口上运行 SSH 服务器。
重启 服务器 sshd.service
,您就快完成了。您仍然需要配置您的客户端以使用其他端口而不是默认端口。有很多解决方案可以解决这个问题,但让我们在这里介绍其中两种。
从套接字读取失败:连接被对端重置
在连接到较旧的 ssh 服务器时,新版本的 OpenSSH 有时会失败并显示上述错误消息。可以通过为该主机设置各种客户端选项来解决此问题。有关以下选项的更多信息,请参阅 ssh_config(5)。
问题可能是 ecdsa-sha2-nistp*-cert-v01@openssh
椭圆曲线主机密钥算法。可以通过将 HostKeyAlgorithms
设置为排除这些算法的列表来禁用它们。在客户端,客户端想要使用的 HostKeyAlgorithms
也可以通过在 HostKeyAlgorithms
列表前加上 -
来设置,以从默认集合中删除指定的算法(包括通配符)(请参阅 ssh_config(5)
手册页)。您可以使用 ssh -v server_to_connect_to
在包含 kex: host key algorithm:
的行中检查实际使用的主机密钥算法。
如果这不起作用,可能是密码列表太长。将 Ciphers
选项设置为较短的列表(少于 80 个字符应该足够)。同样,您也可以尝试缩短 MACs
列表。
另请参阅 OpenSSH 错误论坛上的讨论。
"[您的 shell]: 没有那个文件或目录" / ssh_exchange_identification 问题
一个可能的原因是某些 SSH 客户端需要在 $SHELL
中找到绝对路径(例如,whereis -b [您的 shell]
返回的路径),即使 shell 的二进制文件位于 $PATH
条目之一中。
"终端未知" 或 "打开终端时出错" 错误消息
如果您在登录时收到上述错误,则表示服务器无法识别您的终端。像 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 hack
或者,您可以简单地在服务器上的环境中设置 TERM=xterm
(例如,在 .bash_profile
中)。这将消除错误并允许 ncurses 应用程序再次运行,但您可能会遇到奇怪的行为和图形故障,除非您的终端的控制序列与 xterm 的完全匹配。
连接被 x.x.x.x [preauth] 关闭
如果您在 sshd 日志中看到此错误,请确保您已设置有效的 HostKey
HostKey /etc/ssh/ssh_host_ed25519_key
子系统请求失败
自 OpenSSH 8.8 起,scp 使用 SFTP 作为数据传输的默认协议,方法是请求名为 sftp
的子系统。如果您在 verbose 模式下运行 scp,scp -v
,您可以确定您的客户端正在使用哪个子系统(例如,Sending subsystem: <subsystem-name>
)。诸如 subsystem request failed on channel 0
之类的错误可以通过配置服务器的 Subsystem 设置来修复:sshd_config(5) § Subsystem。服务器配置应类似于以下示例。
/etc/ssh/sshd_config
... Subsystem subsystem-name /path/to/subsystem-executable ...
id_dsa 被拒绝
OpenSSH 7.0 弃用了 DSA 公钥,因为其安全性较低,并且 OpenSSH 9.8 在构建时默认不支持 DSA 密钥。2025 年的第一个 OpenSSH 版本将完全删除 DSA 支持。目前,如果您绝对必须使用它们,您需要重新构建 openssh,同时将 --enable-dsa-keys
传递给 configure
。[4]
OpenSSH 7.0 找不到匹配的密钥交换方法
OpenSSH 7.0 弃用了 diffie-hellman-group1-sha1 密钥算法,因为它很弱,并且在所谓的 Logjam 攻击的理论范围内(请参阅 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 会话被终止
如果您的进程在会话结束时被终止,则可能是您正在使用套接字激活,并且当 systemd 注意到 SSH 会话进程退出时将其终止。在这种情况下,有两种解决方案。一种是通过使用 ssh.service
而不是 ssh.socket
来避免使用套接字激活。另一种是在 ssh@.service
的 Service 部分中设置 KillMode=process
。
KillMode=process
设置对于经典的 ssh.service
也可能有用,因为它避免在服务器停止或重启时终止 SSH 会话进程或 screen 或 tmux 进程。
SSH 会话停止响应
SSH 响应 流控制命令 XON
和 XOFF
。当您按下 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
Match all IPQoS reliability
reliability
(0x04
) 服务类型应该可以解决问题,0x00
和 throughput
(0x08
) 也是如此。
终止无响应的 SSH 连接
如果客户端会话不再响应,并且无法通过指示正在运行的程序(例如shell)来终止,您仍然可以通过依次按下 Enter
、~
和 .
来终止会话。
~
是伪终端转义字符(请参阅 ssh(1) § ESCAPE CHARACTERS),可以根据客户端会话添加多次以终止。例如,如果您从 A 连接到 B,然后从 B 连接到 C,并且从 B 到 C 的会话冻结,您可以通过按下 Enter
并键入 ~~.
来终止它,这将使您在 B 上处于工作会话中。
警告:远程主机标识已更改!
如果客户端警告 ssh 服务器的密钥已更改,您应该通过经过身份验证的(不一定是加密的)通道验证新提供的密钥是否真的属于服务器运营商。然后使用 ssh-keygen -R $SSH_HOST
从 known_hosts
文件中删除旧密钥,并接受新密钥,就像它是新服务器一样。
连接到没有相应 terminfo 条目的远程主机
当连接到没有您的终端的 terminfo 条目的主机时,例如,当使用 terminfo 条目未与 ncurses 一起提供的终端模拟器(例如 kitty 和 rxvt-unicode),或者当连接到具有有限 terminfo 数据库的主机(例如运行 OpenWrt 的系统)时,依赖于 terminfo(5) 的软件会发生各种问题。
正确的解决方案是在主机上放置相应的 terminfo 条目。如果这不可行,另一种方法是将 TERM
设置为远程主机支持且与终端兼容的值。
自 OpenSSH 8.7 起,可以使用简单的配置片段将自定义 TERM
环境变量传递给远程主机
~/.ssh/config
Host example.com SetEnv TERM=xterm-256color
通过跳板机连接失败,并显示 "bash: 没有那个文件或目录"
如果您没有将 SHELL
环境变量设置为完整的有效路径(在跳板服务器上),则连接将失败,并显示类似于此错误消息的消息
bash: No such file or directory kex_exchange_identification: Connection closed by remote host Connection closed by UNKNOWN port 65535
您可以通过将 SHELL
设置为在跳板服务器上也有效的 shell 的完整路径名,或者通过在 ~/.ssh/config
文件中为每个服务器设置特定的 SHELL
变量来轻松解决此问题。
参见
- Wikibooks:OpenSSH
- 防御 SSH 暴力破解攻击
- OpenSSH 密钥管理:IBM developerWorks 上的 第 1 部分,funtoo.org 上的 第 2 部分,第 3 部分
- 安全 Secure Shell