水风清,晚霞明

微霞

13.ssh知识整理

更新于
· 字数: 4157 · 阅读: 16 分钟
# 学习
Table of Contents

这并不是一篇指导性的文章,而是一篇初学者的笔记,可能会随时改动,其中也可能遍布错误。此外,我感觉这更像是一篇冗长啰嗦的唠叨。😪

以下代码都是在 Debian 系统上进行的操作。

基础

一般情况下linux默认安装了ssh。linux一般使用ssh连接。 没有安装的话可以按照一下命令安装

Terminal window
#安装
sudo apt-get install openssh-server # 对于Debian/Ubuntu
sudo yum install openssh-server # 对于RHEL/CentOS
#启动
sudo service ssh start # 对于系统V(System V)初始化系统
sudo systemctl start ssh # 对于使用systemd的系统

/etc/ssh/sshd_config可以调整ssh配置,调整前先备份。

Terminal window
cp /etc/ssh/sshd_config /etc/ssh/backup.sshd_config # 备份好习惯
sudo vim /etc/ssh/sshd_config # 使用vim
sudo nano /etc/ssh/sshd_config # 使用nano
sshd -t #用于测试ssh服务器配置文件是否正确
sudo service ssh restart # 修改完之后重启

ssh最常见的用途之一是远程登录到远程服务器或计算机。

Terminal window
ssh username@remote_host # 替换为你的username和remote_host

第一次连接服务器大概会出现以下情况。

The authenticity of host '1.1.1.1 (1.1.1.1)' can't be established.
ED25519 key fingerprint is SHA256:rqEuH0ymaN0LbB1vPKzRpfgew+5hBusv1/ReDGJ6bDs.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])?
# 翻译
无法确定主机 "1.1.1.1 (1.1.1.1) "的真实性。
ED25519 密钥指纹为SHA256:rqEu130ymaN0LbB1vPKzRpfgew+5hBusv1/ReDGJ6bDs。
此密钥没有其他名称
您确定要继续连接(是/否/[指纹])?

这个消息通常是在你首次通过 ssh 连接到一个远程服务器时出现的。它是 ssh 的一种安全机制,目的是确保你连接的服务器确实是你想要连接的服务器,而不是中间人攻击(Man-in-the-Middle Attack)的一部分。

一般情况下只需按下”Enter”即可。 接下来就是输入密码,linux默认输入密码的时候不会有任何提示或者显示。输入完密码再次回车即可登入服务器。
以后将不会再次提醒无法验证该服务器的真实性,因为ssh客户端将保存该主机的公钥,并在将来的连接中使用它来验证主机的真实性。
不过,当服务器修改了公钥或者对系统进行了重置,那么ssh客户端会在下一次连接中警告称:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256: [新的密钥指纹]
Please contact your system administrator.
Add correct host key in /path/to/your/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /path/to/your/.ssh/known_hosts:1
remove with:
ssh-keygen -f "/path/to/your/.ssh/known_hosts" -R [服务器IP地址]
ECDSA host key for [服务器IP地址] has changed and you have requested strict checking.
Host key verification failed.
# 翻译
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ 警告:远程主机标识已更改! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
有可能有人在做坏事!
可能有人正在窃听你(中间人攻击)!
也有可能是主机密钥刚刚被更改。
远程主机发送的 ECDSA 密钥的指纹是
sha256: [新的密钥指纹] 请联系系统管理员。
请联系系统管理员。
在 /path/to/your/.ssh/known_hosts 中添加正确的主机密钥,以消除此信息。
在 /path/to/your/.ssh/known_hosts:1 中的违规 ECDSA 密钥
删除:
ssh-keygen -f "/path/to/your/.ssh/known_hosts" -R [服务器 IP 地址] ECDSA 主机密钥。
服务器 IP 地址] 的 ECDSA 主机密钥已更改,您要求进行严格检查。
主机密钥验证失败。

ssh无密码登录

我们会发现,每一次连接的时候,服务器都要求我们输入密码。
如果我们每一次都使用诸如ssh username@remote_host+password的方式,可能会感到十分的厌烦,这时候我们就可以使用ssh密钥对来连接到远程服务器。如果私钥没有设置密码,就不需要输入密码。从而达到无密码登录。
ssh-keygen可以生成密钥对,接下来连续三次回车即可生成密钥对.

ssh-keygen -t rsa -b 2048
# 生成一个2048位的RSA密钥对,可以选择更长的
❯ ssh-keygen -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/admin/.ssh/id_rsa):# 存储位置(回车)
Enter passphrase (empty for no passphrase): # 可以选择输入密码(回车)
Enter same passphrase again: # 再次输入密码(回车)
Your identification has been saved in /c/Users/admin/.ssh/id_rsa
Your public key has been saved in /c/Users/admin/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:a9G5vG/6Qz6Aptj/cFQsPZtt+DjiAMIBVI9fW/OIENM admin@PC
The key's randomart image is:
+---[RSA 2048]----+
| .o.. o. |
| . o oE o |
| o o . + = |
| . o o = B * |
| o o S.= = o |
| . .o=...+ |
| o o= =+o . |
| . o. = o=. |
| ...==oo |
+----[SHA256]-----+

