Docker Clash 旁路由网关模式透明代理

这个功能,我晚用上了 5 年……只要设备接入 Wi-Fi,就能无感科学上网,还是蛮舒服的。

首先说说我的想法:

  1. 不想在路由器上直接跑 Clash:路由器这种东西,稳定性是首要的,然后由于我刷它的频率比较高,所以配置不能太复杂。官方 OpenWRT,里面啥都不带。如果直接装个 OpenClash,那么每次刷机都需要再配置一遍,比较麻烦;虽说路由器已经是一代传奇 K2P 和 NeWifi 了,但性能总是孱弱的,开启 Clash 之后假死是经常的事儿,会导致 All-In-Boom。所以路由器本身一定要负载轻一点,配置简单一点
  2. 目前用的是树莓派 3B+,过几天会新到一个 x86 的小主机做 HomeLab。那么我肯定不会直接在主机上跑 Clash。而且人家 Docker 都给你做好了,为啥还要装个 Debian,再自己在 Debian 里面搞 Clash 呀?直接用 Docker 不香么?
  3. 我真的看不懂 iptables……尝试了无数次了,只会把网络搞炸,所以能不用 iptables 就尽量不用

于是就这样洁癖下来……嗯,搞出了这样一套方案。

Docker

我希望 Clash 有自己的 IP,这样会便于管理。这里另一个考虑是,我不想占用宿主机的端口(哦,说实话,是「记不住端口」)。

那么怎么搞固定 IP 地址呢?这里有请强大的 macvlan 登场。使用 macvlan 可以给 docker 搞自定义 ip 地址,甚至可以搞到和宿主机相同网段的 ip 地址。

这里我提前在树莓派上装了 portainer,所以各种操作都是在 portainer 上来完成的。当然命令行也可以完成一切,只是……我不会😂

设置 macvlan 网络

在「网络」里面新建一个网络,名字的话我叫做 base_macvlan。驱动选 macvlan ,然后设置选 Configuration。网卡的话,我去树莓派里面查了一下,网卡名称叫 eth0(有些 Debian 系统叫 en0 吧?)。 下面的网络选项里面,都填和宿主机相同的东西,例如子网是 192.168.1.1/24 ,ip 范围是 192.168.1.1/24 ,网关是 192.168.1.1 之类的。点击保存。

然后,再添加一个网络,名字的话我叫做 static_ip ,驱动依旧是 macvlan ,不过这次下面要选成 Creation 了。下面还有个地方让选「从哪个配置创建网络」,就选择刚才创建的 base_macvlan 就好了。

如果想直接在 docker-compose.yaml 里面写的话,也行:

networks:
  magic:
    name: static_ip
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: "192.168.1.0/24"
          ip_range: "192.168.1.0/24"
          gateway: "192.168.1.1"

到这里,我们有给 Docker 分配固定 IP 的能力了。

部署容器

直接写个 Docker-compose 比较省心:

version: "3"
services:
    clash:
        container_name: Clash
        image: dreamacro/clash-premium
        restart: always
        privileged: true
        devices:
            - /dev/net/tun
        volumes:
            - /path/to/config/dir/Clash:/root/.config/clash
        networks:
            magic:
                ipv4_address: 192.168.1.2
    adguard:
        container_name: Adguard
        image: adguard/adguardhome
        restart: always
        volumes:
            - /path/to/config/dir/Adguard/conf:/opt/adguardhome/conf
            - /path/to/config/dir/Adguard/work:/opt/adguardhome/work
        networks:
            magic:
                ipv4_address: 192.168.1.53
networks:
    magic:
        name: static_ip
        external: true

可以看到,给 clash 了比较高的权限,或者只加 NET_ADMIN 好像也成,我没有自己试验。另外需要注意,如果不加 /dev/net/tun 的话,用 TUN 模式会报错,说开启 TUN 模式不成功。

另外如果想直接在 docker-compose.yaml 里面创建网络的话,从上面抄过来替换掉就好了

AdGuard Home

哎?似乎有什么东西乱入了?

主要是想用 AdGuard 来去广告。但是网上几乎没有和 AdGuard 做集成的方案。那就自己捣鼓一下。

分配了固定 ip,因为 53 比较好记。配置也很简单,就直接部署就好了,http 管理端口甚至选择成了 80,这样输入 ip 就能进管理界面了。

Clash

这里其实没啥好说的,照着文档写就是了。

