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 | Host * |
使用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