singbox-linux-laptop-gateway
Find a file
2026-06-22 20:25:40 +08:00
.gitignore refactor: final config — AliDNS-only DNS + official route rules, docs cleanup 2026-06-22 20:25:40 +08:00
config.json.example refactor: final config — AliDNS-only DNS + official route rules, docs cleanup 2026-06-22 20:25:40 +08:00
proxy-lan-off.sh feat: first commit 2026-06-20 15:02:07 +08:00
proxy-lan-on.sh feat: first commit 2026-06-20 15:02:07 +08:00
proxy-local-off.sh feat: first commit 2026-06-20 15:02:07 +08:00
proxy-local-on.sh feat: first commit 2026-06-20 15:02:07 +08:00
proxy-status.sh feat: first commit 2026-06-20 15:02:07 +08:00
README.md refactor: final config — AliDNS-only DNS + official route rules, docs cleanup 2026-06-22 20:25:40 +08:00

Debian 13 使用 sing-box 搭建透明代理网关(便携旁路方案)

适用场景:笔记本随身携带,本机和手机通过 TUN 模式透明代理上网,国内直连、国外走代理节点。 支持 sing-box 所有协议AnyTLS / VLESS / Trojan / Shadowsocks / Hysteria2 等),仅需替换配置文件中的出站节点。 一切都不开机自启,手动开启,回家后一键完全恢复。

一、架构总览

手机网关指向本机DNS 指向公网 IP ──→ 策略路由 ──→ sing-tun ──┐
                                                        ├── sing-box
本机浏览器/终端 ──→ TUN (auto_route) ──→ sing-tun ──┘        │
                                                            │
   ┌── DNS: 全量 → AliDNS DoH (223.5.5.5)                  │
   ├── 路由: geosite-geolocation-cn + geoip-cn → direct-out│
   └── 路由: 其余 → 代理节点                              │

两种使用模式:

模式 本机 LAN 设备 原理
仅本机 TUN auto_route sing-box 自动创建 TUN 路由接管本机流量
本机 + LAN TUN 策略路由 ip rule + ip route 把手机流量送入 sing-tun,与本机共用一套 TUN 处理

二、安装 sing-boxapt 方式)

sudo mkdir -p /etc/apt/keyrings
sudo curl -fsSL https://sing-box.app/gpg.key -o /etc/apt/keyrings/sagernet.asc
sudo chmod a+r /etc/apt/keyrings/sagernet.asc

echo 'Types: deb
URIs: https://deb.sagernet.org/
Suites: *
Components: *
Enabled: yes
Signed-By: /etc/apt/keyrings/sagernet.asc' | sudo tee /etc/apt/sources.list.d/sagernet.sources

sudo apt update && sudo apt install sing-box

更新 / 卸载

sudo apt update && sudo apt upgrade sing-box   # 更新
sudo apt remove sing-box                       # 卸载
sudo rm /etc/apt/sources.list.d/sagernet.sources
sudo rm -r /etc/sing-box

三、版本兼容性

通过 apt 安装的 sing-box 会跟随发行版滚动。以下字段在不同版本已被废弃/移除,配置时注意:

废弃字段 移除版本 替代方案
dns.servers[].address 1.12.0 type + server
dns.fakeip(顶层) 1.12.0 合并到 type: "fakeip"
inbounds[].sniff 1.13.0 route.rules[].action: "sniff"
outbounds[].type: "dns" 1.13.0 route.rules[].action: "hijack-dns"
inbounds[].inet4_address 1.12.0 address
domain_strategy 1.12.0 domain_resolver.strategy

迁移文档:https://sing-box.sagernet.org/migration/

四、配置文件 /etc/sing-box/config.json

