ssh 知识整理
这并不是一篇指导性的文章,而是一篇初学者的笔记,可能会随时改动,其中也可能遍布错误。此外,我感觉这更像是一篇冗长啰嗦的唠叨。😪
以下代码都是在 Debian 系统上进行的操作。
基础
一般情况下 linux 默认安装了 ssh。linux 一般使用 ssh 连接。没有安装的话可以按照一下命令安装
1 | #安装 |
在 /etc/ssh/sshd_config
可以调整 ssh 配置,调整前先备份。
1 | cp /etc/ssh/sshd_config /etc/ssh/backup.sshd_config # 备份好习惯 |
ssh 最常见的用途之一是远程登录到远程服务器或计算机。
1 | ssh username@remote_host # 替换为你的username和remote_host |
第一次连接服务器大概会出现以下情况。
1 | The authenticity of host '1.1.1.1 (1.1.1.1)' can't be established. |
这个消息通常是在你首次通过 ssh 连接到一个远程服务器时出现的。它是 ssh 的一种安全机制,目的是确保你连接的服务器确实是你想要连接的服务器,而不是中间人攻击(Man-in-the-Middle Attack)的一部分。
一般情况下只需按下 "Enter" 即可。接下来就是输入密码,linux 默认输入密码的时候不会有任何提示或者显示。输入完密码再次回车即可登入服务器。以后将不会再次提醒无法验证该服务器的真实性,因为 ssh 客户端将保存该主机的公钥,并在将来的连接中使用它来验证主机的真实性。不过,当服务器修改了公钥或者对系统进行了重置,那么 ssh 客户端会在下一次连接中警告称:
1 | @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ |
ssh 无密码登录
我们会发现,每一次连接的时候,服务器都要求我们输入密码。如果我们每一次都使用诸如 ssh username@remote_host
+password
的方式,可能会感到十分的厌烦,这时候我们就可以使用 ssh 密钥对来连接到远程服务器。如果私钥没有设置密码,就不需要输入密码。从而达到无密码登录。ssh-keygen
可以生成密钥对,接下来连续三次回车即可生成密钥对,
1 | ssh-keygen -t rsa -b 2048 |
此时我们就生成好了一个 2048 位的 RSA 密钥对,此时它存储在 c/Users/admin/.ssh/id_rsa
这个位置,可以从自己的终端看到文件所在位置。接下来我们可以使用 ssh-copy-id
将它复制到远程服务器上。
1 | ssh-copy-id username@remote-server |
执行这个命令后,系统会要求您输入远程服务器的密码,然后会将您本地计算机上的 ~/.ssh/id_rsa.pub
(或其他公钥文件)的内容追加到远程服务器上的 ~/.ssh/authorized_keys
文件中。此时,就完成了公钥的复制。此时就已经完成了无密码登录的步骤,以后使用 ssh 连接都只需要输入以下代码即可
1 | ssh username@remote-server |
如果不想用 ssh-copy-id,可以使用 scp
指令,将公钥发送到服务器。
1 | scp /Users/admin/.ssh/id_rsa.pub username@remote_host:~/.ssh |
多讲’亿’句。其中,scp
(Secure Copy Protocol)是一个用于在本地计算机和远程服务器之间安全地复制文件的命令行工具。基础指令如下。
可以将本地的文件复制到服务器。
1
scp local_file.txt user@remote_server_ip:/path/to/destination/
local_file.txt: 本地文件的路径。
user: 远程服务器上的用户名。
remote_server_ip: 远程服务器的 IP 地址。
/path/to/destination/: 目标目录在远程服务器上的路径。
反过来可以将服务器的文件复制回来。
1
scp user@remote_server_ip:/path/to/remote_file.txt /local/destination/
user: 远程服务器上的用户名。
remote_server_ip: 远程服务器的 IP 地址。
/path/to/remote_file.txt: 远程服务器上要复制的文件路径。
/local/destination/: 本地目录,用于保存复制的文件。
复制整个目录(递归)到远程服务器
1
scp -r local_directory user@remote_server_ip:/path/to/destination/
-r: 表示递归复制,用于复制整个目录。
local_directory: 本地目录的路径
user: 远程服务器上的用户名。
remote_server_ip: 远程服务器的 IP 地址。
-/path/to/destination/: 目标目录在远程服务器上的路径,指定复制到远程服务器的位置。
复制整个目录(递归)到本机
1
scp -r user@remote_server_ip:/path/to/remote_directory /local/destination/
-r: 表示递归复制,用于复制整个目录。
user: 远程服务器上的用户名。
remote_server_ip: 远程服务器的 IP 地址。
/path/to/remote_directory: 远程服务器上要复制的目录路径。
/local/destination/: 本地目录,用于保存复制的目录。
更简便一点
经过了刚才繁琐冗赘的说明。此时,我们完成了无密码登录,以后使用 ssh 连接都只需要输入我们想登录的服务器和用户即可登录。那么,我们还可以再简便一点吗?
当然,这样做还可以更懒一点,比如建立一个 sh 文件。
1 |
|
这下每次只需运行脚本,输入数字即可连接。
或者说,你的目前在用移动端类 unix\linux 系统(比如 termux,一个适用于 Android 操作系统的开源终端模拟器应用),你打开它的唯一目的就是远程连接服务器,那么我们还可以玩的更极端点,直接使用 alias
来起一个别名。而 alias
是一个用于创建命令别名的 shell 内建命令。别名允许用户为常用的命令或一系列命令定义短而易记的替代名称。alias
基本语法为 alias name='command'
。别名只在当前会话中有效,如果您想要使别名在每个新的 shell 会话中都可用,可以将别名定义添加到 shell 配置文件(如~/.bashrc 或~/.bash_profile)中。
1 | echo 'alias link=ssh username@remote_host' >> ~/.bashrc # 使用bash |
此时在终端输入 link
即可直接连接到 username@remote_host
,alias
只做替换功能,我们完全可以继续使用其他参数诸如 -p
和 -t
。
注:termux 好像没有 bashrc,需要自己新建,以上代码可以直接新建。
ssh 别名
想必看到这里,你已经基础了解了 ssh 是如何使用的了。尽管刚刚,我们已经会使用 alias 来起一个别名,但是就我而言,我其实并不喜欢为 ssh 专门新建一个 alias。那么,难道我们每一次都要完整的输入一次 ssh username@remote_host
吗?其实 ssh 也有一个专门的配置文件来帮助你为不同的 SSH 连接设置简短易记的别名,从而简化连接命令。
SSH 别名可以通过配置文件 .ssh/config
实现,这个文件位于用户的主目录下 ~/.ssh/config
。如果文件不存在,你可以手动创建它。
基本的配置如下所示:
1 | Host myserver |
Host: 自定义别名。在连接时使用这个名称,而不需要输入完整的主机名。
HostName: 实际的主机名或 IP 地址。
User: 登录所使用的用户名。
Port: 服务器的 SSH 端口。如果不是默认的 22 端口,则需要指定。
IdentityFile: 私钥文件路径。如果你有多个私钥文件,可以指定特定的文件。
配置好别名后,你只需要使用 ssh 命令加上别名即可:
1 | ssh myserver |
还有一件事。使用 SSH 别名后,仍然需要密钥进行无密码登录,但 SSH 别名可以让连接过程更加简便。
ssh 别名的其他选项
一般情况下,以上的配置就已经够用了。不过还有一些选项有时候也是会用上的。
ForwardAgent
ForwardAgent,它允许将本地 SSH 代理转发到远程服务器,从而使你可以在连接到远程服务器后,无需重新输入密码或私钥,即可在远程服务器上发起其他 SSH 连接。说的再详细一点就是:SSH Agent 的功能是,你只需要在本地机器上解锁一次私钥,后续的 SSH 连接会使用这个已经解锁的密钥,而不需要你再次输入密码。那么,ForwardAgent 是用来将本机的 SSH 代理转发到远程机器上,使得远程机器可以利用本机的 SSH 代理进行进一步的 SSH 连接。通过 ForwardAgent,在第一台机器上启动了 SSH 代理,之后连接到第二台机器时,这个代理会被转发到第二台机器上。然后第二台机器就可以使用在第一台机器上的密钥来进行连接,从而实现无密码登录,而不用将密钥拷贝到中间机器上。
1 | Host server |
ServerAliveInterval 和 ServerAliveCountMax
1 | Host server |
ServerAliveInterval: 通过设置一个间隔来发送 keep-alive 消息,防止连接断开。详细点说就是:定义 SSH 客户端在多长时间内(以秒为单位)没有收到服务器响应时,会主动发送 keep-alive 消息以检查连接是否仍然有效。这个选项有助于防止长时间闲置的 SSH 连接因超时而断开。
ServerAliveCountMax:设置在没有收到服务器响应的情况下,客户端可以发送多少次保持活动信号。
其他的指令
既然都讲到这里了,不如再多讲讲有关 ssh 的知识。现在说说 -t
选项。-t
是 ssh 命令的一个选项,用于在远程服务器上分配一个伪终端,在某些情况很有用。例子:
1 | ssh -t username@remote_host 'sudo apt update && sudo apt upgrade' |
可以看到,此时参数 -t
表示要分配一个伪终端(pseudo-tty)。在执行完 sudo apt update && sudo apt upgrade
后,伪终端则是会立即关闭。这种行为是由于指令执行完毕后没有额外的交互需要,所以终端会自动关闭。可以增加一个 &&bash
来启动一个新的 bash
会话,能够在保持 ssh 连接的情况下继续与服务器互动。但是我暂时还不知道这个能用来干什么。🤔
看了一下文档,发现 ssh 还有用作代理的方法,使用 -D 端口号
参数,即可指定动态端口转发,创建一个 SOCKS 代理服务器,该代理服务器将在本地计算机的指定端口上监听。
1 | ssh -D 1080 username@remote_host |
以上代码建立了一个 ssh,它将在本地计算机的 1080 端口上监听,并且转发流量。
1 | ssh -fNCqTn -D 1080 username@remote_host |
如果我们使用 ssh 作为代理的话,可以用以下的参数
-f:将 ssh 连接放到后台运行,使其在后台运行,以便您可以继续使用终端。
-N:告诉 ssh 不要执行任何远程命令,它只会建立连接而不执行任何额外的命令。
-C: 启用数据压缩。这将通过 zlib 库对传输的数据进行压缩,以减小传输的数据量。
-q: 静默模式。该选项用于减少输出,使 ssh 在执行时更为静默,不输出不必要的信息。
-T: 禁用伪终端分配。通常,ssh 会为远程连接分配伪终端,但使用 -T 选项会禁用这个分配,适用于不需要交互的连接。
-n: 防止远程命令执行时,ssh 从标准输入读取数据。
而 -L
也是大差不差。在使用 -L
选项时,可本地主机上的一个端口映射到远程主机的指定端口。
1 | ssh -L 9999:example.org:80 -N -T username@remote_host |
此时,访问 local:9999 即为访问 example.org:80
这个 ssh 命令的目的是通过 ssh 隧道将本地端口(localhost:9999)转发到远程主机(example.org)的端口 80。
-J
,这个 ssh 参数是用于通过跳板主机(jumphost)连接到远程服务器的。跳板主机充当一个中间站,帮助我们间接地连接到目标服务器。
1 | ssh -J username@jump_host username@remote_host |
-J
: 指定跳板主机,表示要通过跳板主机连接到目标服务器。
可以用来连接当作外网连接内网的跳板机。而在一些安全要求较高的环境中,跳板主机可以作为一个堡垒机(Bastion Host),所有外部连接都必须先通过堡垒机,再通过内部网络连接到其他服务器。还有的时候需要通过多个跳板主机才能达到目标服务器,这就形成了一个跳板链。通过 ssh 的 - J 选项,可以指定多个跳板主机,以建立跳板链。比如 ssh -J user1@jump_host1,user2@jump_host2 user@remote_host
累了,不想写了。over.😇
参考:
ssh | tldr InBrowser.App
ssh 命令的三种代理功能(-L/-R/-D)
记录
2024-02-02 初稿完成。
2024-02-10 订正初稿,发布。
2024-05-10 更新杂七杂八的其他指令.
2024-10-20 更新 ssh 别名,和 ServerAliveInterval、ForwardAgent、ProxyJump 讲解。
无关紧要的念念碎:怎么这玩意越写越多了,而且的 ssh 内容真的好多啊,再写下去还不如去看官方文档了。