这个功能,我晚用上了5年……只要设备接入Wi-Fi,就能无感科学上网,还是蛮舒服的。
首先说说我的想法:
- 不想在路由器上直接跑Clash:路由器这种东西,稳定性是首要的,然后由于我刷它的频率比较高,所以配置不能太复杂。官方OpenWRT,里面啥都不带。如果直接装个OpenClash,那么每次刷机都需要再配置一遍,比较麻烦;虽说路由器已经是一代传奇K2P和NeWifi了,但性能总是孱弱的,开启Clash之后假死是经常的事儿,会导致All-In-Boom。所以路由器本身一定要负载轻一点,配置简单一点
- 目前用的是树莓派3B+,过几天会新到一个x86的小主机做HomeLab。那么我肯定不会直接在主机上跑Clash。而且人家Docker都给你做好了,为啥还要装个Debian,再自己在Debian里面搞Clash呀?直接用Docker不香么?
- 我真的看不懂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下发的配置,就不用挨个设备手动改了,可谓一劳永逸。
发表回复