ssh端口转发及其应用

ssh端口转发可以用来灵活地实现对主机的访问, 主要有三种类型: 本地转发, 远程转发, 动态转发

以下例子中的命令都在A主机上执行, 可以认为A就是我们

需要保证你可以使用公钥免密登录跳板机1231

本地转发

基本形式: ssh -L 本机上的端口X:目标主机:目标主机上的端口Y 跳板机用户名@跳板机

其中, -L是"本地转发"的意思. 本命令意为: 访问本机上的X端口就相当于访问目标主机上的Y端口, 中间经由跳板机的转发

模式很像我们常用的代理

image-20220803162508640

以下是一个用于辨析概念的例子:

ssh -L X:localhost:Y B_username@B_host

你肯定会想, "目标主机"参数填了localhost, 这不是闲的吗? 自己访问本地端口需要转发?

错, "目标主机"参数是相对于跳板机来说的, 对于跳板机来说, localhost是跳板机自己. 也就是说该案例中目标主机和跳板机是同一台机器

image-20220803162530836

远程转发

本地转发建立好了以后是我们自己用, 远程转发建立好了以后是给别人用的. 即, 我们充当了"跳板机"的角色

基本形式: ssh -R 使用者的端口X:目标主机:目标主机的端口Y 使用者用户名@使用者主机

其中, -R意为"远程转发", 本命令意为: 对于使用者来说, 访问自己的X端口就相当于访问目标主机的Y端口, 中间经由"我们"这个跳板机转发

image-20220803164344418

你可能会发现, 这个图好像只是把A和B换了个位置, 所以有人把远程转发理解为"本地转发的镜像". 实际上并不是一个简单的对称, 请求方向是由B到A, 但ssh连接方向是反过来的, 并非像本地转发一样两个方向一致.

这个是有实际应用价值的, 例如花生壳等内网穿透服务提供商. 他们允许你把内网主机的某个端口暴露到公网上, 并给你分配一个公网可访问的域名. 在前后端人员进行本机联调时会很方便

例如, 你在自己的电脑上的8080端口跑了一个web服务, 你希望让和你相隔千里的前端同学能访问到你本机(既是A又是C)上的web服务.

你可以选择使用花生壳, 也可以自己搭.

这时你需要一台公网可访问的服务器(B). 然后你在本机上执行: ssh -R 80:localhost:8080 B_username@B_host

这时, B访问自己的80端口就相当于访问你本机上的8080, 任何一个能访问B:80的人也就能访问到你本机上的8080. 前端同学这时候去访问B:80就可以给你本机上的web服务发请求了, 你可以打断点debug......

实战: 内网穿透

  1. 利用docker在本机的8080端口上跑一个nginx, 访问可以看到nginx欢迎页

    image-20220803172616782

  2. 在自己的电脑上执行ssh -R 80:localhost:8080 root@你服务器的ip或域名(这里我的域名是wallnutdaily.com)

  3. 此时, 端口映射其实已经做好了, 我们在服务器上使用curl http://localhost:80可以看到nginx的欢迎页

    image-20220803174640377

  4. 如果这时候你去用浏览器访问的话其实是访问不到的, 因为在远程转发的情况下, OpenSSH服务器默认只接受来自自己的请求.

    要想让其他主机可以访问, 需要:

    1. 保证/etc/ssh/sshd_config中的GatewayPortsAllowTcpForwarding选项均为yes.

    2. 执行sudo service sshd restart重启服务使配置生效.

    3. 退出本机和服务器之间的连接, 然后重新进行ssh端口转发

  5. 再去访问服务器的80端口, 就可以访问到你本机8080端口的nginx

    image-20220803180434909

同理, 你可以用类似的方式把内网服务暴露到外网

动态转发

以下几段引用来自Divergence的文章

动态端口转发可以把本机上运行的SSH客户端转变成一个SOCKS代理服务器;实际上它是一种特殊的本地端口转发,或者说叫它「动态本地端口转发」更科学。这个动态,就动在这种转发不规定目标地址和目标端口,而是去读取应用发起的请求,从请求中获取目标信息。

基本形式: ssh -D 本地端口X 跳板机用户名@跳板机

其中, -D意为动态转发. 现在所有访问本地端口X的流量都会被跳板机转发.

好像很强,但有一个问题:之前使用固定的端口转发时,应用的访问请求都是指向被转发的那个端口X的,但现在应用的访问请求必须指向目标,以指定动态端口转发的目标。可如果不指向端口X,如何让数据走SSH隧道呢?这就要求我们在系统或应用(浏览器等)中设置一个使用SOCKS5协议、服务器为localhost、端口为X的代理,利用代理使请求走端口X。

关于引用中提到的"SOCKS5代理", 举个例子: 我曾经用过一个Chrome插件叫SwitchyOmega, 通过在里面配置一个localhost:X的SOCKS5代理, 可以让Chrome所有的流量都去本地X端口. 进而被跳板机转发

关于动态转发的用途, 举个例子:

我们都知道"代理"是为了让你通过代理服务器访问到你无法直接访问的服务器.

你可能无法直接访问github, 但是位于美国的服务器就可以访问, 如果你拥有一台这样的服务器, 你就可以把它作为跳板机/代理, 从而访问到github与他人交流代码.

如何关闭ssh端口转发

ssh端口转发依赖于ssh连接, 如果你通过exit命令或者关闭会话窗口的方式断开了ssh连接, 端口转发自然就会关闭

文章作者: 白烛魁
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 白烛魁的小站
喜欢就支持一下吧