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 all three protocols (VLESS-Vision-TCP-443 with fallbacks, Trojan-WS-443 via fallback, and Hysteria2-UDP-60000).
Index ¶
- Constants
- func EnabledInboundTags(set *model.Settings) []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 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 Sockopt
- 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) Running() bool
- func (s *Supervisor) SetOnAccess(fn func(email, ip 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) UptimeSeconds() int64
- func (s *Supervisor) Version() string
- func (s *Supervisor) WriteConfig(cfg *Config) error
- type SystemPolicy
- type TLSSettings
- type Traffic
- type TrojanClient
- type TrojanInboundSettings
- type VLESSClient
- type VLESSInboundSettings
- type WSSettings
- type WireGuardPeer
- type WireGuardSettings
Constants ¶
const ( TagVLESS = "vless-in" TagTrojan = "trojan-in" TagHysteria = "hysteria-in" TagReality = "vless-reality-in" )
Inbound tags (also the keys the live add/remove-user API addresses).
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`).
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. fallbacks route by path → loopback Trojan-WS inbound; default → the Go panel (decoy/panel/sub).
- Trojan inbound on 127.0.0.1:<trojan_port>, WS transport, no TLS (the 443 inbound already terminated it).
- Hysteria2 inbound on :<hysteria_port> (UDP), its own TLS; host nftables redirects the hop range to it.
- 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"`
}
GRPCSettings configures the gRPC transport.
type HTTPInboundSettings ¶
type HTTPInboundSettings struct {
Accounts []ProxyUser `json:"accounts,omitempty"`
}
HTTPInboundSettings is the "settings" object for an http forward-proxy inbound.
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.
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
}
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 Sockopt ¶
type Sockopt struct {
TrustedXForwardedFor []string `json:"trustedXForwardedFor,omitempty"`
}
Sockopt carries socket-level inbound options. trustedXForwardedFor whitelists the upstream peers whose X-Forwarded-For header Xray will trust.
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 string `json:"network,omitempty"` // "tcp" | "ws" | "hysteria" | "grpc"
Security string `json:"security,omitempty"` // "tls" | "reality" | "" (none)
TLSSettings *TLSSettings `json:"tlsSettings,omitempty"`
WSSettings *WSSettings `json:"wsSettings,omitempty"`
HysteriaSettings *HysteriaSettings `json:"hysteriaSettings,omitempty"`
RealitySettings *RealitySettings `json:"realitySettings,omitempty"`
GRPCSettings *GRPCSettings `json:"grpcSettings,omitempty"`
Sockopt *Sockopt `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) 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.
func (*Supervisor) SetOnAccess ¶
func (s *Supervisor) SetOnAccess(fn func(email, ip 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).
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 prevents further (re)starts (used on panel shutdown).
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) 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) 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 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"`
}
TLSSettings configures the TLS layer for an inbound.
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"`
// AcceptProxyProtocol lets the loopback Trojan inbound read the real client
// IP from the PROXY-protocol header the VLESS fallback prepends (xver).
AcceptProxyProtocol bool `json:"acceptProxyProtocol,omitempty"`
}
WSSettings configures the WebSocket transport (Trojan-WS).
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).