158. SSH
Secure Shell (SSH) 是一个网络协议,它主要被用来加密客户端和服务端之间的连接。 在客户端和服务端的每一次交互都被加密。
这个教程解释了如何在 Ubuntu 机器上启用 SSH。
启用 SSH 将会允许你远程连接到你的系统,并且执行管理员任务。你将能够通过 scp
和sftp
安全传输文件。
在 Ubuntu 上启用 SSH
默认情况下,当 Ubuntu 最初被安装的时候,通过 SSH 进行远程访问是不被允许的。在 Ubuntu 上启用 SSH 非常的简单直接。
以 root 或者其他 sudo 用户身份执行下面的步骤,在你的 Ubuntu 系统上安装并且启用 SSH。
01.使用Ctrl+Alt+T
打开终端,并且安装openssh-server
软件包:
1 | sudo apt update |
当被提示时,输入你的密码并且按 Enter,继续安装。
02.一旦安装完成,SSH 服务将会被自动启动。你可以验证 SSH 是否正在运行,输入:
1 | sudo systemctl status ssh |
输出将会告诉你服务正在运行,并且启用开机启动:
1 | ● ssh.service - OpenBSD Secure Shell server |
按q
返回命令行。
03.Ubuntu 自带一个配置防火墙配置工具,称为 UFW。如果防火墙在你的系统上被启用,请确保打开了 SSH 端口:
1 | sudo ufw allow ssh |
就这些。现在你可以从任何远程机器上通过 SSH 连接到你的 Ubuntu 系统。Linux 和 macOS 系统默认都安装了 SSH 客户端。想要从一个 Window 机器上连接,使用一个 SSH 客户端,例如:PUTTY。
连接到 SSH 服务器
想要在局域网内连接到你的 Ubuntu 机器,以下面的格式输入 ssh 命令,加上用户名和 IP 地址。
1 | ssh username@ip_address |
1 | 确保你将`username`修改成你自己的用户名,`ip_address`修改成你安装了 SSH 的 Ubuntu 机器的 IP 地址。 |
如果你不知道你的 IP 地址,你可以使用ip
命令轻易地找到它:
1 | ip a |
你可以从输出中看到,系统 IP 地址是10.0.2.15
。
一旦你找到 IP 地址,通过运行下面的ssh 命令登录远程机器:
1 | ssh linuxize@10.0.2.15 |
当你第一次连接时,你将看到下面的信息:
1 | The authenticity of host '10.0.2.15 (10.0.2.15)' can't be established. |
输入yes
并且你将会被提示输入你的密码:
1 | Warning: Permanently added '10.0.2.15' (ECDSA) to the list of known hosts. |
一旦你输入密码,你将会看到默认的 Ubuntu 消息:
1 | Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64) |
现在你可以登录到你的 Ubuntu 机器上。
连接到 NAT 后面的 SSH
想要通过互联网连接到你的 Ubuntu 机器,你需要知道你的公网 IP 地址,并且配置你的路由器接收端口22的数据,并且发送它到正在运行 SSH 的 Ubuntu 机器。
想要获取你尝试通过 SSH 连接的机器的公网 IP,在这个机器上访问 URL 地址:https://api.ipify.org
。
当设置端口转发时,每一个路由器都有不同的方式来设置端口转发。你应该参考你的路由器文档,关于如何设置端口转发的信息。简单来讲,你应该输入之前设置的 SSH 端口号 22,以及之前服务器的私有 IP 地址。
一旦你找到 IP 地址,配置你的路由器,输入:
1 | ssh username@public_ip_address |
如果你将你的机器暴露在互联网中,你最好采取一些安全措施。最基础的一个措施就是配置你的路由器接受一个非标准端口的 SSH 流量,并且转发到你运行 SSH 服务的机器的端口22。
你也可以设置 SSH 密钥公钥验证方式,之后你就可以不使用密码就可以连接到你的 Ubuntu 机器上了。
在 Ubuntu 上禁用 SSH
想要在你的 Ubuntu 系统上禁用 SSH 服务器,简单停止 SSH 即可,输入:
1 | sudo systemctl disable --now ssh |
稍后,你可以重新启用,输入:
1 | sudo systemctl enable --now ssh |
SSH登录
SSH 无密登录
step1 客户端生成公私钥
本地客户端生成公私钥:(一路回车默认即可)
1 | ssh-keygen |
生成之后会在用户的根目录生成一个 “.ssh
“的文件夹,进入”.ssh
“会生成如下几个文件:
1 | cd ~/.ssh |
下创建两个密钥:
authorized_keys
: 存放远程免密登录的公钥,主要通过这个文件记录多台机器的公钥id_rsa
: 生成的私钥文件id_rsa.pub
: 生成的公钥文件know_hosts
: 已知的主机公钥清单
ps
ssh公钥生效需满足至少下面两个条件:
.ssh
目录的权限必须是700.ssh/authorized_keys
文件权限必须是600
step2 上传公钥到服务器
这里测试用的服务器地址为:192.168.32.32
用户为:root
方法1
1 | ssh-copy-id -i ~/.ssh/id_rsa.pub <remote_ip> |
上面这条命令是写到服务器上的ssh目录下去了
1 | cd ~/.ssh |
可以看到客户端写入到服务器的 id_rsa.pub
(公钥)内容。
方法2
使用命令ssh-copy-id <remote_ip>
1 | ssh-copy-id root@192.168.32.32 |
方法3
通过scp
将内容写到对方的authorized_keys
文件中
1 | scp -p ~/.ssh/id_rsa.pub root@<remote_ip>:/root/.ssh/authorized_keys |
step3 测试免密登录
客户端通过ssh连接远程服务器,就可以免密登录了。
1 | ssh root@192.168.32.32 |
设置指定用户
step1 配置SSH服务器
编辑SSH服务器配置文件(通常位于/etc/ssh/sshd_config
)。
1 | $ sudo vim /etc/ssh/sshd_config |
确保以下行未注释(没有#
):
1 | PubkeyAuthentication yes |
这允许使用SSH密钥和密码进行身份验证。
step2 设置Match
块
在配置文件的末尾添加Match
块,限制只允许用户user1, user2, user3
使用密钥登录。您可以这样做:
1 | Match User user1,user2,user3 |
或
1 | Match User user1 |
这将禁用user1,user2,user3
用户的密码登录。其他用户将按照默认设置进行身份验证,允许密码登录。
多个用户也可以单独
step3 重启SSH服务
保存配置文件并重启SSH服务,以使更改生效:
1 | $ sudo systemctl restart ssh |
现在,user1,user2,user3
用户只能使用其SSH密钥进行身份验证,而其他用户仍然可以使用密码进行身份验证。
请确保在执行此操作之前,您已经测试过SSH密钥对的工作方式,并且确保您至少有一种方法可以访问服务器,以防止自身被锁定。
SSH设置环境变量
方法1
在 ~/.ssh/config
中设置如下内容:
1 | Host * |
它的作用是为所有主机(Host * 表示匹配所有主机)设置一个环境变量 TERM, 其值为 xterm-256color
, 具体含义如下:
Host *
: 这是一个通配符规则,表示该配置适用于所有远程主机。 如果你只想针对特定主机应用配置,可以将*
替换为主机名或 IP 地址。SetEnv TERM=xterm-256color
: SetEnv 是 SSH 配置指令, 用于在连接到远程主机时传递环境变量.TERM=xterm-256color
设置了终端类型为xterm-256color
, 这是一种支持 256 色的终端模拟器类型。这对于需要彩色输出的程序(如 vim、tmux 等)非常重要。
TERM=xterm-256color
的是为了解决远程连接用户时, 键入字符错乱的问题

