Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
fundebug
V2EX  ›  Linux

玩转 SSH 端口转发

  •  3
     
  •   fundebug · Sep 12, 2018 · 2535 views
  •   You need to sign in to view this topic
    This topic created in 2882 days ago, the information mentioned may be changed or developed.

    SSH 有三种端口转发模式,本地端口转发(Local Port Forwarding)远程端口转发(Remote Port Forwarding)以及动态端口转发(Dynamic Port Forwarding)。对于本地 /远程端口转发,两者的方向恰好相反。动态端口转发则可以用于科学上网。

    SSH 端口转发也被称作 SSH 隧道(SSH Tunnel),因为它们都是通过 SSH 登陆之后,在SSH 客户端SSH 服务端之间建立了一个隧道,从而进行通信。SSH 隧道是非常安全的,因为 SSH 是通过加密传输数据的(SSH 全称为 Secure Shell)。

    在本文所有示例中,本地主机 A1 为 SSH 客户端,远程云主机 B1 为 SSH 服务端。从 A1 主机通过 SSH 登陆 B1 主机,指定不同的端口转发选项(-L、-R 和-D),即可在 A1 与 B1 之间建立 SSH 隧道,从而进行不同的端口转发。

    本地端口转发

    应用场景:

    远程云主机 B1 运行了一个服务,端口为 3000,本地主机 A1 需要访问这个服务。

    示例为一个简单的 Node.js 服务:

    var http = require('http');
    
    var server = http.createServer(function(request, response)
    {
        response.writeHead(200,
        {
            "Content-Type": "text/plain"
        });
        response.end("Hello Fundebug\n");
    });
    
    server.listen(3000);
    

    假设云主机 B1 的 IP 为103.59.22.17,则该服务的访问地址为:http://103.59.22.17:3000

    为啥需要本地端口转发呢?

    一般来讲,云主机的防火墙默认只打开了 22 端口,如果需要访问 3000 端口的话,需要修改防火墙。为了保证安全,防火墙需要配置允许访问的 IP 地址。但是,本地公忘 IP 通常是网络提供商动态分配的,是不断变化的。这样的话,防火墙配置需要经常修改,就会很麻烦。

    什么是本地端口转发?

    所谓本地端口转发,就是将发送到本地端口的请求,转发到目标端口。这样,就可以通过访问本地端口,来访问目标端口的服务。使用**-L**属性,就可以指定需要转发的端口,语法是这样的:

    -L 本地网卡地址:本地端口:目标地址:目标端口 
    

    通过本地端口转发,可以将发送到本地主机 A1 端口 2000 的请求,转发到远程云主机 B1 的 3000 端口。

    # 在本地主机 A1 登陆远程云主机 B1,并进行本地端口转发
    ssh -L localhost:2000:localhost:3000 [email protected]
    

    这样,在本地主机 A1 上可以通过访问http://localhost:2000来访问远程云主机 B1 上的 Node.js 服务。

    # 在本地主机 A1 访问远程云主机 B1 上的 Node.js 服务
    curl http://localhost:2000
    Hello Fundebug
    

    实际上,-L 选项中的本地网卡地址是可以省略的,这时表示 2000 端口绑定了本地主机 A1 的所有网卡:

    # 在本地主机 A1 登陆远程云主机 B1,并进行本地端口转发。2000 端口绑定本地所有网卡
    ssh -L 2000:localhost:3000 [email protected]
    

    若本地主机 A2 能够访问 A1,则 A2 也可以通过 A1 访问远程远程云主机 B1 上的 Node.js 服务。

    另外,-L 选项中的目标地址也可以是其他主机的地址。假设远程云主机 B2 的局域网 IP 地址为 192.168.59.100 ,则可以这样进行端口转发:

    # 在本地主机 A1 登陆远程云主机 B1,并进行本地端口转发。请求被转发到远程云主机 B2 上
    ssh -L 2000:192.168.59.100:3000 [email protected]
    

    若将 Node.js 服务运行在远程云主机 B2 上,则发送到 A1 主机 2000 端口的请求,都会被转发到 B2 主机上。

    远程端口转发

    应用场景:

    本地主机 A1 运行了一个服务,端口为 3000,远程云主机 B1 需要访问这个服务。

    将前文的 Node.js 服务运行在本地,在本地就可以通过http://localhost:3000访问该服务。

    为啥需要远程端口转发呢?

    通常,本地主机是没有独立的公网 IP 的,它与同一网络中的主机共享一个 IP。没有公网 IP,云主机是无法访问本地主机上的服务的。

    什么是远程端口转发?

    所谓远程端口转发,就是将发送到远程端口的请求,转发到目标端口。这样,就可以通过访问远程端口,来访问目标端口的服务。使用**-R**属性,就可以指定需要转发的端口,语法是这样的:

    -R 远程网卡地址:远程端口:目标地址:目标端口 
    

    这时,通过远程端口转发,可以将发送到远程云主机 B1 端口 2000 的请求,转发到本地主机 A1 端口 3000。

    # 在本地主机 A1 登陆远程云主机 B1,并进行远程端口转发
    ssh -R localhost:2000:localhost:3000 [email protected]
    

    这样,在远程云主机 A1 可以通过访问http://localhost:2000来访问本地主机的服务。

    # 在远程云主机 B1 访问本地主机 A1 上的 Node.js 服务
    curl http://localhost:2000
    Hello Fundebug
    

    同理,远程网卡地址可以省略,目标地址也可以是其他主机地址。假设本地主机 A2 的局域网 IP 地址为 192.168.0.100 。

    # 在本地主机 A1 登陆远程云主机 B1,并进行远程端口转发
    ssh -R 2000:192.168.0.100:3000 [email protected]
    

    若将 Node.js 服务运行在本地主机 A2 上,则发送到远程云主机 A1 端口 2000 的请求,都会被转发到 A2 主机上。

    动态端口转发

    应用场景:

    远程云主机 B1 运行了多个服务,分别使用了不同端口,本地主机 A1 需要访问这些服务。

    为啥需要动态端口转发呢?

    一方面,由于防火墙限制,本地主机 A1 并不能直接访问远程云主机 B1 上的服务,因此需要进行端口转发;另一方面,为每个端口分别创建本地端口转发非常麻烦。

    什么是动态端口转发?

    对于本地端口转发远程端口转发,都存在两个一一对应的端口,分别位于 SSH 的客户端和服务端,而动态端口转发则只是绑定了一个本地端口,而目标地址:目标端口则是不固定的。目标地址:目标端口是由发起的请求决定的,比如,请求地址为192.168.1.100:3000,则通过 SSH 转发的请求地址也是192.168.1.100:3000

    -D 本地网卡地址:本地端口
    

    这时,通过动态端口转发,可以将在本地主机 A1 发起的请求,转发到远程主机 B1,而由 B1 去真正地发起请求。

    # 在本地主机 A1 登陆远程云主机 B1,并进行动态端口转发
    ssh -D localhost:2000 [email protected]
    

    而在本地发起的请求,需要由 Socket 代理(Socket Proxy)转发到 SSH 绑定的 2000 端口。以 Firefox 浏览器为例,配置 Socket 代理需要找到首选项>高级>网络>连接->设置:

    这样的话,Firefox 浏览器发起的请求都会转发到 2000 端口,然后通过 SSH 转发到真正地请求地址。若 Node.js 服务运行在远程云主机 B1 上,则在 Firefox 中访问localhost:3000即可以访问。如果主机 B1 能够访问外网的话,则可以科学上网…...

    链式端口转发

    本地端口转发远程端口转发结合起来使用,可以进行链式转发。假设 A 主机在公司,B 主机在家,C 主机为远程云主机。A 主机上运行了前文的 Node.js 服务,需要在 B 主机上访问该服务。由于 A 和 B 不在同一个网络,且 A 主机没有独立公共 IP 地址,所以无法直接访问服务。

    通过本地端口转发,将发送到 B 主机 3000 端口的请求,转发到远程云主机 C 的 2000 端口。

    # 在 B 主机登陆远程云主机 C,并进行本地端口转发
    ssh -L localhost:3000:localhost:2000 [email protected]
    

    通过远程端口转发,将发送到远程云主机 C 端口 2000 的请求,转发到 A 主机的 3000 端口。

    # 在 A 主机登陆远程云主机 C,并进行远程端口转发
    ssh -R localhost:2000:localhost:3000 [email protected]
    

    这样,在主机 B 可以通过访问http://localhost:3000来访问主机 A 上的服务。

    # 在主机 B 访问主机 A 上的服务
    curl http://localhost:3000
    Hello Fundebug
    

    参考链接

    关于 Fundebug

    Fundebug专注于 JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js 和 Java 实时 BUG 监控。 自从 2016 年双十一正式上线,Fundebug 累计处理了 6 亿+错误事件,得到了 Google、360、金山软件等众多知名用户的认可。欢迎免费试用!

    版权声明:

    转载时请注明作者Fundebug以及本文地址:
    https://blog.fundebug.com/2017/04/24/ssh-port-forwarding/

    10 replies    2018-09-13 00:29:34 +08:00
    Hardrain
        1
    Hardrain  
       Sep 12, 2018   ❤️ 2
    顺带一提,过墙就别用 ssh -D 了,某长城早就能识别你在用 SSH 管理服务器还是跑隧道了
    (当然,SSH/SFTP/SCP 传文件也在一定程度上会被封)
    fundebug
        2
    fundebug  
    OP
       Sep 12, 2018
    @Hardrain 知乎上带"科学上网"已经不让发了: https://zhuanlan.zhihu.com/p/26547381
    vonsy
        3
    vonsy  
       Sep 12, 2018   ❤️ 1
    这个更清晰: https://www.ibm.com/developerworks/cn/linux/l-cn-sshforward/index.html

    最近在用,转发多个端口
    (for macOS)
    ```
    vi ~/.ssh/config
    Host shinbada
    HostName 23.251.124.131
    Port 22
    User root
    PasswordAuthentication yes
    LocalForward 8161 localhost:8161
    LocalForward 61616 localhost:61616
    LocalForward 27017 localhost:27017
    LocalForward 6379 localhost:6379
    LocalForward 2181 localhost:2181
    LocalForward 5432 localhost:5432
    ```
    nilrust
        4
    nilrust  
       Sep 12, 2018
    我记得有个 linux 小工具 nc 一行命令 好像就能解决楼主的需求。。汗
    fundebug
        5
    fundebug  
    OP
       Sep 12, 2018
    @nilrust SSH 也是一条命令啊...
    d0m2o08
        6
    d0m2o08  
       Sep 12, 2018
    原来用 ssh 做内网穿透,后来用了 frp
    Famio
        7
    Famio  
       Sep 12, 2018
    @Hardrain 难怪……我之前阿里云 HKB 的 ECS,平时好好的,一跑 SFTP 就有可能炸,IP 要等 24 小时甚至更久才能恢复。
    感谢解释
    fundebug
        8
    fundebug  
    OP
       Sep 12, 2018
    我们测试服务器只开了 22 端口,跑了 N 个服务,都是通过本地端口转发访问,所以是配置了~/.ssh/config
    flynaj
        9
    flynaj  
       Sep 13, 2018
    端口转发就不要用这种 ssh 了,推荐 https://github.com/ginuerzh/gost 转发代理,支持多级转发(代理链),支持标准 HTTP/HTTPS/HTTP2/SOCKS4(A)/SOCKS5 代理协议 SNI 代理
    fundebug
        10
    fundebug  
    OP
       Sep 13, 2018
    @flynaj 看了一下,确实不错!
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2043 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 00:01 · PVG 08:01 · LAX 17:01 · JFK 20:01
    ♥ Do have faith in what you're doing.