1. 前言

1.1. 更新历史

更新时间 更新内容
2020-09-13 初稿
2020-09-18 启用密钥登录; 使用ssh_config;

最近新装了一台ubuntu, 照例又是配置各种环境. 在配置ssh的时候遇到很多操作都不记得具体步骤, 又得从网上查怎么操作. 因此觉得有必要记录一下ssh的一些常用操作, 方便下次再配置ssh时进行查阅.

2. 正文

2.1. 生成密钥对

ssh-keygen

私钥路径: ~/.ssh/id_rsa 公钥路径: ~/.ssh/id_rsa.pub

2.2. 添加公钥

cat ./id_rsa.pub >> ~/.ssh/authorized_keys

2.3. 禁用密码登录&&启用密钥登录

参考[2]

# 编辑 sshd_config 文件 
vim /etc/ssh/sshd_config

# 禁用密码验证 
PasswordAuthentication no
# 启用密钥验证 
RSAAuthentication yes
PubkeyAuthentication yes
# 指定公钥数据库文件 
AuthorsizedKeysFile .ssh/authorized_keys

2.4. 使用跳板机登录目标服务器

一种方法是使用ProxyCommand参考[3]. 不过实际使用的话并不推荐, 比较麻烦.

可以结合 ssh -L 端口转发功能. 比如有三台主机: A, B, C. 其对应ip为 ip_A, ip_B, ip_C. A可以访问B, B可以访问C, 但是A不能直接访问C.

我们想要在A上用ssh登录C. 那么可以进行如下操作:

A上执行如下命令

ssh -L 2333:ip_C:22 root@ip_B
# 需要配置密钥登录`B`或输入主机``上`root`用户的密码

此时在A上访问 127.0.0.1:2333就等价于访问ip_C:22.

所以在A上执行如下命令即可登录C

ssh root@127.0.0.1 -p 2333
# 需要配置密钥登录`C`或输入主机`C`上`root`用户的密码

2.5. ssh_config

官方文档参考[4]

说来惭愧, 用了ssh这么久一直不知道有ssh_config这个东西. 还是前不久查vscoderemote-ssh插件的文档时才无意间知道有这么个东西.

通过配置ssh_config可以免去每次使用ssh/sftp时输入用户名, ip, 端口等操作.

配置文件通常位于 ~/.ssh/ssh_config, 配置文件具体怎么写我们就用上一节的2.4. 使用跳板机登录目标服务器举个例子.

在配置好代理之后我们连接主机C需要通过如下命令:

ssh root@127.0.0.1 -p 2333

我们可以在 ~/.ssh/ssh_config 添加如下内容

Host host_C
    HostName 127.0.0.1
    User root
    Port 2333

之后再想要连接主机C只需要执行如下命令即可

ssh host_C

想要用sftp传文件的话也可以用类似的命令

sftp host_C

ssh_config支持配置多个主机.

Host host_C
    HostName 127.0.0.1
    User root
    Port 2333
Host host_B
    HostName ip_B
    User root
    Port 22

ssh_config甚至还支持域名通配符等操作, 这儿就不再细说, 可以参考官方文档[4].

2.6. 端口转发功能

2.6.1. ssh -L

设有三台主机: A, B, C. 其对应ip为 ip_A, ip_B, ip_C.

如果在主机A上执行:

ssh -L 1234:ip_C:5678 root@ip_B

那么访问主机A1234端口就等价于访问主机 C5678 端口(两者直接会通过主机B作为中介建立一个隧道)

这种转发方式的应用场景为: A可以访问B, B可以访问C, 但是A不能直接访问C.

2.6.2. ssh -R

设有两台主机: A, B. 其对应ip为 ip_A, ip_B.

如果在主机A上执行:

ssh -R 1234:127.0.0.1:5678 root@ip_B

注意: 这儿一定要是root用户

那么此时在B上访问 localhost:1234 就等价于访问 A5678 端口.

若想实现可以通过ip_B:1234访问主机A127.0.0.1:5678还需要配置一层代理, 具体方式后面关于内网穿透的章节会说

这种转发方式的应用场景为: A是一个内网主机, B 是一个公网主机. 用户想随时随地可以访问A, 就需要做一个反向代理实现内网穿透, 使得用户可以通过 B 作为中介访问 A.

2.6.3. ssh -D

设有两台主机: A, B. 其对应ip为 ip_A, ip_B.

如果在主机A上执行:

ssh -D 1234 root@ip_B

那么主机Alocalhost:1234 就会有一个socks代理, 所有走这个代理的流量都会通过主机B转发出去.

这种转发方式的应用场景为: 懒得安装/启动socks代理软件客户端.

2.7. autossh + xinetd 实现内网穿透

设有两台主机: A, B. 其对应ip为 ip_A, ip_B, A是一个内网主机, B 是一个公网主机. 我们的需求是随时随地可以访问A上的资源.

我们可以使用前面提到的 ssh -R 转发方式, 在A上执行:

ssh -R 1234:127.0.0.1:22 root@ip_B

注意: 22是ssh server的端口

此时我们若在B上执行

ssh root@127.0.0.1 -p 1234

并输入Aroot用户的密码, 我们就可以成功登录主机A.

但是B127.0.0.1只有自己能访问, 别的主机想访问B上的1234端口只能通过ip_B进行访问, 所以我们这儿可以在B上启动一个转发服务: 将ip_B:5678来的流量转发至127.0.0.1:1234(两个端口建议不相同, 避免可能的冲突). 我这儿用的是 xinetd:

$ sudo apt install xinetd
$ cat ./proxy
service http-switch
{
 disable = no
 type = UNLISTED
 socket_type = stream
 protocol = tcp
 wait = no
 redirect = 127.0.0.1 1234
 bind = 0.0.0.0
 port = 5678
 user = nobody
}
$ cp ./proxy /etc/xinetd.d/
$ sudo /etc/init.d/xinetd restart
[ ok ] Restarting xinetd (via systemctl): xinetd.service.

此时我们在任何一台可以访问外网的主机上执行如下命令:

ssh root@ip_B -p 5678

并输入Aroot用户的密码, 就可以登录上A了.

autosshssh功能差不多, 但是多一个自动断线重连功能, 因此搭建内网穿透服务的时候稳定性更好.

使用命令和ssh类似:

$ sudo apt install autossh
$ autossh -M 7788 -NfR 1234:127.0.0.1:22 root@ip_B

-M 参数声明一个没有被占用的端口, autossh 会使用这个端口检测连接是否存在, 如果断掉的话就需要进行重连操作.

-N-f 参数是让 autossh 不打印信息, 在后台运行. (ssh同样可以加上这两个参数.)

3. 结语

不会用ssh的网管不是好程序员

4. 参考

  1. SSH 反向隧道 内网穿透,AutoSSH自动重连
  2. SSH 使用密钥登录并禁止口令登录实践
  3. SSH ProxyCommand example: Going through one host to reach another server
  4. ssh_config(5) Linux manual page