方法2
ssh 连接时, 使用命令行 -o
选项设置环境变量: ssh -o SetEnv="TERM=xterm-256color" user@hostname
SSH 上传下载
上传
上传本地文件到服务器
格式:scp 要上传的文件路径 用户名@服务器地址:服务器保存路径
例如:把本机 /home/test.txt
文件上传到 192.168.0.101
这台服务器上的 /data/
目录中
1 | scp /home/test.txt root@192.168.0.101:/data/ |
上传目录到服务器
格式:scp -r 要上传的目录 用户名@服务器地址:服务器的保存目录
例如:把 /home
目录上传到服务器的 /data/
目录
1 | scp -r /home root@192.168.0.101:/data/ |
下载
从服务器上下载文件
格式:scp 用户名@服务器地址:要下载的文件路径 保存文件的文件夹路径
例如:把 192.168.0.101
上的 /data/test.txt
的文件下载到 /home
(本地目录)
1 | scp root@192.168.0.101:/data/test.txt /home |
从服务器下载整个目录
格式:scp -r 用户名@服务器地址:要下载的服务器目录 保存下载的目录
例如:把 192.168.0.101
上的 /data
目录下载到 /home
(本地目录)
1 | scp -r root@192.168.0.101:/data /home/ |
注:目标服务器要开启写入权限。
访问服务器的 127.0.0.1:port
服务器 port 允许外部 IP 访问时
假设目标服务器的 ip 地址为: 192.168.32.32
, port 为 8080
则在本地的浏览器地址栏输入: <ip>:<port>
, 这里输入: 192.168.32.32:8080
服务器 port 不允许外部 IP 访问时
将服务器 port 端口转发到本地 port
如将服务器 9090 端口转发到本地 19090.
1
ssh -L 19090:127.0.0.1:9090 <ip>:<port>
地址栏输入:
localhost:19090
或127.0.0.1:19090
设置特定用户的sshd_config
1 | Match User <用户名> |
透过跳板机访问服务器
方法1 (简单却暴力)
很多环境都有一台统一登录跳板机,我们需要先登录跳板机,然后再登录自己的目标机器.登录流程如下
1 | ssh root@跳板机ip |
方法2 (使用端口转发)
首先通过 ssh 连接跳板机, 并设置端口转发, 如将本地端口 2222 通过跳板机 (132.60.171.142) 转发到服务器 (192.168.2.28) 的 22 端口,
~/.ssh/config
配置如下:1
2
3
4
5Host linkrm
HostName 132.60.171.142
User qeuroal
Port 15220
LocalForward 2222 192.168.2.28:22在本地运行命令:
ssh linkrm
通过 ssh 连接本地端口 2222, 访问服务器 (192.168.2.28),
~/.ssh/config
配置如下:1
2
3
4
5Host rm
HostName localhost
User qeuroal
Port 2222
LocalForward 16006 127.0.0.1:6006在本地另开一个终端, 并运行命令
ssh rm
方法3 (使用 ProxyCommand)
有一台机器A,欲与机器C建立SSH连接,但由于隔离限制(比如”存在防火墙”)该SSH连接不能直接建立。ssh命令的”ProxyCommand”选项被设计用来解决以上问题。
通过“ProxyCommand”选项,机器A能够灵活使用任意代理机制与机器C上的SSH Server端口建立连接,接着机器A上的SSH Client再与该连接进行数据交互,从而机器A上的SSH Client与机器C上的SSH Server之间建立了与一般“直接SSH连接”不太一样的“间接SSH连接”。不过由于“间接SSH连接”的透明性,逻辑上可认为机器A上的SSH Client与机器C上的SSH Server建立了“直接SSH连接”。
“直接SSH连接”示意图如图1,“间接SSH连接”示意图如图2。


