比方说要把当前机器的8789端口映射到服务器的6100端口:
ssh -R 6100:localhost:8789 服务器IP |
然后登录上服务器,就能通过6100端口连上这台机器了:
ssh localhost 6100 |
要允许所有IP都能通过服务器的6100端口连接上这台机器,需要在服务器上的/etc/ssh/sshd_config
里加上
GatewayPorts yes |
然后重启sshd
:
sudo systemctl restart sshd |
(没试过systemctl reload
可不可以)
改这个配置的原因见man ssh
:
-R [bind_address:]port:host:hostport |
一定要看英文的manual page,中文的好像很久没有更新了,不全。
然后再跑ssh -R 6100:localhost:8789 服务器IP
,服务器的6100
端口就可以接受任何IP的连接请求了。注意已有的ssh -R
连接好像仍然看不到GatewayPorts yes
,要先把原来的ssh -R
的连接断开才行(在客户端ctrl+c
或者采用后面描述的方法在服务器端把监听这个端口的sshd
进程杀掉)。
¶ autossh
直接用ssh的话,断开连接之后并不会重连。所以使用autossh,在连接断开后重连。网上的教程通常是使用monitor
port监测连接是否正常的,但是这样要在服务器上额外占用一个端口。其实man autossh
已经提示我们可以用SSH自带的ServerAliveInterval
和ServerAliveCountMax
来检测连接是否正常,而且这可能是更好的方法:
-M port[:echo_port] |
autossh -M 0 -R 6100:localhost:8789 服务器IP -o ServerAliveInterval=60 |
有些发行版比如Debian可以省略掉-M 0
。
可以在服务器端查一下有没有额外的monitor port:
sudo lsof -i |
¶ 后台静默运行
-f
: 要求 ssh 在执行命令前退至后台。
-N
: 不执行远程命令. 用于转发端口. (仅限协议第二版)。
所以可以:
autossh -M 0 -fNR 6100:localhost:8789 服务器IP -o ServerAliveInterval=60 |
ssh -fNR 6100:localhost:8789 服务器IP -o ServerAliveInterval=60 |
¶ 开机自启
可以用supervisor设置开机自启,配置文件:
[program:ssh-intranet-penetration] |
注意这里没有-f
。这里用的是ssh
而不是autossh
,并且加上了-o ExitOnForwardFailure=yes
,这样连接中断或者出现其他错误之后supervisor
会自动重试。
¶ 客户端崩溃后重新连接
客户端崩溃后,重新连接时可能会出现这个错误:
Warning: remote port forwarding failed for listen port 端口号 |
这时可以在服务器上查找监听这个端口的进程:
sudo lsof -i:端口号 |
这个进程是sshd fork出来的进程,杀掉它不影响其他端口的监听,而且可以把这个端口释放出来:
kill 进程号 |
然后再在客户端上重新构建反向隧道即可。