{
    "log": {
        "level": "info",
        "timestamp": true
    },
    "dns": {
        "servers": [
            {
                "tag": "local",
                "type": "https",
                "server": "223.5.5.5"
            }
        ]
    },
    "inbounds": [
        {
            "type": "tun",
            "tag": "tun-in",
            "interface_name": "sing-tun",
            "address": "172.19.0.1/30",
            "auto_route": true,
            "strict_route": true,
            "stack": "mixed"
        },
        {
            "type": "mixed",
            "tag": "mixed-in",
            "listen": "0.0.0.0",
            "listen_port": 7890,
            "tcp_fast_open": true
        }
    ],
    "outbounds": [
        {
            "type": "direct",
            "tag": "direct-out"
        },
        {
            "type": "anytls",
            "tag": "proxy",
            "server": "YOUR_SERVER",
            "server_port": YOUR_PORT,
            "password": "YOUR_PASSWORD",
            "tls": {
                "enabled": true,
                "server_name": "YOUR_SNI",
                "insecure": false
            }
        }
    ],
    "route": {
        "rule_set": [
            {
                "type": "remote",
                "tag": "geosite-geolocation-cn",
                "format": "binary",
                "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs"
            },
            {
                "type": "remote",
                "tag": "geosite-geolocation-!cn",
                "format": "binary",
                "url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-!cn.srs"
            },
            {
                "type": "remote",
                "tag": "geoip-cn",
                "format": "binary",
                "url": "https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs"
            }
        ],
        "rules": [
            {
                "action": "sniff"
            },
            {
                "type": "logical",
                "mode": "or",
                "rules": [
                    {
                        "protocol": "dns"
                    },
                    {
                        "port": 53
                    }
                ],
                "action": "hijack-dns"
            },
            {
                "ip_is_private": true,
                "outbound": "direct-out"
            },
            {
                "type": "logical",
                "mode": "or",
                "rules": [
                    {
                        "port": 853
                    },
                    {
                        "network": "udp",
                        "port": 443
                    },
                    {
                        "protocol": "stun"
                    }
                ],
                "action": "reject"
            },
            {
                "rule_set": "geosite-geolocation-cn",
                "outbound": "direct-out"
            },
            {
                "type": "logical",
                "mode": "and",
                "rules": [
                    {
                        "rule_set": "geoip-cn"
                    },
                    {
                        "rule_set": "geosite-geolocation-!cn",
                        "invert": true
                    }
                ],
                "outbound": "direct-out"
            }
        ],
        "auto_detect_interface": true,
        "default_domain_resolver": "local",
        "final": "proxy"
    },
    "experimental": {
        "cache_file": {
            "enabled": true,
            "path": "/var/lib/sing-box/cache.db",
            "store_rdrc": true
        },
        "clash_api": {
            "default_mode": "Enhanced"
        }
    }
}

配置修改后先检查语法,通过后再启动:

sing-box check -c /etc/sing-box/config.json

节点信息填充

出站类型(type)可替换为 sing-box 支持的任何协议:anytls / vless / trojan / shadowsocks / hysteria2 等。以下以 AnyTLS 为例。

占位符 说明
YOUR_SERVER 真实连接地址servertqvnarulexmo.com
YOUR_PORT 端口,如 6602
YOUR_PASSWORD 密码
YOUR_SNI TLS SNIserver_namesg3.ninjanode.pro
tls.insecure 按需设置 true/false

可选字段(从 passwall 配置提取):

"min_idle_session": 5,
"idle_session_check_interval": "30s",
"idle_session_timeout": "30s"

五、五个脚本

脚本 功能
proxy-local-on.sh 仅本机代理:启动 sing-box
proxy-local-off.sh 仅本机代理:停止 sing-box
proxy-lan-on.sh 本机 + LAN自动检测网段ip_forward + 策略路由 → sing-tun
proxy-lan-off.sh 停止所有:停止 sing-box + 删除策略路由 + 关闭 ip_forward
proxy-status.sh 检查当前状态:运行中/未运行、local/LAN 模式

仅本机模式

./proxy-local-on.sh   # 启动
./proxy-local-off.sh  # 停止

本机 + LAN 模式

# 先停止 local 模式,再启动 LAN 模式(二者互斥)
./proxy-local-off.sh
./proxy-lan-on.sh

手机将网关设为本机 IPDNS 设为国内公共 DNS114.114.114.114223.5.5.5),即可透明代理。

