Skip to content

Instantly share code, notes, and snippets.

@davidwu111
Last active September 11, 2024 07:17
Show Gist options
  • Save davidwu111/c3c4ec8e6e6a03676bf2121b9ee352c5 to your computer and use it in GitHub Desktop.
Save davidwu111/c3c4ec8e6e6a03676bf2121b9ee352c5 to your computer and use it in GitHub Desktop.
Clash Docker & Openwrt 配置与踩坑记录

Clash Docker & Openwrt 配置与踩坑记录


使用Openwrt作为主路由,另一台Ubuntu 18.04主机上使用Docker运行Clash来作为网关进行转发,以达到按规则智能翻墙的目的。也是很多人提到的“旁路由”方法。

注:Openwrt可以直接编译OpenClash,我这次只是纯粹为了折腾而折腾。


1. Docker 的安装

首先在Ubuntu中安装Docker,直接apt安装即可

两个包 docker和 docker-compose

sudo apt install -y docker docker-compose

2. Clash配置文件准备

如果不熟悉vi或者nano建议先在自己电脑上编辑好再SSH传上去即可。一共两个文件 docker-compose.yml和 config.yaml

docker-compose.yml 是给docker启动的配置文件,示例如下:

version: '3'
services:
clash:
    image: dreamacro/clash
    volumes:
    - ./config.yaml:/root/.config/clash/config.yaml
    ports:
    - "7890:7890"
    - "7891:7891"
    - "7892:7892"
    - "9090:9090"
    - "5353:5353/udp"
    - "5353:5353/tcp"
    restart: always
    # When your system is Linux, you can use `network_mode: "host"` directly.
    network_mode: "host"
    container_name: clash

其中9090端口是给web ui用的,linux可以直接使用host模式,相当于把主机的网络直接套用给容器使用。 5353给Clash内置的DNS服务使用。不使用默认53端口是防止与Ubuntu自带的systemd冲突。

config.yaml 可以直接将你的Clash托管地址输入浏览器地址栏,会自动下载好包含节点的一个简单设置文件。下载好之后用编辑器打开,我们需要修改一些设置。以下为示例:

port: 7890 # Http代理端口
socks-port: 7891 # Socks 代理端口
redir-port: 7892 # 转发端口
# 因为是局域网转发所以此项必须设置为true
allow-lan: true
mode: Rule
# 日志等级先设置为info以便debug,没问题后设置为silent
log-level: info
# 为web ui设置端口为9090, 其中0.0.0.0为所有IP都可以访问
external-controller: 0.0.0.0:9090
# web ui的链接密码
secret: "123456"
# Clash 自带的DNS 设置,如果你的规则是基于地址的则必须使用。
dns:
enable: true
listen: 0.0.0.0:5353
enhanced-mode: redir-host
nameserver:
    - 114.114.114.114
    - tls://dns.rubyfish.cn:853
fallback:
    - tcp://208.67.222.222:443
    - tls://dns.google
# 以下为节点和规则,通常clash托管会自己有
Proxy:
- name: "?????"
type: vmess
server: ?????
port: 153
uuid: ????
alterId: 64
cipher: auto
network: ???
ws-headers:
    Host: ????

注:使用Fake IP模式的配置文件

dns:
  enable: true
  listen: 0.0.0.0:5353
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  fake-ip-filter: # fake ip white domain list
    - '*.lan'
    - localhost.ptlogin2.qq.com
  nameserver:
    - 218.4.4.4

Fake-IP模式下会自动将符合proxy规则的域名解析需求发给代理服务器,所以不需要fallback,而且可以避免DNS污染。

3. 安装Nginx为web ui提供服务

直接用docker pull最新的nginx镜像,这里我们使用yacd作为管理Clash的web ui,安装也是非常简单的。 下载yacd到本地的目录 下载地址 下载好之后解压到一个本地目录,然后直接启动nginx把这个目录挂上去即可: $ docker container run
-d
-p 127.0.0.2:8080:80
--rm
--name mynginx
--volume "your local yacd path":/usr/share/nginx/html
nginx

4. 配置systemd-resolve

因为53默认端口被占用,所以上面我们给Clash分配了5353端口用于DNS服务。尤其在使用Fake-IP的模式下,如果将Ubuntu自带的systemd-resolved干掉,DNS将会直接由Clash返回假IP,此时则必须配置代理服务器让流量经过代理端口。见第11节添加代理的设置。 推荐根据上面的设置,将Clash的DNS设置为其他端口则不会影响宿主机器本身的网络。建议设置Ubuntu本身直接走路由器,参考下面第五节。

不推荐因为在ubuntu中,DNS的端口53默认已经被占用,所以需要使用DNS的话就不能让systemd占用这个端口。这个问题耗费了我大概一个多小时,大部分的教程都没有提到这个问题。

sudo service systemd-resolved stop
sudo systemctl disable systemd-resolved

5. 为Ubuntu设置静态地址

因为后续要更改路由器下发的网关和DNS,而且本机也需要一个固定IP地址,所以设置静态IP是必须的。 新的Ubuntu使用netplan管理本地网络,通过yaml配置文件来实现。注意yaml文件的名称每个电脑可能不同。 打开文件 /etc/netplan/01-netcfg.yaml 注意netplan对缩进有严格的要求,而且不能用tab必须打空格,以下为我的文件结构:

network:
    ethernets:
        ens18:
            dhcp4: no
            addresses: [192.168.0.10/24, ]
            gateway4:  192.168.0.1
            nameservers:
                addresses: [192.168.0.1, 8.8.4.4]
    version: 2

