V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
fundebug
V2EX  ›  Linux

玩转 SSH 端口转发

  •  3
     
  •   fundebug · 2018-09-12 10:44:07 +08:00 · 1571 次点击
    这是一个创建于 2266 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 条回复    2018-09-13 00:29:34 +08:00
    Hardrain
        1
    Hardrain  
       2018-09-12 13:12:43 +08:00   ❤️ 2
    顺带一提,过墙就别用 ssh -D 了,某长城早就能识别你在用 SSH 管理服务器还是跑隧道了
    (当然,SSH/SFTP/SCP 传文件也在一定程度上会被封)
    fundebug
        2
    fundebug  
    OP
       2018-09-12 14:20:38 +08:00
    @Hardrain 知乎上带"科学上网"已经不让发了: https://zhuanlan.zhihu.com/p/26547381
    vonsy
        3
    vonsy  
       2018-09-12 14:21:21 +08:00   ❤️ 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  
       2018-09-12 15:38:45 +08:00
    我记得有个 linux 小工具 nc 一行命令 好像就能解决楼主的需求。。汗
    fundebug
        5
    fundebug  
    OP
       2018-09-12 16:54:39 +08:00
    @nilrust SSH 也是一条命令啊...
    d0m2o08
        6
    d0m2o08  
       2018-09-12 16:57:14 +08:00
    原来用 ssh 做内网穿透,后来用了 frp
    Famio
        7
    Famio  
       2018-09-12 17:01:07 +08:00
    @Hardrain 难怪……我之前阿里云 HKB 的 ECS,平时好好的,一跑 SFTP 就有可能炸,IP 要等 24 小时甚至更久才能恢复。
    感谢解释
    fundebug
        8
    fundebug  
    OP
       2018-09-12 17:32:08 +08:00
    我们测试服务器只开了 22 端口,跑了 N 个服务,都是通过本地端口转发访问,所以是配置了~/.ssh/config
    flynaj
        9
    flynaj  
       2018-09-13 00:26:36 +08:00
    端口转发就不要用这种 ssh 了,推荐 https://github.com/ginuerzh/gost 转发代理,支持多级转发(代理链),支持标准 HTTP/HTTPS/HTTP2/SOCKS4(A)/SOCKS5 代理协议 SNI 代理
    fundebug
        10
    fundebug  
    OP
       2018-09-13 00:29:34 +08:00
    @flynaj 看了一下,确实不错!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1057 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:23 · PVG 03:23 · LAX 11:23 · JFK 14:23
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.