此时我们就生成好了一个2048位的RSA密钥对,此时它存储在c/Users/admin/.ssh/id_rsa这个位置,可以从自己的终端看到文件所在位置。 接下来我们可以使用ssh-copy-id将它复制到远程服务器上。

Terminal window
ssh-copy-id username@remote-server

执行这个命令后,系统会要求您输入远程服务器的密码,然后会将您本地计算机上的 ~/.ssh/id_rsa.pub(或其他公钥文件)的内容追加到远程服务器上的 ~/.ssh/authorized_keys 文件中。此时,就完成了公钥的复制。
此时就已经完成了无密码登录的步骤,以后使用ssh连接都只需要输入以下代码即可

Terminal window
ssh username@remote-server

如果不想用ssh-copy-id,可以使用scp指令,将公钥发送到服务器。

Terminal window
scp /Users/admin/.ssh/id_rsa.pub username@remote_host:~/.ssh

多讲’亿’句。其中,scp(Secure Copy Protocol)是一个用于在本地计算机和远程服务器之间安全地复制文件的命令行工具。
基础指令如下。

  1. 可以将本地的文件复制到服务器。

    Terminal window
    scp local_file.txt user@remote_server_ip:/path/to/destination/
    • local_file.txt: 本地文件的路径。
    • user: 远程服务器上的用户名。
    • remote_server_ip: 远程服务器的IP地址。
    • /path/to/destination/: 目标目录在远程服务器上的路径。
  2. 反过来可以将服务器的文件复制回来。

    Terminal window
    scp user@remote_server_ip:/path/to/remote_file.txt /local/destination/
    • user: 远程服务器上的用户名。
    • remote_server_ip: 远程服务器的IP地址。
    • /path/to/remote_file.txt: 远程服务器上要复制的文件路径。
    • /local/destination/: 本地目录,用于保存复制的文件。
  3. 复制整个目录(递归)到远程服务器

    Terminal window
    scp -r local_directory user@remote_server_ip:/path/to/destination/
    • -r: 表示递归复制,用于复制整个目录。
    • local_directory: 本地目录的路径
    • user: 远程服务器上的用户名。
    • remote_server_ip: 远程服务器的IP地址。 -/path/to/destination/: 目标目录在远程服务器上的路径,指定复制到远程服务器的位置。
  4. 复制整个目录(递归)到本机

    Terminal window
    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文件。

#!/bin/bash
# 显示菜单
echo "1, 1.1.1.1"
echo "2, 2.2.2.2"
echo "3, 3.3.3.3"
echo "4, 退出"
# 获取用户输入
read -p "请选择需要连接的服务器(输入相应的数字): " choice
# 使用 case 语句进行选择
case $choice in
1)
echo "1.1.1.1"
ssh username@1.1.1.1
;;
2)
echo "连接2.2.2.2"
ssh username@2.2.2.2
;;
3)
echo "连接3.3.3.3"
ssh username@3.3.3.3
;;
4)
echo "退出脚本"
exit 0
;;
*)
echo "无效的选择,请输入1-4之间的数字"
;;
esac

这下每次只需运行脚本,输入数字即可连接。

或者说,你的目前在用移动端类unix\linux系统(比如termux,一个适用于 Android 操作系统的开源终端模拟器应用),你打开它的唯一目的就是远程连接服务器,那么我们还可以玩的更极端点,直接使用alias来起一个别名。
alias是一个用于创建命令别名的shell内建命令。别名允许用户为常用的命令或一系列命令定义短而易记的替代名称。 alias基本语法为alias name='command'
别名只在当前会话中有效,如果您想要使别名在每个新的shell会话中都可用,可以将别名定义添加到 shell 配置文件(如 ~/.bashrc 或 ~/.bash_profile)中。

Terminal window
echo 'alias link=ssh username@remote_host' >> ~/.bashrc # 使用bash
echo 'alias link=ssh username@remote_host' >> ~/.zshrc # 使用zsh

此时在终端输入link即可直接连接到username@remote_hostalias只做替换功能,我们完全可以继续使用其他参数诸如-p-t

注:termux好像没有bashrc,需要自己新建,以上代码可以直接新建。

ssh别名

想必看到这里,你已经基础了解了ssh是如何使用的了。
尽管刚刚,我们已经会使用 alias 来起一个别名,但是就我而言,我其实并不喜欢为ssh专门新建一个alias。
那么,难道我们每一次都要完整的输入一次ssh username@remote_host吗?其实ssh也有一个专门的配置文件来帮助你为不同的 SSH 连接设置简短易记的别名,从而简化连接命令。
SSH 别名可以通过配置文件 .ssh/config 实现,这个文件位于用户的主目录下~/.ssh/config。如果文件不存在,你可以手动创建它。

基本的配置如下所示:

