From f70e131dfea9d5b6bd89c5821332ea55091c06cc Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sun, 10 May 2026 11:32:06 +0200 Subject: [PATCH] fix(nodes): bind form-encoded posts and skip node inbounds in central xray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Node model only carried `json:` tags, so when the panel's axios posted form-encoded bodies to /panel/api/nodes/add and /test, Gin's form binder produced a zero-valued Node — empty Name, empty Address, Port=0 — surfacing as "node name is required" and a probe URL of "https://:0/...". Add `form:` tags so add/test bind correctly. Also skip inbounds with NodeID set when building the central xray config; otherwise the central panel tried to listen on ports owned by node-managed inbounds and xray-core failed to start with a bind collision. Co-Authored-By: Claude Opus 4.7 --- database/model/model.go | 18 +++++++++--------- web/service/xray.go | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/database/model/model.go b/database/model/model.go index b098ab2d..56a76b6e 100644 --- a/database/model/model.go +++ b/database/model/model.go @@ -128,15 +128,15 @@ type Setting struct { // endpoint over HTTP using the per-node ApiToken to populate the runtime // status fields below. type Node struct { - Id int `json:"id" gorm:"primaryKey;autoIncrement"` - Name string `json:"name" gorm:"uniqueIndex"` - Remark string `json:"remark"` - Scheme string `json:"scheme"` // "https" | "http" - Address string `json:"address"` // host or IP - Port int `json:"port"` - BasePath string `json:"basePath"` // "/" or "/myprefix/" - ApiToken string `json:"apiToken"` // plaintext, matches existing tg/ldap pattern - Enable bool `json:"enable" gorm:"default:true"` + Id int `json:"id" form:"id" gorm:"primaryKey;autoIncrement"` + Name string `json:"name" form:"name" gorm:"uniqueIndex"` + Remark string `json:"remark" form:"remark"` + Scheme string `json:"scheme" form:"scheme"` + Address string `json:"address" form:"address"` + Port int `json:"port" form:"port"` + BasePath string `json:"basePath" form:"basePath"` + ApiToken string `json:"apiToken" form:"apiToken"` + Enable bool `json:"enable" form:"enable" gorm:"default:true"` // Heartbeat-updated fields. UpdatedAt advances on every probe even when // the row is otherwise unchanged so the UI's "last seen" tooltip is diff --git a/web/service/xray.go b/web/service/xray.go index fed863fb..09908aab 100644 --- a/web/service/xray.go +++ b/web/service/xray.go @@ -113,6 +113,9 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) { if !inbound.Enable { continue } + if inbound.NodeID != nil { + continue + } // get settings clients settings := map[string]any{} json.Unmarshal([]byte(inbound.Settings), &settings)