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下发的配置,就不用挨个设备手动改了,可谓一劳永逸。


评论

  1. qaq 的头像
    qaq

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

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

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

发表回复

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