你获批的代理运行在一台跳板主机上,只监听 loopback,因此该机器之外的任何东西都无法访问它。你不需要VPN 或新的代理;你需要把该机器的一个端口搬到自己的一个端口上。本地转发做的正是这件事,只需一条命令加上一项应用设置。混乱通常来自把哪个 loopback 地址属于哪台机器搞混。

先判断是否已有固定代理

这项技术转发的是已经在运行的服务。如果远端主机只有 SSH 守护进程而没有代理,转发再多也变不出代理,连接会被远端拒绝。要确认代理已经绑定、端口是多少,以及它监听的是 127.0.0.1 还是某个特定接口地址,因为转发必须指向那个地址。

先确认这一点,就能免去调试一条从未连接过任何东西的隧道。

搭好转发并读懂命令

需要的写法会在笔记本上绑定一个 loopback 端口,并从服务器一侧把它接到服务器所看到的代理地址。

ssh -NT -o ControlPath=none -o ExitOnForwardFailure=yes \
  -L 127.0.0.1:13128:127.0.0.1:3128 [email protected]

-N 抑制远程命令,-T 抑制 termios 分配,因为你要的是隧道而不是 shell。第一个 loopback 地址是笔记本监听的位置,第二个由 SSH 服务器解析,所以那里的 127.0.0.1 指的是那台机器上的代理。如果本地端口已被占用,ExitOnForwardFailure 会让命令直接报错,而不是启动一个什么都不转发的会话。目标地址要按服务器解析的方式来写,因为只有你的笔记本能解析的名字在对面会失败。

在这一切生效之前,服务器自身的策略先起作用。AllowTcpForwarding 必须允许它,PermitOpen 可能限制会话能到达的目标和端口,所以客户端接受的转发仍可能被服务器拒绝。拒绝会以转发或通道错误的形式出现在客户端,读那条信息比改命令更快。

让一个应用指向该转发

把应用配置为使用 http://127.0.0.1:13128 上的 HTTP 代理,若远端代理要求则带上凭据。HTTPS 目标仍要保留应用自身的证书校验,代理隧道并不替代它。这是单个服务的固定转发,所以必须告诉应用有代理,而不是让它自己去发现。

在做成任何永久配置前先快速验证:curl -x http://127.0.0.1:13128 -I https://example.com,它会实际走一遍代理必须支持的 HTTP CONNECT 方法。

权限仍留在原处

远端代理仍然决定允许哪些目标和哪些方法,SSH 登录不该悄悄给每个账号一个通用 Web 中继。在笔记本上绑定 127.0.0.1 可以避免把端口发布到你的局域网,但它并不能让端口对同一台机器上的其他进程保密。把这种绑定换成通配地址来共享代理,正是产生不受管理的开放中继的方式。

SSH 传输保护到服务器这一段。再往后由代理自己建立连接,所以指向目标明文的 HTTP 请求在服务器之后仍是明文,尽管第一段是加密的。

两端都验证,然后收尾

本地隧道搭好和远端服务成功是两个不同的结果,命令的退出状态只能说明前者。用 ss -ltn 确认监听存在,然后发一个允许的应用请求和一个应被代理拒绝的请求。两者都符合预期,说明路径是真的;如果隧道在而所有请求都失败,则是代理在拒绝或到达不了目标。

完成后,停掉拥有它的 SSH 进程,从应用中删掉代理设置,并确认本地端口确实消失,而不是留下一个比任务活得更久的监听。

相关文章