Cherysun’s Tech Cafe

在 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 的版本,毕竟只需要命令行就足够了,没有桌面还能提高一些运行效率。

Raspberry Pi 的准备配置

启动全新的 Raspbian 后需要做的自然是配置 SSH 相关的信息。这里,为了方便,我选择删除默认的 pi 用户,直接使用 root 用户进行后续的管理。

如果你不希望删除 pi 用户,那么可以忽略接下来的配置。

首先使用 pi 用户的默认密码 raspberry 登录,然后通过 sudo supasswd 命令为 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: 8888socks-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 进行解析了。

至于 proxiesproxy-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-controllerexternal-uisecret,并配置 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

这样,就可以在终端中使用 setproxyunsetproxy 命令分别配置或取消配置代理服务器了,并且默认地为终端启用代理服务器。

为 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 处理的所有当前连接。

感谢您的支持与贡献

您的捐款将使您阅读到的内容变得更好。

支持微信支付和支付宝。

感谢您的支持与贡献

您的捐款将使您阅读到的内容变得更好。

触摸并按住二维码,选择识别图中二维码