DNS 为什么不能设成本机或路由器 IP第八关

六、LAN 模式工作原理

手机LAN_IP发送 TCP 到 baidu.com:443
          │
          ▼ (WAN_IF如 wlp3s0)
    ┌─────────────────────────┐
    │ ip rule:                │
    │  from $LAN_CIDR         │
    │  iif $WAN_IF            │──→ table 101 ──→ default via sing-tun
    │  lookup 101             │
    └─────────────────────────┘
          │
          ▼
    sing-tun → sing-box TUN 入站 → 路由规则 → direct-out/proxy

LAN_CIDRWAN_IF 由脚本自动检测,无需手动配置。

这是"软路由"方案:手机流量到笔记本后被策略路由送入 TUN 接口,和本机流量共享同一套 sing-box 处理。相比 TProxy这完全规避了内核 TProxy TCP 投递的兼容性问题(详见第九节)。

七、服务管理

sudo systemctl status sing-box     # 查看状态
sudo journalctl -u sing-box -f     # 实时日志

不要执行 systemctl enable sing-box,确保不开机自启。

八、效果覆盖表

场景 实现方式
本机浏览器/终端 TUN auto_route 自动接管
手机/平板等 LAN 设备 设备网关指向本机DNS 指向公网 IP → 策略路由 → TUN
国内域名/IP geosite-geolocation-cn + geoip-cndirect-out
国外 IP final → 代理节点
防 DNS 泄漏 阻断 DoT(853)/QUIC(443)/STUNDNS 劫持端口 53
手机 Chrome 跳转 google.cn 访问 google.com/ncr 一次种 cookie永久解决

九、调通历程(辛酸史)

第一关:版本地狱

预想的配置基于 sing-box 旧版语法。实际 apt 装的是 1.13.12,以下字段全部失效:

  • DNS server 的 address → 需要 type + server
  • dns.fakeip 顶层块 → 合并到 type: "fakeip"
  • sniff 在 inbound 里 → 改为 route.rules[].action: "sniff"
  • dns 类型 outbound → 改为 action: "hijack-dns"
  • inet4_address → 合并为 address

反复踩坑,每修复一个就报下一个,前后迭代了 10+ 个配置版本才通过语法检查。

第二关DNS 死循环

cn-dnsDoH to doh.pubdetour: direct-outdirect-out 又依赖 default_domain_resolver: cn-dns 解析域名 → 无限循环。最终砍掉 DoH改用 local 类型(系统 DNS简化 DNS 链。

最终方案: 经过多轮测试Google DNS 8.8.8.8 被 GFW 封锁、Cloudflare 1.1.1.1 同样被封锁、fakeip 的非 SNI 协议缺陷),最终采用单 AliDNS DoH223.5.5.5。阿里公共递归 DNS 在国内直连零延迟,对国外域名同样返回真实 IP。路由规则独立负责直连/代理分流DNS 与路由完全解耦。手机 Chrome 跳转 google.cn/m 是 Android 浏览器的网络检测行为,访问一次 google.com/ncr 永久解决。

第三关:规则集下载走代理死循环

raw.githubusercontent.com 在国内无法直连,规则集下载失败。去掉 download_detour 后下载走代理。但代理需要节点信息——前期一直用占位符 YOUR_SERVER 导致代理不通,规则集也下不了。

第四关TProxy 的 TCP 黑洞(最耗时的关卡)

为了让手机能用,先后尝试了:

  • nftables TProxyUDP DNS 能劫持TCP 经过 counter 计数但永远送不到 sing-box
  • iptables TPROXY同样的结果——UDP 通 TCP 不通
  • iptables TPROXY + fwmark 策略路由:还是不行
  • iptables TPROXY + MARK --set-mark 1:依然不行