保存此文件后使用以下命令让设置生效:

sudo netplan apply

然后通过ifconfig来查看设置是否已经起作用。

6. 配置iptables

参考网上其他人的配置,找到一个做的比较好的,请根据自己的网络更改IP地址段和ubuntu主机地址!! 可以写一个简单的bash批处理文件一次运行完成。

#!bin/bash

iptables -t nat -A PREROUTING -p tcp -j clash
iptables -t nat -A PREROUTING -p tcp --dport 53 -j clash_dns
iptables -t nat -A PREROUTING -p udp --dport 53 -j clash_dns
# 将收到的DNS请求转至Clash监听的5353端口。监听端口在config中设置。
iptables -t nat -A clash_dns -p udp --dport 53 -j DNAT --to-destination 192.168.0.10:5353
iptables -t nat -A clash_dns -p tcp --dport 53 -j DNAT --to-destination 192.168.0.10:5353

iptables -t nat -A clash -d 0.0.0.0/8 -j RETURN
iptables -t nat -A clash -d 10.0.0.0/8 -j RETURN
iptables -t nat -A clash -d 127.0.0.0/8 -j RETURN
iptables -t nat -A clash -d 169.254.0.0/16 -j RETURN
iptables -t nat -A clash -d 172.16.0.0/12 -j RETURN
iptables -t nat -A clash -d 192.168.0.0/16 -j RETURN
iptables -t nat -A clash -d 224.0.0.0/4 -j RETURN
iptables -t nat -A clash -d 240.0.0.0/4 -j RETURN

# 转发全部流量
iptables -t nat -A clash -p tcp -j REDIRECT --to-ports 7892

注意当系统重启后,这些iptables的规则会消失,我们需要在测试完成之后,让这些规则还在。 默认情况下,Ubuntu没有iptables的文件,如果想要查看当前的设置,可以参考这篇文章生成一个当前设置的文件。

设置完iptables后设置转发,打开文件/etc/sysctl.conf 找到'net.ipv4.ip_forward=1'之后把注释去掉即可。保存然后运行以下命令让设置生效:

sudo sysctl -p

7. 启动Clash并测试yacd

进入在第二部放两个配置文件的目录,用以下命令启动容器:

sudo docker-compose up -d

启动后查看日志是否有错误:

docker logs clash -f

应该可以看到5个端口都正常在监听的状态:

time="2020-01-29T16:45:30Z" level=info msg="DNS server listening at: 0.0.0.0:53"
time="2020-01-29T16:45:30Z" level=info msg="Redir proxy listening at: :7892"
time="2020-01-29T16:45:30Z" level=info msg="RESTful API listening at: 0.0.0.0:9090"
time="2020-01-29T16:45:30Z" level=info msg="HTTP proxy listening at: :7890"
time="2020-01-29T16:45:30Z" level=info msg="SOCKS proxy listening at: :7891"

Clash 正常启动之后,打开yacd的地址(第三步绑定的是8080),我这里是 192.168.0.10:9091,在界面中输入你的主机IP,管理端口和密码就应该可以正常进去了。 在yacd中可以看到节点已经有正常的ping值就说明clash已经在正常运转了。

8. 测试

使用手机或者电脑将网关和DNS都设置为Ubuntu的IP地址,此时应该可以正常访问网络了。 如果无法正常访问,请查看clash的日志是否端口都已经正常监听。再查看DNS设置是否正确。 另外提醒iptables的设置,一定要按自己的网络实际情况来进行设置。

9. 保持iptables的设置

前面提到iptables重启后会被复位,所以我们需要一个额外的小工具,直接apt安装即可:

sudo apt install iptables-persistent

如果之后有对iptables进行其他更改可以使用iptables-persistent save来保存更改。

10. 更改Openwrt下发网关和DNS

设置的地方在“接口-LAN-DHCP服务器-高级设置-DHCP选项” 在这里分别填入两行内容:

3,192.168.0.10
6,192.168.0.10

第一个3代表下发的网关地址,第二个6代表下发的DNS地址。 当然如果你不想让所有局域网的设备流量都通过Clash可以不做这个更改。

11. 本机的代理设置

需要注意的是Clash不更改本机自身的网络访问模式,所以当我这台运行Docker的Ubuntu访问网络时是直接走的路由器。 特别注意在Fake IP模式下,DNS解析直接给的是一个假的IP地址,这个IP地址直接走路由器网关出去肯定是无法访问任何地址的。参考Ubuntu的代理配置,走的是bash分用户的配置文件。所以分别在自己用户和root下配置一个简单的function。打开.bashrc然后在最后加入以下内容:

# proxyon
proxyon() {
    export https_proxy=http://127.0.0.1:7890
    export http_proxy=http://127.0.0.1:7890
    export all_proxy=socks5://127.0.0.1:7891
    echo "HTTP/HTTPS Proxy on"
}

# proxyoff
proxyoff() {
    unset http_proxy
    unset https_proxy
    unset all_proxy
    echo "HTTP/HTTPS Proxy off"
}

保存后source ./.bashrc让配置文件生效。 当需要使用代理时直接执行proxyon即可。

总结

我在iptables和DNS端口两个坑里面挣扎了将近三小时才搞定,建议各位遇到问题先去查一下组件运行的原理,这样才可以更快debug。 经过测试,这种转发的方法比Openwrt直接编译OpenClash的效率和稳定性要高。当然也有可能是与我Openwrt中其他的东西有冲突造成的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment