SSH Tunnel

SSH Tunnel解决的问题是让原本不能被访问的端口(通常是因为在不同局域网)可以被访问。

SSH Tunne按监听端口是本地还是远程分为两种命令,格式分别如下:

在本地端口(bind_address:port,指定bind_address是因为本机可能有多个网络接口,缺省在localhost上监听,只接受来自本机的链接,接受任意需指定为*)上开启监听,将收到的数据通过tunnel转发到(hostname:22),在由hostname转发到host:hostport

1
ssh [-L [bind_address:]port:host:hostport] [user@]hostname -p 22

在远程端口(bind_address:port)上开启监听,将收到的数据通过tunnel转发到本机,再由本机转发到(host:hostport)

1
ssh [-R [bind_address:]port:host:hostport] [user@]hostname -p 22

用法举例

假设A要访问D:6379,A、D在不同局域网,最简单方法是在D所在的局域网网关上配置端口映射把D:6379映射到公网,但是很多时候出于某些因素(例如:安全考量、没有配置网关的权限、服务本身配置了只允许本地访问),不希望或无法通过把D:6379映射到公网解决,就可以考虑使用SSH Tunnel。

情形1:

D所在的局域网有主机C的22端口是被映射到公网的,不妨假设映射成了X:30022,X是C和D所在局域网网关在公网的IP地址,那么可以在主机A上通过命令

1
HostA$ ssh -L 36379:D:6379 root@X -p 30022

把D:6379映射成了A:36379,特别情况C和D是同一台主机,D可以写成localhost。

情形2:

A所在的局域网有主机B的22端口是被映射到公网的,不妨假设映射成了X:30022,X是A和B所在局域网网关在公网的IP地址,那么可以在主机D上通过命令

1
HostD$ ssh -g -R 36379:D:6379 root@X -p 30022

把D:6379映射成了B:36379,而A和B是同一局域网的,因此A可以访问到B:36379。

按理说上面的命令加了-g参数,B:36379应该被绑定在0.0.0.0:36379,但实际测试发现绑定在了127.0.0.1:36379,导致无法在A上访问,原因暂时未知(确定不是因为redis配置了保护模式),不过可以通过类似情形1的方式再把B:36379映射成A:36379,这样A就可以访问了。

1
HostA$ ssh -L 36379:localhost:36379 root@B

情形3:

A和D所在局域网都没有主机的ssh端口被映射到公网,但我有另一台具有公网IP的主机,不妨假设为X开启着22端口,类似情形2通过命令

1
HostD$ ssh -R 36379:D:6379 root@X
1
HostA$ ssh -L 46379:localhost:36379 root@X

之后让A访问A:46379即可。

通过命令建立SSH Tunnel之后会登录到作为跳板的机器,通常我们是不需要使用这个控制台的,因此可以通过-f参数让ssh在后台运行,需要关闭tunnel时直接杀死进程。

常用选项

C表示压缩数据传输

f表示后台用户验证,这个选项很有用,没有shell的不可登陆账号也能使用.

N表示不执行脚本或命令

g表示允许远程主机连接转发端口

例如情形1中的命令可以写成

1
ssh -CfNg -L 36379:D:6379 root@X -p 30022

通过

1
ps -ef|grep ssh -CfNg

可以查看打开的tunnel。

保持ssh连接(防止超时自动断开)

在客户端设置/etc/ssh/ssh_config

1
2
3
Host *
ServerAliveInterval 300
ServerAliveCountMax 5

使用autossh

当网络不稳定时还可以使用autossh工具来帮助自动重连。

只需要把ssh命令中的ssh换成autossh -M

例如情形1中的命令可以写成

1
autossh -M 46379 -CfNg -L 36379:D:6379 root@X -p 30022

-M 后面的端口号是用来监视连接状态的,允许指定为0,这里指定为0是否可以正常监视重连以及如何监视有待研究。

另外如果autossh带了-f参数则不支持输入密码,可以配合expect脚本自动输入密码或者通过SSH密钥登录,更推荐使用密钥方式。

生成密钥

1
ssh-keygen -t rsa

会询问将密钥放在何处,默认即可。然后是输入密码,留空(否则你登录不仅需要私钥还要输入密码)。

完成后在~/.ssh目录下会生成另个文件id_rsa和id_rsa.pub,一个私钥一个公钥。

然后将公钥写入远程用户家目录下的~/.ssh/authorized_keys文件中,通过ssh-copy-id命令可以帮我们实现这一操作(相当于把公钥复制过去再追加到authorized_keys的尾部)

1
ssh-copy-id [-p SSH端口默认22] [user@]hostname

参考:

https://blog.csdn.net/wxqee/article/details/49234595

https://www.cnblogs.com/youxin/p/5220916.html

https://blog.csdn.net/wesleyflagon/article/details/85304336