tcpdump 确认手机 TCP SYN 到了 wlp3s0iptables/nftables counter 显示数百个 TCP 包被 TPROXY 处理,但 sing-box 的 TProxy 入站零 TCP 日志。最终确认是 Debian 内核(实际上并非 debian 13而是我的 debian testing/debian forky内核版本 7.0.10+deb14-amd64上 nftables/iptables TProxy 对 TCP 的投递存在兼容性问题。

ps: 下面说到内核或 TCP 投递存在的兼容性问题均一样,都是我在我的 debian testing 上测试不通过,有可能是内核 7.0.10+deb14-amd64 过新debian 源当中的各个包没有经过足够测试,导致的问题。

第五关:策略路由 → TUN破局

放弃 TProxy 方案,改用"软路由"思路:

ip rule add from 10.10.10.0/24 iif wlp3s0 table 101
ip route add default dev sing-tun table 101

手机流量不再做包重定向,而是在路由层面直接送入 sing-tun 接口,和本机一样走 sing-box 的 TUN 入站处理。手机 DNS 也被 hijack-dns 自动接管。

第六关FakeIP 引爆的 Android 联网检测

手机上网功能正常后Chrome 始终显示"未连接到互联网"。根因是 Android 的 connectivitycheck.gstatic.comfake-dns 解析成假 IP 198.18.0.x。此域名触发联网检测逻辑——Android 向这个假 IP 发 HTTP 请求,永远得不到 204 响应,系统判定无网。

修复DNS 规则中让 .gstatic.com.googleapis.comlocal-dns 解析真实 IP。路由不做任何特殊处理final → proxy 正常代理即可。

注意: 当前配置已完全移除 FakeIP。全量使用 AliDNS DoH 做真实 IP 解析,此问题不再需要特殊处理。

第七关FakeIP 黑洞——SSH 等非 SNI 协议的直连站点连通失败

浏览器访问一个非 geosite-cn 域名的国内站(如自建 Forgejo 的 git.example.xyz)完全正常,但 SSH / git pull / git push 一直卡住。nslookup 返回的是 198.18.0.x 的假 IP。

根本原因在于 FakeIP + 代理出站对域名信息传递的依赖差异:

HTTPS 浏览器DNS → fakeip 198.18.0.x → TUN → 路由 → proxy
               代理节点嗅探 TLS SNIgit.example.xyz → 连接真实服务器 ✅

SSH / git   DNS → fakeip 198.18.0.x → TUN → 路由 → proxy
               代理节点看到的是 198.18.0.4:22222 → 无 SNI 可嗅探 → 无法连接 ❌

HTTPS 的 TLS 握手中携带了 SNI 字段,代理节点能从中提取域名并解析连接到真实的 frps 服务器。SSH 是裸 TCP 协议,没有域名信息,代理节点只能看到一个假 IP无法确定真实目的地。

修复:在 DNS 规则的 domain_suffix 中添加你的域名,走 local-dns 解析真实 IP

"domain_suffix": [".gstatic.com", ".googleapis.com", "your-domain.xyz"],
"server": "local-dns"

local-dns 返回真实的国内 frps 服务器 IP路由规则中的 geoip-cn 自动命中 → direct-out 直连。无需额外路由规则。

如果你需要添加多个私有域名,直接追加到 domain_suffix 数组即可。此方案适用于任何不依赖 SNI 的 TCP 协议SSH、FTP、rsync 等)指向国内服务器的场景。

注意: 当前配置已完全移除 FakeIP。全量使用 AliDNS DoH 做真实 IP 解析,非 SNI 协议SSH/git 等)直连国内站点不再有此问题。

第八关LAN 设备的 DNS 劫持陷阱

手机 DNS 如果设为旁路网关自身的 IP192.168.5.106DNS 包的目标地址就是本机。内核识别为本地投递,包直接进 INPUT 链,不经过 ip_forward,也不进入策略路由表 table 101,更不会到达 sing-tunhijack-dns 完全抓不到,手机 DNS 超时后回退到 ISP 的污染 DNS。

为什么 ImmortalWrt+passwall 可以把 DNS 设成旁路网关 IP Passwall 自带 dnsmasq/smartdns 等本地 DNS 服务,直接监听在旁路网关的 53 端口上。LAN 设备的 DNS 查询到达网关 IP:53 → INPUT 链 → 本地 DNS 服务处理 → 返回结果。这是"本地服务响应",不需要 ip_forward 或 TUN 劫持。而本项目没有本地 DNS 服务,完全依赖 hijack-dns 在转发路径FORWARD → TUN中拦截因此 DNS 目标必须是公网 IP 才能进入转发路径。

