ssh 反向代理
ssh反向代理
1 基本操作
设 A主机 内网主机 192.168.37.132 sshd 服务开在22端口
B主机 外网主机 122.10.10.10 sshd 服务开在22端口
在A主机使用如下命令
ssh -NR 1234:localhost:22 [email protected] -p 22
指派B的1234端口映射到自己的22端口上,B的ssh开在22上(-p 22)
可简写为
ssh -NR 1234:localhost:22 [email protected]
-R remote_free_port:localhost:local_ssh_port
指派远程上的 remote_free_port 到本地地址上的 local_ssh_port上
建立远程SSH隧道(隧道服务端建立监听端口)
将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口.
-N 不执行远程指令,否则会出现一个B主机的shell,可以执行命令
参数详解:https://www.jianshu.com/p/5865c9c39acc
A主机执行该命令的意思是将B主机的1234端口绑定到A主机的22端口
就是说B主机1234端口接收到的数据都会转发给A主机的22端口
这样我们就可以在B主机使用命令:
ss -ant
可以看到B主机的127.0.0.1:1234端口已经占用了
说明ssh反向连接成功了
接下来在B主机使用如下命令即可连接处于内网的A主机
ssh user@localhost -p 1234
2 免密码
另外我们可以使用ssh-copy-id 命令实现公匙登录,每次就不用输入密码了。
A,B主机都各自将对方的id_rsa.pub加入自己的authorized_keys,这样A主机反向连接不需要输入密码,B主机连接A也不需要输入密码了。
不懂ssh-copy-id的话可以看看我的另一篇关于ssh免密登录的博客
3 修改sshd_config使得允许B公网主机作为网关
基本的操作后你的使用方法是:
ssh到公网服务器B,有了一个B的shell,然后用这个B的shell,ssh本地的1234端口,到A。
那么使用的方法如下:
ssh [email protected] -p 22
ssh root@localhost -p 1234
但是可以将/etc/ssh/sshd_config配置文件中的GatewayPorts属性改为yes。
GatewayPorts:
是否允许远程主机连接本地的转发端口。默认值是"no"。
sshd(8) 默认将远程端口转发绑定到loopback地址。这样将阻止其它远程主机连接到转发端口。
GatewayPorts 指令可以让 sshd 将远程端口转发绑定到非loopback地址,这样就可以允许远程主机连接了。
"no"表示仅允许本地连接,"yes"表示强制将远程端口转发绑定到统配地址(wildcard address),
这样一来,你就可以直接去连接B的1234端口了,而不用先进入B,获得一个B的shell。
直接像下面这样使用:
ssh [email protected] -p 1234
4 配置config为服务器取别名,实现tcp持久化连接
同时,配置~/.ssh/config会使连接更加简单。
vim ~/.ssh/config
然后写入你需要的内容,例如:
Host *
ControlMaster auto
ControlPath ~/.ssh/multiplex/%r@%h:%p
ControlPersist 4h
ServerAliveInterval 6
ServerAliveCountMax 200
Compression yes
Host github.com
Hostname ssh.github.com
User "*************@qq.com"
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa
Port 443
Host vps
Hostname **.**.**.**
User root
Port 1289
IdentityFile ~/.ssh/id_rsa
Host shiyanshi
Hostname **.**.**.**
User root
Port 8444
IdentityFile ~/.ssh/id_rsa
上述配置的意思大致解释如下:
对于所有Host,就是主机,
自动使用tcp多路复用
控制tcp的临时文件放在multiplex文件夹下(需要自己创建)
一个tcp连接的持续时间是4小时,4小时内不管啥时候重连,都是用的这个tcp,可能会快一点吧,哈哈
每6秒查看服务器是否还活着,保存连接
连续200次查看
传输的数据确定压缩
对于github.com
连接的主机的名字是ssh.github.com
user是*************@qq.com
使用id_rsa这个私匙
端口是443
对于vps
hostname(即ip) 是**.**.**.**
连接过去用的用户是 root
对面的端口是1289
...
有了这个,你根据你的情况配置好config后,就可以用别名来连接了。
如:
ssh vps
5 使用脚本帮助断开重连
上述config的配置也包含了持久化操作,可以保证在不出现意外断开情况时,保证连接通畅,但是如果出现断网,等意外断线情况时如何重连呢?
有的博客说是使用autossh帮助我们掉线重连,但是经我自己测试,发现这个东西并没有什么卵用,配置文件的说明也找不到,并不能帮助我们断线重连。
这个不靠谱的autossh的参考链接:https://zhuanlan.zhihu.com/p/112227542
有兴趣可以看看,反正我感觉是没啥卵用。
靠谱的方法还是自己写个shell脚本。
第一步:公网服务器配置
修改公网主机 B 的 SSH 配置文件/etc/ssh/sshd_config
GatewayPorts yes
这样可以把监听的端口绑定到任意 IP 0.0.0.0 上,否则只有本机 127.0.0.1 可以访问。
重启 sshd 服务
sudo service sshd restart
第二步:断线免密登录自动重连
ssh 反向链接会因为超时而关闭,如果关闭了那从外网连通内网的通道就无法维持,为此我们需要结合免密码登录及 AutoSSH 来提供稳定的 ssh 反向代理隧道。
1、在内网主机 A 上产生公钥和私钥
ssh-keygen
然后按三次回车执行默认选项生成公钥和私钥。会生成密钥文件和私钥文件 id_rsa,id_rsa.pub 或 id_dsa,id_dsa.pub
2、拷贝秘钥 在内网主机 A 上继续执行如下命令,将内网主机 A 上的秘钥文件 copy 到公网主机 B 中。
ssh-copy-id username@ip
其中“username”是公网主机 B 的用户名,ip 为公网主机 B 的 ip,然后按照提示输入公网主机 B 的密码就完成了。
第三步:写脚本实现断线重连
思路是使用ss命令检查我们的反向代理是否存在,如果不存在说明断开了,那么就重连
样例:
rproxy.sh:
#!/bin/bash
while true
do
ssans=`ss -ant | grep "192.168.42.131:22" | wc -l`
if [ $ssans == 0 ]
then
ssh -fNR 8765:localhost:22 [email protected] -p 22 >/dev/null 2>&1
fi
sleep 60
done
基本说明:
首先用变量ssans接住检查结果。
然后如果检查结果为0,说明连接断开了,那么就去连,并将输出和错误信息重定向到/dev/null中
第四步:开启自启动
方法一,直接修改rc.local
vi /etc/rc.d/rc.local
添加内容:
(bash rproxy.sh &)
chmod 755 /etc/rc.d/rc.local
方法二,添加服务
把上边的rproxy.sh脚本放在/etc/rproxy这里(哪里都行,你对应修改下面脚本就好)
去/etc/init.d/下创建文件rproxy(随便叫啥名字都行,不一定是这个)
#!/bin/bash
### BEGIN INIT INFO
# Provides: rproxy
# Required-Start: $remote_fs $network
# Required-Stop: $remote_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: rproxy
### END INIT INFO
case "$1" in
start)
ps -aux | grep "rproxy.sh" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
ps -aux | grep "xxx.xxx.xxx.xxx" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
(bash /etc/rproxy/rproxy.sh > /dev/null 2>&1 &)
;;
stop)
ps -aux | grep "rproxy.sh" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
ps -aux | grep "xxx.xxx.xxx.xxx" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
;;
restart)
ps -aux | grep "rproxy.sh" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
ps -aux | grep "xxx.xxx.xxx.xxx" | awk '{print $2}' | xargs kill -9 > /dev/null 2>&1
(bash /etc/rproxy/rproxy.sh > /dev/null 2>&1 &)
;;
esac
exit 0
修改权限
chmod 755 rproxy
开启服务
update-rc.d rproxy defaults
这样以来他就实现了开机自启,并且你可以想服务一样操作了
service rproxy start
service rproxy stop
service rproxy restart