在中国大陆的 Linux 服务器上做透明分流:
- 访问国外(非中国 IP)的 TCP 流量 → 经 SOCKS5/HTTP 代理出去
- 中国 IP 直连(国内网站/服务速度快、走国内 CDN)
- DNS 按域名分流:国内域名走国内 DNS 直连,国外域名经代理用 TCP 解析,规避 DNS 污染
基于 redsocks + nftables + dnsmasq + unbound,纯内核转发,无需改应用配置。
English: README.en.md · 变更记录: CHANGELOG.md · 博客: 在 RHEL/CentOS/Rocky 上部署透明分流
📖 在线文档:https://chenxianlong.github.io/redsocks-transparent-proxy/
源文件:
docs/architecture.svg(中文)/docs/architecture.en.svg(English); 用python3 docs/architecture.py重新生成,PNG 用rsvg-convert -z 2 -o docs/architecture.png docs/architecture.svg渲染。
应用
├─ DNS → 127.0.0.1:53 (dnsmasq)
│ ├─ 中国域名(11万条表 + .cn) ──→ 223.5.5.5 (UDP 直连)
│ └─ 其它域名 ──→ 127.0.0.1:5353 (unbound)
│ └─ 上游 TCP 8.8.8.8/1.1.1.1:53(经代理)
└─ TCP
▼
nftables (nat/OUTPUT, table ip redsocks)
├─ 私有/保留地址、代理服务器、直连白名单、中国 IP 段 → RETURN 直连
└─ 其它 TCP → REDIRECT 127.0.0.1:12345 → redsocks → SOCKS5/HTTP 代理
unbound 的上游 TCP 同样会被最后一条规则代理出去,所以 DNS 不会被污染。
-
操作系统(自动识别):
发行版 redsocks 来源 备注 Debian 12/13、Ubuntu 22.04+ 软件包 redsocks原支持平台 RHEL / CentOS / Rocky / Alma / Fedora 从源码编译 自动应用 CRLF 修复补丁 -
systemd+nftables+python3+curl -
root 权限
-
一个可用的 SOCKS5 / HTTP 代理,先自测:
curl -x socks5h://HOST:PORT -sI https://www.google.com
RHEL 系会在安装时用
dnf安装编译依赖(gcc make libevent-devel patch), 并在 SELinux 为Enforcing时自动为 unbound 的非 53 端口打dns_port_t标签。 详见docs/platform-support.md。
方式一,克隆后安装:
git clone https://github.com/chenxianlong/redsocks-transparent-proxy
sudo bash redsocks-transparent-proxy/scripts/install.sh --proxy HOST:PORT方式二,一行安装(无需克隆):
curl -fsSL https://raw.githubusercontent.com/chenxianlong/redsocks-transparent-proxy/main/install.sh \
| sudo bash -s -- --proxy HOST:PORT若
raw.githubusercontent.com被墙,请先通过代理或镜像 clone 仓库,再执行sudo bash scripts/install.sh --proxy HOST:PORT。在 RHEL / CentOS / Rocky / Alma 上无需额外操作:脚本会自动
dnf安装依赖、 从源码编译 redsocks、生成 systemd unit,并处理 SELinux。
| 参数 | 说明 | 默认 |
|---|---|---|
--proxy HOST:PORT |
代理地址(必填) | - |
--type |
socks5 / socks4 / http-connect / http-relay |
socks5 |
--user / --pass |
代理认证 | 无 |
--direct-dns |
国内 DNS | 223.5.5.5 |
--remote-dns / --remote-dns2 |
国外 DNS(经代理 TCP 查询) | 8.8.8.8 / 1.1.1.1 |
--no-dns-split |
所有 DNS 都走代理 | 关闭 |
--allowlist |
只代理 not_cn.txt 里的 IP(默认是「中国 IP 直连」的 bypass 模式) |
关闭 |
--gateway |
同时为局域网其它机器转发(ip_forward + nat/prerouting) |
关闭 |
--port |
redsocks 本地端口 | 12345 |
--splice |
on / off,redsocks 数据泵开关 |
Debian=on,RHEL 系=off |
# 最常见
sudo bash scripts/install.sh --proxy 10.0.0.1:1080 --yes
# 带认证
sudo bash scripts/install.sh --proxy 10.0.0.1:1080 --user me --pass secret
# 同时做局域网网关
sudo bash scripts/install.sh --proxy 10.0.0.1:1080 --gatewaycurl -s -o /dev/null -w 'google: %{http_code}\n' https://www.google.com # 200
curl -s -o /dev/null -w 'baidu : %{http_code} %{time_total}\n' https://www.baidu.com
dig +short @127.0.0.1 www.baidu.com # 国内解析(与 @223.5.5.5 一致)
dig +short @223.5.5.5 www.google.com # 被污染(假 IP)
dig +short @127.0.0.1 www.google.com # 真实 IP
sudo redsocks-nft show- bypass(默认,推荐):把中国 IP 段表
chnroute.txt作为排除集。不在表内的 (即国外 IP)一律走代理。漏掉的国内 IP 最多多走一次代理,不会导致国外站点直连失败。 - allowlist:只把
not_cn.txt里列出的(已分配的)国外 IP 走代理。 适合你想严格控制「哪些目标走代理」的场景。
sudo bash scripts/install.sh --proxy HOST:PORT --allowlist不是运行时探测,而是一张社区维护的静态域名表 + dnsmasq 的后缀匹配。
dnsmasq(127.0.0.1:53)里:
- 默认所有域名 →
127.0.0.1#5353(unbound,上游 TCP 经代理,防污染); - 命中中国域名表的域名 →
--direct-dns(默认223.5.5.5)直连解析。
中国域名表由 redsocks-refresh-domains 从
felixonmars/dnsmasq-china-list
生成(accelerated-domains.china.conf + apple.china.conf,约 11 万条),加上内置的
.cn 兜底,写成 /etc/dnsmasq.d/china-domains.conf:
server=/baidu.com/223.5.5.5
server=/taobao.com/223.5.5.5
...
server=/.cn/223.5.5.5匹配规则是 按域名后缀(server=/baidu.com/ 命中 baidu.com 及其子域,不命中
notbaidu.com),多条命中时 最长(最具体)优先。没命中的一律走代理 DNS。
⚠️ 域名分流 ≠ 流量分流,两者是独立的:
| 层 | 判定依据 | 决定什么 |
|---|---|---|
| DNS | 域名表(静态、后缀匹配) | 用国内 DNS 直连解析,还是经代理解析(防污染) |
| TCP | 目标 IP 是否在 chnroute.txt(APNIC 等 RIR 数据) |
直连,还是走代理 |
也就是说:域名表只决定「用哪个 DNS 解析」,真正决定流量走不走代理的是解析出的目标 IP。 后果:未收录的国内域名会经代理解析,但拿到国内 CDN 的 IP 后 TCP 仍按 IP 直连 (只是 DNS 多绕一跳),不会断。
自定义域名:把 server=/你的域名/223.5.5.5 写进 /etc/dnsmasq.d/ 下的独立文件,
再 systemctl restart dnsmasq。别直接改 china-domains.conf,它会被
redsocks-refresh-domains 覆盖。
加 --gateway 后:
net.ipv4.ip_forward=1(持久化到/etc/sysctl.d/99-redsocks-transparent-proxy.conf)- 额外生成
nat/prerouting链,把其它机器转发进来的「非中国 TCP」重定向到 redsocks redsocks监听0.0.0.0;dnsmasq/unbound额外监听本机 LAN IP- 其它机器把默认网关和 DNS 都指向本机 LAN IP
- 若本机还有额外防火墙/安全组,记得放行
FORWARD
结论:国内流量几乎零开销;开销几乎全在「国外流量经 redsocks 中继」这一段, 对普通服务器(< 1 Gbps、几百并发)可以忽略。
| 场景 | 吞吐 | 连接延迟 | redsocks CPU |
|---|---|---|---|
| 国内直连下载(USTC 镜像) | 25.2 MB/s(≈202 Mbps) | connect 31 ms | 0.0 ms(不经过 redsocks) |
| 国外经代理下载(Cloudflare 50 MB) | 25.0 MB/s(≈200 Mbps) | connect 174 ms | 90 ms / 2.0 s = 单核 4.5% |
反推:50 MB ≈ 0.4 Gbit 用掉 90 ms CPU → 约 225 ms CPU / Gbit, 粗略外推单核可跑 2–4 Gbps(高带宽下非线性,仅作量级参考)。
DNS 解析(dig Query time,本机 127.0.0.1):
| 域名 | 首次 | 缓存后 |
|---|---|---|
www.taobao.com / www.163.com(国内) |
8 / 4 ms | 0 ms |
www.google.com(国外) |
52 ms | 4 ms |
www.wikipedia.org / www.reddit.com(国外) |
408 / 224 ms | 0 ms |
redsocks 常驻内存 ~1.5 MB(RSS),空闲 CPU 0%。
- 国内直连流量:只多走一遍内核 nftables 集合匹配。
chnroute是flags interval集, 内核用红黑树查找,5513 条约 13 次比较/包,纳秒级且不产生用户态开销 —— 实测 redsocks CPU 0.0 ms,吞吐打满链路。 - 110,573 条中国域名规则:dnsmasq 内部是域名树后缀匹配,与规则条数关系不大; 内存几十 MB 量级,查询仍是个位数 ms。
- 直连白名单 / 私有地址:同样是内核 set / 前缀匹配。
- 国外首次 DNS:200–400 ms
因为
dnsmasq → unbound → TCP 连接 → redsocks → 代理 → 8.8.8.8要串好几个 RTT。 这是「防污染」必须付的代价;命中缓存后为 0 ms,只影响冷启动/新域名。 - 国外 TCP:redsocks 用户态中继
每个国外连接在内核被 REDIRECT 到
127.0.0.1:12345,redsocks accept 后再以 SOCKS5 连到代理并双向转发。redsocks 0.5 在 Linux 上用splice()(日志里能看到redsplice_write_cb),数据不进用户态、走内核 pipe,比普通 read/write 中继省很多; 但它仍是单线程 epoll,极高带宽(> 1 Gbps)时单核会成为瓶颈。 延迟上多一跳「本机 → 代理」,本例代理在局域网,这一跳 <1 ms。 - 并发连接数(默认值是个坑)
redsocks_conn_max不配置时 =0.75 × nofile / 6(splice 模式)。 systemd 默认LimitNOFILESoft=1024→ 默认只能同时 128 条连接,超出直接丢。 安装脚本已默认写入rlimit_nofile = 65536+redsocks_conn_max = 8192(--conn-max可调),实测生效conn_max=8192。
| 需求 | 建议 |
|---|---|
| 本机浏览 / API / 一般下载(< 1 Gbps) | 本方案足够,开销可忽略 |
| 高强度下载、> 1 Gbps | redsocks 单线程可能成瓶颈,考虑多线程透明代理(如 sing-box tproxy)或内核态方案 |
| 局域网网关(几十~几百客户端) | 本方案 + --gateway,--conn-max 给足 |
| 只要极致性能、不介意每应用配置 | 应用层直配 SOCKS5,省掉内核转发与 redsocks 中继 |
完整版与复现脚本见 docs/performance.md。
sudo redsocks-refresh # 更新中国 IP 段表 + 中国域名表
sudo redsocks-refresh-domains # 只更新中国域名表
sudoedit /etc/redsocks/direct_dst.txt # 直连白名单,改完 systemctl restart redsocks-nftdirect_dst.txt 用于把某些 IP/CIDR 排除出代理,例如某个国外 API 直连更稳定。
sudo bash scripts/uninstall.sh # 保留软件包
sudo bash scripts/uninstall.sh --purge # 连同 redsocks/unbound/dnsmasq 一起卸载本仓库同时是一个 Agent Skills 技能包,
入口是 SKILL.md。可放到:
git clone https://github.com/chenxianlong/redsocks-transparent-proxy \
~/.agents/skills/redsocks-transparent-proxy
# 或 ~/.pi/agent/skills/ 、 ~/.claude/skills/- 不要用 redsocks 的
redudp配 clash/mihomo 类代理做 DNS:这类代理的 SOCKS5 UDP 回复来自随机源端口,而redudp用connect()过的 UDP socket,会丢弃源端口不符的包。现象是Client timeout ... last_relay: 0。 本方案改用 DNS over TCP 绕开该问题。 - 本地 DNS 对墙外域名是被污染的,DNS 必须走代理。
- 单独
systemctl stop redsocks-nft会连带 DNS 一起挂(unbound 上游依赖它)。 要停就整套停,或把/etc/resolv.conf改回223.5.5.5。 - ICMP 不会被代理,
ping墙外地址仍然不通,redsocks 只处理 TCP。 - 检测 SOCKS5 UDP relay 时注意回复源端口可能不同,要用未 connect 的 socket 看。
更多细节见 references/troubleshooting.md。
- 把「Debian 专属」的透明分流方案移植到 Rocky Linux 10
—— 完整记录 RHEL 系适配过程,重点剖析「代理已返回
200 Connection established却一直卡住」的 libevent 陷阱,以及daemon = on假死、SELinux 端口标签等问题。 - 平台支持与发行版差异 —— 平台矩阵、原理与手工部署步骤。
- 中国 IP:APNIC
delegated-apnic-latest - 非中国 IP:APNIC / ARIN / RIPE NCC / LACNIC / AFRINIC
delegated-*-latest - 中国域名:felixonmars/dnsmasq-china-list
MIT(见 LICENSE)
