Veer 是一个面向虚拟机宿主机和二级路由场景的可编程 Linux 网络转发服务。它用 Go 编写,内置 Web UI、管理 API、SQLite 持久化和 Linux 内核 dataplane,可把端口转发、共享建站、端口范围、Egress NAT、托管网络、IPv6 分发和运行时诊断统一收敛到一个进程里管理。
开发者 API 见 API.md。
Linux 服务器推荐直接使用一键引导脚本。请先进入 root shell(例如执行 sudo -i),并确认宿主机正在运行 systemd 或 OpenRC;容器或 chroot 中没有可用服务管理器时不能完成整套部署:
bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)如果 GitHub Raw 不通:
tmpdir="$(mktemp -d)" && \
curl -fsSL https://codeload.github.com/Unicode01/veer/tar.gz/refs/heads/main | tar -xzf - --strip-components=1 -C "$tmpdir" && \
bash "$tmpdir/bootstrap.sh"Alpine 的默认 shell 是 ash,首次安装请先准备 Bash、curl 和证书,再使用不依赖进程替换的入口:
apk add --no-cache bash curl ca-certificates
bootstrap_file="$(mktemp)" && \
curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh -o "$bootstrap_file" && \
bash "$bootstrap_file"
rm -f -- "$bootstrap_file"常用部署参数:
VEER_REF=main bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)
WEB_BIND=0.0.0.0 bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)
WEB_UI_ENABLED=false bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)
READY_TIMEOUT_SECONDS=180 bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)
VEER_INSTALL_PLUGINS=1 bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh)
bash <(curl -fsSL https://raw.githubusercontent.com/Unicode01/veer/refs/heads/main/bootstrap.sh) -- --no-inherit-statsWEB_BIND=0.0.0.0 会让管理面接受远程连接,但 Veer 本身只提供 HTTP。仅应在受信管理网或 VPN 内使用;公网访问应保持 Veer 监听回环地址,并由启用 TLS 与访问控制的反向代理转发。对新建非回环配置、首次从回环地址改为远程监听,或在远程监听下显式更换令牌,deploy.sh 要求 web_token(以及非空的 plugin_admin_token)至少包含 24 个字符,一键部署生成的 32 字符随机令牌已满足要求。Veer 运行时为兼容既有及手工管理的配置,只会对远程监听下的短令牌输出安全警告而不会拒绝启动;应安排轮换,但不要在未同步更新 WHMCS/API 客户端时直接更换。
bootstrap.sh 会安装依赖、拉取源码、执行 release.sh 构建,再调用 deploy.sh 安装或热更新。默认只构建和安装 Veer 核心;设置 VEER_INSTALL_PLUGINS=1 才会构建并安装 bundled stable 插件。它支持 apt、dnf/yum、apk 以及 systemd/OpenRC。中国大陆网络环境下会自动优先使用可用的 Go 镜像和 Go module 代理。
从更名前的 main 版本升级时,deploy.sh 会把默认目录 /opt/forward 迁移到 /opt/veer,将服务切换为 veer.service,并保留 /opt/forward、forward 二进制名和 forward.service 兼容入口。现有 forward.db、内核状态目录和配置文件不会改名;旧 FORWARD_* 部署变量仍可使用,同时设置时 VEER_* 优先。
需要手动部署时:
./release.sh amd64
scp veer-linux-amd64 deploy.sh config.example.json root@server:/tmp/
ssh root@server 'cd /tmp && chmod +x deploy.sh && ./deploy.sh'需要插件时额外上传 veer-plugins.tar.gz,并以 VEER_INSTALL_PLUGINS=1 ./deploy.sh 部署。安装插件文件与启用插件相互独立,升级时未请求安装不会删除或覆盖现有插件目录。
部署后默认访问:
http://127.0.0.1:8080
本机探针:
http://127.0.0.1:8080/healthz
http://127.0.0.1:8080/readyz
Veer 适合把 Linux 宿主机作为 VM/容器的默认转发器或二级路由,统一管理入口、出口和下联网络。
典型场景:
- Proxmox VE、KVM、Linux bridge、veth/tap 等宿主机网络
- 公网端口、端口段转发到 VM 或容器
- 多台 VM 共享宿主机 TCP
80/443,并可选共享 UDP443的 QUIC/HTTP/3,按域名回源 - 下联 bridge 的 IPv4 DHCP、静态保留、IPv6 分发和 Egress NAT
userspace / TC / XDP多 dataplane 转发与自动回退
核心功能:
- 单端口转发:TCP、UDP、TCP+UDP
- 共享站点:HTTP/HTTPS 共享入口,可选 QUIC/HTTP/3,按域名转发到不同后端
- 端口范围:连续端口区间映射到指定后端
- Egress NAT:按父接口、子接口、出接口、源地址管理出向 NAT
- 托管网络:创建或托管 existing bridge,维护 IPv4 DHCP、保留地址、自动 Egress NAT
- IPv6 分发:向目标接口下发
/128或/64 - 诊断页:Kernel Runtime、Worker 状态、规则/站点/范围/Egress NAT 统计
配套能力:
- Web UI 和 Bearer Token API
- SQLite 配置与状态持久化
- Worker 热重载和 draining
- TC/XDP 内核态热更新、状态观测和异常恢复
- Goja 控制面与 TC eBPF pipeline 插件系统
- WHMCS addon 插件
共享站点的 QUIC 开关默认关闭。启用后,Veer 会监听同一入口 IP 的 UDP 443,从 QUIC v1/v2 Initial 中解析 TLS SNI,再把原始数据报转发到 backend_https_port;Veer 不终止 TLS,也不替后端校验证书。deploy.sh 不会为这个可选功能自动开放 UDP 443;启用前需确认防火墙允许该端口、后端在同一端口提供 QUIC/HTTP/3,且没有普通 UDP 规则或端口范围占用该监听地址。使用 UFW 时可执行:
ufw allow 443/udpECH 隐藏实际 SNI、QUIC 连接迁移,以及同一客户端端点复用多条连接时的未知 CID 轮换目前不在支持范围内。
明文 HTTP 的每个 keep-alive 请求都会重新检查 Host 并清除客户端提供的来源转发头,支持流式响应和 Upgrade。HTTPS 支持跨 TLS record 的 ClientHello,但路由缓冲总量限制为 64 KiB,单个 record 限制为 16 KiB。
生产建议:
- 运行在 Linux 上
- 默认把管理面绑定到
127.0.0.1 - 内核 dataplane 优先使用
TC - 默认
kernel_engine_order为["tc"] XDP只在目标拓扑验证通过后显式加入启用
典型 VM 宿主机拓扑:
公网
|
| 203.0.113.10
|
宿主机
├─ eth0 上联/公网接口
└─ vmbr0 下联/VM bridge,198.51.100.1/24
├─ VM-A 198.51.100.10
└─ VM-B 198.51.100.20
典型规则:
in_interface = eth0
in_ip = 203.0.113.10
in_port = 2222
out_interface = vmbr0
out_ip = 198.51.100.10
out_port = 22
protocol = tcp
典型 Egress NAT:
parent_interface = vmbr0
child_interface = tap100i0
out_interface = eth0
out_source_ip = 203.0.113.10
protocol = tcp+udp+icmp
nat_type = symmetric
本地运行:
cp config.example.json config.jsonPowerShell:
Copy-Item config.example.json config.json修改 config.json:
web_token必须填写真实随机值- 不能继续使用
change-me-to-a-secure-token
启动:
go run .访问:
http://127.0.0.1:8080
API 认证:
Authorization: Bearer <web_token>
完整示例见 config.example.json。根 README 不再复制整份 JSON,避免示例配置和实际默认值漂移。
关键字段:
web_bind:Web UI / API 监听地址,默认127.0.0.1web_ui_enabled:是否启用静态 Web UI;关闭后仍保留/api/*、/metrics、/healthz、/readyzweb_port:监听端口web_token:Web UI 和 API 共用的 Bearer Tokendefault_engine:auto、userspace、kernelkernel_engine_order:Linux 内核引擎尝试顺序;省略时默认["tc"]managed_network_auto_repair:托管网络链路变化后的自动修复plugins_enabled:是否扫描并运行外部插件;默认关闭,必须手动设为true才会启动外部插件控制面;内置veer_core始终可见plugins_dataplane_enabled:是否允许外部插件进入 TC 数据面;默认关闭,当前支持按 priority 围绕Veer Core排序的 forward/reply TC 链plugins_isolation:是否让每个插件控制 VM 和命名 Worker 运行在独立子进程;默认开启,仅受信任的本地调试才应关闭plugins_min_sandbox_level:插件 Host 最低隔离等级,允许none、minimal、partial、full;默认full,达不到时在执行插件 JavaScript 前拒绝启动plugins_require_signed_packages:是否要求插件包带可独立验证的 Ed25519 签名;默认开启。首次出现的发布者可直接在安装审核中确认,无需预先维护信任列表;开发环境可显式关闭后审批未签名包plugin_admin_token:插件安装、信任、启停和热加载使用的独立高权限令牌;留空时相关写 API 禁用,非空时必须不同于web_tokenplugins_max_installed/plugins_max_staged/plugins_storage_limit_mb:插件安装数、暂存数和插件持久状态总量上限;plugins_repository_refresh_minutes控制启用插件后 TUF 元数据的后台刷新周期plugins_enabled=true时,lab/preview/stable插件可执行控制脚本;进入外部 TC 数据面仍需同时开启plugins_dataplane_enabled;deprecated插件始终禁用plugins_dir:运行时插件目录,默认pluginskernel_rules_map_limit:内核规则 map 容量,0表示自适应kernel_flows_map_limit:内核 flow map 容量,0表示自适应kernel_tcp_established_idle_timeout_seconds:内核已建立 TCP flow 的空闲超时;0表示按 IPv4/IPv6 flow map 的最高利用率自动选择,正数表示固定秒数。auto 在利用率达到 50% / 70% / 85% 时依次采用 6 小时 / 1 小时 / 10 分钟,低负载采用 24 小时;回落阈值分别为 45% / 65% / 80%,避免临界点抖动kernel_nat_ports_map_limit:内核 NAT 端口 map 容量,0表示自适应kernel_nat_port_min/kernel_nat_port_max:内核 Full NAT 临时端口池experimental_features:实验特性开关,默认都应保持关闭,按需验证后再开
Veer 有三条主要 dataplane:
userspace:兼容面最广,作为最终回退路径tc:当前推荐的 Linux 内核主线路径xdp:路径更短,但对网卡、bridge/veth/tap、attach mode 更敏感
引擎选择:
default_engine = userspace:全部走用户态default_engine = kernel:优先内核态,失败后按规则回退default_engine = auto:自动选择可用路径- Linux 下会按
kernel_engine_order尝试内核引擎
用户态转发有进程级资源保护:Linux 的监听数和同时处理的 TCP 连接数分别限制为 min(1024, RLIMIT_NOFILE / 8),以保留后端连接和控制通道的文件句柄空间。范围的 TCP+UDP 每端口占两个监听名额;超过预算的内核回退会报告错误,不会继续创建大量 socket。内核 flow 容量不受这一用户态限制影响。
进入内核态通常需要:
- Linux 上具备 eBPF/TC/XDP 能力
- 规则的入口接口和出口接口可解析
- 后端地址和出接口可达
- Full NAT / Egress NAT 可得到可用源地址,或显式配置
out_source_ip - 规则类型在当前内核路径支持范围内
TC 与 XDP 选择建议:
TC更适合 bridge、tap、veth、PVE 等宿主机场景XDP可用但应按目标拓扑单独验证xdp_generic默认关闭;veth/tap/netns 测试拓扑通常需要显式启用bridge_xdp、kernel_tc_*系列开关都属于实验路径
托管网络有两种模式:
create:由 Veer 动态创建 bridgeexisting:托管宿主机已有 bridge
当前能力:
- IPv4 DHCP
- IPv4 静态保留
- IPv6
/128或/64分发 - 自动 Egress NAT
- 链路变更自动修复
- PVE
qemu-server/lxc配置识别 - PVE guest 链路识别与修复,覆盖
fwpr*、tap*、veth*
PVE 建议:
- 更推荐托管已有 bridge
- 动态创建的 bridge 不一定会被 PVE UI 当作可配置网络
create模式可以持久化到/etc/network/interfaces,写入前会创建备份- bridge 持久化面向 ifupdown/PVE 环境,不是通用网络管理器
IPv6 分发用于给指定接口下发 /128 或 /64:
/128更适合精确分配给单个 VM 或接口/64更适合让下游继续分发,但需要明确下游是否可信- DHCPv6/RA 负责地址下发,不等于强制防伪造
- 如需强约束地址使用,应在链路层、bridge、hypervisor、nftables/TC 或上游路由策略上配合
Web UI 的诊断页和 GET /api/kernel/runtime 可查看:
- 当前默认引擎与配置顺序
- TC/XDP active entries
- attach 状态和 attach mode
- map 占用、容量、自适应配置
- degraded / pressure / retry / self-heal 状态
- Worker 状态和 runtime error
- 规则、站点、范围、Egress NAT 统计
热更新与异常退出:
deploy.sh热更新时会尝试交接活动的 userspace rule/range/shared-proxy worker;无法交接的 worker 会由新进程重建- shared-proxy 二进制更新会关闭旧 QUIC/UDP 监听和中继会话,QUIC 客户端可能需要重连;TCP 已建立连接可以排空,不能据此推断 QUIC 同样无损交接
- TC/XDP 路径会尽量继承内核 flow / NAT / stats 状态;使用
--no-inherit-stats时 stats 会重新累计 - 新版本启动、重启或
/readyz检查失败时,已有安装会自动回滚二进制、配置、服务定义和本次部署替换的 bundled plugins - 自动回滚不恢复 SQLite 数据库,也不恢复任意外部插件产生的状态;部署前服务原本未运行时只回滚文件,不会自动启动旧版本
- 上述机制以尽量不断流为目标,不是绝对零中断承诺
- 如果进程被
kill -9、OOM kill 或异常崩溃,内核附加点可能短时间继续存在 - 下次启动会尝试识别并清理 orphan 附加点
release.sh 会把 wan_core、lan_core、vtolocal 和 pppoe_client 四个 stable 插件打成可选包;部署默认不安装插件,设置 VEER_INSTALL_PLUGINS=1 才会安装。安装后仍需手动设置 plugins_enabled=true 才会运行插件控制面,进入 TC 数据面还需设置 plugins_dataplane_enabled=true。packet_observer 与 router_wizard 仍是源码内的 lab 插件,不进入默认发布包。插件架构、开发接口和边界说明见 PLUGIN.md。
推荐运行环境:
- Debian 11+
- Ubuntu 22.04+
- RHEL-compatible 9+
- Fedora 38+
- Alpine 3.19+
- Proxmox VE 7+,更推荐 PVE 8+
最终以宿主机实际内核版本和 eBPF 能力为准,不只看发行版版本号。旧内核可能只能运行用户态路径,或无法稳定使用内核 dataplane。默认 full 插件沙箱还要求 cgroup v2 提供 cpu、memory、pids controller;不满足时核心仍可运行,但外部插件会被拒绝启动。
引导脚本同时安装 nftables 和 iptables:透明用户态转发目前仍需要 iptables 的 socket match 与 mangle MARK 支持,不能只安装 nftables。systemd 与 OpenRC 部署均设置 65535 的文件句柄上限。systemd 保留 ProtectSystem=strict,插件 namespace 的创建和删除由父进程进入宿主挂载空间执行,以保留跨服务重启的命名 namespace;打开该句柄需要父进程具有 CAP_SYS_PTRACE,插件子进程不继承此权限。
OpenRC 部署会在 cgroup 尚未挂载时启动并启用系统的 cgroups 服务;每次启动将 Veer 与 supervisor 分配到不同子组,供插件启用 cpu/memory/pids 资源隔离。热更新保留的 worker 不会被移动或清理;停止服务时只移除空 cgroup。已有的 cgroup 挂载与 controller 配置不会被重新挂载或替换。
两种服务管理器每次启动都会准备 /run/netns、bpffs 与状态目录,确保重启系统后仍可启动。systemd 用前置服务准备宿主目录与挂载,Veer 主进程继续使用上述文件系统保护。
托管网络的运行时桥使用 netlink,跨上述发行版可用;“持久化桥”目前只写 /etc/network/interfaces。RHEL/Fedora 默认使用 NetworkManager 时,应由 nmcli 或发行版网络配置管理宿主桥。
构建要求:
- Go 1.26.6+
clang- Debian/Ubuntu 通常需要
linux-libc-dev - RHEL-compatible/Fedora 通常需要
kernel-headers
运行内核 dataplane、透明转发或低位端口可能需要:
CAP_NET_BIND_SERVICECAP_NET_RAWCAP_NET_ADMINCAP_BPFCAP_PERFMON
本地构建:
go build -o veer .交叉构建 Linux 二进制:
./release.sh只构建指定架构:
./release.sh amd64
./release.sh arm64release.sh 会先编译并嵌入 core eBPF 对象,同时生成可选的 veer-plugins.tar.gz 和独立开发者产物 veer-plugin-sdk.tar.gz:
internal/app/ebpf/forward-tc-bpf.ointernal/app/ebpf/forward-tc-bpf-stats.ointernal/app/ebpf/forward-xdp-bpf.ointernal/app/ebpf/forward-xdp-bpf-stats.ointernal/app/ebpf/plugin-xdp-dispatcher-bpf.o
只重建 eBPF object 时可使用:
sh scripts/build-ebpf.sh
sh scripts/build-plugin-ebpf.sh
sh scripts/build-all-ebpf.sh
sh scripts/verify-plugin-manifests.sh
sh scripts/package-plugins.sh发布构建优先使用 release.sh。上面的脚本仅用于开发时单独重建 eBPF、校验插件或生成插件运行时包。
常规测试:
sh scripts/build-all-ebpf.sh # fresh clone 或清理过 .o 后先执行一次
go test ./...插件发布使用 sh scripts/verify-plugin-release.sh portable;root Linux 的完整验收与性能门槛见 PLUGIN.md。
兼容性门槛包括:Debian 11、Ubuntu 22.04、Rocky Linux 9、Alpine 3.19 和当前 Fedora 容器中的真实依赖安装与 release 构建;Ubuntu amd64/arm64 原生 Linux 测试和 core dataplane;实际部署 unit 下命名 namespace 的创建、跨服务退出保留、重启复用和删除。容器只验证发行版用户环境与编译器。
CI 另外启动官方 Alpine 3.19.8 和 Rocky Linux 9.8 云镜像的 QEMU VM,使用各自默认内核验证实际安装、热更新、崩溃恢复、开机启动、插件沙箱与 TC/XDP 的 IPv4/IPv6 转发和 egress NAT;Alpine 验证 OpenRC 及保留 worker 时的 cgroup 隔离,Rocky 全程保持 SELinux enforcing。镜像固定版本并校验摘要,关键测试被跳过会使验收失败,串口与测试日志保留为 CI artifact。这些结果只覆盖所列镜像与默认策略,自定义内核或 SELinux 策略仍需单独验收。
在装有 QEMU、genisoimage 和 OpenSSH 的 Linux 主机上可复现 VM 验收(可用时使用 KVM,否则使用 TCG):
sh scripts/build-all-ebpf.sh
CGO_ENABLED=0 go build -o /tmp/veer-vm-binary .
CGO_ENABLED=0 go test -c -o /tmp/veer-vm.test ./internal/app
python3 scripts/verify-qemu-platform.py alpine --binary /tmp/veer-vm-binary --test-binary /tmp/veer-vm.test
python3 scripts/verify-qemu-platform.py rocky --binary /tmp/veer-vm-binary --test-binary /tmp/veer-vm.test最低兼容版本不代表发行版仍受上游安全维护,生产环境应选择仍在维护的版本。Debian 11 的官方 LTS 已于 2026-08-31 结束;其 CI 容器仅使用 LTS 末期归档快照验证旧版用户环境,安装脚本不会替用户修改 apt 源。RHEL-compatible 系统会保留已安装的 curl-minimal / coreutils-single,避免与完整版软件包冲突。
WHMCS addon 插件源码位于:
whmcs/forward/
部署到 WHMCS:
modules/addons/forward/
最少配置:
默认 Veer API 地址默认 Veer Bearer Token,对应config.json的web_token默认入口 IP,或按宿主机配置server_ip_server_map
多宿主机场景建议配置:
server_ip_server_mapapi_server_mapallowed_product_ids- 按产品配置端口规则和共享站点上限
客户同步、暂停、恢复和终止操作只同步已有客户/服务归属记录,不再按后端 IP 自动认领远端资源。管理员全量同步导入的未绑定资源保持无归属,后续需显式分配;历史重复绑定不会自动选择一个客户。暂停、恢复使用 /api/rules/enabled 和 /api/sites/enabled 的明确状态接口,请先升级 Veer 服务端再升级 addon;旧服务端不支持该接口时会报错,不回退到可能因重试而反转状态的 toggle。
- 不要提交真实
config.json - 不要泄露
web_token - 管理面默认绑定
127.0.0.1,不要无保护暴露到公网 - 如需远程管理,建议放在 VPN、堡垒机、反向代理鉴权或受限管理网后面
- 部署脚本仅在首次交互安装时显示新生成的管理令牌;升级或非交互执行会隐藏令牌,避免写入自动化日志
- WHMCS 插件里的 Veer Bearer Token 与
web_token是同一个认证语义