背景

在实际工作中,经常会遇到这样的场景:手头有一台内网机器(比如 A100 训练节点),它无法直接访问外网,但有另一台机器既能访问内网又能访问外网,可以作为跳板。本文记录如何在没有 root 权限的情况下,让内网机器的当前终端会话通过跳板机访问外网。

环境信息:

  • 机器A:内网机器,无外网,无 root 权限
  • 机器B(跳板机):172.22.26.185,用户名 tianlejin,有外网访问能力

整体思路

大多数工具只认 HTTP 代理,不支持 SOCKS5。因此用 SSH 建立 SOCKS5 隧道后,还需要用 gost 将其转为 HTTP 代理,再统一让所有工具走 HTTP 代理:

1
2
应用 → HTTP代理(gost) → SOCKS5隧道(SSH) → 机器B → 外网
127.0.0.1:8118 127.0.0.1:1080

第一步:建立 SSH SOCKS5 隧道

检查端口是否被占用

1
ss -tlnp | grep 1080

无输出则端口空闲,若被占用换 1081、1082 等端口再查。

建立隧道

1
ssh -D 1080 -N -f [email protected]

参数说明:

  • -D 1080:在本地 1080 端口开启 SOCKS5 代理
  • -N:不执行远程命令,只做端口转发
  • -f:后台运行

第二步:安装 gost

下载 gost

首先查看机器A的系统架构,确认需要下载哪个版本:

1
uname -m

架构与安装包后缀对应关系:

uname -m 输出 对应包后缀
x86_64 amd64
aarch64 arm64

前往 https://github.com/go-gost/gost/releases 找到对应系统和架构的压缩包下载,然后拷贝到机器A上

上传后在机器A上解压:

1
2
tar -xzf ~/software/gost_3.2.6_linux_amd64.tar.gz
chmod +x ~/software/gost

启动 gost,将 SOCKS5 转为 HTTP 代理

1
2
3
4
5
# 先检查 8118 端口是否被占用
ss -tlnp | grep 8118

# 后台启动,日志静默
~/software/gost -L http://:8118 -F socks5://127.0.0.1:1080 > /dev/null 2>&1 &

设置 HTTP 代理环境变量

1
2
3
4
5
export ALL_PROXY=http://127.0.0.1:8118
export http_proxy=http://127.0.0.1:8118
export https_proxy=http://127.0.0.1:8118
export HTTP_PROXY=http://127.0.0.1:8118
export HTTPS_PROXY=http://127.0.0.1:8118

验证 gost 是否生效

  • ping 命令无法测试代理,因为 ping 使用 ICMP 协议,代理不支持转发 ICMP,要用 curl 测试。

  • 测试查询公网IP

    1
    curl https://ifconfig.me

    返回机器B的公网IP则说明配置成功。

  • 测试请求百度首页

    1
    curl https://www.baidu.com

    返回百度首页的信息则说明能成功访问外网。


第三步:处理 SSH 流量(针对通过 SSH 连 GitHub 的工具)

1
strace -e trace=network -f droid 2>&1 | grep -i "connect\|proxy\|factory"

通过以上命令排查发现,droid会直接通过 SSH 协议(22端口)连接 GitHub,完全绕过 HTTP 代理环境变量。需要单独配置 SSH 走 SOCKS5 隧道:

1
2
# 确认 nc 命令存在
which nc

然后编辑 ~/.ssh/config,在已有的 Host github.com 块里加上 ProxyCommand 一行:

1
2
3
4
5
6
7
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
UserKnownHostsFile ~/.ssh/known_hosts
IdentitiesOnly yes
ProxyCommand nc -X 5 -x 127.0.0.1:1080 %h %p

注意:如果 ~/.ssh/config 里已经有 Host github.com 的配置块,不能再新增一个同名的块,SSH 只认第一个匹配的。必须把 ProxyCommand 合并进已有的块里。如果没有则直接新增整个块。

这样所有发往 github.com 的 SSH 连接都会通过本地 SOCKS5 隧道转发。


每次打开新终端时

  • SSH 隧道和 gost 是后台进程,只要没有被 kill 或机器重启,跨终端是共享的,不需要重复启动。但环境变量是终端级别的,每个新终端都必须重新 export。

  • 保险期间,需要先检查 SSH 隧道和 gost 进程是否还活着:

第一步:重新建立 SSH 隧道(如果之前的进程还在则跳过)

1
2
3
4
5
# 检查隧道是否还活着
ps aux | grep "ssh -D 1080" | grep -v grep

# 没有输出则重新建立
ssh -D 1080 -N -f [email protected]

第二步:重新启动 gost(如果之前的进程还在则跳过)

1
2
3
4
5
# 检查 gost 是否还活着
ps aux | grep gost | grep -v grep

# 没有输出则重新启动
~/~/software/gost -L http://:8118 -F socks5://127.0.0.1:1080 > /dev/null 2>&1 &

第三步:重新设置环境变量(每个新终端都必须执行)

1
2
3
4
5
export ALL_PROXY=http://127.0.0.1:8118
export http_proxy=http://127.0.0.1:8118
export https_proxy=http://127.0.0.1:8118
export HTTP_PROXY=http://127.0.0.1:8118
export HTTPS_PROXY=http://127.0.0.1:8118

关闭SSH 隧道和 gost 进程

1
2
3
4
5
6
7
8
# 关闭 SSH 隧道
pkill -f "ssh -D 1080"

# 关闭 gost
pkill -f "gost"

# 清除环境变量(或者直接关闭终端)
unset ALL_PROXY http_proxy https_proxy HTTP_PROXY HTTPS_PROXY

补充:SOCKS5 vs HTTP 代理

SOCKS5 HTTP 代理
工作层级 传输层,协议无关 应用层,仅 HTTP/HTTPS
支持协议 TCP/UDP 任意流量 HTTP、HTTPS
工具兼容性 需要应用明确支持 几乎所有工具都认 HTTP_PROXY
典型用途 SSH 动态转发 通用代理环境变量

SSH -D 参数建立的是 SOCKS5 代理。如果工具不支持 SOCKS5,用 gost 转一层即可。


作者:Claude Sonnet 4.6