❌ DNS → 192.168.5.106(本机)→ INPUT 链 → 被本地 DNS 栈处理或丢弃 → 不进 TUN
✅ DNS → 114.114.114.114(公网 IP→ 策略路由 → sing-tun → hijack-dns 劫持

正确做法: LAN 设备的 DNS 设为国内公共 DNS 服务的 IP114.114.114.114DNSPod223.5.5.5AliDNS不要设成路由器 IP也不要设成旁路网关 IP。DNS 目标是公网 IP 才能通过策略路由送入 TUN 被劫持。

主 DNS 设公共 DNS IP 即可,不要配置辅助 DNS。否则第一条超时后辅助 DNS 走直连返回污染结果。

十、扩展阅读Linux 透明代理方案对比

方案一TProxy内核包重定向

原理: 用 iptables/nftables 在 PREROUTING 钩子上拦截所有流量,通过 TPROXY 目标将包"透明地"重定向到本地代理进程端口。代理使用 IP_TRANSPARENT socket 选项接收,保留原始目标地址。

客户端 → 网卡 → [PREROUTING TPROXY] → 代理端口 → 出站

优点:

  • 不修改路由表,纯包级别操作
  • 性能损耗极低(内核层面处理)
  • 可以按端口、协议、源 IP 精细化控制哪些流量走代理

缺点:

  • 依赖内核模块 nf_tproxy_ipv4 / xt_TPROXY
  • 不同内核/发行版兼容性差异大(我们在 Debian 13 内核上 TCP 投递彻底失败)
  • 调试困难,出了问题只能抓包 + 看内核 counter
  • rp_filterip_forward、fwmark 策略路由等因素相互影响,排查链路长

方案二:策略路由 + TUN本项目最终方案

原理: 不为包做"手术",而是用 ip rule 把特定流量(如手机所在的 LAN 子网)的策略路由指向 TUN 接口。流量到了 TUN 就和本机流量一样被 sing-box 接管。

客户端 → 网卡 → [策略路由] → sing-tun → sing-box → 出站

为什么叫"软路由" 本质上是让笔记本扮演路由器的角色——收到手机发来的 IP 包后,根据策略路由表决定下一跳(dev sing-tun),而非按默认路由转发。和硬路由的唯一区别是转发逻辑由 Linux 内核 + sing-box 实现,不依赖专用硬件。

与 ImmortalWrt/passwall 软路由的区别

ImmortalWrtOpenWrt 分支)+ passwall 是常见的 x86 软路由方案。我们的 Debian + sing-box + 策略路由与之有本质不同:

ImmortalWrt + passwall Debian + sing-box本项目
角色 网络主网关——所有设备流量必经此地 旁路设备——LAN 上的一台普通机器
网络拓扑 路由器 NAT + DHCP + DNS + 防火墙 只做透明代理,不干预 DHCP/NAT/防火墙
流量入口 所有设备默认网关就是它 只有主动将网关指向它的设备才走代理
透明代理方式 iptables TProxy / REDIRECT内核模块成熟 策略路由 → TUN绕开 TProxy 兼容性问题)
DNS 自己跑 dnsmasq/smartdns 不提供 DNS 服务sing-box hijack-dns 劫持即可
接管范围 全家设备自动覆盖 谁改网关谁用,灵活但需手动配置
部署影响 断网部署——路由器下线全家断网 无感部署——停掉 sing-box 网络立即恢复原状
适用场景 家庭/办公室固定部署 便携笔记本,随走随用

简而言之ImmortalWrt 是"修路的人"(改网络基础设施),我们是"指路的人"(给个别的设备指一条经过代理的路)。前者全家自动生效、断电全网瘫痪;后者随意插拔、停服务零影响。

与 ImmortalWrt/passwall 旁路网关的区别