# Outbound interface name
# interface-name: eth0
# fwmark on Linux only
routing-mark: 7777
# DNS server settings
# This section is optional. When not present, the DNS server will be disabled.
dns:
  enable: true
  listen: :53
  ipv6: true # when the false, response to AAAA questions will be empty
  # These nameservers are used to resolve the DNS nameserver hostnames below.
  # Specify IP addresses only
  default-nameserver:
    - 192.168.1.53
    # - 223.5.5.5
    # - 114.114.114.114
    # - 8.8.8.8
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16 # Fake IP addresses pool CIDR
  # use-hosts: true # lookup hosts and return IP record
  
  # Hostnames in this list will not be resolved with fake IPs
  # i.e. questions to these domain names will always be answered with their
  # real IP addresses
  fake-ip-filter:
    - '*.lan'
  
  # Supports UDP, TCP, DoT, DoH. You can specify the port to connect to.
  # All DNS questions are sent directly to the nameserver, without proxies
  # involved. Clash answers the DNS question with the first result gathered.
  nameserver:
    - 192.168.1.53
    # - tls://dns.rubyfish.cn:853 # DNS over TLS
    # - https://1.1.1.1/dns-query # DNS over HTTPS
    - dhcp://eth0 # dns from dhcp
  # When `fallback` is present, the DNS server will send concurrent requests
  # to the servers in this section along with servers in `nameservers`.
  # The answers from fallback servers are used when the GEOIP country
  # is not `CN`.
  fallback:
    - tls://8.8.8.8:853
    - tls://8.8.4.4:853
    - https://1.1.1.1/dns-query
    - https://dns.google/dns-query
  # If IP addresses resolved with servers in `nameservers` are in the specified
  # subnets below, they are considered invalid and results from `fallback`
  # servers are used instead.
  #
  # IP address resolved with servers in `nameserver` is used when
  # `fallback-filter.geoip` is true and when GEOIP of the IP address is `CN`.
  #
  # If `fallback-filter.geoip` is false, results from `nameserver` nameservers
  # are always used if not match `fallback-filter.ipcidr`.
  #
  # This is a countermeasure against DNS pollution attacks.
  fallback-filter:
    geoip: true
    geoip-code: CN
    # ipcidr:
    #   - 240.0.0.0/4
    # domain:
    #   - '+.google.com'
    #   - '+.facebook.com'
    #   - '+.youtube.com'
  
  # Lookup domains via specific nameservers
  # nameserver-policy:
  #   'www.baidu.com': '114.114.114.114'
  #   '+.internal.crop.com': '10.0.0.1'
tun:
  enable: true
  stack: system 
  auto-route: true
  auto-detect-interface: true 
  dns-hijack:
    - any:53
    - tcp://any:53
auto-redir:
  enable: true
  auto-route: true
# ebpf:
#   redirect-to-tun:
#     - eth0

额,还是说两句吧。网上各种教程比较多,但还是建议直接看 Clash 的文档

default-nameserver 对应 AdGuardHome 里面的 bootstrap name server ,是用来将 nameserver 里面的各式各样的 DNS 服务器解析成 IP,这样 nameserver 里面的 DNS 服务器才能起作用。所以 default-nameserver 随便填一个 IP 形式的 DNS 服务器就好, nameserver 填常用的各种形式的服务器。

因为我想用 AdGuard 嘛,所以 default-nameserver 和 nameserver 这里都填成了我的 AdGuard。如果你没有用 AdGuard 的话, default-nameserver 填几个 IP 形式的 DNS 服务器, nameserver 随便填一些公共 DNS 就好。

然后看 fallback-filter ,在注释里写得比较明白了,但是有些是正逻辑有些是反逻辑,就比较绕:

  • 如果 DNS 解析出来的东西在某个 IP 范围内,那么认为结果不可信,所以再用 fallback DNS 再解析一次(正逻辑)
  • 如果地理位置是 CN,那么直接认为是可信,不会再走 fallback DNS(反逻辑)
  • 有些域名可以强制用 fallback DNS 进行解析(正逻辑)

哦对了,这里解释一下为啥 DNS 设置会这么复杂和重要。由于我们直接获取到的 DNS 不可信,那么 Clash 拿到查来的 DNS 结果后会再进行校验,如果符合一定的规则就直接用,否则就再用 fallback DNS 去再请求一次,拿到干净的结果。其实吧,如果我们的 DNS 是非常干净的,那么也就没这么多麻烦事儿了,直接配上一个干净的 DNS(比如我们假设 AdGuardHome 里面能拿到某些网站的无干扰解析结果),然后流量从 Clash 里面走,也能用。所以 DNS 其实和流量路由是完全两个事情。只不过……Clash 说「都可以包在我身上」,那就……那就这样吧别纠结了。

最后是 TUN 部分。打开 auto-route 其实就好了。然后如果使用 ebpf 的话,需要关掉 auto-route ,并开启 ebpf 那部份的配置。

最后是 auto-redir ,有了这个就不用我们自己写 iptables 了。

OpenWRT

之前一直只用 AdGuard Home,所以知道 DHCP 可以直接下发 DNS 配置。那么这次我们也可以让 DHCP 直接下发网关配置。

去「网络-接口-LAN」,找到「DHCP-高级设置」,在 DHCP 选项里面添加这两个东西:

3,192.168.100.2
6,192.168.100.2

第一行,是下发网关配置的,第二行是下发 DNS 配置的。然后保存并应用。

开始使用吧

最后,让各种设备重新连接路由器。你会发现,新世界的大门已经打开。


遇到的坑

给 Docker 设置和宿主机一样的网段,并设置固定 IP。这个事情之前在威联通上搞过,不过不太清楚原理。本来也不清楚 macvlan 需要配置两次,都是只配置了一次,导致部署 Docker 一直失败,说什么只读的配置啥啥的。

然后是 DNS。配置好后,发现手机和 Pad 都可以科学上网了,但是电脑死活都不行。那就在电脑上开着 Surge 排查问题。无意中发现,即使把 Surge 放到全局直连,Mac 也能科学上网,而且走的是 Clash,但是把 Surge 关掉,就各种哑巴了。于是去网络里面看了一下,DNS 默认为路由器,手动改成 Clash 就好了。那么这下子简单了:直接去 OpenWRT 里面改一下 DHCP 下发的配置,就不用挨个设备手动改了,可谓一劳永逸。


已发布

分类

作者:

标签

评论

《“Docker Clash 旁路由网关模式透明代理”》 有 2 条评论

  1. qaq 的头像
    qaq

    设置完之后,去 dashboard 里,所有节点都 ping 不通怎么办。。国内网络都是通的,需要那啥的网都上不去

    1. 小金鱼儿 的头像
      小金鱼儿

      看看是不是系统/镜像里面没开包转发?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注