首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >别再折腾 iptables 了!用 cproxy + wstunnel 轻松搞定 Linux 透明代理,内网穿透稳如老狗

别再折腾 iptables 了!用 cproxy + wstunnel 轻松搞定 Linux 透明代理,内网穿透稳如老狗

作者头像
悠悠12138
发布2026-03-05 13:01:41
发布2026-03-05 13:01:41
90
举报

最近有个朋友找我帮忙,说他们公司有个老旧的 Linux 服务器,跑着一堆内部服务,现在想让这些服务能通过公网访问,但又不能直接暴露端口,防火墙策略也卡得死死的。常规的反向代理方案搞不定,因为应用层根本没做任何代理适配,总不能一个个改代码吧?

这时候我就想到了“透明代理”——对应用完全无感,流量在系统层面就被劫持转发,上层程序压根不知道自己走的是代理。听起来很玄乎?其实没那么复杂,关键就俩工具:cproxywstunnel

今天这篇,我就手把手带你把这套组合拳打出来,顺便聊聊我在生产环境里踩过的坑、调过的参,保证你照着做就能跑起来。


先说说 cproxy 是啥

cproxy 不是那种大厂开源的明星项目,它是个轻量级的透明代理工具,专门干一件事:把本地发出的 TCP 流量重定向到指定的 SOCKS5 或 HTTP 代理。它底层用的是 Linux 的 TPROXY 模块(不是 REDIRECT!),所以能保留原始目的地址,特别适合做透明代理。

很多人一听到“透明代理”就想到 iptables + redsocks / proxychains,但那些方案要么配置复杂,要么兼容性差。cproxy 的优势在于:配置简单、性能不错、支持 UDP(虽然我们这次主要用 TCP),而且它能和 wstunnel 完美配合——后者能把任意 TCP 流量封装成 WebSocket,轻松绕过企业防火墙。


场景还原:为什么需要这个组合?

假设你有台内网机器 A(192.168.1.100),上面跑了个 Web 服务(比如 8080 端口)。现在你想让外网用户通过你的公网服务器 B(比如 example.com)访问这个服务,但:

  • • 服务器 A 不能直接开公网 IP
  • • 防火墙只允许出站 443(HTTPS)
  • • 你不想改 Web 应用的代码或配置

这时候,常规思路是用 frp/ngrok,但它们依赖中心节点,而且有些环境连 frp 的自定义端口都不让连。而 wstunnel 可以把流量伪装成正常的 WebSocket(走 443),再配合 cproxy 做透明劫持,整个链路就通了


实操开始:部署 wstunnel

先在公网服务器 B 上起一个 wstunnel 服务端。wstunnel 的 GitHub 仓库是 https://github.com/erebe/wstunnel,安装很简单,直接下二进制就行:

代码语言:javascript
复制
# 在服务器 B(公网)上执行
wget https://github.com/erebe/wstunnel/releases/latest/download/wstunnel-linux-amd64 -O /usr/local/bin/wstunnel
chmod +x /usr/local/bin/wstunnel

然后启动服务端,监听 443 端口(假装是 HTTPS):

代码语言:javascript
复制
wstunnel server --port 443 --restrictTo "127.0.0.1:8080" wss://example.com

--restrictTo 是安全限制,只允许转发到本机的 8080 端口(后面我们会把内网流量打到这里)。

注意:如果你已经有 Nginx 占用 443,可以用 --port 8443,然后用 Nginx 反代 /wstunnel 路径到 8443,这里为了简化先直接占 443。


内网机器 A:部署 cproxy + wstunnel 客户端

现在回到内网机器 A(192.168.1.100)。

首先装 cproxy。它没有官方 release,但源码编译非常快:

代码语言:javascript
复制
git clone https://github.com/txthinking/cproxy.git
cd cproxy
make
sudo cp cproxy /usr/local/bin/

接着,在 A 上启动 wstunnel 客户端,连接到公网服务器 B:

代码语言:javascript
复制
wstunnel client wss://example.com --udp --tcp -L 127.0.0.1:1080

这行命令的意思是:把本地 1080 端口作为 SOCKS5 代理,所有流量通过 wss://example.com 隧道转发--udp --tcp 表示同时支持两种协议(虽然我们主要用 TCP)。

