SSH反向代理配合Nginx实现内网网址域名访问

有关内网穿透的第二篇文章,上一篇参见VScode 使用跳板机访问

SSH 反向代理配合 Nginx 实现内网网址域名访问

个人需求是在外网访问实验室内部搭建(使用校园网)的课程主页,作者本人并不是网络安全相关的,仅做一次 SSH 反代的学习记录。

有关 SSH 的三种代理功能(-L/-R/-D)

详细可以参考知乎上这篇文章SSH 命令的三种代理功能,之前只熟悉-D参数做 SOCKS 通道,并不十分理解正向、反向代理的区别,这次算是补补课。

正向代理

ssh -L,又被称为本地代理,实际上是在本地启动端口,把本地端口的数据转发至远端。ssh client 在本地。常用来做端口映射(到已知 ip 的其他机器)或是跳板机映射到其他机器。

  1. 端口映射

    HostB 上启动一个 PortB 端口,映射到 HostC:PortC 上,在 HostB 上运行下面指令:

    1
    ssh -L 0.0.0.0:PortB:HostC:PortC user@HostC

    此时访问 HostB:PortB 相当于访问 HostC:PortC(和 iptable 的 port-forwarding 类似),这里 0.0.0.0 表示任意 ip 地址都可以访问,而如果配置 127.0.0.1 则只转发本地。

  2. 跳板访问

    HostA 上启动一个 PortA 端口,通过 HostB 转发到 HostC:PortC 上,在 HostA 上运行:

    1
    ssh -L 0.0.0:PortA:HostC:PortC user@HostB

    这时访问 HostA:PortA 相当于访问 HostC:PortC

    两种用法的区别是,第一种用法本地到跳板机 HostB 的数据是明文的,而第二种用法一般本地就是 HostA,访问本地的 PortA,数据被 ssh 加密传输给 HostB 又转发给 HostC:PortC

反向代理

反向代理,就是让远端启动端口,对远端该端口的数据都转发到本地。

反向代理对于所在机器位于内网且无固定公网 ip 的时候很有用。

HostA 将自己可以访问的 HostB:PortB 暴露给外网服务器 HostC:PortC,在 HostA 上运行:

1
ssh -R HostC:PortC:HostB:PortB user@HostC

可以在 HostC 上使用lsof -i:PortC查看端口使用,我们会发现一个 sshd 命令监听本地 PortC,这时 HostC 就会将该端口请求转发给 HostA 处理。链接 HostC:PortC 就相当于链接 HostB:PortB。使用时需要修改 HostC 的 ssh 配置/etc/ssh/sshd_config,添加如下指令并systemctl sshd restart重启服务:

1
GatewayPorts yes

相当于内网穿透,比如 HostA 和 HostB 是同一个内网下两台机器,网站在 HostB 上,HostA 可以访问但是 HostC 无法访问,HostC 是外网跳板机,不能直接访问 HostA 但是 HostA 可以访问 HostC。

那么通过在内网 HostA 上运行ssh -R就是告诉 HostC:“创建 PortC 端口监听,把该端口数据都转发给我(HostA),我会在转发给同一内网下的 HostB:PortB。”同内网下的 HostA/HostB 也可以是同一台机器,换句话说就是“内网 HostA 把自己可以访问的端口暴露给了外网 HostC

一直没有理清反向代理与正向代理区别在哪里。我的理解,首先是代理对象不同,本地代理与请求方在一侧,转发至代理的端口。而反向代理,代理的是服务器,可以将提供服务的机器的实际 ip 隐藏起来。因为与远程服务器在一侧,将“远处”(此时对应的是请求方)访问端口的请求都转发到本地。

动态转发

使用ssh -D会在本地启动一个 SOCKS5 代理服务器,构建的 SOCKS5 隧道可以让很多服务使用,本地 SOCKS5 代理的数据会通过 ssh 链接先发给 HostB,然后再从 HostB 转发给远程主机。

比如在 HostA 上启动:

1
ssh -D 1080 user@HostB

这时候 A 可以利用这个 SOCKS5 代理服务器访问一些原本不能被访问的地址,比如:

1
curl -x socks5://127.0.0.1:1080 www.google.com

或者

1
curl --socks5-hostname 127.0.0.1:1080 www.google.com

我在后面的实验中也想使用,不过 nginx 里面配置的 proxy 仅支持 http 协议,用 privoxy 过滤得到 http 代理的端口,但似乎方向还是反了。又去重新温习了反向代理的含义。

使用优化

附加参数

使用时建议加上-fCqTnN参数,各参数含义如下:

-f后台执行,-C压缩所有数据,-q静默模式,-T禁止分配伪终端,-n关闭标准输入,-N不执行 ssh 命令。

链接稳定性

实际案例

HostA:放在阿里云上的公网服务器 HostB:内网个人服务器(有控制权限) HostC:内网实验室服务器(只可访问资源)

现在我希望能通过外界(公网上的各个终端)通过一指定域名,访问 HostC 上指定资源,示意图如下:

SSH 反代配置

Nginx 配置

在阿里云的HostA本来维护有个人博客,在Nginx配置目录/etc/nginx/conf.d/下编写新的proxy.conf


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!