2026/9/23

在 Omarchy 上使用 Specola

本文从一台全新的 Omarchy 开始,最终做到:gitcargonpmdocker pull 走公司代理,其他流量保持直连;用一个 Hyprland 快捷键开关分流,并在 Waybar 里看到当前状态。

本文假设 specola-core 安装在 /usr/local/bin/specola-core。官方 AUR 包在路线图中;在那之前, 请安装 Linux 版本,放在其他位置时相应调整路径。

1. 检查内核

Linux eBPF 增强模式需要 Linux 5.17 或更新版本、挂载在 /sys/fs/cgroup 的 cgroup v2,以及内核 BTF。Omarchy 自带的 Arch 内核三者都满足,不过还是检查一下:

uname -r                          # 5.17 或更新
stat -fc %T /sys/fs/cgroup        # cgroup2fs
test -r /sys/kernel/btf/vmlinux && echo BTF ok

2. 编写配置

Specola 读取一份 TOML 配置。把它放在服务会读取的位置:

sudo mkdir -p /etc/specola
sudo nvim /etc/specola/profile.toml
[general]
route-mode = "rule"
log-level = "info"
port = 7890
protocols = ["socks5", "http"]

# 公司代理。替换成你有权使用的服务器。
[[proxy]]
name = "office"
type = "http"
server = "proxy.corp.example"
port = 8443
username = "you"
password = "replace-me"

[proxy.tls]
enabled = true

# 公司代理健康时使用它,否则直连。
[[proxy-group]]
name = "work"
type = "fallback"
proxies = ["office", "DIRECT"]
url = "https://www.gstatic.com/generate_204"
interval = 300

[rule]
list = [
  # 开发工具,按内核可见的进程名匹配。
  "PROCESS-NAME,git-remote-http,work",  # HTTPS 协议的 git(comm 截断为 15 字节)
  "PROCESS-NAME,cargo,work",
  "PROCESS-NAME,node,work",             # npm、pnpm、yarn 实际进程都是 node
  "PROCESS-NAME,dockerd,work",          # 拉取镜像的是守护进程,不是 docker 命令本身
  # 内部域名。
  "DOMAIN-SUFFIX,corp.example,office",
  # 局域网保持本地。
  "IP-CIDR,192.168.0.0/16,DIRECT,no-resolve",
  "IP-CIDR,10.0.0.0/8,DIRECT,no-resolve",
  "FINAL,DIRECT",
]

# eBPF 后端始终启用 Core 的 DNS 模块;Fake-IP 保证域名规则可用。
[dns.tun]
mode = "fake-ip"

[enhanced-mode]
enable = true
type = "ebpf"
ip-version = "ipv4"

[enhanced-mode.ebpf]
process-routing = true

几个能省下排错时间的细节:

先以普通用户校验配置,不改动网络:

specola-core -t --config /etc/specola/profile.toml

3. 以服务方式运行

增强模式需要 root 权限来加载 BPF 程序并挂到 cgroup 层级上。用 systemd 服务把这份权限隔离在 桌面会话之外:

# /etc/systemd/system/specola.service
[Unit]
Description=Specola traffic router
After=network-online.target
Wants=network-online.target

[Service]
ExecStart=/usr/local/bin/specola-core --config /etc/specola/profile.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target

systemd 用 SIGTERM 停止服务,Specola 借此干净地卸载 BPF 程序。不要用 SIGKILL 停止它。

sudo systemctl daemon-reload
sudo systemctl start specola
journalctl -u specola -f

启动成功时日志包含:

Linux IPv4 process proxy started with cgroup eBPF socket redirection (IPv6 bypassed)

如果希望当前用户无需输入密码即可启停服务,添加一条 polkit 规则:

// /etc/polkit-1/rules.d/50-specola.rules
polkit.addRule(function (action, subject) {
  if (action.id == "org.freedesktop.systemd1.manage-units" &&
      action.lookup("unit") == "specola.service" &&
      subject.isInGroup("wheel")) {
    return polkit.Result.YES;
  }
});

4. Hyprland 快捷键

创建一个开关脚本:

#!/usr/bin/env bash
# ~/.local/bin/specola-toggle
if systemctl is-active --quiet specola; then
  systemctl stop specola && notify-send "Specola" "Routing off"
else
  systemctl start specola && notify-send "Specola" "Routing on"
fi
pkill -RTMIN+8 waybar
chmod +x ~/.local/bin/specola-toggle

然后在 ~/.config/hypr/bindings.conf 中绑定:

bind = SUPER SHIFT, N, exec, ~/.local/bin/specola-toggle

5. Waybar 状态模块

直接用服务状态作为信号:

#!/usr/bin/env bash
# ~/.local/bin/specola-waybar
if systemctl is-active --quiet specola; then
  echo '{"text": "SPC", "tooltip": "Specola: routing on", "class": "on"}'
else
  echo '{"text": "SPC", "tooltip": "Specola: routing off", "class": "off"}'
fi

~/.config/waybar/config.jsoncmodules-right 中加入 "custom/specola",再定义模块:

"custom/specola": {
  "exec": "~/.local/bin/specola-waybar",
  "return-type": "json",
  "interval": 10,
  "signal": 8,
  "on-click": "~/.local/bin/specola-toggle"
}

~/.config/waybar/style.css 中加上样式:

#custom-specola.off { opacity: 0.4; }

signal: 8 与开关脚本里的 pkill -RTMIN+8 waybar 对应,按下快捷键后模块立即刷新。支持切换 模式的官方 Waybar 模块在我们的路线图中;这个脚本版本今天就能用。

6. 验证

git ls-remote https://github.com/git/git HEAD   # 日志中可以看到它经由 "work" 转发
sudo bpftool cgroup tree /sys/fs/cgroup          # 列出 Specola 挂载的程序

执行 systemctl stop specola 后,bpftool cgroup tree 中应不再有这些程序。遇到问题时, Linux eBPF 手册列出了常见错误及其含义。