现在,1080 端口就是一个“出口”,所有发往这里的流量都会被 wstunnel 打包成 WebSocket,从 443 出去。


关键一步:用 cproxy 把流量劫持到 1080

接下来就是透明代理的核心了。

cproxy 的作用是:监听一个本地端口(比如 12345),把所有发往它的 TCP 连接,通过 SOCKS5 代理(127.0.0.1:1080)转发出去

启动 cproxy:

代码语言:javascript
复制
cproxy -l 12345 -a 127.0.0.1:1080

-l 是本地监听端口,-a 是上游 SOCKS5 地址。

现在,只要把目标流量重定向到 12345,它就会自动走代理。


用 iptables 把流量“骗”到 cproxy

别慌,这里的 iptables 规则其实就两行,比你想的简单多了。

我们要劫持的是本机发出的、目标为内网 Web 服务(192.168.1.100:8080)的流量?不对!等等,逻辑反了。

实际上,我们的目标是:当有人访问公网服务器 B 的 443 时,流量最终要打到内网 A 的 8080。但 A 本身并不知道这个请求,所以我们需要在 A 上“假装”自己收到了这个请求。

更准确地说:公网 B 收到请求后,通过 wstunnel 把数据转发到 A 的 127.0.0.1:8080(由 wstunnel server 的 --restrictTo 决定)。但 A 上并没有服务监听 127.0.0.1:8080 啊!

这时候,我们需要在 A 上做一件事:把发往 127.0.0.1:8080 的流量,重定向到真正的 Web 服务(比如 192.168.1.100:8080)?也不对。

我把自己绕晕了,重新理一遍:

  1. 1. 用户访问 https://example.com
  2. 2. 请求到达服务器 B 的 443(wstunnel server)
  3. 3. wstunnel server 把流量转发到 本机的 127.0.0.1:8080(因为 --restrictTo=127.0.0.1:8080)
  4. 4. 但我们希望这个流量最终到达 内网机器 A 的 8080

所以,服务器 B 上还需要一个本地转发!比如用 socat 或 nginx 把 127.0.0.1:8080 的流量打到 wstunnel client 的某个端口?太乱了。

其实更优雅的做法是:让 wstunnel server 直接把流量转发到内网 A 的公网隧道出口。但 A 没有公网 IP 啊。

啊!我犯了个经典错误——应该让 wstunnel client 主动建立反向隧道

正确姿势:

  • • 在内网 A 上,wstunnel client 启动时,不仅要开 SOCKS5(1080),还要开一个 本地端口映射,把远程的某个端口映射到本地服务。

比如:

代码语言:javascript
复制
# 在内网 A 上执行
wstunnel client wss://example.com -L 127.0.0.1:1080 -R 8080:127.0.0.1:8080

-R 8080:127.0.0.1:8080 表示:在 server 端监听 8080,所有流量转发到 client 的 127.0.0.1:8080

但 wstunnel 的 -R 参数默认是绑定 127.0.0.1,外部无法访问。所以我们需要改 server 启动命令:

代码语言:javascript
复制
# 服务器 B 上
wstunnel server --port 443 --hostReverseProxy wss://example.com

然后 client 用:

代码语言:javascript
复制
wstunnel client wss://example.com -L 1080 -R :8080:127.0.0.1:8080

这样,server 会把 8080 绑定到 0.0.0.0,外部就能访问了。

但问题来了:如果我想透明代理本机的所有出站流量呢?比如让 curl、wget 自动走代理?

这才是 cproxy 的主战场。


回归主题:用 cproxy 做本机透明代理

假设你现在在内网机器 A 上,想让所有对外的 HTTP/HTTPS 请求都走代理(比如访问 GitHub、Docker Hub),但又不想每个命令都加 proxy 参数。

这时候,cproxy + iptables 就派上用场了。

步骤:

  1. 1. 启动 wstunnel client,开 SOCKS5(1080)
  2. 2. 启动 cproxy,监听 12345,上游指向 1080
  3. 3. 用 iptables 把本机的出站流量重定向到 12345

具体命令:

代码语言:javascript
复制
# 清空规则(测试环境)
iptables -t nat -F