Terminal window
Host myserver
HostName remote_host
User username
Port 22
IdentityFile ~/.ssh/id_rsa
  • Host: 自定义别名。在连接时使用这个名称,而不需要输入完整的主机名。
  • HostName: 实际的主机名或 IP 地址。
  • User: 登录所使用的用户名。
  • Port: 服务器的 SSH 端口。如果不是默认的 22 端口,则需要指定。
  • IdentityFile: 私钥文件路径。如果你有多个私钥文件,可以指定特定的文件。

配置好别名后,你只需要使用 ssh 命令加上别名即可:

Terminal window
ssh myserver
#同等于ssh -i ~/.ssh/id_rsa username@remote_host -p 22

还有一件事。使用 SSH 别名后,仍然需要密钥进行无密码登录,但 SSH 别名可以让连接过程更加简便。

ssh别名的其他选项

一般情况下,以上的配置就已经够用了。不过还有一些选项有时候也是会用上的。

ForwardAgent

ForwardAgent,它允许将本地 SSH 代理转发到远程服务器,从而使你可以在连接到远程服务器后,无需重新输入密码或私钥,即可在远程服务器上发起其他 SSH 连接。
说的再详细一点就是:SSH Agent的功能是,你只需要在本地机器上解锁一次私钥,后续的 SSH 连接会使用这个已经解锁的密钥,而不需要你再次输入密码。那么,ForwardAgent 是用来将本机的 SSH 代理转发到远程机器上,使得远程机器可以利用本机的 SSH 代理进行进一步的 SSH 连接。
通过 ForwardAgent,在第一台机器上启动了 SSH 代理,之后连接到第二台机器时,这个代理会被转发到第二台机器上。然后第二台机器就可以使用在第一台机器上的密钥来进行连接,从而实现无密码登录,而不用将密钥拷贝到中间机器上。

Terminal window
Host server
ForwardAgent yes

ServerAliveInterval 和 ServerAliveCountMax

Terminal window
Host server
ServerAliveInterval 60
ServerAliveCountMax 3

ServerAliveInterval: 通过设置一个间隔来发送 keep-alive 消息,防止连接断开。
详细点说就是:定义 SSH 客户端在多长时间内(以秒为单位)没有收到服务器响应时,会主动发送 keep-alive 消息以检查连接是否仍然有效。这个选项有助于防止长时间闲置的 SSH 连接因超时而断开。
ServerAliveCountMax:设置在没有收到服务器响应的情况下,客户端可以发送多少次保持活动信号。

其他的指令

既然都讲到这里了,不如再多讲讲有关ssh的知识。
现在说说-t选项。-t是ssh命令的一个选项,用于在远程服务器上分配一个伪终端,在某些情况很有用。

例子:

Terminal window
ssh -t username@remote_host 'sudo apt update && sudo apt upgrade'
Hit:1 http://mirrors.cloud.aliyuncs.com/debian bullseye InRelease
......
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Connection to remote_host closed.
~/

可以看到,此时参数-t表示要分配一个伪终端(pseudo-tty)。
在执行完sudo apt update && sudo apt upgrade后,伪终端则是会立即关闭。这种行为是由于指令执行完毕后没有额外的交互需要,所以终端会自动关闭。可以增加一个&&bash来启动一个新的bash会话,能够在保持 ssh 连接的情况下继续与服务器互动。
但是我暂时还不知道这个能用来干什么。🤔

看了一下文档,发现ssh还有用作代理的方法,使用 -D 端口号参数,即可指定动态端口转发,创建一个SOCKS代理服务器,该代理服务器将在本地计算机的指定端口上监听。

Terminal window
ssh -D 1080 username@remote_host

以上代码建立了一个ssh,它将在本地计算机的1080端口上监听,并且转发流量。

Terminal window
ssh -fNCqTn -D 1080 username@remote_host
# 加这么多参数好像有点重复,实际使用上可以看需删减参数

如果我们使用ssh作为代理的话,可以用以下的参数

  • -f:将ssh连接放到后台运行,使其在后台运行,以便您可以继续使用终端。
  • -N:告诉ssh不要执行任何远程命令,它只会建立连接而不执行任何额外的命令。
  • -C: 启用数据压缩。这将通过zlib库对传输的数据进行压缩,以减小传输的数据量。
  • -q: 静默模式。该选项用于减少输出,使ssh在执行时更为静默,不输出不必要的信息。
  • -T: 禁用伪终端分配。通常,ssh会为远程连接分配伪终端,但使用 -T 选项会禁用这个分配,适用于不需要交互的连接。
  • -n: 防止远程命令执行时,ssh从标准输入读取数据。

-L 也是大差不差。在使用-L选项时,可本地主机上的一个端口映射到远程主机的指定端口。

Terminal window
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)连接到远程服务器的。跳板主机充当一个中间站,帮助我们间接地连接到目标服务器。

Terminal window
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讲解。
  • 2025-03-01 订正文章格式错误。

无关紧要的念念碎:怎么这玩意越写越多了,而且的ssh内容真的好多啊,再写下去还不如去看官方文档了。

水氵冫

Written by 水氵冫

再努力一点点的说!

本文作者: 水氵冫
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!

评论

评论加载中...