3x-ui agent: 轻量节点 agent 化

- Agent 通过 token 向主控注册,心跳/拉取 xray 配置/上报流量
- 主控按节点下发完整 xray 配置(含出站+路由),agent 只应用不自建
- Agent 心跳同步更新节点在线状态;后台探针跳过 agent 托管节点
- 「添加节点」支持 Agent 类型,自动生成 token 并弹窗展示
- VLESS/SS2022 入站;同机测试支持 api_port 隔离
- 新增 install-master.sh / install-agent.sh 一键安装脚本
- systemd + OpenWrt procd 服务文件,docs/AGENT.md
This commit is contained in:
Muse
2026-10-19 12:29:38 +00:00
parent f727d04f65
commit 0ba1ec0596
19 changed files with 1444 additions and 10 deletions
+42
View File
@@ -18,6 +18,7 @@ import (
"github.com/mhsanaei/3x-ui/v3/internal/crypto/nodetoken"
"github.com/mhsanaei/3x-ui/v3/internal/database"
"github.com/mhsanaei/3x-ui/v3/internal/logger"
"github.com/mhsanaei/3x-ui/v3/internal/agent"
"github.com/mhsanaei/3x-ui/v3/internal/sub"
"github.com/mhsanaei/3x-ui/v3/internal/tunnelmonitor"
"github.com/mhsanaei/3x-ui/v3/internal/util/crypto"
@@ -66,6 +67,44 @@ func initNodeTokenCrypto() error {
}
// runWebServer initializes and starts the web server for the 3x-ui panel.
func runAgent(args []string) {
agentCmd := flag.NewFlagSet("agent", flag.ExitOnError)
var configPath string
agentCmd.StringVar(&configPath, "config", "/etc/x-ui/agent.json", "Path to agent config file")
agentCmd.Parse(args)
// Agent mode always uses the panel's directory layout for the xray binary,
// geo files and config.json. Scoped to agent mode only so the panel's own
// relative "bin" default is untouched.
if os.Getenv("XUI_BIN_FOLDER") == "" {
_ = os.Setenv("XUI_BIN_FOLDER", agent.DefaultBinFolder)
}
cfg, err := agent.LoadConfig(configPath)
if err != nil {
log.Fatalf("Failed to load agent config from %s: %v", configPath, err)
}
// Initialize logger
logger.InitLogger(logging.INFO)
log.Printf("Starting 3x-ui agent (node: %s)", cfg.NodeName)
ag := agent.New(cfg)
// Handle shutdown signals
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigCh
log.Println("Shutting down agent...")
ag.Stop()
}()
if err := ag.Run(); err != nil {
log.Fatalf("Agent error: %v", err)
}
}
func runWebServer() {
log.Printf("Starting %v %v", config.GetName(), config.GetPanelVersion())
@@ -644,6 +683,8 @@ func main() {
return
}
runWebServer()
case "agent":
runAgent(os.Args[2:])
case "migrate":
migrateDb()
case "encrypt-tokens":
@@ -742,6 +783,7 @@ func commandHelp() string {
return `
Commands:
run run web panel
agent run in agent mode (lightweight node, no web panel)
migrate migrate from other/old x-ui
migrate-db SQLite <-> .dump (--dump/--restore) or copy into PostgreSQL (--dsn)
encrypt-tokens encrypt node bearer tokens with the configured active key