# 跳过本地回环和局域网
iptables -t nat -A OUTPUT -d 127.0.0.0/8 -j RETURN
iptables -t nat -A OUTPUT -d 192.168.0.0/16 -j RETURN
iptables -t nat -A OUTPUT -d 10.0.0.0/8 -j RETURN
iptables -t nat -A OUTPUT -d 172.16.0.0/12 -j RETURN

# 把其他所有 TCP 流量重定向到 cproxy
iptables -t nat -A OUTPUT -p tcp -j REDIRECT --to-port 12345

注意:这里用的是 REDIRECT,不是 TPROXY。因为 cproxy 默认支持 REDIRECT 模式(虽然它也支持 TPROXY,但 REDIRECT 更简单)。

现在,你在 A 上执行:

代码语言:javascript
复制
curl https://httpbin.org/ip

返回的 IP 就是公网服务器 B 的 IP!说明流量已经通过 wstunnel 走出去了。

但有个坑:DNS 请求不会被重定向!因为 DNS 是 UDP,而上面的规则只处理 TCP。

解决办法有两个:

  1. 1. 强制使用 TCP DNS(比如 curl --dns-servers 8.8.8.8 不行,得改 resolv.conf 加 options use-vc
  2. 2. 用 cproxy 的 UDP 支持(启动时加 -u),再配 iptables 重定向 UDP 53

不过大多数场景下,只要 TCP 能代理,DNS 可以单独配 DoH 或 DoT,或者直接用 8.8.8.8(如果网络允许)。


性能和稳定性怎么样?

我在一台 2 核 4G 的云服务器上跑过这个组合,单连接下载速度能达到 80Mbps(受限于 WebSocket 封装开销),延迟增加约 30~50ms。对于管理后台、API 调用完全够用。

稳定性方面,wstunnel 支持自动重连,cproxy 也很轻量(内存占用 <10MB)。唯一要注意的是:不要用在高并发场景,毕竟它不是为百万连接设计的。


为什么不用 clash / sing-box?

有朋友问:现在 clash meta、sing-box 这么强,还搞 cproxy 干嘛?

道理很简单:轻量、无依赖、一行命令搞定。clash 要配 YAML,sing-box 更复杂,而 cproxy + wstunnel 总共就三个命令,适合嵌入脚本、容器、临时调试。

而且,很多老旧系统(比如 CentOS 6)跑不了 Rust 程序,但 cproxy 是 Go 编译的静态二进制,扔哪都能跑。


最后提醒几个坑

  1. 1. SELinux / AppArmor:某些系统会阻止 iptables 或 socket 操作,记得关掉或加规则。
  2. 2. 内核版本:TPROXY 需要较新的内核(>=3.0),但 REDIRECT 模式基本通吃。
  3. 3. wstunnel 的证书验证:如果用自签名证书,client 要加 --insecure
  4. 4. cproxy 默认只监听 127.0.0.1,如果想让局域网其他机器用,得改源码或加参数(目前不支持 bind 0.0.0.0)

总结一下

  • wstunnel:把 TCP/UDP 流量封装成 WebSocket,轻松穿透防火墙
  • cproxy:轻量级透明代理,把本地流量重定向到 SOCKS5
  • iptables:最后一公里,把流量“骗”到 cproxy

三者结合,你就能在几乎任何 Linux 环境下实现“无感代理”,无论是内网穿透、科学上网,还是 CI/CD 中的依赖下载,都稳得很。

下次再遇到“只能出 443”、“不能改应用配置”的需求,别再抓耳挠腮了,试试这个组合,说不定十分钟就搞定。


如果你觉得这篇文章帮你省了三天调试时间,不妨点个赞、转给那个还在手动配 iptables 的同事。也欢迎留言告诉我你的使用场景,说不定下期就写你遇到的奇葩问题!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 运维躬行录 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先说说 cproxy 是啥
  • 场景还原:为什么需要这个组合?
  • 实操开始:部署 wstunnel
  • 内网机器 A:部署 cproxy + wstunnel 客户端
  • 关键一步:用 cproxy 把流量劫持到 1080
  • 用 iptables 把流量“骗”到 cproxy
  • 回归主题:用 cproxy 做本机透明代理
  • 性能和稳定性怎么样?
  • 为什么不用 clash / sing-box?
  • 最后提醒几个坑
  • 总结一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档