GeoLoom 是一个基于 Go 的代理节点聚合与筛选工具:
- 接收多种来源的节点输入(订阅、本地文件、单节点链接)
- 按地理策略(allow/block)筛选候选节点
- 交由 sing-box 内核构建统一出口并对外提供 SOCKS5 代理入口
source输入:http:///https://订阅链接@本地文件路径- 裸文件路径(无
@前缀),会自动按本地文件处理(相对路径相对配置文件目录解析)
node输入(最小字段子集):hysteria2://socks5://socks4://vless://trojan://vmess://ss://
source内容扩展:支持 URI 列表、Clash YAML、Sing-box JSON,以及远程/本地逐行文本文件。
- DNS 解析目标地址
- MaxMind MMDB 国家识别
- IP -> 国家缓存
- allow/block 过滤(
block优先) - 节点稳定 fingerprint 与跨 source 去重(geo 前执行,避免重复节点放大候选池)
- 最小可用拓扑:SOCKS 入站 + 统一
lb-out出口 - 负载策略:
random:基于health_score的全候选 weighted-random,连接级随机时更倾向高质量候选代理urltest:基于主动探测结果选择当前更优单节点hybrid:先收敛到当前高质量候选子集,再在子集内做 weighted-random;可通过policy.hybrid_top_k控制基础子集大小,若 cutoff 名次存在并列health_score,会把同分节点一并纳入
- 健康检查:失败惩罚窗口、全惩罚兜底、周期统计日志
- 运行时编排:统一
Runtime快照、按Fingerprint增量刷新、source 状态跟踪 - 管理 API:默认本地回环监听,提供
/api/v1/status|sources|nodes|candidates|health|logs,可选静态 token header 鉴权 - 健康状态持久化:本地 JSON 文件恢复惩罚窗口与最近检查状态
- source 内容扩展:支持 URI 列表、Clash YAML、Sing-box JSON
- 管理 API 默认建议仅监听本地回环地址,例如
127.0.0.1:9090,避免在未做鉴权时直接暴露到公网。 - 默认未配置
api.token时保持免鉴权;配置后,所有管理 API 路由都必须携带指定 header。 - 默认鉴权 header 为
X-GeoLoom-Token,可通过api.auth_header自定义。 - 当前只提供只读接口:
GET /api/v1/status:运行状态、节点聚合计数、refresh/api/state 配置摘要GET /api/v1/sources:每个 source 的最近处理状态、输入类型、unsupported 数与错误摘要GET /api/v1/nodes:当前已完成 geo 解析的节点列表GET /api/v1/candidates:当前参与 core 的候选节点列表GET /api/v1/health:健康检查配置摘要、最近跟踪节点数、惩罚池与内部健康快照GET /api/v1/logs:当前进程最近内存日志,便于控制台只读查看与本地排障
state.path指向本地 JSON 状态文件,当前保存:Fingerprint -> penalty_untilFingerprint -> last_check_at / last_reachableFingerprint -> last_country_code
- 状态恢复语义:
- 状态文件不存在或为空:按空状态启动,不报错
- 状态文件损坏:记录 warn,并降级为空状态继续启动
- 已过期惩罚窗口:加载时自动清理,不会错误恢复
{
"version": "v0.2.7",
"started_at": "2026-03-09T10:00:00Z",
"last_refresh_at": "2026-03-09T10:05:00Z",
"source_count": 2,
"strategy": "random",
"raw_node_count": 12,
"deduped_node_count": 10,
"resolved_node_count": 9,
"candidate_node_count": 6,
"dropped_node_count": 3,
"core_supported_count": 6,
"core_unsupported_count": 1,
"refresh": {
"enabled": true,
"interval": "10m"
},
"api": {
"enabled": true,
"listen": "127.0.0.1:9090"
},
"state": {
"enabled": true,
"path": "geoloom-state.json"
}
}{
"items": [
{
"name": "remote-subscription",
"type": "source",
"url": "https://example.com/subscription.txt",
"normalized_url": "https://example.com/subscription.txt",
"input_type": "source",
"node_count": 8,
"unsupported_count": 2,
"success": true,
"updated_at": "2026-03-09T10:05:00Z"
},
{
"name": "local-file",
"type": "source",
"url": "sub.txt",
"normalized_url": "@/etc/geoloom/sub.txt",
"node_count": 0,
"unsupported_count": 0,
"success": false,
"error": "订阅拉取失败: 读取本地输入文件失败: open /etc/geoloom/sub.txt: no such file or directory",
"updated_at": "2026-03-09T10:05:00Z"
}
]
}{
"count": 2,
"items": [
{
"id": "socks5-1.1.1.1-1080",
"fingerprint": "socks5-aaaabbbbcccc",
"name": "hk-entry",
"source_names": [
"remote-subscription"
],
"country_code": "HK",
"protocol": "socks5",
"address": "1.1.1.1",
"port": 1080,
"last_checked": "0001-01-01T00:00:00Z",
"raw_config": {
"protocol": "socks5",
"address": "1.1.1.1",
"port": 1080
}
},
{
"id": "trojan-2.2.2.2-443",
"fingerprint": "trojan-ddddeeeeffff",
"name": "sg-edge",
"source_names": [
"remote-subscription",
"manual-node"
],
"country_code": "SG",
"protocol": "trojan",
"address": "2.2.2.2",
"port": 443,
"last_checked": "0001-01-01T00:00:00Z",
"raw_config": {
"protocol": "trojan",
"address": "2.2.2.2",
"port": 443,
"sni": "edge.example.com"
}
}
]
}{
"count": 3,
"items": [
{
"id": "trojan-2.2.2.2-443",
"fingerprint": "trojan-ddddeeeeffff",
"name": "sg-edge",
"source_names": [
"remote-subscription",
"manual-node"
],
"country_code": "SG",
"protocol": "trojan",
"address": "2.2.2.2",
"port": 443,
"last_checked": "0001-01-01T00:00:00Z",
"health_score": 93,
"raw_config": {
"protocol": "trojan",
"address": "2.2.2.2",
"port": 443,
"sni": "edge.example.com"
}
},
{
"id": "socks5-1.1.1.1-1080",
"fingerprint": "socks5-aaaabbbbcccc",
"name": "hk-entry",
"source_names": [
"remote-subscription"
],
"country_code": "HK",
"protocol": "socks5",
"address": "1.1.1.1",
"port": 1080,
"last_checked": "0001-01-01T00:00:00Z",
"health_score": 78,
"raw_config": {
"protocol": "socks5",
"address": "1.1.1.1",
"port": 1080
}
},
{
"id": "vmess-3.3.3.3-443",
"fingerprint": "vmess-111122223333",
"name": "jp-backup",
"source_names": [
"remote-subscription"
],
"country_code": "JP",
"protocol": "vmess",
"address": "3.3.3.3",
"port": 443,
"last_checked": "0001-01-01T00:00:00Z",
"health_score": 42,
"raw_config": {
"protocol": "vmess",
"address": "3.3.3.3",
"port": 443,
"security": "tls"
}
}
]
}说明:
items已按当前 runtime 候选优先顺序返回,高分节点通常会排在前面。health_score是 weighted-random 的输入分值,当前会映射为离散权重而不是直接作为概率值使用。- 若
policy.strategy=random,GeoLoom 会基于这里的候选顺序与health_score对全候选生成 weighted-random 配置;若为hybrid,则仅截取当前高质量子集后再生成 weighted-random;policy.hybrid_top_k表示基础截断数量,若 cutoff 名次存在并列health_score会一并纳入;若为urltest,则仍沿用 sing-boxurltest行为。
| 视图 | 主要用途 | 数据范围 | 是否包含运行时排序 | 是否包含质量分值 | 关键字段 | 适合场景 |
|---|---|---|---|---|---|---|
/api/v1/nodes |
展示解析 + Geo 后的节点全量视图 | resolved_nodes |
否 | 否 | id、fingerprint、source_names、country_code、protocol、address、port、raw_config |
节点清单、来源排查、协议/地域分布查看 |
/api/v1/candidates |
展示当前参与 core 的候选集合 | candidates |
是 | 是,health_score |
/api/v1/nodes 共有字段 + health_score |
观察当前生效候选、weighted-random 倾斜方向、候选优先级 |
/api/v1/health |
展示健康检查与 penalty 的运行时观测 | health checker + penalty pool 内部状态 | 间接包含(health.last_candidates) |
是,health.nodes[*].score |
summary.ready_nodes、summary.degraded_nodes、health.nodes[*].success_count、failure_count、consecutive_failures、score、penalty_pool |
健康排障、稳定性分析、解释 why 某节点被降权/惩罚 |
补充说明:
/api/v1/nodes更偏静态视图,回答“系统识别到了哪些节点”。/api/v1/candidates更偏选路视图,回答“当前真正参与 core 选路的是哪些节点”。/api/v1/health更偏观测视图,回答“这些节点最近为什么被优先、降权或惩罚”。- 若只关心当前可用出口优先级,优先看
/api/v1/candidates;若要解释候选质量变化原因,再联动看/api/v1/health。
{
"config": {
"enabled": true,
"interval": "5m",
"url": "http://cp.cloudflare.com"
},
"summary": {
"tracked_nodes": 6,
"penalized_nodes": 1,
"ready_nodes": 4,
"degraded_nodes": 1,
"last_rebuild_at": "2026-03-09T10:03:00Z"
},
"health": {
"interval": 300000000000,
"debounce": 30000000000,
"test_url": "http://cp.cloudflare.com",
"timeout": 5000000000,
"last_candidates": [
"socks5-aaaabbbbcccc",
"socks5-ddddeeeeffff"
],
"last_rebuild_at": "2026-03-09T10:03:00Z",
"nodes": {
"socks5-aaaabbbbcccc": {
"last_check_at": "2026-03-09T10:04:30Z",
"last_reachable": true,
"last_success_at": "2026-03-09T10:04:30Z",
"last_failure_at": "2026-03-09T09:58:00Z",
"consecutive_failures": 0,
"success_count": 12,
"failure_count": 2,
"score": 93
}
}
},
"penalty_pool": {
"socks5-ddddeeeeffff": "2026-03-09T10:08:00Z"
}
}{
"count": 2,
"capacity": 300,
"truncated": false,
"items": [
{
"time": "2026-03-09T07:30:21Z",
"level": "INFO",
"message": "GeoLoom 版本信息",
"attrs": {
"version": "v0.2.7",
"commit": "bc7bfb2",
"build_time": "2026-03-09T07:30:21Z"
},
"text": "2026-03-09T07:30:21Z INFO GeoLoom 版本信息 version=v0.2.7 commit=bc7bfb2 build_time=2026-03-09T07:30:21Z"
},
{
"time": "2026-03-09T07:31:02Z",
"level": "WARN",
"message": "状态文件损坏,已忽略并按空状态启动",
"attrs": {
"error": "invalid character 'x' looking for beginning of value",
"path": "geoloom-state.json"
},
"text": "2026-03-09T07:31:02Z WARN 状态文件损坏,已忽略并按空状态启动 error=invalid character 'x' looking for beginning of value path=geoloom-state.json"
}
]
}说明:
count表示当前返回的日志条数。capacity表示内存日志环形缓冲的容量上限。truncated=true表示日志写入量已超过缓冲容量,当前仅保留最近日志。items[*].attrs为该条日志附带的结构化属性,具体 key 会随日志事件不同而变化。items[*].text为便于直接展示与复制排障的格式化文本。
说明:
status适合做总览卡片与配置摘要展示。health.summary适合做轻量状态面板;health与penalty_pool适合调试与排障。candidates.items[*].health_score表示当前 runtime 为 weighted-random 计算后的候选质量分值;冷启动或缺少历史健康数据时可退化为默认分值。hybrid默认使用policy.hybrid_top_k=3作为高质量子集的基础大小;若 cutoff 名次存在并列分数,会把同分节点一并纳入,避免硬截断。health.nodes[*].score与 success/failure 统计字段可用于观察节点近期稳定性,但当前仍是基于周期探测的最小评分模型,并非真实流量反馈。logs适合做控制台只读日志面板与最近运行事件排查。health.interval、health.debounce、health.timeout当前按 Gotime.Duration的 JSON 语义输出为纳秒整数;如后续面向外部稳定开放,可再评估是否改为字符串时长。- 未配置
api.token时,/api/v1/*保持当前免鉴权行为。 - 配置
api.token后,所有管理 API 请求都需要携带api.auth_header指定的 header。 - 调用示例:
curl -H 'X-GeoLoom-Token: your-static-token' http://127.0.0.1:9090/api/v1/status
cmd/geoloom/ # 程序入口
internal/app/ # 启动编排与生命周期
internal/provider/ # 输入分发与协议解析
internal/geo/ # 地理识别与缓存
internal/filter/ # 地域过滤策略
internal/core/singbox/ # sing-box options 构建与服务封装
internal/health/ # 健康检查与惩罚池
configs/config.yaml # 默认示例配置
docs/geoloom.prd.md # 产品与架构约束
- Go(建议使用当前稳定版)
- Node.js 20+(用于
frontend/管理面板开发)
go run ./cmd/geoloom -config configs/config.yamlgo build ./cmd/geoloomgo run ./cmd/geoloom -version仓库内已提供 frontend/ 子目录,用于消费现有只读管理 API:
/api/v1/status/api/v1/sources/api/v1/nodes/api/v1/candidates/api/v1/health/api/v1/logs
安装依赖:
cd frontend && npm install开发启动:
cd frontend && npm run dev生产构建(构建产物会输出到 internal/api/frontenddist/,供 Go 服务嵌入):
cd frontend && npm run build说明:
- Vite 开发服务器默认运行在
http://127.0.0.1:5173。 - 开发期通过 Vite proxy 将
/api/*转发到http://127.0.0.1:9090。 - 生产/本地运行期由 GeoLoom 统一提供:
/api/v1/*:只读 JSON API/assets/*:前端静态资源/:前端入口页- 其他非
/api/路径:SPA fallback 到index.html
- 若管理 API 配置了
api.token,静态页面仍可直接打开,但页面内对/api/v1/*的请求必须携带api.auth_header指定的 header;可在右侧侧栏中填写 token 与 header 名,默认 header 为X-GeoLoom-Token。 - 推荐的鉴权联调回归步骤:
- 在配置中设置
api.token与api.auth_header,启动 GeoLoom。 - 直接访问根路径
/,确认页面可打开,但初始 API 请求返回 401。 - 确认页面出现“鉴权失败,请检查 Token/Header。”且右侧状态为“未连接”。
- 在右侧栏填写正确的 header/token 并保存。
- 确认
/api/v1/status|sources|nodes|candidates|health|logs恢复为 200,页面状态切换为“已连接”。
- 在配置中设置
- 若你的 API 不在默认地址,可在开发期页面侧栏中修改
API Base URL(例如http://127.0.0.1:9090);嵌入模式下默认留空走同源。 - 当前前端默认中文,并支持中英切换与亮暗色模式切换。
适用于已发布镜像,例如
ghcr.io/sarices/geoloom:v0.2.7。
- 准备配置文件(示例):
cp configs/config.example.prod.yaml configs/config.prod.yaml- 修改
docker-compose.yml中的配置挂载(默认挂载configs/config.example.prod.yaml),建议改为你自己的配置文件:
volumes:
- ./configs/config.prod.yaml:/etc/geoloom/config.yaml:ro- 启动:
docker compose up -d- 查看日志:
docker compose logs -f geoloom- 停止:
docker compose down示例输出:
GeoLoom version=dev commit=unknown build_time=unknown
生产构建建议通过 -ldflags 注入版本信息:
go build -ldflags "-X main.Version=v0.2.7 -X main.Commit=$(git rev-parse --short HEAD) -X main.BuildTime=$(date -u +%Y-%m-%dT%H:%M:%SZ)" ./cmd/geoloombash scripts/release/build-all.sh v0.2.7可选参数(按顺序覆盖):
VERSION:版本号(默认v0.2.7)COMMIT:提交短哈希(默认自动读取,失败回退unknown)BUILD_TIME:UTC 时间(默认当前时间,ISO8601)
例如:
bash scripts/release/build-all.sh v0.2.7 abc1234 2026-03-05T09:00:00Z执行后会生成 dist/ 目录,包含 6 个平台目录及对应压缩包:
geoloom_<version>_darwin_amd64.tar.gzgeoloom_<version>_darwin_arm64.tar.gzgeoloom_<version>_linux_amd64.tar.gzgeoloom_<version>_linux_arm64.tar.gzgeoloom_<version>_windows_amd64.zipgeoloom_<version>_windows_arm64.zip
每个包内包含:
- 可执行文件(Windows 为
geoloom.exe) config.example.yamlREADME.mdCHANGELOG.md
解压任意产物后执行:
./geoloom -versionWindows:
.\geoloom.exe -version应输出 version/commit/build_time 三项注入信息。
假设你在 configs/ 目录下准备了一个 sub.txt,内容示例:
2.2.2.2:1080#demo-node
对应配置:
gateway:
http_port: 8080
socks_port: 1080
policy:
strategy: random # 可选 random / urltest / hybrid
hybrid_top_k: 3 # 仅对 hybrid 生效;若 cutoff 分数并列,最终入池数可能大于该值
filter:
allow: []
block: []
health_check:
enabled: false
geo:
# 显式路径优先:为空时进入默认逻辑。
mmdb_path: ""
# 当 mmdb_path 为空且程序目录无 GeoLite2-Country.mmdb 时,使用该地址自动下载(仅 http/https)。
mmdb_url: ""
dns_timeout: 3s
sources:
- name: local-source
type: source
url: "sub.txt"go run ./cmd/geoloom -config configs/config.yaml启动成功后,建议重点观察以下日志关键字:
GeoLoom 启动完成输入源处理成功节点去重完成(关注raw_nodes/deduped_nodes/duplicate_nodes)节点过滤完成core wrapper 启动成功
若配置了 health_check.enabled: true,周期内还会看到:
健康检查触发重建成功(在候选变化时)- 可用性统计字段(如
available_proxy_nodes)
- 报错“缺少 scheme”
- 检查
type是否为source;仅source支持裸文件路径自动识别。
- 检查
- 过滤后无候选节点
- 检查
policy.filter.allow/block是否过严。
- 检查
- 地理识别未生效
- 检查
geo.mmdb_path是否已配置且文件可读。
- 检查
参考 configs/config.example.yaml:
# 字段释义详见 configs/config.example.yaml;下面保留一份常用示例。
gateway:
http_port: 8080
socks_port: 1080
policy:
strategy: random # 可选 random / urltest / hybrid
hybrid_top_k: 3 # 仅对 hybrid 生效;若 cutoff 分数并列,最终入池数可能大于该值
filter:
allow: []
block: []
health_check:
enabled: true
interval: 5m
url: http://cp.cloudflare.com
refresh:
enabled: true
interval: 10m
geo:
mmdb_path: ""
mmdb_url: "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/GeoLite2-Country.mmdb"
dns_timeout: 3s
api:
enabled: true
listen: 127.0.0.1:9090
token: ""
auth_header: X-GeoLoom-Token
state:
enabled: true
path: geoloom-state.json
sources:
- name: remote-source
type: source
url: "https://example.com/subscribe?token=YOUR_TOKEN"
- name: local-file
type: source
url: "sub.txt"
- name: subscribe-alias
type: subscribe
url: "@./providers/mixed-proxies.txt"
- name: manual-node-socks5
type: node
url: "socks5://user:[email protected]:1080#manual-socks5"
- name: manual-node-vless
type: node
url: "vless://[email protected]:443?encryption=none&security=tls&sni=example.com#manual-vless"说明:
sources.type支持source/subscribe/node。source与subscribe当前都按“输入源”处理;subscribe主要用于兼容历史写法。- 顶层
type: source|subscribe下的http:///https://表示远程 source URL,不是 HTTP 代理节点。 - 若要表达 HTTP 代理节点,建议写在 source 文本内容里使用显式
http://user:pass@host:port#name条目。
生产环境参考模板:configs/config.example.prod.yaml(默认启用健康检查、API 与状态持久化)。
当 type: source 且 url 不带 scheme、也不以 @ 开头时:
- 绝对路径:直接作为本地文件读取
- 相对路径:相对
-config指定配置文件所在目录解析
例如:
sources:
- name: local-list
type: source
url: "socks5_share_200.txt"本地文件与远程 http/https source 在文本文件语义上保持一致:
- 空行与以
#开头的注释行会被忽略。 - 显式协议条目会原样保留,当前支持常见的
socks5://、socks4://、http://等节点条目。 - 裸行(如
1.2.3.4:1080#name、user:[email protected]:1080#name)会默认补全为socks5://。 - 对远程
http/httpssource,仍优先兼容现有 URI 列表、Base64 URI 列表、Clash YAML、Sing-box JSON;若正文是逐行文本文件,GeoLoom 会自动按逐行规则补齐与解析。
注意:
- 顶层配置里的
http:///https://仍表示远程 source URL。 - 若要在 source 内容里表达 HTTP 代理节点,必须写成显式
http://user:pass@host:port#name条目。 - 裸
host:port不会自动猜测为socks4/http,仍按socks5处理。 - source 层会尽量保留逐行文本里的原始条目;非法端口、非法 URI、未知 scheme 等脏数据通常会在 parser/dispatcher 层进入
unsupported,而不是在 source 层静默丢弃。 - 同地址同认证但仅
#name不同的条目,在 source/parser 阶段会分别保留;进入domain.DedupNodes后,name不参与节点身份判断,最终会按协议关键字段合并,并保留首条记录的名称。
远程文本文件示例:
sources:
- name: remote-mixed-text
type: source
url: "https://example.com/nodes.txt"示例文件内容:
# 默认按 socks5 处理
1.2.3.4:1080#default-socks5
# 显式协议
socks5://user:[email protected]:1080#socks5-node
socks4://[email protected]:1080#legacy-node
http://user:[email protected]:8080#http-node
地理识别配置按以下优先级生效:
geo.mmdb_path非空:直接使用该路径(相对路径相对配置文件目录解析);geo.mmdb_path为空:尝试读取程序目录下GeoLite2-Country.mmdb;- 若 2 不存在且
geo.mmdb_url非空:自动下载到程序目录GeoLite2-Country.mmdb后使用; - 若以上均不满足:跳过地理识别。
geo.mmdb_url 仅支持 http/https。
go fmt ./...
go test ./...
go test -race ./...
go vet ./...
go build ./cmd/geoloom- 产品需求与架构约束:
docs/geoloom.prd.md - 输入样例来源:
docs/sub.txt(测试请使用脱敏样例)
本项目使用 MIT License。
当前仓库仍以 MVP 到阶段化演进为主,默认配置偏向最小可运行链路。如用于生产环境,请补充:
- 完整 MMDB 数据与更新流程
- 资源与并发限制
- 更严格的监控、日志与错误恢复策略