在 Raspberry Pi 上运行 Clash 作为透明代理
家里闲置着一个 Raspberry Pi 3 Model B+,决定简单部署一下 Clash 为局域网中的设备“科学”访问网络提供方便。由于路由器用着 Linksys Veloop 和 AirPort Time Capsule,OpenWrt 不适用,我对于更改路由器固件后的稳定性一直表示怀疑,所以就选择在 Pi 上部署 Clash,然后通过修改 iptables 用作透明代理,这样只需要将接入局域网设备的网关和 DNS 手动设置为 Pi 的 IP 地址即可实现同样的功能。
Raspberry Pi Imager 在今年 3 月发布,这使得 Raspbian 的安装更为简单。只需要在 Mac 上下载 Raspberry Pi Imager 的 DMG 并安装,就可以可视化地将 Pi 的镜像写入 microSD 卡。这里我选择了安装 Raspbian Lite,即仅有 CLI 的版本,毕竟只需要命令行就足够了,没有桌面还能提高一些运行效率。
摘要 TL;DR
- Raspberry Pi 的准备配置
- 安装和配置 Clash
- 以守护进程运行 Clash
- 为终端配置代理服务器
- 为 Raspberry Pi 启用 IP 转发
- 配置 iptables 并使其持久化
- 为局域网内的其他设备配置网关和 DNS
Raspberry Pi 的准备配置
启动全新的 Raspbian 后需要做的自然是配置 SSH 相关的信息。这里,为了方便,我选择删除默认的 pi 用户,直接使用 root 用户进行后续的管理。
如果你不希望删除 pi 用户,那么可以忽略接下来的配置。
首先使用 pi 用户的默认密码 raspberry
登录,然后通过 sudo su
和 passwd
命令为 root 用户设置密码。接着通过 sudo raspi-config
访问 Pi 的软件配置工具,选择 3 Boot Options
> B1 Desktop / CLI
> B1 Console
然后重新启动从而禁用自动登录,否则 Raspbian 将自动登录到 pi 用户,会导致其无法删除。
重新启动后,登录到 root 用户,通过 deluser --remove-home --remove-all-files pi
命令将 pi 用户及其相关文件删除。
接着,配置网络连接。我的 Pi 使用 Wi-Fi 连接到网络,因而需要在 raspi-config
中选择 2 Network Options
> N2 Wi-Fi
,然后分别输入 SSID 名称和密码,使 Pi 连接 Wi-Fi。当然,需要在路由器中为 Pi 分配一个静态的 IP 地址而非由 DHCP 服务器动态分配,以便于其他设备可以通过固定的 IP 地址访问到 Pi,例如这里,我将 Pi 的 IP 地址配置为 10.0.1.11。
安装和配置 Clash
访问 https://github.com/Dreamacro/clash 查看有关 Clash 的信息。
可以使用 Go 直接 build,这里我直接使用 Premium release 的二进制文件,截至文章发布,最新版本为 Premium 2020.05.08。Raspberry Pi 3 Model B+ 为 ARMv7 架构(可以通过 arch
命令查看),因此选择 clash-linux-armv7-2020.05.08.gz。
wget https://github.com/Dreamacro/clash/releases/download/premium/clash-linux-armv7-2020.05.08.gz
gunzip clash-linux-armv7-2020.05.08.gz
mv clash-linux-armv7-2020.05.08.gz /usr/local/bin/clash
chmod +x /usr/local/bin/clash
这样,将 Clash 的二进制文件下载并放置于 /usr/local/bin/
路径中,增加 execute 权限。
执行一次 clash
命令,Clash 会自动创建 $HOME/.config/clash/
配置目录,并新建默认配置文件 config.yaml 和名为 Country.mmdb 的 GeoIP 数据库。接着修改 config,yaml 配置文件,如下是一个示例配置供参考。
port: 8888
socks-port: 8889
redir-port: 8890
allow-lan: true
mode: Rule
log-level: info
# external-controller: 0.0.0.0:6300
# external-ui: clash-dashboard
# secret: "your-secret-passphrase"
experimental:
ignore-resolve-fail: false
dns:
enable: true
ipv6: false
listen: 0.0.0.0:53
enhanced-mode: redir-host
nameserver:
- https://dns.alidns.com/dns-query # DNS-over-HTTPS
hosts:
"dns.alidns.com": 223.5.5.5
proxies:
...
proxy-groups:
...
rules:
...
GEOIP,DIRECT
MATCH,Proxy
需要注意以下的一些配置。
allow-lan: true
允许 Clash 处理来自局域网内其他设备的流量。redir-port: 8890
意味着 Clash 将会监听 8890 端口以处理局域网内其他设备所转发的流量。而port: 8888
和socks-port: 8889
分别声明了用作 HTTP / HTTPS 和 SOCKS5 代理的端口。- 在
dns
中需要配置enable: true
允许 Clash 用作 DNS 服务器,配置enhanced-mode: redir-host
以用于透明代理,并声明listen: 0.0.0.0:53
以监听 53 端口。如果要绑定例如 53 等低位端口,就必须要使用root
用户;如果使用pi
等普通用户运行 Clash 将会出现端口绑定的权限错误。 - 关于
dns
中的nameserver
配置,可以使用常用的公共 DNS 如 114.114.114.114、8.8.8.8 等,也可以配置 DNS-over-HTTPS。这里我使用https://dns.alidns.com/dns-query
即阿里 DNS 的 DoH,并且增加了一条hosts
配置"dns.alidns.com": 223.5.5.5
,这样就不需要再对 dns.alidns.com 进行解析了。
至于 proxies
、proxy-groups
以及 rules
的配置,则可以根据需要自行编辑。更多 Clash 示例配置及说明可以参考 https://github.com/Dreamacro/clash#config 中的内容。
如果需要通过浏览器可视化地查看 Clash 运行情况,可以下载 clash-dashboard。
cd $HOME/.config/clash/
git clone https://github.com/Dreamacro/clash-dashboard.git
git checkout -b gh-pages origin/gh-pages
取消注释 external-controller
、external-ui
和 secret
,并配置 secret
作为访问 dashboard 的口令。
在终端中通过 clash
命令启动 Clash。如果配置了 dashboard,可以在局域网内的其他设备上开启浏览器,访问 http://10.0.1.11:6300/ui/,其中 10.0.1.11 即此前配置的 Pi 的 IP 地址,端口 6300 即 Clash 监听的外部控制器端口。然后输入如下信息:
- Host 为 10.0.1.11,即 Pi 的 IP 地址。
- 端口为 6300,即
external-controller: 0.0.0.0:6300
所配置的端口。 - 密钥即
secret
所配置的口令,上述示例中为your-secret-passphrase
。
至于 clash-dashboard 的后续用法应该非常简单明了,这里就不再介绍。
以守护进程运行 Clash
显然,直接在终端中运行 clash
会使 Clash 随着终端的退出而关闭。这时就需要将其作为守护进程运行,这里选择使用 PM2。
运行 wget -qO- https://getpm2.com/install.sh | bash
安装 PM2。有关 PM2 的一些基本使用方法,可以 查阅其文档。如下是一些简要的 PM2 的用法。
# Start, restart, stop and delete Clash instance
pm2 start|restart|stop|delete clash
# 查看所有 PM2 实例
pm2 list
# 删除所有 PM2 示例
pm2 kill
# 查看 Clash 日志
pm2 logs clash
# 清空 Clash 日志
pm2 flush clash
通过 pm2 list
查看 Clash 实例的状态为 online 并且 pm2 logs clash
的日志中没有错误输出,这表明 Clash 已经作为守护进程正确运行了。
为终端配置代理服务器
尽管我们的目的是为局域网内的其他设备配置代理服务器,但我们也经常需要在终端通过代理服务器访问一些资源。由于在 Clash 配置文件中声明了 port: 8888
,所以我们可以在 .zshrc、.bashrc 或 .bash_profile 中增加以下内容。
# Define `setproxy` command to enable proxy configuration
setproxy() {
export http_proxy="http://localhost:8888"
export https_proxy="http://localhost:8888"
}
# Define `unsetproxy` command to disable proxy configuration
unsetproxy() {
unset http_proxy
unset https_proxy
}
# By default, enable proxy configuration for terminal login
setproxy
这样,就可以在终端中使用 setproxy
或 unsetproxy
命令分别配置或取消配置代理服务器了,并且默认地为终端启用代理服务器。
为 Raspberry Pi 启用 IP 转发
编辑 /etc/sysctl.conf 文件,将 net.ipv4.ip_forward=0
修改为 net.ipv4.ip_forward=1
,然后执行 sysctl -p
以使配置生效。
配置 iptables 并使其持久化
在启用 IP 转发后,我们需要增加 iptables 规则对流量进行处理。通过以下命令,创建名为 CLASH 的链,将 TCP 流量转发到 8890 端口并将访问专有网络 IP 地址的流量排除其外。
# Create CLASH chain
iptables -t nat -N CLASH
# Bypass private IP address ranges
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
# Redirect all TCP traffic to 8890 port, where Clash listens
iptables -t nat -A CLASH -p tcp -j REDIRECT --to-ports 8890
iptables -t nat -A PREROUTING -p tcp -j CLASH
不过,iptables 规则会在 Pi 重新启动后清空,因而需要借助 iptables-persistent 实现持久化。
apt install iptables-persistent netfilter-persistent
netfilter-persistent save
运行 netfilter-persistent save
会将刚才配置的 iptables 规则保存在 /etc/iptables/rules.v4 文件中,并会在 Pi 重新启动后自动加载,也可以使用 netfilter-persistent reload
命令手动加载到 iptables。
为局域网内的其他设备配置网关和 DNS
最后,将局域网内其他设备的网关和 DNS 均配置为 Pi 的 IP 地址 10.0.1.11 即可,下图以 iOS 设备为例。在浏览器中访问 http://10.0.1.11:6300/ui/,可以查看到经由 Clash 处理的所有当前连接。