SSH的端口转发--不止连接服务器

本文首发于idc flare站

前言(假设你已经具有SSH连接服务器的基本经验)

众所周知,ssh工具已经内置在macos/Linux系统内,Windows非常容易安装这一工具。

假设你已经懂了SSH连接服务器的基础知识
不懂的话,可以考证暴走砂糖的前文:从零配置一台VPS:图形化配置安全的SSH密钥登录

你懂简笔画的基本原理,现在开始画八骏图

你是一个理工科的牛马研究生,目前面临以下场景,但你只懂SSH,并能通过密钥熟练访问服务器。但你没有服务器的管理员权限,如何解决?

场景一:

[!example]
你有一台IDC服务器,只能访问SSH的22端口,上面部署了mysql服务3306端口,但你需要在本地连接mysql进行调试,并且管理员不同意将mysql的服务端口暴露在公网上。

场景二:

[!example]
你有一台国内服务器,需要访问外网下载数据集,并且没有权限安装clash verge一类的代理软件

场景三:

[!example]
你在国内失联了,但你手里有台国外的服务器,你急需依靠这台外网服务器访问Google搜索论文

SSH的五张面孔

为了解决上面的三个场景,我们重新认识下SSH。

作为日常使用最多的,就是ssh user@ip连接远程服务器。在这一点上,大家习以为常。

实际上,SSH包含(我们这次只介绍第三点,port forwarding功能)

  1. securely 远程命令行访问 (ssh)

  2. 安全文件传输 (sftp 和 scp)

  3. 端口转发 (Port Forwarding) 或 隧道 (Tunneling)

  4. X11 转发 (X11 Forwarding)

  5. 代理转发 (Agent Forwarding)

这次介绍的,就是SSH的核心功能之一:端口转发。

简要来说,端口转发核心参数为-L,-R和-D。

聪明的你已经想到了,这三个参数对应能解决文章一开始提出的三个问题。

参数 功能名称 流量方向 核心用途
-L 本地转发 远程服务 → 本地端口 访问远程内网服务(如数据库)
-R 远程转发 本地服务 → 远程端口 将本地内网服务暴露到公网
-D 动态转发 本地 SOCKS → 远程服务器 创建一个 SOCKS 代理(科学上网)

让我们画完这三匹马(解决这三个场景)

场景一:

你有一台IDC服务器,只能访问SSH的22端口,上面部署了mysql服务3306端口,但你需要在本地连接mysql进行调试,并且管理员不同意将mysql的服务端口暴露在公网上。

我们可以通过-L参数,将远程服务器的3306端口的mysql服务,通过SSH转发到本地的端口,然后在本地访问这个端口

简明扼要:

ssh -L [本地端口]:[目标主机]:[目标端口] [SSH服务器]

[本地端口]:你在本地电脑上打开的端口。

[目标主机]:你最终想访问的主机地址。(注意:这个地址是 从 SSH 服务器的角度 去访问的)。如果服务就在 SSH 服务器上,这里就写 localhost 或 127.0.0.1。

[目标端口]:[目标主机] 上服务的实际端口。

[SSH服务器]:你用来当中转“跳板机”的 SSH 服务器。

以上关于本地/目标,主机/端口的介绍也适用于场景二和场景三的表述,后面不再赘述。

对于场景一来说,bash命令变成了

ssh -L 8888:localhost:3306 user@remote-server

运行上面命令后,你在本地电脑上连接 127.0.0.1:8888,SSH 会自动将所有流量加密转发到 remote-server,然后服务器再替你连接它自己的 localhost:3306。这样mysql 3306端口没有暴露,但你拥有了本地访问远程mysql服务的能力。

场景二:

你有一台国内服务器,需要访问外网下载数据集,并且没有权限安装clash verge一类的代理软件

为了解决这个问题,让我们追加一个假设。你的本地电脑有代理软件+访问外网的能力。那我们能否让这台国内服务器访问外网的服务都通过本地电脑转发呢,这样不需要重复部署clash verge等软件,而且随用随走,优雅极了。

话不多说,端上来吧。

ssh -R 8888:127.0.0.1:7890 user@remote-server

这里假设你本地代理端口是7890,(这个端口取决于你代理软件的设置,请在clash verge软件的设置中找这个端口),运行这条命令,它会将远程服务器的8888端口通过SSH转发到本地的7890端口。

那么,我们现在只要将远程服务器的服务通过自己的8888端口访问,就能走本地代理了。

在服务器上运行:

export HTTP_PROXY="http://127.0.0.1:8888"
export HTTPS_PROXY="http://127.0.0.1:8888"
# 第三条可不设置,一般wget等软件只需要http或https代理即可
export ALL_PROXY="socks5://127.0.0.1:8888"

(如果你不想每次输入export命令,也可以在.bashrc中写入http代理地址)

这样,你可以在国内的远程服务器上也访问外网的数据集了。
更详细的讨论,见L站的三级帖子:https://linux.do/t/topic/942421

场景三:

原理:在本地创建一个 SOCKS 代理服务,所有流向这个代理的流量,都会被转发到远程服务器,再由远程服务器代为访问互联网。

ssh -D 1080 user@remote-server

假设你本地socks代理端口为1080,执行这条命令后,你只需在本地电脑的浏览器或系统设置中,将 SOCKS5 代理设置为 127.0.0.1:1080,你的所有浏览器流量都将通过 remote-server 转发。

这么看SSH翻墙就足够了,为什么还需要vless/vmess/hy2等协议呢?

这就是另一篇文章了,因为SSH协议的特征非常明显,极容易被防火墙发现。因此只建议在极端失联,且有外网访问需求的场景下使用。而且SSH是tcp连接,与udp相比在高峰期更容易降速、丢包,无法解锁流媒体等等。

[!danger]
如果你无视公司it的安全需求,擅自打洞,被抓去坐牢,本文和本文的撰写者概不负责!
上网不涉密,涉密不上网!如果你的环境不允许上网,不要滥用SSH,轻则逮捕,重则坐牢!

111 个赞

谢谢你的教程

2 个赞

这个功能确实巨有用,数据库为了安全起见,一般监听localhost,通过端口转发可以在本地开发终端和服务器之间建立安全隧道连接到数据库。

4 个赞

谢谢,学到不少

2 个赞

感谢分享教程 :folded_hands:

2 个赞

感谢佬教程,学习啦

2 个赞

[!success] 很不错的教程,感谢分享 :tieba_013:

2 个赞

之前用-L转发过数据库端口,确实挺方便的

5 个赞

感谢大佬教程,学习了

1 个赞

感谢 学习一下

2 个赞

实用的 感谢

2 个赞

感谢分享教程,学习一下

2 个赞

长姿势了。有没讲讲代理服务器的搭建,有台服务器装了某个盗版软件,断网了。但是代码又得访问外网下载文件。找了内网其它能上网的服务器搭一个http代理。自己用goproxy的docker没搞定,访问总是有问题。后面找了goproxy的面板项目搞了下,内网倒是没啥问题,但如果外网服务器部署这玩意,怎么做安全呢。有没佬讲讲详细goproxy这个

2 个赞

感谢大佬教程

4 个赞

感谢分享教程 :tieba_013:

3 个赞

佬可以开个新帖问问,我还没用过goproxy哈哈

1 个赞

感谢大佬教程

2 个赞

转发数据库,真香

2 个赞

是的砂糖佬,SSH的加密传输比直接暴露公网数据库端口安全得多。
场景二的端口转发同样优雅,不需要在国内的服务器上装各种代理软件,随用随走。

说得很详细,连接远程服务器的数据库时非常实用

2 个赞