【Linux】内网机器通过跳板机科学上网
上回书说道,我们通过 SSH 隧道 + gost 的组合,成功让内网机器A借助跳板机B访问了外网。但访问的是普通外网,遇到需要科学上网的场景(比如访问 Google、GitHub 下载资源等)还是会失败。本文在上篇基础上,进一步让机器A借助机器B上已有的代理服务实现科学上网。
前置条件: 本文方案依赖机器B上已配置好科学上网代理。如果机器B还没有配置,请先参考:【Linux】使用 Clash 科学上网
环境信息:
- 机器A:内网机器,无外网,无 root 权限
- 机器B(跳板机):
172.22.26.185,用户名tianlejin,本地 7890 端口运行着科学上网代理(HTTP 协议)
整体思路
两种模式对应两条链路,需要同时保持三个后台进程运行:
1 | 普通外网:机器A → gost(8118) → SSH隧道(1080, SOCKS5) → 机器B → 外网 |
1 | 科学上网:机器A → SSH隧道(7891) → 机器B的7890代理 → 科学上网 |
通过切换环境变量来选择走哪条链路,无需重启任何进程。
为什么普通外网需要 gost 而科学上网不需要? SSH
-D建立的是 SOCKS5 隧道,大多数工具不认 SOCKS5,需要 gost 转成 HTTP。而机器B的 7890 本身就是 HTTP 代理,直接映射过来就能用,不需要 gost 再转一次。
第一步:确认机器B上 7890 端口的代理协议
不同的科学上网工具(Clash、V2Ray 等)监听的协议可能不同,先确认是 SOCKS5 还是 HTTP:
1 | # 测试 SOCKS5 |
返回 200 或 302 说明协议正确(Google 返回 302 是正常的重定向行为,不是失败)。返回 000 说明协议不对,换另一个试。
本文场景中 7890 是 HTTP 代理协议。
第二步:启动三个后台进程
1 | # 1. 普通外网隧道(SOCKS5) |
验证三个进程都在跑:
1 | ps aux | grep "ssh -D 1080" | grep -v grep |
第三步:配置切换函数
创建脚本文件:
1 | mkdir -p ~/bash_scripts |
然后在 ~/.bashrc 末尾添加一行 source:
1 | echo 'source ~/bash_scripts/proxy.sh' >> ~/.bashrc |
执行生效:
1 | source ~/.bashrc |
之后随时切换:
1 | proxy_normal # 切换到普通外网 |
验证
1 | # 验证普通外网 |
用完清理
1 | pkill -f "ssh -D 1080" |
下次打开新终端时
三个后台进程只要没有被 kill 或机器重启,跨终端共享,不需要重复启动。每次新终端只需要检查进程是否存活,然后设置环境变量即可。
第一步:检查并恢复后台进程
1 | # 检查普通外网隧道 |
第二步:选择模式(每个新终端必须执行)
1 | proxy_normal # 或 proxy_vpn |
Q&A
Q:为什么普通外网需要 gost 而科学上网不需要?
SSH -D 建立的是 SOCKS5 隧道,但大多数工具只认 HTTP 代理格式的环境变量,不认 SOCKS5,所以需要 gost 在中间做一次协议转换。而机器B的 7890 本身就是 HTTP 代理,通过 SSH -L 映射到本地后可以直接使用,不需要 gost 再转一次。
Q:SSH 为什么不能直接建立 HTTP 隧道,只能建立 SOCKS5?
SSH 协议设计上只支持 -L(静态端口转发)和 -D(动态 SOCKS5 转发)两种模式,没有 HTTP 代理模式。原因是 SOCKS5 比 HTTP 代理更底层、更简单,只需要把数据从A搬到B,不需要理解数据内容。而 HTTP 代理需要解析请求头、处理 CONNECT 方法、理解 HTTP 语义,实现复杂得多。SSH 的核心职责是安全的远程登录和文件传输,内置一个完整的 HTTP 代理实现没有必要,所以干脆没做。这也是为什么需要 gost 来补这个缺口。
扩展阅读
- 【Linux】使用 Clash 科学上网:https://tianlejin.top/blog/Linux_Clash/
- 【Linux】内网机器通过跳板机访问外网:https://tianlejin.top/blog/linux_proxy_via_jumphost/
作者:Claude Sonnet 4.6