当你把 ImmortalWrt+passwall 部署成旁路网关(主路由是硬路由),这和本项目的定位其实更接近。但实现上有本质不同:

ImmortalWrt 旁路网关 Debian + sing-box本项目
操作系统 OpenWrt/ImmortalWrt专为路由优化的 Linux Debian 通用桌面 Linux
内核 OpenWrt 定制内核 Debian 主线内核
TProxy 可用性 内核完整支持passwall 标准方案 Debian 内核 TProxy TCP 投递 bug无法使用
透明代理方式 iptables TProxy + fwmark 策略路由 策略路由 → TUNip rule + sing-tun
配置界面 Web UIpasswall 面板) JSON 配置文件 + shell 脚本
网络接管 同网段设备改网关指向旁路 IP 同网段设备改网关指向本机 IP
自身上网 勾选"路由器本机代理"+"客户端代理"即可Web UI 两个复选框覆盖所有设备 本机 TUN auto_route 自动接管,无需额外配置
便携性 固定在局域网,需要外接电源和网线 笔记本 WiFi 连接,随走随用
管理 作为独立盒子运行,需远程 SSH 或 Web 直接在桌面终端操作
调试复杂度 passwall 封装了细节,出问题靠猜 全栈可见——规则、路由、日志全透明

核心差异就一个:Debian 主线内核的 TProxy 有 TCP 投递 bug迫使我们必须走策略路由 → TUN 这条路。在 ImmortalWrt 上 TProxy 是标准答案,在 Debian 上反而成了死胡同。

优点:

  • 不依赖任何防火墙模块,只用标准 ip route / ip rule
  • 完全绕开了 TProxy 的内核兼容性问题
  • 和本机流量共享同一套 TUN 处理逻辑,配置统一
  • 调试直观:ip rule show / ip route show table 101 一眼看出流向

缺点:

  • 需要开启 ip_forward(本机变成路由器角色,增加攻击面,但在信任的局域网内可接受)
  • 不能按端口/协议精细化控制(所有匹配子网的流量全部进 TUN
  • 依赖 sing-box 的 TUN 入站正常工作

方案三REDIRECT / DNAT端口重定向

原理: 用 iptables/nftables 的 REDIRECTDNAT 将流量目标地址改写为本地代理端口。代理收到后解析原始目标(通过 SO_ORIGINAL_DST 获取 DNAT 前的地址)。

客户端 → [DNAT dst→127.0.0.1:port] → 代理端口 → 出站

优点: 最简单,REDIRECT 一条规则就能工作,无需内核模块(标准 NAT 即可)。

缺点:

  • 目标地址被改写,代理必须支持获取 SO_ORIGINAL_DST
  • 仅适用于 TCP 和部分 UDP 场景
  • 代理看到的来源地址是 127.0.0.1,无法区分客户端

方案四TUN 全局路由VPN 模式)

原理: 创建 TUN 虚拟网卡,将所有流量(0.0.0.0/0)路由到 TUN代理进程完全接管 IP 层。sing-box 的 auto_route 就是这个模式。

所有流量 → sing-tun → sing-box → 出站

优点: 最彻底接管一切Android/iOS VPN API 的标准做法。

缺点:

  • 本机流量和路由复杂的需要精细配置 bypass 规则如局域网、DNS 等)
  • 适用本机;做网关给其他设备用需要配合方案二

方案五HTTP/SOCKS 正向代理(非透明)

原理: 客户端主动配置代理地址(如 localhost:7890),浏览器/App 显式连接代理。

优点: 不需要任何系统级配置,最简单可靠。

缺点: 非透明——终端 App 必须支持代理设置,无法覆盖所有流量。

本项目的选择

场景 方案
本机 TUN 全局路由方案四sing-box auto_route
LAN 设备 策略路由 → TUN方案二

这是 方案二 + 方案四 的组合,用 TUN 的全局代理能力配合策略路由的流量引导,做到了本机和手机统一的透明代理效果,且完全绕开了 TProxy 的内核兼容性问题。

十一、参考资料