常使用代理机制有两种,接下来进行介绍。
常使用代理机制
代理机制1
ProxyCommand 选项值形式为 ssh -W C:CPort -l USER -i PRIVATE_KEY -p BPort B
. 原理是 ssh 命令自提供的代理机制,在机器A上另外单独建立与B的SSH连接(使用-l USER -i PRIVATE_KEY -p BPort B
这些参数),该SSH连接的B端侧与机器C上的SSH Server端口(即C:CPort
)建立连接,该SSH连接的A端侧与机器A上的SSH Client(即w最终欲建立’间接SSH连接’在机器A上的SSH Client”)建立连接。
假定A上ssh_config配置文件内容如下:
1 | Host B |
在A上执行 ssh C
命令,发现A与C成功建立SSH连接。根据以上所述,此时在A上应该有两个SSH进程,一个对应于”A与B的SSH连接”,另外一个对应于”A与C的SSH连接”。在A上执行 ps -ef | grep 'ssh'
命令,得到如下结果,得证。
1 | 7851 7689 15:55 S pts/10 ssh C |
代理机制2
“ProxyCommand”选项值形式为”nc -X 5 -x B:BPort C CPort”,原理:利用”nc”命令,在机器A上使用”nc”命令与代理服务器(即”-x B:BPort”,通过”-X 5”参数来指定与代理服务器的通信协议为”SOCKS4/SOCKS5/HTTPS”)建立代理连接,该代理连接的B端侧与机器C上的SSH Server端口(即”C CPort”)建立连接,该代理连接的A端侧与机器A上的SSH Client(即”最终欲建立‘间接SSH连接’在机器A上的SSH Client”)建立连接。
假定A上ssh_config配置文件内容如下:
1 | Host C |
在A上执行ssh C
命令,发现A与C成功建立SSH连接。根据以上所述,此时在A上应该有一个NC进程和一个SSH进程,前者对应于”A与B的代理连接”,后者对应于”A与C的SSH连接”。在A上执行ps -ef | grep -e 'ssh' -e 'nc'
命令,得到如下结果,得证。
1 | $ ps -ef | grep -e 'ssh' -e 'nc' |
ssh命令”端口转发”和”ProxyCommand”选项之间的关系
端口转发包括:本地转发,远端转发和动态转发。其中”本地转发”和”远端转发”属于”静态转发”(因为转发目标端口是固定的)。
ProxyCommand选项能够使用基于”动态转发”的代理机制(在外面封装nc
命令层),而不能使用基于”静态转发”的代理机制。
参考文献:
- man ssh_config
- man ssh
- https://serverfault.com/questions/337120/ssh-via-3rd-machine
- https://www.lainme.com/doku.php/blog/2011/01/%E9%80%8F%E8%BF%87%E4%BB%A3%E7%90%86%E8%BF%9E%E6%8E%A5ssh
- what-is-the-difference-between-ssh-proxycommand-w-nc-exec-nc
FAQ
ssh 连接 remote host identification has changed

找到.ssh
目录,下面有一个known_hosts
文件,删除 ~/.ssh/known_hosts
文件,或者如果你可以判断出known_hosts
中原ssh服务器的公钥,删去那部分,
Double and random letters when typing on a SSH MacOS -> Ubuntu connection
见这里, 设置远程机器的 TERM
变量为 xterm-256color
.