Documentation
¶
Overview ¶
Package xray models the Xray-core config as typed Go structs (so field-name mistakes are compile errors) and supervises the Xray child process.
Engine note: Xray-core is the single proxy engine for every lane — the three built-in ones (VLESS-Vision-TCP-443 with a fallback to the panel, VLESS-XHTTP- REALITY on its own port, Hysteria2-UDP with port-hopping) and every operator- defined custom inbound.
Index ¶
- Constants
- func EnabledInboundTags(set *model.Settings, custom []model.Inbound) []string
- func EnsureBinary(dir string) (string, error)
- func VersionMatchesPinned(v string) bool
- type API
- type Balancer
- type BalancerStrategy
- type Certificate
- type Config
- type DNS
- type DokodemoSettings
- type Fallback
- type GRPCSettings
- type HTTPInboundSettings
- type HTTPRequest
- type HTTPResponse
- type HTTPUpgradeSettings
- type HysteriaClient
- type HysteriaInboundSettings
- type HysteriaSettings
- type Inbound
- type LevelPolicy
- type Log
- type Observatory
- type Options
- type Outbound
- type Policy
- type ProxyOutboundSettings
- type ProxyServer
- type ProxyUser
- type RealitySettings
- type RouteRule
- type Routing
- type Sniffing
- type SocksInboundSettings
- type Stats
- type StreamSettings
- type Supervisor
- func (s *Supervisor) APIAddr() string
- func (s *Supervisor) AddUsers(apiAddr string, inbounds []Inbound) error
- func (s *Supervisor) Apply(cfg *Config) error
- func (s *Supervisor) ApplyRaw(data []byte) error
- func (s *Supervisor) AssetDir() string
- func (s *Supervisor) BinPath() string
- func (s *Supervisor) ConfigBytes() ([]byte, error)
- func (s *Supervisor) HasBackup() bool
- func (s *Supervisor) LogTail() []string
- func (s *Supervisor) QueryStats(apiAddr string) (map[string]Traffic, error)
- func (s *Supervisor) RemoveUsers(apiAddr string, tags, emails []string) error
- func (s *Supervisor) Restart() error
- func (s *Supervisor) Resume() error
- func (s *Supervisor) Running() bool
- func (s *Supervisor) Serving() bool
- func (s *Supervisor) SetOnAccess(fn func(email, ip, dest string))
- func (s *Supervisor) SetOnCrash(fn func(err error))
- func (s *Supervisor) SetOnRecover(fn func())
- func (s *Supervisor) StartedAt() int64
- func (s *Supervisor) Stop()
- func (s *Supervisor) SubscribeLogs() (<-chan string, func())
- func (s *Supervisor) Suspend()
- func (s *Supervisor) UptimeSeconds() int64
- func (s *Supervisor) ValidateBytes(data []byte) error
- func (s *Supervisor) ValidateConfig(cfg *Config) error
- func (s *Supervisor) Version() string
- func (s *Supervisor) WriteConfig(cfg *Config) error
- type SystemPolicy
- type TCPHeader
- type TCPSettings
- type TLSSettings
- type Traffic
- type TrojanClient
- type TrojanInboundSettings
- type VLESSClient
- type VLESSInboundSettings
- type WSSettings
- type WireGuardPeer
- type WireGuardSettings
- type XHTTPSettings
Constants ¶
const ( TagVLESS = "vless-in" TagHysteria = "hysteria-in" TagReality = "vless-reality-in" )
Inbound tags (also the keys the live add/remove-user API addresses). A custom inbound's tag is derived from its row id — see model.Inbound.Tag.
const APIPort = 10085
APIPort is the loopback port for the Xray gRPC StatsService.
const PinnedVersion = "v26.6.27"
PinnedVersion is the Xray-core release auto-installed when no binary is found. Keep in sync with deploy/install-xray.sh and the Dockerfile ARG.
Why pinned: Xray 26.3.27 shipped a broken Hysteria2 server-side auth handshake (26.6.x fixes it). A floating "latest" can silently regress, so we pin an exact release and its checksums.
const VisionFlow = "xtls-rprx-vision"
VisionFlow is the VLESS flow used for raw-TCP Vision.
Variables ¶
This section is empty.
Functions ¶
func EnabledInboundTags ¶
EnabledInboundTags lists the inbound tags that currently carry users (the targets for live user removal via `xray api rmu`) — built-in lanes plus custom inbounds.
func EnsureBinary ¶
EnsureBinary returns the path to an Xray binary in dir, downloading the pinned release there if one isn't already present. It lets a fresh box come up without a separate install step when no system Xray (XRAY_BIN / PATH) is found.
func VersionMatchesPinned ¶ added in v1.0.0
VersionMatchesPinned reports whether a reported Xray version is the pinned release, tolerating a leading "v": PinnedVersion carries it, but `xray version` output does not (Supervisor.Version parses "26.6.27"), so a plain string compare would spuriously flag every node as version-skewed.
Types ¶
type Balancer ¶
type Balancer struct {
Tag string `json:"tag"`
Selector []string `json:"selector"`
Strategy *BalancerStrategy `json:"strategy,omitempty"`
FallbackTag string `json:"fallbackTag,omitempty"`
}
Balancer load-balances across the outbounds whose tag matches a Selector prefix. leastPing + the Observatory route to the fastest live one; FallbackTag is used when none are healthy.
type BalancerStrategy ¶
type BalancerStrategy struct {
Type string `json:"type"`
}
BalancerStrategy selects the balancing algorithm ("leastPing" | "random" | …).
type Certificate ¶
type Certificate struct {
CertificateFile string `json:"certificateFile,omitempty"`
KeyFile string `json:"keyFile,omitempty"`
}
Certificate points at on-disk PEM files (shared cert for all listeners).
type Config ¶
type Config struct {
Log *Log `json:"log,omitempty"`
Stats *Stats `json:"stats,omitempty"`
API *API `json:"api,omitempty"`
Policy *Policy `json:"policy,omitempty"`
DNS *DNS `json:"dns,omitempty"`
Inbounds []Inbound `json:"inbounds"`
Outbounds []Outbound `json:"outbounds"`
Routing *Routing `json:"routing,omitempty"`
Observatory *Observatory `json:"observatory,omitempty"`
}
Config is the top-level Xray configuration document.
func Generate ¶
func Generate(set *model.Settings, users []model.User, opts Options, proxies map[string][]model.ProxyEndpoint) (*Config, error)
Generate builds the full Xray config from settings + enabled users.
Layout (all on one box):
- VLESS-Vision inbound owns :443 + TLS. Its only fallback is the default one → the Go panel (decoy/panel/sub), so :443 has no path that behaves differently from an ordinary website under probing.
- VLESS-XHTTP-REALITY on its own port, borrowing the donor's TLS.
- Hysteria2 inbound on :<hysteria_port> (UDP), its own TLS; host nftables redirects the hop range to it.
- Every operator-defined custom inbound, each on its own port (opts.Custom).
- One credential set per user (uuid for VLESS, password for Trojan/Hy2).
proxies holds the live upstream proxies of each egress lane, keyed by lane ID.
type DNS ¶
type DNS struct {
Servers []string `json:"servers,omitempty"`
}
DNS is the Xray DNS block. Servers are upstream resolvers — plain IPs ("1.1.1.1"), DoH URLs ("https://dns.google/dns-query"), or "localhost".
type DokodemoSettings ¶
type DokodemoSettings struct {
Address string `json:"address"`
}
DokodemoSettings is the settings block for the api inbound.
type Fallback ¶
type Fallback struct {
Path string `json:"path,omitempty"`
Dest any `json:"dest"`
Xver int `json:"xver,omitempty"`
}
Fallback routes non-VLESS traffic on the shared port. Dest is an int port or "host:port" string. Used in M2+ to send browser/Trojan traffic to the panel.
type GRPCSettings ¶
type GRPCSettings struct {
ServiceName string `json:"serviceName"`
Authority string `json:"authority,omitempty"`
MultiMode bool `json:"multiMode,omitempty"`
}
GRPCSettings configures the gRPC transport. Authority overrides the :authority pseudo-header; MultiMode multiplexes several streams over one connection.
Note: current Xray marks the gRPC transport itself deprecated in favour of XHTTP stream-up over H2 (it prints a warning on every start). It stays available because existing clients speak it, but new lanes are better off on XHTTP.
type HTTPInboundSettings ¶
type HTTPInboundSettings struct {
Accounts []ProxyUser `json:"accounts,omitempty"`
}
HTTPInboundSettings is the "settings" object for an http forward-proxy inbound.
type HTTPRequest ¶ added in v1.5.0
type HTTPRequest struct {
Version string `json:"version,omitempty"`
Method string `json:"method,omitempty"`
Path []string `json:"path,omitempty"`
Headers map[string][]string `json:"headers,omitempty"`
}
HTTPRequest is the client-to-server half of the raw-TCP HTTP masquerade.
type HTTPResponse ¶ added in v1.5.0
type HTTPResponse struct {
Version string `json:"version,omitempty"`
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
Headers map[string][]string `json:"headers,omitempty"`
}
HTTPResponse is the server-to-client half.
type HTTPUpgradeSettings ¶ added in v1.5.0
type HTTPUpgradeSettings struct {
Path string `json:"path,omitempty"`
Host string `json:"host,omitempty"`
// AcceptProxyProtocol reads the real client IP from a PROXY-protocol header
// prepended by an upstream that forwards to this inbound.
AcceptProxyProtocol bool `json:"acceptProxyProtocol,omitempty"`
}
HTTPUpgradeSettings configures the HTTPUpgrade transport — a WebSocket-shaped upgrade without the WebSocket framing, so it fronts the same CDNs but carries no per-frame masking.
type HysteriaClient ¶
HysteriaClient is one Hysteria2 user. Xray's infra/conf parser maps the JSON "auth" field directly to the Account.Auth protobuf field — using "password" silently gives empty auth.
type HysteriaInboundSettings ¶
type HysteriaInboundSettings struct {
Version int `json:"version"` // must be 2
Users []HysteriaClient `json:"users"`
}
HysteriaInboundSettings is the "settings" object for a Hysteria2 inbound. Per Xray's schema the per-user list is "users" (NOT "clients" like Trojan/ VLESS) — using the wrong key leaves Xray with no users, so traffic isn't attributed to an email (breaking per-user stats and IP/access logging).
type HysteriaSettings ¶
type HysteriaSettings struct {
Version int `json:"version"` // must be 2
}
HysteriaSettings is the Hysteria2 transport block. Xray models Hysteria2 as a streamSettings transport (network "hysteria"); per-user auth lives in the inbound's settings.clients[].auth.
type Inbound ¶
type Inbound struct {
Tag string `json:"tag,omitempty"`
Listen string `json:"listen,omitempty"`
Port int `json:"port"`
Protocol string `json:"protocol"`
Settings any `json:"settings,omitempty"`
StreamSettings *StreamSettings `json:"streamSettings,omitempty"`
Sniffing *Sniffing `json:"sniffing,omitempty"`
}
Inbound is one listening proxy endpoint. Settings is protocol-specific.
func UserInbounds ¶
func UserInbounds(set *model.Settings, custom []model.Inbound, users []model.User, serverID int64, access map[int64]model.Access) []Inbound
UserInbounds builds inbound stubs (tag + protocol + clients) for the given users on every inbound that carries users — the built-in lanes AND each custom inbound. Used by the live add-user API (`xray api adu`) so a new user joins the running Xray without a restart.
Driving this from the actual inbound list, rather than from the settings booleans, is what keeps custom inbounds in step: a user added while one exists reaches it immediately instead of at the next full restart, and — the half that matters more — a user removed is gone from it just as fast. serverID + access gate which inbounds each added user is placed into, exactly as the full generator does — so a live add can never put a user into a lane their groups don't grant.
type LevelPolicy ¶
type LevelPolicy struct {
StatsUserUplink bool `json:"statsUserUplink"`
StatsUserDownlink bool `json:"statsUserDownlink"`
ConnIdle int `json:"connIdle,omitempty"`
BufferSize int `json:"bufferSize,omitempty"`
}
LevelPolicy enables per-user traffic stats for a policy level and bounds a connection's memory: ConnIdle reaps idle connections; BufferSize caps the per-connection buffer (KB) so many concurrent flows can't balloon RSS.
type Log ¶
type Log struct {
Loglevel string `json:"loglevel,omitempty"`
}
Log configures Xray logging.
type Observatory ¶
type Observatory struct {
SubjectSelector []string `json:"subjectSelector"`
ProbeURL string `json:"probeUrl,omitempty"`
ProbeInterval string `json:"probeInterval,omitempty"`
EnableConcurrency bool `json:"enableConcurrency,omitempty"`
}
Observatory periodically probes the proxy-pool outbounds (subjectSelector tag prefixes) so the balancer's leastPing strategy can skip dead/slow proxies.
type Options ¶
type Options struct {
// PanelDest is where the VLESS default fallback forwards non-proxy traffic
// (the Go panel's loopback HTTP address, e.g. "127.0.0.1:8080").
PanelDest string
// Groups resolves the "iplist:<source>/<group>" routing entries to their
// domains/CIDRs. Parsed from the on-disk iplist databases and cached by the
// caller (they only change on a geo refresh). Nil or missing groups simply
// drop those rules — see expandGroups.
Groups geo.GroupSet
// Custom are this server's operator-defined inbounds (already filtered to the
// enabled ones). Each gets its own listener beside the built-in lanes; none of
// them share :443, so nothing here can disturb the Vision inbound or the decoy.
Custom []model.Inbound
// ServerID is the server this config is for (LocalNodeID for the master), used to
// resolve per-user access to the built-in lanes. Access maps a user id to what
// they may connect to; a user absent from it is unrestricted (see model.AccessOf).
// A nil Access means the feature is off and every user reaches every lane — the
// historical behaviour.
ServerID int64
Access map[int64]model.Access
}
Options carries non-DB generation parameters.
type Outbound ¶
type Outbound struct {
Tag string `json:"tag,omitempty"`
Protocol string `json:"protocol"`
Settings any `json:"settings,omitempty"`
}
Outbound is one egress. Settings is protocol-specific (nil for freedom/blackhole).
type Policy ¶
type Policy struct {
Levels map[string]LevelPolicy `json:"levels,omitempty"`
System *SystemPolicy `json:"system,omitempty"`
}
Policy turns on per-user up/down counters.
type ProxyOutboundSettings ¶
type ProxyOutboundSettings struct {
Servers []ProxyServer `json:"servers"`
}
ProxyOutboundSettings is the "settings" object for a socks/http proxy outbound.
type ProxyServer ¶
type ProxyServer struct {
Address string `json:"address"`
Port int `json:"port"`
Users []ProxyUser `json:"users,omitempty"`
}
ProxyServer is one upstream proxy (with optional auth).
type RealitySettings ¶
type RealitySettings struct {
Show bool `json:"show"`
Dest string `json:"dest"` // "host:port" of the borrowed site
Xver int `json:"xver"` // PROXY protocol version (0 = off)
ServerNames []string `json:"serverNames"` // accepted SNIs (the borrowed site)
PrivateKey string `json:"privateKey"` // X25519 private (base64 raw-url)
ShortIds []string `json:"shortIds"`
// MaxTimeDiff is the anti-replay window in ms: a client whose handshake clock
// differs by more than this is rejected, so a probe can't replay a captured
// REALITY auth later. 0 (omitted) disables the check.
MaxTimeDiff int `json:"maxTimeDiff,omitempty"`
}
RealitySettings configures the REALITY security layer. Instead of presenting our own cert, the inbound forwards the TLS handshake of a real site (Dest / ServerNames) and authenticates clients via the X25519 key + shortId.
type RouteRule ¶
type RouteRule struct {
Type string `json:"type"` // always "field"
InboundTag []string `json:"inboundTag,omitempty"`
Domain []string `json:"domain,omitempty"`
IP []string `json:"ip,omitempty"`
Port string `json:"port,omitempty"`
Network string `json:"network,omitempty"` // "tcp,udp" — catch-all matcher
Protocol []string `json:"protocol,omitempty"`
OutboundTag string `json:"outboundTag,omitempty"`
BalancerTag string `json:"balancerTag,omitempty"`
}
RouteRule is one Xray field rule. Same-field values are OR'd; different fields are AND'd. Traffic goes to OutboundTag, or BalancerTag (a proxy pool).
type Routing ¶
type Routing struct {
DomainStrategy string `json:"domainStrategy,omitempty"`
Rules []RouteRule `json:"rules,omitempty"`
Balancers []Balancer `json:"balancers,omitempty"`
}
Routing holds the ordered field rules. Unmatched traffic uses the first outbound (direct). Balancers group several outbounds into one egress.
type Sniffing ¶
type Sniffing struct {
Enabled bool `json:"enabled"`
DestOverride []string `json:"destOverride,omitempty"`
}
Sniffing inspects proxied connections to recover their real destination (HTTP host / TLS SNI / QUIC) so domain routing rules can match it.
type SocksInboundSettings ¶
type SocksInboundSettings struct {
Auth string `json:"auth"`
Accounts []ProxyUser `json:"accounts,omitempty"`
UDP bool `json:"udp"`
}
SocksInboundSettings is the "settings" object for a socks forward-proxy inbound (proxy mode). Auth is "password" when accounts are present, else "noauth".
type StreamSettings ¶
type StreamSettings struct {
// Network is the transport: "tcp" | "ws" | "xhttp" | "grpc" | "httpupgrade" |
// "hysteria".
Network string `json:"network,omitempty"`
Security string `json:"security,omitempty"` // "tls" | "reality" | "" (none)
TLSSettings *TLSSettings `json:"tlsSettings,omitempty"`
TCPSettings *TCPSettings `json:"tcpSettings,omitempty"`
WSSettings *WSSettings `json:"wsSettings,omitempty"`
XHTTPSettings *XHTTPSettings `json:"xhttpSettings,omitempty"`
HTTPUpgradeSettings *HTTPUpgradeSettings `json:"httpupgradeSettings,omitempty"`
HysteriaSettings *HysteriaSettings `json:"hysteriaSettings,omitempty"`
RealitySettings *RealitySettings `json:"realitySettings,omitempty"`
GRPCSettings *GRPCSettings `json:"grpcSettings,omitempty"`
// Sockopt is the operator's socket-option block, passed through verbatim. Raw
// rather than typed: the field set is long, entirely server-local, and validated
// against a key whitelist before it gets here (model.SockoptKeys), so a typed
// mirror would be twenty fields of pure transcription with nothing to check.
Sockopt json.RawMessage `json:"sockopt,omitempty"`
}
StreamSettings configures transport + transport-level security.
type Supervisor ¶
type Supervisor struct {
// contains filtered or unexported fields
}
Supervisor owns the Xray child process and the on-disk config.json. It serializes config applies: marshal -> validate -> atomic swap -> restart, and supervises the process — an unexpected exit is auto-restarted with backoff.
If no Xray binary is available (e.g. local dev on macOS), Apply still writes and the panel keeps running; it just logs that Xray isn't being (re)started.
func NewSupervisor ¶
func NewSupervisor(binName, configPath, assetDir string) *Supervisor
NewSupervisor resolves binName (via PATH or as an absolute path) and targets configPath for the generated config. assetDir holds the geo databases.
func (*Supervisor) APIAddr ¶
func (s *Supervisor) APIAddr() string
APIAddr is the loopback address of Xray's gRPC API (StatsService + live user add/remove). The wiring lives here so callers don't rebuild it ad hoc.
func (*Supervisor) AddUsers ¶
func (s *Supervisor) AddUsers(apiAddr string, inbounds []Inbound) error
func (*Supervisor) Apply ¶
func (s *Supervisor) Apply(cfg *Config) error
Apply writes the config atomically (validating first when possible) and restarts Xray.
func (*Supervisor) ApplyRaw ¶ added in v1.0.0
func (s *Supervisor) ApplyRaw(data []byte) error
ApplyRaw is Apply for a config that is already marshaled JSON — used by the node agent, which receives the exact config the panel generated and applies it verbatim (after substituting its own cert paths) rather than round-tripping it through the Config struct. Same validate → atomic swap → restart, with the same rollback backup, so a config the node's Xray can't parse never kills it.
func (*Supervisor) AssetDir ¶
func (s *Supervisor) AssetDir() string
AssetDir returns the directory holding the geoip.dat / geosite.dat databases.
func (*Supervisor) BinPath ¶ added in v0.15.0
func (s *Supervisor) BinPath() string
BinPath returns the resolved Xray binary, or "" if none was found. The self-test spawns a throwaway Xray client from the same binary, so it needs this.
func (*Supervisor) ConfigBytes ¶
func (s *Supervisor) ConfigBytes() ([]byte, error)
ConfigBytes returns the on-disk config.json currently applied to Xray.
func (*Supervisor) HasBackup ¶
func (s *Supervisor) HasBackup() bool
HasBackup reports whether a rollback config (config.json.bak) is available.
func (*Supervisor) LogTail ¶
func (s *Supervisor) LogTail() []string
LogTail returns the buffered recent Xray log lines.
func (*Supervisor) QueryStats ¶
func (s *Supervisor) QueryStats(apiAddr string) (map[string]Traffic, error)
QueryStats reads per-user traffic counters from the running Xray StatsService (via `xray api statsquery`). Keyed by user email (we use "u<id>").
func (*Supervisor) RemoveUsers ¶
func (s *Supervisor) RemoveUsers(apiAddr string, tags, emails []string) error
RemoveUsers removes users (by email) from each given inbound tag via `xray api rmu` (no restart).
func (*Supervisor) Restart ¶ added in v0.13.0
func (s *Supervisor) Restart() error
Restart stops the running Xray and starts a fresh one from the config already on disk. Unlike Apply it neither regenerates nor re-validates the config — it is the operator's "kick it" button for a wedged or misbehaving process, and it also makes a process-level change (e.g. the TZ the child runs in) take effect without waiting for the next config change.
Every live VPN connection is dropped, so this is only ever operator-initiated.
func (*Supervisor) Resume ¶ added in v1.4.0
func (s *Supervisor) Resume() error
Resume lifts a Suspend and starts Xray from the config on disk.
Lifting the suspension is deliberately NOT a side effect of Apply or Restart. A suspended node is one the panel switched off, and it still does everything else — renews its certificate, accepts a config, keeps checking in — so any of those paths would quietly put it back to serving users. Coming back has to be something the caller asks for by name, in the one place that knows the panel switched it on again.
func (*Supervisor) Running ¶
func (s *Supervisor) Running() bool
Running reports whether the Xray child process is currently up. Reflects reality: a crashed process clears s.cur until a restart succeeds. Callers that drive logic (health decisions, auto-restart) want this exact instantaneous truth.
func (*Supervisor) Serving ¶ added in v1.4.0
func (s *Supervisor) Serving() bool
Serving reports whether Xray is up OR in the middle of a deliberate restart — the answer to "is this server working", not "is a process alive this instant".
It exists for status REPORTING, where Running() lies by omission. A restart (operator button, cert renewal, config push) holds the process down for about a second; a node's sync landing in that window would report xray_running=false and paint the server as down for a full poll cycle, for what is really a healthy bounce. A crash is different — that clears s.cur without setting restarting, so Serving is false for it, which is correct: a crash IS an outage.
func (*Supervisor) SetOnAccess ¶
func (s *Supervisor) SetOnAccess(fn func(email, ip, dest string))
SetOnAccess registers a callback invoked for each Xray access-log line that carries a user email + source IP (used to track online status / connections). dest is the destination host when the line has a usable one, else empty.
func (*Supervisor) SetOnCrash ¶ added in v0.7.0
func (s *Supervisor) SetOnCrash(fn func(err error))
SetOnCrash registers a callback invoked when the Xray child exits unexpectedly (a genuine crash, not an intentional Stop/Apply). Used to alert the operator.
func (*Supervisor) SetOnRecover ¶ added in v1.2.0
func (s *Supervisor) SetOnRecover(fn func())
SetOnRecover registers a callback invoked when Xray comes back after a crash.
func (*Supervisor) StartedAt ¶
func (s *Supervisor) StartedAt() int64
StartedAt returns the unix start time of the current Xray process, or 0 if it's down. It changes on every (re)start, so clients can detect a config reload.
func (*Supervisor) Stop ¶
func (s *Supervisor) Stop()
Stop terminates the Xray process and permanently closes the supervisor: every later Apply/Restart is silently ignored. It is for process shutdown only — use Suspend for a stop you intend to come back from.
func (*Supervisor) SubscribeLogs ¶
func (s *Supervisor) SubscribeLogs() (<-chan string, func())
SubscribeLogs returns a channel of new Xray log lines and an unsubscribe func.
func (*Supervisor) Suspend ¶ added in v1.4.0
func (s *Supervisor) Suspend()
Suspend terminates the Xray process but leaves the supervisor usable, so a later Apply or Restart brings it back. The auto-restart never fires for it: stopProc marks the process as killed on purpose, which is what the monitor keys on — the closed latch is not needed for that and is exactly what makes Stop one-way.
This exists because a node stops serving for two very different reasons. One is the agent going away; the other is the panel revoking it (disabled or deleted), which is reversible — re-enable it and it must serve again. Using Stop for the second poisoned the supervisor for good: the node kept syncing, applied every config it was pushed, reported each operator restart as a success, and never ran Xray again until its process was restarted by hand.
func (*Supervisor) UptimeSeconds ¶
func (s *Supervisor) UptimeSeconds() int64
UptimeSeconds reports how long the current Xray process has been running, or 0 if it's down.
func (*Supervisor) ValidateBytes ¶ added in v1.5.0
func (s *Supervisor) ValidateBytes(data []byte) error
ValidateBytes runs `xray run -test` over a config WITHOUT applying it, and returns Xray's own complaint when it refuses.
This is what lets the panel reject a bad advanced setting in the editor instead of storing it, pushing it, and finding out from a crashed Xray and a rollback. Nothing but Xray can answer the question — the settings it accepts are defined by its parser, and a panel-side whitelist only catches misspelled keys, not values it dislikes.
A missing binary means "cannot judge", not "invalid": the caller then falls back to its own checks rather than blocking every save.
func (*Supervisor) ValidateConfig ¶ added in v1.5.0
func (s *Supervisor) ValidateConfig(cfg *Config) error
ValidateConfig is ValidateBytes for a config still in struct form.
func (*Supervisor) Version ¶
func (s *Supervisor) Version() string
Version returns the Xray version string (e.g. "26.6.1"), cached after the first call. Empty when no binary is available.
func (*Supervisor) WriteConfig ¶
func (s *Supervisor) WriteConfig(cfg *Config) error
WriteConfig atomically writes config.json WITHOUT validating or restarting Xray. Used after live user add/remove so a crash-restart (the monitor reloads from disk) preserves the change. The content is generated by trusted code, so validation (which would reparse the geo DBs and cost seconds) is skipped.
type SystemPolicy ¶
type SystemPolicy struct {
StatsInboundUplink bool `json:"statsInboundUplink"`
StatsInboundDownlink bool `json:"statsInboundDownlink"`
StatsOutboundUplink bool `json:"statsOutboundUplink"`
StatsOutboundDownlink bool `json:"statsOutboundDownlink"`
}
SystemPolicy enables system-wide traffic stats.
type TCPHeader ¶ added in v1.5.0
type TCPHeader struct {
Type string `json:"type"`
Request *HTTPRequest `json:"request,omitempty"`
Response *HTTPResponse `json:"response,omitempty"`
}
TCPHeader is the raw-TCP masquerade. Type is "none" or "http"; for "http" the request/response templates decide what the framing claims to be.
type TCPSettings ¶ added in v1.5.0
type TCPSettings struct {
Header *TCPHeader `json:"header,omitempty"`
}
TCPSettings configures the raw-TCP transport. Header carries the optional HTTP masquerade — the framing that makes a raw proxy stream open like an ordinary HTTP exchange. Left nil the transport sends proxy bytes straight away.
type TLSSettings ¶
type TLSSettings struct {
ServerName string `json:"serverName,omitempty"`
RejectUnknownSni bool `json:"rejectUnknownSni,omitempty"`
ALPN []string `json:"alpn,omitempty"`
MinVersion string `json:"minVersion,omitempty"`
Certificates []Certificate `json:"certificates,omitempty"`
// Extra are additional tlsSettings keys the operator supplied. Merged at
// marshal time (see MarshalJSON) rather than stored as a sibling block, because
// Xray reads one flat tlsSettings object — there is nowhere for a second one to
// go. Validated against model.TLSExtraKeys before it reaches here, so it cannot
// contain the fields above that the panel owns.
Extra json.RawMessage `json:"-"`
}
TLSSettings configures the TLS layer for an inbound.
func (TLSSettings) MarshalJSON ¶ added in v1.5.0
func (t TLSSettings) MarshalJSON() ([]byte, error)
MarshalJSON emits the derived fields with the operator's extra keys folded in.
Written by hand because the alternative is making the whole block a raw blob, which would cost every other call site its compile-time field checking — the reason these structs are typed at all. The alias type breaks the recursion.
type TrojanClient ¶
type TrojanClient struct {
Password string `json:"password"`
Email string `json:"email,omitempty"`
}
TrojanClient is one Trojan user.
type TrojanInboundSettings ¶
type TrojanInboundSettings struct {
Clients []TrojanClient `json:"clients"`
}
TrojanInboundSettings is the "settings" object for a Trojan inbound.
type VLESSClient ¶
type VLESSClient struct {
ID string `json:"id"` // UUID
Flow string `json:"flow,omitempty"` // "xtls-rprx-vision"
Email string `json:"email,omitempty"`
}
VLESSClient is one VLESS user.
type VLESSInboundSettings ¶
type VLESSInboundSettings struct {
Clients []VLESSClient `json:"clients"`
Decryption string `json:"decryption"` // always "none" for VLESS
Fallbacks []Fallback `json:"fallbacks,omitempty"`
}
VLESSInboundSettings is the "settings" object for a VLESS inbound.
type WSSettings ¶
type WSSettings struct {
Path string `json:"path,omitempty"`
Host string `json:"host,omitempty"`
// AcceptProxyProtocol reads the real client IP from a PROXY-protocol header
// prepended by an upstream that forwards to this inbound.
AcceptProxyProtocol bool `json:"acceptProxyProtocol,omitempty"`
}
WSSettings configures the WebSocket transport.
type WireGuardPeer ¶
type WireGuardPeer struct {
PublicKey string `json:"publicKey"`
Endpoint string `json:"endpoint"`
AllowedIPs []string `json:"allowedIPs,omitempty"`
}
WireGuardPeer is one WireGuard peer (Cloudflare's WARP endpoint).
type WireGuardSettings ¶
type WireGuardSettings struct {
SecretKey string `json:"secretKey"`
Address []string `json:"address"`
Peers []WireGuardPeer `json:"peers"`
Reserved []int `json:"reserved,omitempty"`
MTU int `json:"mtu,omitempty"`
}
WireGuardSettings is the "settings" object for a wireguard outbound (used for the Cloudflare WARP egress).
type XHTTPSettings ¶ added in v1.5.0
type XHTTPSettings struct {
Path string `json:"path,omitempty"`
Host string `json:"host,omitempty"`
Mode string `json:"mode,omitempty"`
Extra json.RawMessage `json:"extra,omitempty"`
}
XHTTPSettings configures the XHTTP transport (Xray's HTTP-shaped transport, the successor to SplitHTTP). Mode is "" (Xray's default), "packet-up", "stream-up" or "stream-one"; with REALITY the default resolves to stream-one — one HTTP request per connection, which is both the smallest surface and the only shape that would survive path-based dispatch.
Host is the Host header the client sends; empty means the client uses the address it dialled, which is what we want when the inbound isn't behind a CDN.
Extra is the operator's advanced block, passed through verbatim. Xray reads `extra` as a COMPLETE XHTTP config and then overwrites its host/path/mode from the outer three, which is what lets the same object be handed to the client in the share link's extra= parameter with no translation.