172 Commits
Author SHA1 Message Date
Muse 739f35f804 release: panel V2.7.2 (panel-only, agent line A2.6.0)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-24 17:00:01 +00:00
Muse d19d7f39f3 Merge branch 'fix/notification-to-probe-settings' into merge/v272-combined 2026-10-24 16:35:07 +00:00
Muse f6f93cf973 Merge branch 'fix/public-title-inject' into merge/v272-combined 2026-10-24 16:35:04 +00:00
Muse 1d340b5abd release: panel V2.7.1 (panel-only, agent line A2.6.0)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Docs CI / build (push) Waiting to run
Docs Deploy (GitHub Pages) / build (push) Waiting to run
Docs Deploy (GitHub Pages) / deploy (push) Blocked by required conditions
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-24 16:26:10 +00:00
Muse 495115f869 fix(probe): align theme store cards: equal height, bottom actions 2026-10-24 16:20:30 +00:00
Muse 2212604636 probe: latency add row always visible, single-line with select-all nodes
- Drop the '+ add probe' toggle button; the add/edit form is now
  always shown, resetting to a blank add state after save/cancel.
- Single nowrap row: name, host:port (flex 6), interval (flex 1),
  auto-join switch, node multi-select (flex 2), select-all-nodes
  button (disabled with no agent nodes), save/cancel.
- Remove the region input from the task editor (region value is
  still kept in the draft and in the save payload, so editing an
  existing task never wipes its region; grouping display unchanged).
- i18n: drop probeTasks.add / probeTasks.region (13 locales),
  add probeTasks.selectAllNodes (13 locales, key sets in sync).
2026-10-24 16:15:10 +00:00
Muse 71e9ee1767 Restore locale test fixtures deleted in error
The internal/web/locale/translation/ files (en-US, fa-IR, zh-CN) are
not production data — the panel embeds internal/web/translation —
but they ARE test fixtures: locale_lazy_test.go embeds this package's
own translation/ directory (//go:embed translation) and asserts lazy
parsing against hello/greet keys in exactly these three languages.
Deleting them broke the locale package's test setup
('pattern translation: no matching files found'), which the full Go
run caught. The 'zero references' check missed the test's relative
embed pattern because it grepped for the full locale/translation path.

Restored byte-identical to 5a9c983; locale package tests pass again.
2026-10-24 16:01:13 +00:00
Muse 20db43210e Move probe settings into sub-pages; per-node probe metadata to node edit dialog; drop probe-task batch add
Probe settings page (settings#probe) is now a tab container with three
second-level sub-pages, following the same antd Tabs pattern the other
settings tabs use for in-section grouping, in this order:
- status: status-page settings (the former public-status-page form),
  tab and heading renamed from public-status-page to status-page
  settings (new pages.settings.probe.statusPageTitle key, all 13
  locales);
- latency: latency probing task manager (ProbeTasksPanel), with its
  batch-add module removed (see below);
- notify: notifications, moved unchanged from the public-page tab
  (PublicPageTab, theme-store section) into ProbeNotifyTab.

Per-node probe metadata (ProbeMetaSection) no longer lives on the
probe settings page: it moved into the node edit dialog's
public-status-page section (NodeFormModal), where it is edited in
place per node — the component was already designed for that
embedding (own endpoints, immediate save, outside the node form).
The dialog's 'moved to probe settings' placeholder goes away with
it. The global probe settings stay where they were (status tab).

Batch-add removal (latency page): the batch card, its frontend state
and handlers (parseTargets, onBatchAdd), the POST
/panel/api/agent/probe-tasks/batch endpoint (route, form type,
handler), its dedicated TestProbeTasksBatch test, and the six
probeTasks.batch* locale keys are all deleted. The endpoint's only
production caller was the removed module; the single-task add/edit
flow, the target list and all other task endpoints are untouched.

Orphaned locale keys removed across all 13 locales (settingsTitle,
metaTitle, metaNodePlaceholder, movedHint, goSettings, plus the six
batch keys); the 13-locale key sets stay identical, enforced by the
i18n-dead-keys test. Backend APIs, setting keys, TG/webhook channel
logic and theme-store content are unchanged.
2026-10-24 15:57:28 +00:00
Muse 1acf4643b6 Close out panel API token removal (V2.7.1 follow-up)
1. Drop the dormant api_tokens table on startup: initModels now runs
dropApiTokensTable (GORM Migrator, string table name since the model is
gone). No-ops on fresh databases, where AutoMigrate never creates it;
covers databases carried over from V2.7.0 whose install row was already
deleted by hand. Covered by TestDropApiTokensTable_DropsLegacyTable.

2. Delete provably dead Nord/PIA integration: service/integration/nord.go
and pia.go (+ pia_test.go), the whole internal/pia package (only pia.go
imported it), the nord/pia setting keys and getters, the HasNordSecret
view field, and the frontend model/schema fields; openapigen regenerated
(generated diff is exactly the hasNordSecret removal). Evidence: zero
production callers for NordService/PiaService, no controller routes, no
jobs, no frontend UI, no openapi exposure; panel egress is a separate
netproxy mechanism and does not consume them. maxResponseSize moves to
warp.go, which is its remaining user (it was declared in nord.go).

3. Delete unreferenced internal/web/locale/translation/ (3 files):
the runtime loads internal/web/translation (web.go embed + locale.go
disk fallback); zero references to the locale/translation path.

4. gofmt-align the AllSetting SubPort block (pre-existing drift).

5. Docs: architecture.md token table row, API-tokens troubleshooting
row, api_token.go tree entry, setting/api gateway token comments, the
mtls 'API token optional' phrase, and the integration provider list
(now warp.go only); the 4 api-tokens.mdx pages plus their meta.json
entries; the per-node apiToken prose in nodes.mdx (4 languages, title
and anchor slugs updated in pairs; frontmatter re-parsed clean).

Deliberately NOT changed: install-agent.sh RELEASE_BASE stays V2.7.0
(agent installs keep pulling from V2.7.0); install-master.sh LUI_URL
V2.7.0 -> V2.7.1 is left to the release commit; no forced first-login
password change.

Kept as live, with evidence: WARP (hourly WarpIpJob in web.go),
mtproto (live inbound protocol + sidecar manager + traffic job),
xray_version (NodeList UI fallback when singboxVersion is absent),
session.apiAuthUserKey (spa_test login simulation + GetLoginUser
production fast path).
2026-10-24 15:47:49 +00:00
Muse 54dc346697 fix(probe): inject configured site name into served theme index title
The public page is an SPA: browsers show the theme package's static
<title> on first paint (a CFSM-era package still says
CF-Server-Monitor) and only switch to the configured title once the
theme JS fetches /api/me. Serve the configured title in the shell
itself so the first paint is already correct.

serveProbeThemeFile now rewrites the first <title> of index.html
with the site_name probe setting — the same setting /api/me's
site_name comes from, so the injected title and the JS rewrite can
never disagree. Theme files on disk are untouched, so any upstream
theme package works unmodified. With no site name configured the
bytes pass through unchanged (no empty title injected). The title
is HTML-escaped and spliced in place, so a $ in the title is safe.

Caching is unchanged and already correct: index.html is served
no-cache with a strong ETag over the final (injected) bytes, so a
title change lands on the next revalidation; hashed assets stay
immutable and pass through byte-identical.
2026-10-24 15:36:31 +00:00
Muse 5a9c9837e1 Remove panel API token system (panel-only, V2.7.1)
Delete the whole ApiToken stack from the panel: the api_tokens table
model and seed/migrate/normalize paths, the Bearer auth and
admin/monitor scope chain in the panel API (session login is now the
only panel API credential), the settings token-management endpoints,
the CLI -getApiToken bootstrap command, and the SecurityTab token
management UI plus its models/schemas/i18n keys. Regenerate the
frontend OpenAPI files (31 -> 26 schemas).

Agent side untouched: agent runtime, agent version (A2.6.0),
install-agent.sh, subscription/probe paths and node behavior are
unchanged. The /panel/api/agent group never went through checkAPIAuth
and is unaffected.

Also drop provably dead weight found in the same pass: the unimported
internal/xray/geodata package and its generated schemas, the retired
SPA shell routes (/groups, /xray, /outbound, /routing, /api-docs;
unregistered paths still reach the shell via the NoRoute fallback),
the never-set SettingController.xrayService field, and the CSRF
api_authed exemption whose only setter was the deleted Bearer branch.

Deliberately NOT dropped: the api_tokens table itself (left dormant
and empty in existing databases; a DROP migration needs a separate
decision) and the session apiAuthUserKey helper (test-only use remains).
2026-10-24 15:04:06 +00:00
Muse 739c18ce48 release: panel V2.7.0 / agent line A2.6.0
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Docs CI / build (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
Deploy Smoke Tests / noninteractive-install (ubuntu-24.04-arm) (push) Waiting to run
Deploy Smoke Tests / noninteractive-install (ubuntu-latest) (push) Waiting to run
Deploy Smoke Tests / release-tag-install (ubuntu-24.04-arm) (push) Waiting to run
Deploy Smoke Tests / release-tag-install (ubuntu-latest) (push) Waiting to run
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
Agent code changed in the rename batch (lui-agent binary, LUI_ env prefix, /etc/l-ui paths and services), so the agent line moves 2.5.0 -> 2.6.0 and its default-expectation tests move with it; panel version is injected at build time (V2.7.0). install-agent.sh RELEASE_BASE and install-master.sh LUI_URL move V2.6.0 -> V2.7.0. Repo name settled as rogue/l-ui (user decision 2026-10-24); the rename-batch placeholder warnings in docs/release.md, selfupdate.go and install-master.sh are closed by the Gitea rename that precedes publishing this release.
2026-10-24 20:53:51 +08:00
Muse f2695ddb22 test: track LUI_ skip gates in bot-context checks
The rename changed the env prefix XUI_ -> LUI_, so the gate regexes only matched XRAY_E2E_BINARY (1 < 5) and TestBotContextSkipGatesExist failed on the rename branch while passing on base. LUI_ joins the alternation; XUI_ stays so a stray old gate is still checked, not silently ignored. REVIEW.md's LUI_SCALE_TEST is now covered by the review check too.
2026-10-24 20:53:13 +08:00
Muse e0ed2b0352 fix: gofmt NodeView AgentOS field alignment 2026-10-24 12:15:41 +00:00
Muse 2b914d374f docs: RENAMING.md + l-ui migration runbook
RENAMING.md: exact mapping, LUI_ inventory, sing-box orphan-scan
re-verification, Tianyi badge mechanism, intentionally-kept items
(module path, upstream mentions, frozen Windows, ps1, log
filenames, Postgres creds, generated schemas, stale test
binaries), and pending items (repo spelling BLOCKER, version
bump, ps1 URL after repo rename, schema regeneration).
docs/migration-l-ui.md: operator-only mv table, DB file rename,
unit-env translation, backup-then-delete, old-core stop rule,
rollback before acceptance only, per-machine acceptance
checklist, pilot order (probe node, master, rest one by one,
TYYUN untouched). docs/release.md: placeholder-repo warning.
2026-10-24 12:03:26 +00:00
Muse 269c37653c ui: suppress agent-update badge on Windows rows, refuse Windows update intents
NodeView gains agentOs from AgentNode.ProbeOS (overlaid ahead of
the telemetry early-exit, like ProbeOnly). NodeList gates both
badge sites (list column + detail) on !isWindowsAgentOS(agentOs).
Backend requestAgentUpdate refuses Windows rows up front instead
of recording an intent that would only age out.

ProbeOS is reliable here: the frozen A2.2.1 Windows agent reports
probeFacts.os 'Windows 10' on register and heartbeat (see the
legacy-Windows contract test) and the panel persists it to
probe_os. Empty ProbeOS fails open on both sides. No fake
version, no per-node freeze switch, no Windows agent change, no
new win asset. The one-click action button itself is unchanged;
clicking it on a Windows row now errors clearly instead of
recording a dangling intent.
2026-10-24 12:02:05 +00:00
Muse 6a5ee8f77b rename: 3x-ui/x-ui -> L-UI/l-ui/lui-agent (paths, services, env, assets)
Display L-UI; panel binary/process l-ui, agent lui-agent.
Dirs /usr/local/l-ui, /etc/l-ui, /var/log/l-ui; DB /etc/l-ui/l-ui.db
(name file drives it via GetName), probe.db beside it, cert
/etc/l-ui/cert, bin /usr/local/l-ui/bin. Services l-ui.service /
lui-agent.service, OpenRC lui-agent, l-ui.sh, cmd/lui-agent.
Env prefix XUI_ -> LUI_ (code reads new prefix only). Release
assets l-ui-linux-* / lui-agent-linux-*; Gitea repo rogue/l-ui is
a placeholder pending user confirmation (see selfupdate.go note).
Go module path github.com/mhsanaei/3x-ui/v3 intentionally kept.
Versions unchanged: panel V2.6.0 / agent A2.5.0.
2026-10-24 12:00:55 +00:00
Muse 8158cedfc1 release: panel V2.6.0 / agent line A2.5.0 (agent code changed in V2.6.0 batch); install-agent RELEASE_BASE -> V2.6.0 (ps1 frozen at V2.4.0)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-24 11:20:23 +00:00
Muse 1b255eb414 test(web): retire TestRouteRegistryContract (api-docs surface removed in P6) 2026-10-24 19:00:26 +08:00
Muse f1132461db merge: item 4 vitest red + MinuteFold stabilization 2026-10-24 10:09:16 +00:00
Muse 9ceca7d58f merge: item 3 agent v4 beacon 2026-10-24 10:09:16 +00:00
Muse e7676f8635 merge: item 2 node-deletion cascade 2026-10-24 10:09:15 +00:00
Muse b6e8fc558d merge: item 1 agent orphan-core handle recovery 2026-10-24 10:09:15 +00:00
Muse 460b02cec6 test(i18n,probe): clear new vitest red + stabilize MinuteFold flaky (item 4)
- i18n dead-keys: delete 64 keys unreferenced in frontend/Go sources
  (menu donate/docs, old index config actions, the whole removed
  traditional-node/mTLS node form incl. its mtls subtree, xray
  Outbounds/Balancers) from all 13 locales; 1536 -> 1472 keys each.
  Verified repo-wide: only stale prebuilt binaries still embed them.
- probe TestMetricHistoryMinuteFold: replace wall-clock base with a
  fixed 120 s-aligned instant; an odd-minute base split the 120 s fold
  into two buckets (want 1, got 2) on ~half of all runs.
2026-10-24 10:08:04 +00:00
Muse 9681dc6f4a fix(node): cascade node deletion to agent bindings and probe rows
Deleting a panel node left its agent_nodes rows and probe.db rows
behind, so deleted nodes kept showing as ghosts and their probe
latency stayed attributed to leftover rows (TYYUN case). Delete now
removes agent rows bound by agent_nodes.node_id inside the existing
panel transaction, then drops each agent's probe rows (meta, traffic,
both history tiers, ping records and ping assignments) and the
public-page snapshot. Agents link by node_id, probe rows by agent row
id: matching probe rows on the node id would strike another node's
data (Oracle-JP: node 33, agent row 20).
2026-10-24 10:05:19 +00:00
Muse 12aff835ed feat(agent): periodic IPv4 beacon proves public v4 to panel (item ③)
Agent posts an empty beacon over a tcp4-forced connection every
5 minutes (plus once at startup); panel files the observed source
as SeenIPv4 only when it is a public IPv4 literal, never touching
the reported telemetry address, so 1:1 NAT nodes stop falling back
to their private address in share links.
2026-10-24 09:43:56 +00:00
Muse 66bf6a88eb fix(agent): reconcile orphaned sing-box core before start
After an agent restart the tracked sing-box handle is lost while
the old core survives reparented holding the inbound ports, so
every apply died on bind, rollback died the same way, and the
agent retried forever. startSingboxLocked now scans /proc for
processes whose argv carries run -c <exact live config path>
(excluding the tracked pid) and stops them SIGTERM-then-SIGKILL
before starting, covering the apply, rollback, and
unchanged-but-not-running paths. The exact-path match never
touches cores on other config files; Linux only.
2026-10-24 09:38:09 +00:00
Muse 6842da3c7e release: panel V2.5.0 / agent line A2.4.0 (agent code changed in P3); install-agent RELEASE_BASE -> V2.5.0 (ps1 frozen at V2.4.0)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Docs CI / build (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
2026-10-24 02:16:33 +00:00
Muse 6f4a4379d9 merge: feat/agent-version-decouple (agent version line decoupling + P3 memory tuning) 2026-10-24 01:59:19 +00:00
Muse 11afed3bac P3 A1: move memory tuning into stdlib-only util/memtuning (keeps agent closure lean) 2026-10-23 22:10:51 +00:00
Muse 1ee07ba73d P3 M1 test fix: assert go-i18n fallback contract (default text + MessageNotFoundErr) 2026-10-23 22:08:05 +00:00
Muse d70fd38978 P3 M4: column-level raw updates on agent ingest hot paths 2026-10-23 21:59:05 +00:00
Muse 5a7f89ee21 P3 M1: lazy per-language i18n parsing (fallback + bot language at startup) 2026-10-23 21:59:05 +00:00
Muse 6dd31b3619 P3 rider: stop sing-box core as well as xray before update re-exec 2026-10-23 21:59:05 +00:00
Muse c59882b846 P3 A1+M5: agent memory tuning profile and XUI_PPROF gate on both agent entries 2026-10-23 21:59:05 +00:00
Muse e5d42224aa decouple agent version line from panel version
Agent display version now comes from the agent line's own source
(config.agentDisplayVersion injection + defaultAgentDisplayVersion
constant, currently A2.3.0) instead of being derived from the panel's
displayVersion. Masters resolve the agent line's latest from each
release's agent-version.txt marker (selfupdate.ResolveLatestAgentTarget,
legacy tag derivation as fallback for pre-marker releases): update
intents target the marker under the panel tag, panel-only releases
produce no intent, and the nodes page badges agent rows against
their own line via PanelUpdateInfo.displayLatestAgentVersion.

Windows agent frozen at A2.2.1: release discipline in docs/release.md
+ scripts/release-build.sh (agent assets reused verbatim when the
agent code is unchanged, marker always emitted, no Windows exe),
install-agent.ps1 pinned at V2.4.0, and the A2.2.1 protocol shapes
locked by TestAgentLegacyWindows221Contract.

Agent update tests now derive their targets from the live agent
line instead of a hardcoded A2.0.x the line has passed.
2026-10-23 21:47:10 +00:00
Muse 7244f3c9da install-agent: RELEASE_BASE -> V2.4.0 (sh + ps1)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-23 19:40:01 +00:00
Muse f9183e9dbb merge: feat/b6-traditional-removal (B6 phase 2: traditional node removal) 2026-10-23 19:39:51 +00:00
Muse f99c43dd2a tests: restore legacy ApiToken trim in normalize; update probe public contract for stack markers (rider 6); drop legacy panel-probe job test 2026-10-23 19:14:01 +00:00
Muse ef89259a49 B6 frontend: agent-only node form/list, drop mTLS modal and homepage config button (rider 5); regenerate contracts 2026-10-23 19:08:26 +00:00
Muse 4c04cdb1bc rider: anonymous probe view emits ipv4/ipv6 stack markers, never addresses 2026-10-23 19:08:25 +00:00
Muse bdfcce0e11 B6 backend: remove traditional node path, node mTLS and remote merge engine; drop restartXrayOnClientDisable (rider 1) and ApiScopeNodeSync (rider 3) 2026-10-23 19:08:24 +00:00
Muse 7ba1841df2 riders: drop sidebar donate/docs links; rename zh-CN TG bot tab label 2026-10-23 19:08:08 +00:00
Muse 3a3c7c0dc9 install-agent: RELEASE_BASE -> V2.3.0 (sh + ps1)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-23 17:26:25 +00:00
Muse 388e26c292 geoip: pin default weekly-update URL to Gitea geoip-country asset (V2.3.0) 2026-10-23 17:26:15 +00:00
Muse 1d1258a10d merge fix/no-probeonly-flag into main (V2.3.0) 2026-10-23 17:25:59 +00:00
Muse 81299db6ff merge feat/geoip-flag into main (V2.3.0) 2026-10-23 17:25:55 +00:00
Muse 89b65f1606 merge feat/agent-split into main (V2.3.0) 2026-10-23 17:25:50 +00:00
Muse d16b888146 geoip: tests — known-address calibration, source order, pin precedence, updater download/validate/replace, contract frame 2026-10-23 16:42:28 +00:00
Muse c94136c8a1 geoip: resolve node countries locally for the public views (Q7)
country/country_auto in buildProbeNodeView now come from a local
MMDB lookup of the node's public address (held v4, held v6, seen
v4, seen v6) instead of the pin alone / a hardcoded empty string.
Layered data: local file in the data folder wins, embedded factory
snapshot is the fallback, no database means the pre-flag empty
shape. A weekly job conditionally downloads a fresher copy,
validates it, atomically replaces the local file and hot-swaps the
reader; no URL configured (geoipCountryDefaultURL / the
geoip_country_url setting) means the updater stays silent. No
address ever leaves the master.
2026-10-23 16:42:28 +00:00
Muse e7f4bfed24 geoip: embed DB-IP Lite country database snapshot (CC BY 4.0, provenance in NOTICE) 2026-10-23 16:42:28 +00:00
Muse 6b9832cdcc install-agent: download the standalone agent artifact
XUI_URL default switches from x-ui-linux-<arch> (panel binary) to
x-ui-agent-linux-<arch>; RELEASE_BASE mechanism unchanged. The new
asset exists from the first split release on — bumping RELEASE_BASE
stays a release-step action.
2026-10-23 16:40:35 +00:00
Muse e78cb8ccc5 feat(agent): standalone Linux agent binary + agent assets in update chain
New entry cmd/xui-agent links only the agent dependency closure
(internal/agent + config/logger/selfupdate/xray/util leaves), a
drop-in replacement for the dual-mode binary's agent subcommand:
same invocation (xui-agent agent -config ...), same agent.json and
state files, same wire protocol.

selfupdate gains AgentAssetName (x-ui-agent-linux-<arch>); the
agent's one-click update now downloads the agent asset instead of
the panel binary. Pre-split agents keep fetching the panel asset —
the two forms are interchangeable at the install path.
2026-10-23 16:40:35 +00:00
Muse ef662c9fdb panel: install commands no longer append --probe-only
Probe-only is governed solely by the master-side flag so unchecking it
in the panel takes effect on its own; an agent.json preset would pin
it via the dual-source OR gate. The install-agent.sh/ps1 --probe-only
flag stays for manual installs. tsc --noEmit clean.
2026-10-24 00:22:24 +08:00
Muse a81eff8c0d install-agent: RELEASE_BASE -> V2.2.1 (sh + ps1)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 15:25:09 +00:00
Muse 1d7eb16784 merge feat/v221: windows probe degradation + agent heartbeat probe + update-check fallback + procd/OpenRC script fixes + probe traffic GB unification + public remark name (V2.2.1) 2026-10-23 15:24:55 +00:00
Muse a13179ed9b v221 ⑦ public views: node name prefers the public remark
buildProbeNodeView now sources its 'name' from probeDisplayName:
the node's public remark (probe_meta.public_remark) when non-empty
after trimming, else the node name as before. Contract field name
unchanged, theme packages untouched, both audiences (anonymous and
admin frames share the builder); the panel's internal node list is
a different surface and keeps the plain node name.

Tests: display-name unit cases (remark / empty / whitespace) and
view-level assertions for both audiences; the public contract
test's seeded expectation updated to the remark (its fixture sets
public_remark='shown publicly' on node 'PubNode').
2026-10-23 15:02:12 +00:00
Muse 93c1620c15 v221 ⑥ probe traffic: binary GB convention + one-shot calibration
Unit unification: GB entries converted at 1e9 while every byte
formatter is binary (1024^3), so a 3000 GB limit rendered 2.73 TB
instead of 2.93 TB. calBytes and the form's limit conversion now
use 1024^3. Stored traffic_limits (bytes, typed x1e9) are rescaled
x1.073741824 exactly once at store open, guarded by the
probe_setting mark gb_1024_migrated_v1; calibration values are
stored in GB (no rescale — only their conversion changed) and
price/sort/reset-day are unitless.

One-shot calibration: the form's cal fields are deltas to apply
now. probe.MergeCalDelta folds a non-zero submitted value into the
stored standing correction and keeps the standing value on a
zero/absent submission; putMeta merges against the stored row
(SaveMeta/UpsertMeta keep plain replace — the notify sweep relies
on it). GET no longer echoes the standing correction into the form,
and the frontend keeps the cal inputs as local state that starts
empty and clears on successful save, so a later unrelated save
resubmits nothing.

Tests: calBytes(3000)=3000x2^30; migration 3.0e12 -> 3000x2^30 with
no second rescale on reopen; one-shot flow (save delta, save
unrelated with zero cal -> calibrated traffic unmoved, second delta
accumulates once). Existing TestTrafficCalibrationAppliedAndFloored
expectation updated to the binary figure. No vitest covers
ProbeMetaSection (disclosed in the report).
2026-10-23 15:02:11 +00:00
Muse ba57fb3c00 v221 ⑤ install-agent: OpenRC respawn_period=0 rejected by supervise-daemon
The item-23 template wrote respawn_period=0 assuming it meant 'no
window' like respawn_max=0; supervise-daemon validates the value at
service start and refuses: Invalid respawn-period value '0'
(Alpine real-machine report). Template now writes 1800, the value
the machine's other supervise-daemon services use; with
respawn_max=0 (unlimited) the period is only the counting window.

Why existing Alpine nodes (Leg-US) never hit it: the respawn lines
exist only since 27a5097 (2026-10-22, item 23) — before that the
template used command_background with no respawn parameters at all,
and panel one-click agent updates swap only the binary, never
regenerate /etc/init.d/x-ui-agent. Only fresh installs (or script
reruns) on OpenRC with the post-item-23 template were exposed.
2026-10-23 14:27:23 +00:00
Muse 151b07b73f v221 ④ install-agent: OpenWrt/procd support + honest nohup fallback
detect_init_system gains a procd tier ([ -f /etc/rc.common ] &&
command -v procd, after systemd/OpenRC; XUI_INIT_SYSTEM=procd also
accepted). start_via_procd writes /etc/init.d/xui-agent byte-equal
to the unit hand-verified on AX6600 (paths via AGENT_BIN/CONF_DIR),
stops any previous instance before overwriting, enables + starts,
and verifies the process is alive (pgrep, ps fallback). The nohup
fallback now errors out immediately and clearly when nohup itself
is missing (BusyBox-trimmed systems) instead of pretending to start
and failing at the end.
2026-10-23 14:26:31 +00:00
Muse cec5905483 v221 ③ update check: fall back to raw version when display is unparseable
displayUpdateFields returned avail=false whenever the running
build's display version could not be compared (the VV2.1.0
double-letter builds), so the panel swallowed a real update prompt
and the native updater refused to run. displayUpdateFieldsFor now
takes the current display/raw versions as inputs and, when the
display comparison cannot judge, compares the latest tag against
the raw base version with the same tolerant display parser —
unparseable raw base yields false. (Not isNewerVersion: on this
fork's uppercase-V tags it degrades to string inequality, which
would phantom-report an update on form difference alone.)
Parseable display versions keep the segment rule untouched.
Regression tests cover the VV scenario in both raw forms.
2026-10-23 14:26:31 +00:00
Muse 1df78dd874 v221 ② node probe: agent nodes answer from heartbeat, not a dead dial
NodeService.Probe now checks for a bound agent first: agent-managed
nodes synthesize the result from agent_nodes.last_seen (MAX over
bound agents, ms) — fresh within the same 180s window the heartbeat
job expires by = online with the heartbeat age as latency; stale or
never-seen = offline with LatencyMs -1. No dial, and LastError is
never written for agent nodes (the stored dial error from the
placeholder address https://agent:2053 is also healed on next ⚡,
since the synthesized patch carries an empty error through
UpdateHeartbeat). Traditional-node dial path unchanged; verdict is a
pure function with unit tests.

Frontend: the ⚡ tooltip/menu used t('pages.nodes.probe'), which
since the probe-metadata work resolves to the status-page SECTION
object, so i18next fell back to rendering the raw key. The existing
pages.nodes.testConnection key (present in all 13 locales) is the
right label — point the three usages at it. No new i18n keys.
2026-10-23 14:26:31 +00:00
Muse 92dfdc542c v221 ① windows probe: gate optional procs via Find + per-source recover guard
LazyProc.Call must-finds and panics on a missing export; the trimmed
Tianyi cloud-PC image has no FreeMibIfTable2 in iphlpapi.dll, which
killed the agent on its first collection after a successful register.
Optional procs (GetSystemTimes/GlobalMemoryStatusEx/GetIfTable2Ex+
FreeMibIfTable2 as one gated pair) now resolve through sourceGate
(Find once, missing = source disabled with one warning); the iface
pair is gated together so a missing free proc never leaks the
system table. collectMetrics additionally runs every source through
guardedCall so any residual panic zeroes that source alone.
Pure gate/guard logic lives in probe_guard.go (no build tag) with
Linux-runnable regression tests.
2026-10-23 14:26:22 +00:00
Muse a25c51003e install-agent: RELEASE_BASE -> V2.2.0 (sh + ps1)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 13:30:56 +00:00
Muse b27bcfcb5b merge feat/v210-probeonly-win: windows probe agent + version display + reality sni fix (V2.2.0) 2026-10-23 13:30:40 +00:00
Muse 75f10b27fa windows probe-only agent + agent version display unification + reality sni from sing-box fragment
Scope B (Windows agent):
- probe.go split into shared core + probe_linux.go (verbatim Linux
  sampler, build-tagged) + probe_windows.go (Win32 sampler: GetSystemTimes
  CPU diff, GlobalMemoryStatusEx, fixed-drive df totals, GetIfTable2
  counted set, MachineGuid boot identity, registry facts; load and
  TCP/UDP counts stay zero - x/sys v0.47.0 exports no wrapper)
- update intents are acknowledged and skipped on Windows (the release
  assets are Linux binaries; Windows nodes update via install-agent.ps1)
- cmd/xui-agent-windows: SCM service host (svc.Run + mgr install/
  uninstall/start/stop) mirroring main.go's agent lifecycle wiring
- install-agent.ps1: downloads the exe, writes probeOnly agent.json,
  registers and starts the service, rerun-safe

Scope C (version display):
- config.GetAgentDisplayVersion (and the master getter) compose from
  the bare number so a V-form injection no longer doubles the letter
  (AV2.1.0 -> A2.1.0)
- node list view repairs stored AV-prefixed reports at assembly so
  deployed agents read uniformly without an update

Scope D (production fix):
- share-link reality sni: when the inbound has a sing-box fragment,
  sni is the fragment's tls.server_name - the only name the sing-box
  REALITY server serves. The previous rule picked a uniformly random
  serverNames entry per generation, which xray tolerated but sing-box
  refuses as an invalid connection. sid keeps its random pick: the
  converter carries the whole shortIds list into the fragment, so
  every listed sid is served.
2026-10-23 13:22:51 +00:00
Muse 7df3a338ef install-agent: RELEASE_BASE -> V2.1.0
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 19:57:56 +08:00
Rogue 5ca22ec340 probe-only node mode: master flag + agent gate + panel switch (V2.1.0 A)
agent_nodes gains probe_only; getConfig always serves the flag and withholds the sing-box payload (null config, empty hash) for flagged nodes while probe tasks, fast interval, stat iface and update intents ride as usual. The agent gates both core branches when the local agent.json preset or the master flag is on, retires a running core once (best-effort tail flush, switchover bookkeeping untouched so turning the flag off self-heals through the existing hash-current-but-not-running path), and makes the traffic cycle an explicit no-op. Panel: node create/update accept probeOnly, the node view overlays it from the binding, the node form gains a switch (carried into the generated install command), the list shows a probe-only tag in the core-version cell, and install-agent.sh --probe-only writes the preset, skips the core download/self-check and inherits the flag on no-arg reruns.
2026-10-23 11:54:35 +00:00
Muse 2d37a6de18 install-agent: RELEASE_BASE -> V2.0.3
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-23 18:45:22 +08:00
Muse db6f666ff7 probe: fast report stamps last-seen; snapshot TTL 900ms (V2.0.3)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 18:38:56 +08:00
Muse d4d259fa58 probe ws: frame cadence follows probe_fast_interval (V2.0.2)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 18:15:05 +08:00
Muse 9caa4e0cf9 install-agent: RELEASE_BASE -> V2.0.1
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-23 16:13:25 +08:00
Rogue 29de9761c8 V2.0.1: listen override fix, sing-box core fetch, probe settings page + fast report, spx removal, core mem env
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Docs CI / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
- 0: sing-box gen overrides fragment listen/port from the inbound row
  (empty listen -> "::"), Update/Add recompute the stored fragment;
  non-loopback E2E against the real core binary.
- 1: agent fetches the sing-box core from the Gitea release when
  missing, self-checks it, and only then latches the switch.
- 2: node list shows the sing-box core version (heartbeat field,
  persisted on the node row), xray version as fallback.
- 3: public-page fallback returns 404 to anonymous visitors when the
  page is disabled.
- 4: settings restart hint bar removed, dead i18n keys cleaned.
- 5: two PUT calls missing JSON headers fixed (audit: only those two),
  batch probe-task creation endpoint + UI.
- 6: cf-probe retirement card and coverage pipeline removed.
- 7: generated vless links no longer carry spx (panel export + sub);
  parser still accepts spx; golden fixtures updated.
- probe batch: dedicated probe settings tab (public-page settings,
  tasks, per-node meta), retention_days editable, per-node traffic
  calibration + stat-interface pinning, runtime metrics split into a
  lightweight fast report (default 3s, 1-60s adjustable).
- 8: sing-box core processes start with GOMEMLIMIT=32MiB, GOGC=50.
- 9: dead /getTwoFactorEnable docs entries removed (frontend call and
  contract entry already gone at base; verified by grep).
2026-10-23 07:53:11 +00:00
Muse c2f1840535 Merge feat/singbox-b5 (test contract update)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 02:47:01 +00:00
Muse 06de0e8384 B5: update stats plumbing test to the corrected registration contract 2026-10-23 02:47:01 +00:00
Muse 0a6e9b7a7d Merge feat/singbox-b5: ITEM6 B5 switchover + V2.0.0
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
Sing-box becomes the only runtime payload (master serves
singbox_config only; agents switch on its arrival, flush and
retire xray, roll back to xray on activation failure). Plus the
two rehearsal-caught accounting fixes: stats registration needs
all three name lists (recording gate enforces the switches), and
fragment tags now equal panel row tags so inbound totals land.
2026-10-23 02:43:58 +00:00
Muse 7e15bfbf8e Drop accidentally committed frontend/node_modules symlink (build env artifact) 2026-10-23 02:43:58 +00:00
Muse 6de22ae2e3 Remove throwaway live-stats probe test (rehearsal scaffolding) 2026-10-23 02:15:40 +00:00
Muse 05c164dc8f B5 rehearsal fix: fragment tag = panel row tag
The rehearsal's inbound-level totals never moved: the agent
reports sing-box tags (inbound-<port>) while the master's agent
traffic handler matches inbound rows by their panel tag — which
the B1 model renamed to the n<node>-in- scheme, so the lookup
silently matched nothing (per-user totals, keyed by email, were
unaffected; production on V1 keeps the old tag form and is not
hit until the V2 migration itself).

The converter now takes the row's panel tag as the fragment tag
(migrator passes it through), making one identity serve the DB
row, the generated config, core stats and traffic reports. Bare
fixtures without a panel tag keep the historical form.
2026-10-23 02:15:36 +00:00
Muse c610ab88ea B5 rehearsal fix: sing-box stats registration needs all three lists
The B5 full-stack rehearsal caught a silent accounting killer:
with the production switch set (inbound on, outbound off) the
generated v2ray_api stats block omitted the outbounds list, and
sing-box then registers NO counters at all — QueryStats answered
zero entries while real traffic flowed (A/B against the real core:
adding the list produced full user/inbound/outbound counters).

- builder: whenever the stats block is generated, emit inbounds,
  users and outbounds together; the gates now only decide whether
  the block exists
- master: enforce the inbound category gate at recording time in
  the agent traffic report (the whole-network accounting switch
  semantics: off period is never counted); onlines stay ungated
- golden gate test updated to the corrected contract
2026-10-23 01:57:52 +00:00
Muse 4a532e8c5a B5 switchover: sing-box is the only runtime payload
- master getConfig serves singbox_config only; xray payload retired
  (build failure is a hard 500, agent keeps its current state)
- agent: singbox_config arrival is the switch signal — flush xray
  tail traffic, stop xray, activate sing-box; activation failure
  restarts xray from the last payload and retries next poll; a
  legacy master (no sing-box keys) keeps the xray path untouched
- sing-box log rotation: 8 MiB copy-truncate with one .1 kept,
  checked on the traffic cycle
- install-agent.sh: xray/geo downloads and checks removed, agent
  binary now from the V2.0.0 release, self-check is sing-box
  binary + check on the live config
- display version default 2.0.0 (master V2.0.0 / agent A2.0.0)
2026-10-23 01:24:43 +00:00
Muse 3e2829e49d test(probe): give the contract-test theme a manifest (B5 store lists manifest-less dirs as uninstalled; fixture predates the store)
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-23 01:00:15 +00:00
Muse 19bf6fbc22 merge fix/vitest-reds: clear standing i18n/sub-port vitest reds (item 10)
# Conflicts:
#	internal/web/translation/ar-EG.json
#	internal/web/translation/en-US.json
#	internal/web/translation/es-ES.json
#	internal/web/translation/fa-IR.json
#	internal/web/translation/id-ID.json
#	internal/web/translation/ja-JP.json
#	internal/web/translation/pt-BR.json
#	internal/web/translation/ru-RU.json
#	internal/web/translation/tr-TR.json
#	internal/web/translation/uk-UA.json
#	internal/web/translation/vi-VN.json
#	internal/web/translation/zh-CN.json
#	internal/web/translation/zh-TW.json
2026-10-23 00:41:16 +00:00
Muse 460b314786 merge fix/leftover-tails: per-client link host, placeholder sanitizing, baseURL guard 2026-10-23 00:39:48 +00:00
Muse 3a02211555 merge fix/settings-trim: dead settings, upstream remnants, JSON/Clash subscriptions removed
# Conflicts:
#	frontend/src/models/setting.ts
#	frontend/src/pages/settings/GeneralTab.tsx
#	frontend/src/pages/settings/SettingsPage.tsx
#	frontend/src/pages/settings/SubscriptionBalancersTab.tsx
#	frontend/src/pages/xray/outbounds/OutboundsTab.css
#	frontend/src/schemas/setting.ts
2026-10-23 00:39:44 +00:00
Muse 268e6596bc merge feat/probe-b6: item 7 B1-B6 (probe collector, history, contract API, ping, themes, notify)
# Conflicts:
#	internal/agent/agent.go
2026-10-23 00:37:55 +00:00
Muse 7df7b530d3 merge feat/singbox-b4: item 6 B0-B4 (sing-box model, generation, agent runtime, frontend reshaping) 2026-10-23 00:37:12 +00:00
Muse 9e2807d3ec B6: coverage probeAt is unix ms — render it as such 2026-10-23 00:12:08 +00:00
Muse e43bd68986 B6 fixes from first E2E contact: PUT /probe/notify answers the fresh view; frontend notifyLogin is boolean and secret flags use the notify-prefixed wire names 2026-10-23 00:09:35 +00:00
Muse b889526b0d B6 frontend: notification settings + cf-probe retirement checklist on the public-page tab; probeNotify i18n x13 2026-10-22 23:56:27 +00:00
Muse 031b422365 B6 backend: probe notification engine — hub-faithful sweep (offline/recovery with flap discipline, traffic steps, expiry digest + auto-renewal, login), Telegram via the panel bot + webhook channel, notify settings/test/coverage API, login hook 2026-10-22 23:50:07 +00:00
Muse 277838d7ca ITEM6 B4: frontend reshaping — xray page retired, stats switches to settings, template read paths closed
- Delete the xray settings page (routes/menu/title), geodata UI/service,
  XraySettingController/Service and routing-sync write paths; the stored
  xrayTemplateConfig row loses its last readers (GetXrayConfigTemplate now
  returns the embedded factory template; B1 already deleted the row).
- Settings GeneralTab gains the four trafficStatsSwitches switches
  (settings.trafficStatsSwitches, B1) with the dual warning copy; entity
  AllSetting carries the key end to end (TestTrafficStatsSwitchesPlumbing).
- Tag-directory consumers (panelOutbound, mtproto egress, node/host
  outbound pickers) move from POST /xray/ to GET /server/outboundDirectory.
- Shared Mux/Sockopt forms and balancer helpers relocated to lib/xray;
  converter preserves sniffing ips/domains exclusions into the panel
  sidecar instead of dropping them (B2 gap closed by retention).
- Freedom final-rules DB fix seeders retired; getDefaultJsonConfig
  endpoint removed (no in-repo consumer); locales pruned to referenced
  keys (pages.xray 331 -> 68) plus the five new settings keys.
2026-10-22 23:40:54 +00:00
Muse f646212df2 B5: track the vendored fallback theme's dist/ (gitignore exception — it is embedded source, not build output) 2026-10-22 23:20:05 +00:00
Muse 2ee20b9691 B5 frontend: public-page settings tab — theme store UI, chunked upload install, config editor; 28 i18n keys x13 locales 2026-10-22 23:19:35 +00:00
Muse 000731c4e0 B5 tests: theme store matrix — refusals, replace, chunks, icons, repo parsing, dot-prefixed packages 2026-10-22 23:19:34 +00:00
Muse 2558efd9fb B5: theme admin API, hosting chain hookup, session cookie root path
Admin endpoints under /panel/api/probe/* (list, preview, chunk
upload, repo install, update, select, delete, public settings).
saveThemeConfig gate aligned to hub: selectable, not disk-installed.
Session cookie Path=/ so the root public surface (theme config save,
/api/me authed) can see the operator session under a non-root panel
base path — with basePath-scoped cookies it was unreachable (401).
2026-10-22 23:19:34 +00:00
Muse 7ad65652ec B5: theme store — hub-faithful install pipeline, GitHub install, embedded fallback theme
Install/remove/list/select with hub limits and refusal texts, chunked
upload receiver, site icons, public-surface settings; vendored
upstream default theme as the embedded fallback (MIT, stqfdyr).
The '.' root dir entry of ./-prefixed packages (guboysky LuminaPlus)
is the package root, not a path escape.
2026-10-22 23:19:26 +00:00
Muse 1762e54d5f ITEM6 B3: agent sing-box runtime (parallel path)
Agent consumes singbox_config alongside xray: candidate->check->
flush->swap activation with .previous rollback, wire-level v2ray_api
stats client with NexusGate epoch discipline (mid-query flip voids
the round, new epoch counts in full, agent-first snapshot baselines),
access-log online tracker (authenticated-connection lines, ANSI-safe,
merged with snapshot-active users), per-core traffic baselines with
the sing-box one carrying its epoch. install-agent.sh installs the
self-built sing-box v1.13.21 next to xray (xray/geo removal deferred
to the B5 switchover). Env-gated real-core E2E covers vless-reality,
ss2022, mixed, trojan and the forwarding leg end to end; hysteria2 is
probe-gated (sandbox blocks UDP replies) and stays a B5 pilot item.
2026-10-22 22:48:12 +00:00
Muse 1763f94a5f B4 frontend: probe task management modal on the nodes page
- ProbeTasksModal: self-loading/self-saving surface (B3 probe-meta
  pattern), tasks grouped by region label (ungrouped last), editor
  with name/region/target/interval/auto-join + agent-node multi
  select snapshotting baseNodeIds for the base-diff save; delete
  with confirm. Toolbar entry on NodeList (RadarChart icon), wired
  in NodesPage; NodeList call sites in two component tests updated
  for the new required prop.
- i18n pages.nodes.probeTasks.* (25 keys) in all 13 locales: zh-CN
  translated, en-US English, others English placeholder per repo
  convention; insertion verified pure-additive (351 insertions,
  0 deletions) and the i18n dead-key failures are byte-identical
  to the B3 baseline.
- tsc clean; oxlint 0/0 (baseline parity); oxfmt clean on touched
  files (3 pre-existing drift files untouched).
2026-10-22 22:20:23 +00:00
Muse 0d1607c358 B4 tests: probe store, agent prober, controller + wire
Baseline note: TestMetricHistoryMinuteFold fails identically on
the pristine B3 tip in the same wall-clock window (minute-parity
sensitive seed), passes in others — pre-existing, untouched path.
2026-10-22 22:09:11 +00:00
Muse e03ceaa41f B4: probe task store, panel API, heartbeat ingestion, agent prober
- probe package: probe_ping_task/probe_ping_node tables; task CRUD
  with hub save semantics (id high-water, base-diff assignment,
  64-per-agent crowding refusal, auto_join cap); filing with
  assignment-gated insert; PingHistory weighted-median chart read
  over minute+hour tiers; auto-join on first Record (ensureRows).
- controller: /panel/api/agent/probe-tasks* management endpoints
  (node id space, hub validation chain verbatim); series=ping now
  serves real rows from probe.PingHistory; heartbeat ingests
  probeResults (missing latency skipped, batch capped); config
  response carries probe_tasks (always present, empty = clear).
- agent: per-task probe loops (immediate first probe, ticker,
  900ms resolve/dial budgets, <=3 addresses, resolve overrun = no
  sample), result buffer drained on heartbeat and requeued on
  failure; task set applied before the config-hash early return.
2026-10-22 21:57:23 +00:00
MuseandMuse Spark 741cd905ff ITEM6 B2: sing-box generation side (parallel path)
- SingboxService builds the full sing-box config from the new model:
  stored fragments re-projected against the identity layer (converter
  projections factored into internal/singbox/project.go, shared by
  converter and generator), agent singbox_outbounds/routing_rules
  override, forwarding compiled to sing-box outbounds+route rules,
  default private-CIDR reject rule (geoip:private replacement),
  tun dns landing in the config dns block (closes the B1 'B2' pending).
- trafficStatsSwitches wiring: experimental.v2ray_api.stats lists are
  generated per category only when both direction switches are on;
  all-off yields no experimental block (no backfill, per the switches'
  documented semantics).
- Agent /config endpoint additionally serves singbox_config +
  singbox_config_hash; xray payload untouched, sing-box build failures
  log-and-omit.
- SubService.GetLinkFromModel regenerates share links from identity +
  singbox_config/singbox_preserved only (legacy generators reused over
  rebuilt settings/stream views). Golden fixtures 26/26 byte-equal;
  production backup DB: 107/107 links equal (55 byte-equal, 52 equal
  modulo the legacy generator's own random Reality sni/sid pick),
  generated config passes sing-box check.
- Converter preservation amendments (panel-side, for blocked/discarded
  material link generation still needs): blockedTls for xhttp/kcp,
  verbatim streamNetwork/streamSecurity, vlessEncryption presence,
  ssPassword for removed ciphers, wireguardDns, socksAuth/socksAccounts
  provenance for exact mixed/socks user refresh.

Co-Authored-By: Muse Spark <noreply@muse.dev>
2026-10-22 21:42:40 +00:00
Muse 540c05b0a5 feat(probe): public contract API + theme hosting + meta editing (item 7 B3) 2026-10-22 21:39:06 +00:00
Muse d5dab0229c merge fix/v102-agent-surfaces: agent placeholder host in inbound export links + agent online list wiped by node traffic sync (V1.0.2)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-22 20:16:11 +00:00
Muse 0e9c2031fb fix(v1.0.2): agent placeholder in inbound export links + sync job wiping agent onlines
Fix 1: InboundsPage hostOverrideFor read NodeView.address raw; agent
nodes store the literal placeholder "agent" there, so exported inbound
links came out as vless://...@agent:<port>. Route the pick through the
new shareHostForNode (lib/xray/inbound-link): resolved ipv4/ipv6 first,
raw address only as a non-placeholder fallback; the placeholder can
never reach a link and the fallback chain continues when an agent has
no telemetry yet. Traditional nodes (address only) are unchanged.

Fix 2: agent nodes showed no online users on the nodes page. The
attribution keys were NOT misaligned (write effectiveNodeKey ==
read effectiveNodeGuid == "node:{id}" for guid-less agent nodes,
pinned by TestAgentNodeOnlineEmailsInNodeList). The node traffic sync
job (every 5s) pull-syncs every enabled+online node as if it were a
panel; agent nodes have no panel API, so FetchTrafficSnapshot always
failed and its failure branch ClearNodeOnlineClients wiped the online
tree the agent had just pushed via SetAgentOnlineClients. syncOne now
skips agent-managed nodes (push-only), mirroring the heartbeat job.
Pinned by TestSyncOne_AgentNodeKeepsReportedOnlines (fails pre-fix
with byGuid emptied after one tick, passes post-fix).
2026-10-22 20:11:08 +00:00
Rogue 3e052c42b8 feat(probe): history store + whole-machine traffic ledger in probe.db (item 7 B2)
New internal/web/service/probe package keeps probe history in its own
probe.db beside the panel DB (single connection, WAL), so history
writes never contend with the panel write lock.

- Minute rows per hub semantics: a held-reading rhythm books traffic
  against each reading own arrival; minute buckets merge (means,
  rounded int means, peaks) and the stored net rate derives from the
  kernel counters between row marks, falling back to agent rates at
  epoch breaks.
- probe_traffic ledger: accumulate is a line port of hub traffic.rs
  (baseline alignment, same-boot shrink books 0, epoch change books 0,
  unseen-boot exception books the whole counters-since-boot measured
  against the master last-seen stamp, per-direction period resets,
  saturating adds); reads gate stale day/month stamps to zero.
- probe_meta rows are ensured for every reporting agent (B3 edits
  them in place); probe_ping_* tables are created now, written by B4.
- Hourly roll_up behind a watermark (hour-aligned, late grace,
  pre-retention hours skipped unfoldered) and watermark-guarded
  chunked prune (minute tier 7 days or the retention window when
  shorter; hourly tier to retention_days, default 7, cap 365).
- Wiring: heartbeat files probe samples after the snapshot update
  (last-seen captured before touch); housekeeping hangs off the
  existing robfig/cron in web.startTask (@hourly + one pass a minute
  after startup, mirroring the hub boot pass); Server.stop books held
  readings. Every failure path logs and degrades - a broken probe.db
  never fails a heartbeat or the panel.
2026-10-22 19:43:59 +00:00
Muse 39ad8b8a2e ITEM6 B1: sing-box data model + one-shot migration
New stored model (legacy columns untouched, read paths unchanged
until B2):
- inbounds.singbox_config (converted sing-box inbound/endpoint
  fragment JSON; empty = blocked or external-runtime) and
  inbounds.singbox_preserved (unmapped items verbatim + panel-side
  material + notes)
- agent_nodes.singbox_outbounds / singbox_routing_rules

Converter (internal/singbox, pure functions, ITEM6-CONVERSION-SPEC):
all panel protocols mapped; unmapped constructs are preserved and
registered, never dropped. B0 golden fixtures: 26/26 semantic match
(fragment + unmapped concept/pending sets + disposition).

One-shot migrator (internal/database, InitDB hook after initModels):
marker-gated and idempotent; SQLite file backup before any write
(failure refuses migration/startup); stats switches migrate out of
the template BEFORE the xrayTemplateConfig row is discarded
(SCOPE 4.3.1 order); identity layer is the only client truth with
spec 7-1 mirror reconciliation (adopt/fill/conflict all reported);
fallbacks merged from table + embedded settings, deduped; agent
overrides converted with per-entry issues; everything in one
transaction, marker written last; JSON report written next to the
DB. Malformed rows/templates are hard failures (rollback, old DB
untouched).

settings.trafficStatsSwitches added with factory defaults
(inbound on, outbound off) in defaultValueMap.

Validation: synthetic agent-era DB (mirror drift, fallbacks, xhttp,
agent geo rule, non-default stats) converts as specified; old
production backup (25 inbounds) migrates with credentials, Reality
pbk derivation, traffic counters and reset cycles byte-identical;
idempotent re-run is a no-op; touched packages show zero new test
failures vs the 9-red baseline.
2026-10-22 19:32:15 +00:00
Muse 1bd63e6625 settings trim: remove dead settings, upstream remnants, JSON/Clash subscriptions
Per SETTINGS-AUDIT (all three tiers approved 2026-10-23):

Dead settings:
- panelOutbound, ipLimitAllowlist (+ orphan parser job), outboundDownThreshold
- tg fake events outbound.down/outbound.up/xray.crash (no publisher in lite)
- phantom routing sub-tabs (Happ/Clash/Incy) and subJsonRules direct-rules tab
  (no backend keys); subHideSettings moved to the subscription info tab first

Upstream remnants:
- ldap* / smtp* model+schema keys, EmailNotifications orphan component
- twoFactorEnable/twoFactorToken + login-page probe (no backend handler)
- externalTrafficInform*

Newly approved removals:
- JSON subscription family (producer, routes, UA auto-detect, mux/finalmask/
  observatory) and Clash subscription family (producer, routes, UA detect)
- SubBalancer (table, service, controller, settings tab)
- subThemeDir (subscription page falls back to the built-in template)
- datepicker jalalian option (gregorian only; Persian picker removed)

JSON/Clash endpoints now 404; link-format output pinned by regression tests.
Guarded keys untouched: webListen/webPort/webBasePath/certs, tg* chain,
expireDiff/trafficDiff/tgBotProxy, subHideSettings, pageSize/tgLang.
2026-10-22 19:21:07 +00:00
Muse a47e64f70a test(i18n,sub): clear the three standing vitest reds (item 10)
- i18n dead keys: drop 13 keys with no reference left (pages.xray.routeTester*
  from the P9 feature removal, tgbot.online superseded by tgbot.messages.online,
  tgbot.commands.restartSuccess/restartFailed from the rewritten restart handler)
- i18n key sets: add the P9 forwarding block (20 keys) to the 11 locales that
  missed it, as English placeholders per repo convention; all 13 locales now
  carry identical key sets
- subscription port test: the case predated P7 — clearing the port field is the
  explicit subPort 0 (no port in generated links) opt-in via onNumber onClear,
  so assert updateSetting is called with { subPort: 0 } instead of never called

No component code, UI behavior, or styles touched.
2026-10-22 18:23:22 +00:00
Muse 0a973bc95c feat(probe): port monitor-probe collector into agent, persist latest snapshot (item 7 B1) 2026-10-22 18:22:56 +00:00
Muse 9843a7ce4e ITEM6 B0: add census.sql for production stock census (HW-SG run) 2026-10-22 18:17:18 +00:00
Muse 750a270955 ITEM6 B0: golden fixtures + fixture validation skeleton for sing-box migration
26 cases (protocol x representative transport): current-shape input,
expected sing-box fragment, and share-link baseline generated by running
current main@8e89960 GetLink. Blocked/partial cases (xhttp, kcp,
fallbacks, finalmask, vlessenc, removed SS ciphers, tunnel) record their
unmapped concepts under _b0 for the Q1 decision instead of fabricating
output. Link-route baselines only: JSON/Clash subscription families are
being removed wholesale per the 2026-10-23 decision, Q2 closed.
2026-10-22 18:14:58 +00:00
Muse 3413ccca9f fix three V1.0.1 leftover tails
1. per-client links (LinkProvider.LinksForClient) now apply the
   inbound's managed Host records with the same precedence as
   subscriptions and export-all (host endpoints after fallback
   projection); zero-host inbounds keep the legacy output.
2. agent node writes no longer store the form placeholder
   address='agent', port=2053: CreateFromRequest/UpdateFromRequest
   sanitize it to the node's resolved agent address (update) or
   empty (create / unreported), port 0; normalize gains a lenient
   endpoint mode for agent writes only.
3. runtime Remote.baseURL refuses the legacy 'agent' placeholder
   with a clear no-panel-endpoint error instead of splicing it into
   a dialable https://agent:2053 URL.
2026-10-22 17:55:19 +00:00
Muse 8e89960474 merge wiring: route agent address lookups through ResolveAgentAddresses (V1.0.1)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-23 00:34:33 +08:00
Muse afb5456b8f merge fix/agent-public-addr: master-observed public IP resolution (V1.0.1) 2026-10-23 00:22:58 +08:00
Muse 36acc4c2b1 merge fix/agent-link-address: agent inbounds export telemetry address (V1.0.1)
# Conflicts:
#	internal/web/service/inbound.go
2026-10-23 00:22:36 +08:00
Muse 7f098c6c4e merge fix/online-lists: agent inbound attribution + node page email lists (V1.0.1) 2026-10-23 00:21:04 +08:00
Muse 942b220f80 merge fix/token-backfill-null: legacy NULL token_plain backfill (V1.0.1) 2026-10-23 00:21:04 +08:00
Muse 7d9a38490d fix(sub): agent-hosted inbounds export the agent's telemetry address, not the 'agent' placeholder
Agent nodes store the create form's placeholder in nodes.address
('agent', port 2053; NodeFormModal.buildPayload). The export fallback
chain treated it as a real node address, so every host-less inbound on
an agent node produced links like vless://...@agent:31324.

SubService now loads agent_nodes bindings alongside nodes (latest
last_seen per node, same rule as the node list) and resolves an
agent-managed node's export address through the single convergence
point agentNodeAddress(nodeID): telemetry IPv4, then IPv6, then ""
so the chain continues to listen/public/request host and can never
emit the placeholder. Host-bound inbounds and traditional nodes are
untouched. GetInboundOptions applies the same substitution via
agentAdvertisedAddresses so the frontend share/QR/WireGuard feed
never sees the placeholder either.
2026-10-22 15:35:21 +00:00
Muse 3df652a67d fix(inbounds): slim list stamps agent-hosted inbounds with the agent node's key
Agent inbounds defined centrally store an empty originNodeGuid, and
inbounds re-homed from a panel node keep the previous host's GUID, so
the inbounds page looked the agent's online set up under a key it is
never filed under. GetInboundsSlim now annotates agent-hosted
inbounds at read time with the node's effective attribution key
(the key SetAgentOnlineClients files onlines under).
2026-10-22 15:33:51 +00:00
Muse c91fb454a8 fix(nodes): per-category client email lists behind the node count chips
NodeView carried only the category counts, so the nodes page chips
could hover to nothing but the category title. GetAll/recountByGuid
now emit online/active/disabled/depleted email lists from the same
bucketing pass as the counts (statuses gain the client email;
the online list is the counted set), and the chips pop the list
over with the inbounds page's popover pattern.
2026-10-22 15:33:46 +00:00
Muse c490bdcd76 fix(nodes): resolve agent public address from master-observed source IP
NAT'd agents (cloud 1:1 EIP) only ever report their private
interface address in heartbeat telemetry, so the node list showed
an unusable RFC1918 address. The master now records the source
address of every authenticated agent request (CF-Connecting-IP,
else first X-Forwarded-For hop, else RemoteAddr; change-only
writes) on the agent row as seen_ipv4/seen_ipv6, and the node
list resolves the displayed pair via service.ResolveAgentAddresses:
public telemetry wins, else a public observed source, else the
reported address as-is. CGNAT 100.64/10 observed addresses are
never promoted. Telemetry values are kept verbatim; resolution
is read-time only, and agents need no changes.
2026-10-22 15:25:08 +00:00
Muse 5c432205ad test(agent):回填回归测试——原生 SQL 造 NULL 老行走真实心跳+install 接口 2026-10-22 14:45:57 +00:00
Muse 8901267867 fix(agent):第 19 条 token 回填守卫兼容 SQL NULL 老行(token_plain IS NULL OR = '') 2026-10-22 14:45:55 +00:00
Muse e310abcba0 merge next-scripts: items 15/16/17/23 (install-agent mirror/reuse/self-check, openrc respawn)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
2026-10-22 21:51:51 +08:00
Muse ced5e69de0 merge next-core: items 14/18/19/20/21/22 (L-UI V1.0.0/A1.0.0) 2026-10-22 21:51:50 +08:00
Muse a82d1e56fa style: 本批新代码 gofmt 对齐(config_test/agent_node) 2026-10-22 13:46:02 +00:00
Muse 7e7ab2ecbd feat(update): 发行 tag 查询支持 XUI_RELEASE_LATEST_URL 覆盖(镜像/沙箱冒充发行源) 2026-10-22 13:33:08 +00:00
Muse d46035708e feat(ui): 第22条 改名 L-UI + 第14/21条 + 第18/19/20条前端
- 第22条 L-UI:登录页品牌名、侧栏 brand-text(收起态 L)、抽屉品牌、
  usePageTitle 默认标题(HTML 标题)、13 个语言文件里用户可见串中的
  3X-UI 字样(更新说明×2、TG 版本行)一并改为 L-UI;仓库/二进制/
  服务名/路径/内部包名不动
- 第18条:formatPanelVersion 对 V/A 系显示版本原样返回(新增单测);
  PanelUpdateModal 与首页动作条改用 display* 字段判更新与显示
- 第14条:首页运行时间卡片删除 Xray 半边与分隔线,只留 OS
- 第21条:节点表列宽 操作190→150/已启用80→64/客户端180→150/
  延迟100→84/心跳120→96、地址列 330;agent 行 IPv4·IPv6 单行
  (浅点分隔、沿用可见性 class),传统行不变
- 第20条:agent 行云朵按钮与移动端菜单改用「更新 Agent」文案;
  NodesPage 对 agent 行用无渠道选择的简单确认(传统行不变);
  schemas 增 agentUpdateState/Error/Target
- 第19条:节点编辑页(agent)拉 /panel/api/agent/install/:id 展示
  完整安装命令(master 可编辑、含 token 时完整命令+复制按钮);
  无 token 时展示无 token 命令+agent.json 路径提示,不报错不空白
- i18n 新增 4 键(updateAgent/updateAgentConfirmContent/
  agentInstallCommand/agentTokenNotStored)补齐全部 13 个语言文件
  (zh-CN 中文、其余英文),tsc 干净、panel-version 测试全过、
  i18n 失败仍为既有 forwarding 键集问题(第10条)零新增
2026-10-22 13:30:57 +00:00
Muse 2596880327 feat(update): 第20条 主控面板一键自更新(Go 原生换名 + systemd 重启)
- PanelUpdateInfo 增 displayCurrentVersion/displayLatestVersion/
  displayUpdateAvailable:V 系按个位进位段比较,大于当前才算新版;
  原 currentVersion/latestVersion/updateAvailable 语义不动(节点页
  与传统节点继续用)
- 稳定渠道自更新改 Go 原生路径:查最新 tag→按架构下载发行资产→
  sha256 旁车校验→原子换名(旧二进制留 .bak)→写既有状态文件
  (与 update.sh 同形状,前端轮询协议不变)→脱离进程 systemctl
  restart 本单元(单元名 XUI_SERVICE_NAME 覆盖 / /proc/self/cgroup
  解析 / 回退 x-ui);dev 渠道保留 update.sh 原路径
- 仅 systemd 环境启用(/run/systemd/system 存在或
  XUI_SELFUPDATE_SYSTEMD=1 沙箱钩子),否则报错提示手动更新
- 单测:显示版本比较、cgroup 单元名解析、状态文件往返、systemd
  门拦截
2026-10-22 13:16:35 +00:00
Muse 2365eb138b feat(update): 第20条 agent 一键在线更新(意向→轮询→校验换名→自重启)
- 新增 internal/selfupdate:发行坐标(基址常量+env 覆盖)、Gitea
  latest tag 查询、sha256 旁车校验下载、原子换名(旧二进制留 .bak、
  失败可回滚),含单测
- 主控:UpdatePanels 对 agent 节点改为记录更新意向(最新 tag 的
  V 系→A 系目标;已达标报错不记意向);意向经现有 GET config 轮询
  捎带下发;心跳收 updateStatus 回报(failed/current 清意向留状态、
  过期 requested_at 忽略),遥测版本达标自动确认 success
- agent:识别意向→比自身 A 版本(已达标报 current 不下载)→按架构
  下载资产+sha256 校验→换名留 .bak→刷一次心跳→stopXray→
  syscall.Exec 自重启;exec 失败回滚 .bak 并报 failed;失败 10 分钟
  内不重下同一意向;旧版全程保持运行
- NodeView 增 agentUpdateState/Error/Target 供节点页可观测
- 单测:selfupdate 换名/校验、agent 换名重启/坏校验保旧版/已达标
  跳过/exec 失败回滚、主控意向记录/已达标跳过、config 捎带意向、
  心跳 failed 清意向、心跳新版本确认 success
2026-10-22 13:14:24 +00:00
Muse 27a5097756 feat(install-agent): 第23条 OpenRC 韧性对齐——supervise-daemon 守护替代 command_background
OpenRC 支原用 command_background 后台化,进程崩溃不自动拉起,与 systemd 支
Restart=on-failure 语义不对齐。生成的 /etc/init.d/x-ui-agent 改用
supervisor=supervise-daemon + respawn_delay=5(对齐 RestartSec=5)+
respawn_max=0/respawn_period=0(不限次,对齐持续重试);pidfile 与
output/error_log 约定原样保留,command/command_args 不动,幂等重跑时
init 脚本整文件重写、旧式 command_background 布局自动迁移。

第 15/16/17 条对 OpenRC 路径复核:下载基址、无参沿用、失败报错、收尾
self_check 与 rc-service status 存活断言均在公共段/现有分支内已达标,
未作改动(由新增 OpenRC fake-root 套件实证)。

验证:既有 systemd fake-root 套件 58/58 零回归;新增 OpenRC 套件
(run-tests-openrc.sh,O1–O5)51/51。改动点仅此一处(+7/-1)。
2026-10-22 13:12:57 +00:00
Muse f18aca9410 test(agent): 遥测 AgentVersion 断言对齐第18条 A 系口径 2026-10-22 13:12:14 +00:00
Muse 29b724dae1 feat(nodes): 第19条 agent token 可恢复保存 + 老节点回填 + 安装命令接口
- AgentNode 新增 TokenPlain(json:"-" 永不序列化):建节点/签发 token
  时一并存明文,用户已明确接受"可恢复保存换便利"的口径
- 回填:findAgent 在 token 通过哈希校验后,若该行尚无明文则把本次
  请求携带的 token 回填存下(带 token_plain='' 守卫的 UPDATE,
  已有明文绝不被请求覆盖;只有面板侧签发流程写新值);鉴权语义不变
- 新增管理端点 GET /panel/api/agent/install/:nodeId 返回
  {nodeId,name,token,hasToken},供编辑页重显完整安装命令;老节点
  未回填时 hasToken=false,前端展示无 token 命令 + 本机路径提示
- 单测覆盖:签发存明文 / 回填后接口可读出完整 token / 校验失败
  绝不回填 / 已有明文不被覆盖
2026-10-22 13:04:33 +00:00
Muse 1edb8f71da feat(version): 第18条 显示版本与内部版本解耦(V/A 双系)
- config 新增 displayVersion 注入变量(默认 1.0.0):GetDisplayVersion/
  GetMasterDisplayVersion(V)/GetAgentDisplayVersion(A),以后升版只改注入值
- ParseDisplayVersion/CompareDisplayVersion:三段数值比较,个位进位规则
  (1.0.9<1.1.0) 天然成立;不可解析(dev 标签/3.7.0-agent.1)返回 ok=false
- 显示位切换:dist 注入 X_UI_CUR_VER、-v、TG 报告 → V 系;
  agent 遥测 agentVersion → A 系;节点行 A 系原样显示、老 agent 沿用
  "agent " 前缀兼容
- 内部流不动:GetBaseVersion/GetPanelVersion 及其比较/订阅/远端状态
  消费方保持原样,传统节点更新判定与徽标行为不变
2026-10-22 13:01:50 +00:00
Muse 8900ef68fc feat(install-agent): 镜像下载(15)+无参沿用agent.json(16)+失败报错与收尾自检(17)
- 下载基址统一 RELEASE_BASE 指向 Gitea 发行 V1.0.0:agent 二进制(原在旧
  tag v3.7.0-agent.1)、双架构 xray zip、geoip/geosite 全部走自建镜像,
  不再依赖 GitHub CDN
- 未传 --master/--token/--name 时逐字段沿用本机 /etc/x-ui/agent.json,
  显式参数优先;日志打明沿用的节点名与主控,绝不打印 token;文件不可
  解析且必填仍缺则明确报错退出
- 每步下载/解压显式判失败(拆掉旧 && 链的静默吞错),下载验非空,前置
  检查 curl/unzip;收尾 self_check 真跑 xray version、验 geo 非空与
  agent 可执行,任一不过报错退出且不写配置不起服务
- fake-root 模拟 9 场景 58 断言全 PASS(报告 NEXT-SCRIPTS-REPORT.md)
2026-10-22 12:54:32 +00:00
Muse e5f39ed20b merge: p13-agent-telemetry (agent 遥测上报+节点页显示+地址纯文本)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-22 19:36:50 +08:00
Muse 487b074801 feat(nodes-ui): agent 行地址纯文本显示 IP+更新徽标防误亮(第13条)
地址列: agent 行渲染 ipv4/ipv6 纯文本(两行), 不再是面板 URL 链接;
传统行保持链接。面板版本列: agent 行不参与"有可用更新"判定
(版本比较对 "agent x.y" 字符串走不等回退会恒亮)。
2026-10-22 11:33:58 +00:00
Muse 3536d4174e feat(telemetry): agent 心跳遥测上报+节点列表覆写(第13条)
agent 每 60s 心跳捎带遥测: agentVersion/xrayVersion(按 mtime 缓存重读)/
uptime/最近一次主控请求 RTT/cpu%/mem%/公网 v4+v6(公网优先, ULA/私网兜底);
主控心跳处理按指针语义只存上报字段, 旧 agent 无遥测行为不变;
agent_nodes 加法迁移存遥测, 节点列表对 agent 行覆写真值,
panelVersion 显示 "agent <版本>", NodeView 新增 ipv4/ipv6。
2026-10-22 11:33:56 +00:00
Muse 84d7b85be7 merge: p12-agent-rename (agent 改名 xui-agent+脚本迁移)
Docs Deploy (GitHub Pages) / build (push) Canceled after 0s
Docs Deploy (GitHub Pages) / deploy (push) Canceled after 0s
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Docs CI / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-22 18:40:28 +08:00
Muse 81d89840e4 fix(agent): 流量上报间隔 60s 改为 10s(第9条)
传统节点由主控秒级轮询,agent 旧默认 60s 才推送一次,所有 agent
入站的流量/在线刷新慢一个数量级(用户真机实证,与具体节点无关)。
defaultTrafficInterval 改为 10s;心跳间隔 60s 不动;注册退避上限
(registrationBackoff 的 60s)与流量无关,不动。原注释称 traffic
piggyback 心跳 tick 与实现不符(实为独立 ticker),一并改正。
2026-10-22 10:25:22 +00:00
Muse ff1204ce2d fix(onlines): agent 在线名单按节点归因键存储(第12条修复A)
reportTraffic 旧实现把所有 agent 的在线名单写死存入 "agent" 键,
而入站页按 originNodeGuid / node:{id} 归因键查找,永远查不到:
agent 入站行永不亮在线,且所有 agent 节点被并进同一键。
改为 InboundService.SetAgentOnlineClients:按节点的 effectiveNodeKey
(有唯一 GUID 用 GUID、否则 node:{id})存入;空名单仍走
ClearNodeOnlineClients 清整棵子树。同步修正 online_store_test 中
断言旧键的用例注释与键名;新增两例服务层测试(双 agent 节点键互不
合并、空上报清空)。
2026-10-22 10:25:15 +00:00
Muse 58cdfe73b0 feat(agent): P12 改名 xui-agent——独立二进制文件+改名覆盖+存量迁移清理
install-agent.sh: AGENT_BIN 改 /usr/local/x-ui/xui-agent,下载走 .new 改名
覆盖(agent 自升级不撞 Text file busy),全程不写主控 x-ui 文件;新增
stop_legacy_agent 只精确匹配旧形态 'x-ui agent' 进程(主控裸 x-ui 无参数、
天然不误杀);生成的 systemd/OpenRC 服务改指 xui-agent。仓库 systemd/
x-ui-agent.service 与 openrc/x-ui-agent( procd ) 同步改指;README/docs 的
agent 手动部署段落位改 xui-agent。Go 代码无硬引用、零改动。
fake-root 模拟(systemd/OpenRC/存量重跑)23/23 PASS,见 P12-REPORT.md。
2026-10-22 09:46:46 +00:00
Muse ac39370879 fix(onlines): 恢复被 P9 掏空的在线状态存储(第11条)
根因: 1035d00 删本地核心时, inbound_node.go 的在线存储层被一并掏空
(GetOnlineClients 写死空/SetNodeOnlineTree 等空函数/SetRemoteTraffic
末尾喂树整块删除), 而节点轮询与 agent 上报两条到达路径完好, 数据
送达即被扔, 客户端/入站在线永远全零。

修复: 把原 xray.Process 上的在线存储(算法/锁/grace 20s 语义逐字
移植)落到 service 包单例 onlineStore(sharedOnlineStore, 对应原
currentXrayProcess 的单一持有语义); 恢复六个 wrapper + 新增
SetNodeActiveInboundTree; setRemoteTrafficLocked 补回 guidShared
与喂树块(原 f727d04 逻辑, process. 换 s.)。

偏离: 本地集在精简主控无本地核心喂养, 仅 mtproto job 折入(该 job
已不被调度, 路径保留无害); GetOnlineClients 对 nil 归一为 []。

测试: online_store_test 9 例(-race 全过: 并集/按GUID/替换/清空/
grace 边界/跨实例共享/并发); SetRemoteTraffic 集成 2 例(传统节点
GUID 树+active 树落库、旧节点 flat 回退); 全量 go test 串行复跑失败集合与基线 9 红逐字一致(零新增);
service 包单跑唯一红为基线既有的 TestGetXrayConfig 红, 其余全过。
2026-10-22 09:19:20 +00:00
Muse f569680182 merge: p93-agent-register (注册退避重试+脚本探测服务化+面板地址预填)
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
2026-10-22 04:55:19 +00:00
Muse 9adffd049c merge: p92-socks-clients (SK5 分配用户+记账+订阅 socks 链接) 2026-10-22 04:55:07 +00:00
Muse 8ca1a4647a feat(sub): emit socks:// links for clients on socks/mixed inbounds
GetLink had no socks-family case, so an attached client's
subscription contained no link for the inbound at all, and
getInboundsBySubId's protocol list omitted socks/mixed entirely, so
such a subscription 404'd when the SK5 inbound was the client's
only one. genSocksLink emits socks://user:pass@host:port with the
same credential pair the core config carries — user is the client
email, pass is the client password, both percent-encoded. The
inbound's own fixed account is an operator credential and is never
emitted.
2026-10-21 22:25:18 +00:00
Muse 0ed6d8a1cf fix(nodes): agent 主控地址预填 origin+基础路径,地址为空时不生成安装命令并提示 2026-10-21 22:05:09 +00:00
Muse dcfaf6ace6 feat(install-agent): 启动前探测主控注册接口(404/连不上即中止),改为 systemd/OpenRC 服务化安装带自启 2026-10-21 22:05:09 +00:00
Muse 7d03749246 feat(agent): 注册失败退避重试不停机,404 时日志提示检查 master_url 基础路径 2026-10-21 22:05:09 +00:00
Muse 5efaaef2c2 feat(xray): emit attached clients as accounts for socks/mixed inbounds
Socks-family inbounds authenticate against settings.accounts, so the
clients attached to them never reached the core: the generated config
carried the settings' "clients" mirror (ignored by xray for these
protocols, passwords and all) and only the inbound's own fixed
account. Emit one account per enabled attached client instead —
user = client email, pass = client password — appended after the
inbound's stored accounts, which keep their order and win name
collisions (managed-forwarding resolution reads the fixed account
from the stored settings, untouched). Drop the clients mirror from
the generated settings, and force auth=password when clients exist,
since accounts are inert under noauth.

Accounting needs no new plumbing: xray-core 26.6.27 reports these
accounts under user>>><account user> counters (probe-verified with
two accounts on both mixed and socks), and the agent snapshot ->
report -> AddTraffic chain already keys client traffic by that exact
string, so making the account name the client email aligns booking
end to end. Clientless socks-family inbounds pass through verbatim.
2026-10-21 22:04:49 +00:00
Muse bea7f4b2b6 feat(clients): allow attaching clients to socks/mixed inbounds
The client form, bulk-add form and the inbound-side attach entry all
filtered attachable inbounds by a protocol whitelist that lacked
socks/mixed (inherited from upstream), so SK5 inbounds could never be
picked as a client's associated inbound even though the backend
accepts the association. Add 'socks' and 'mixed' to all three gates.
The client record's existing password field is the socks credential;
no new credential shape is introduced.
2026-10-21 22:01:30 +00:00
Muse 051a74be80 feat(inbounds): forwarding chip on list rows
Rows whose stored ForwardingSpec is enabled get a volcano chip after
the protocol tags: '转发 → <target remark>' for managed landings
(resolved against the full row set), '转发 → <address>:<port>' for
manual endpoints, '转发 → SK5' when the target row is gone. Text is
ellipsised at 180px with a tooltip so narrow rows never overflow.
Data rides the slim list's existing forwarding field — no API change.
2026-10-21 21:01:45 +00:00
Muse d867b15f4a fix(inbounds): forwarding echo lost in DBInbound — add the missing field
The edit modal seeds from the list row wrapped in DBInbound, whose
cloneProps only copies keys the instance already owns. DBInbound had
no forwarding field, so the stored ForwardingSpec JSON was silently
dropped on every row wrap and rawInboundToFormValues fell back to
direct — saved forwarding compiled and worked, but never echoed back
into the form. Backend/API carried the field correctly all along.

Regression test covers managed/manual/direct through the exact
row -> DBInbound -> form-values chain.
2026-10-21 20:59:36 +00:00
Muse 4da8d58307 fix(install-agent): pkill 无匹配时返回 1 会被 set -e 掐死在启动前,加 || true 2026-10-22 04:35:52 +08:00
Muse 6a880aed09 P9(4b): PANEL-LITE-SPEC 同步本地核心整条路径删除与 MTProto/AmneziaWG 退役 2026-10-21 19:30:53 +00:00
Muse 1035d00fe4 精简版P9(4b): 删除本地核心整条路径(进程管理/buildXrayConfig本地分支/local-only注入/本地核心接口与任务)
- service/xray.go 1741->573行: 只剩 agent 配置构建(GetXrayConfigForAgent/buildAgentXrayConfig=模板+节点入站+egress+转发编译); 删进程生命周期/状态机/RestartXray/StopXray/SetToNeedRestart/GetXrayTraffic/GetOnlineUsers/balancer/TestRoute 与 injectPanelEgress/injectNodeEgresses/injectMtproto/injectAmneziawg/mergeSubscriptionOutbounds
- controller: 43处 SetToNeedRestart 与各 RestartXray 调用清除; 删 balancerStatus/balancerOverride/routeTest/getXrayResult 路由与handler(纯本地核心操作); 前端删 RouteTester 页签与组件
- server service: GetConfigJson 改模板直读; 状态Xray块恒 stopped/空版本; Stop/RestartXrayService 改 no-op(DB导入/恢复流程保留形状)
- setting service: PanelEgressProxyURL/NodeEgressProxyURL 恒直连(桥在本地核心内,已不存在); NodeService.withOutboundBridge 恒直连回退
- runtime: Local 改为全 no-op 桩(DB即真源); NewManager() 去 LocalDeps(APIPort/SetNeedRestart)
- job: 删 XrayTrafficJob/CheckXrayRunningJob/CheckClientIpJob 三文件(共享声明 EventBus/IPWithTimestamp/clientStatsSnapshotMaxClients 迁 shared.go); web.go 不再调度 MtprotoJob/AmneziaWGJob, 删 OnCrash 接线与 stop() 的 sidecar StopAll
- MTProto/AmneziaWG 下线: AddInbound/UpdateInbound 对两协议直接拒绝(存量行保留可删); TG bot 的 restart 命令与在线查询按无本地核心收口
- 测试: GetXrayConfig 系列移植到 agent 构建(finalmask/clients/wireguard/scale); 删退役行为测试(lifecycle/restart/mtproto本地应用/client-ip job/inject系列); 共享测试helper迁 mtproto_test_helpers_test.go 与 job/integration_helpers_test.go
- 既有红(非本轮引入,已在 f6d6520 复现): TestGetXrayConfig_EnabledClientsStillEmitted、TestRouteRegistryContract(P6删 endpoints.ts 遗留)
2026-10-21 18:43:55 +00:00
Muse f6d652019d P9(3): per-inbound forwarding module (amo-style form, dynamic egress compile)
Design as decided 2026-10-21 (replaces the raw-JSON egress editor idea):
the forwarding form lives on the inbound, and the entry agent's egress
entries are compiled from it on every config pull — never snapshotted.

- model: Inbound.Forwarding (JSON text) via AutoMigrate; panel-side
  metadata only, never reaches xray itself
- service/forwarding.go: ForwardingSpec (mode direct/forward; landing
  managed|manual), save-time validation (managed target must exist and
  be a SOCKS-family landing — the fork's SK5 inbound is 'mixed'; no
  self-forward; manual endpoint/protocol sanity), live resolution
  (managed: concrete listen IP wins, else hosting node's address;
  credentials from the target's first account), and the compiler that
  appends one socks/http outbound (tag fwd-<inboundId>) plus a prepended
  inboundTag rule per forwarding inbound
- buildXrayConfig agent path: compile runs after applyAgentEgress, so
  entries ride on the live template (or stored egress override) and
  template edits keep flowing; unresolvable entries skip with a warning
  instead of failing the whole config
- UpdateInbound's field-merge now carries Forwarding (its absence was
  caught by the smoke: adds worked, updates silently kept the old spec)
- GET /panel/api/inbounds/forwardTargets: managed-landing candidates
  (id/remark/tag/listen/port/node name) — credentials never exposed
- frontend: new Forwarding tab in the inbound form (mode, landing type,
  managed picker, manual endpoint with link import incl. base64 form),
  adapter round-trips the spec as a JSON string like settings; en/zh
  strings; generated API types refreshed

Acceptance: unit tests for parse/validate/resolve/compile incl. the
dynamic-recompile proof (template edit + spec edit both reflected), and
an end-to-end smoke (real binary, two agent nodes, all inbound writes
in browser form-urlencoded format): 22/22 PASS — see P9-REPORT.md.
2026-10-21 17:40:42 +00:00
Muse ceca96571d P9(5): restore upstream Telegram bot (settings, backup, notifications)
Per user decision 2026-10-21 (reverses the 2026-10-20 drop-Telegram
call): port the upstream 3x-ui v3.7.0-generation Telegram bot wholesale
instead of rewriting a minimal set, adapted to this fork.

- new internal/web/service/tgbot package (telego): bot lifecycle,
  commands, reports, callback router, send helpers; token validation via
  telego; custom API server URL passes the fork's SSRF sanitizer
  (loopback/private bases fall back to the default endpoint, logged)
- settings: full upstream key set (tgBotEnable/Token/Proxy/APIServer/
  ChatId, tgRunTime, tgBotBackup, tgCpu/tgMemory, tgLang,
  tgEnabledEvents) with getters/setters; settings page gains a Telegram
  tab + sidebar entry; token shown masked, clearTgBotToken honored
- wiring (web.go): stats-notify cron registered from tgRunTime when the
  bot is enabled; CheckHashStorage job; CPU/memory alarm jobs gated on
  tgEnabledEvents + thresholds; login notifications via event bus;
  POST /panel/api/setting/testTgBot and /panel/api/backuptotgbot
- lite adaptation: StatsNotifyJob no longer gates on a local Xray core
  (this panel never runs one) so the periodic report and the scheduled
  DB backup (sendDocument) can actually fire
- translations: upstream TG keys restored across all locales

End-to-end smoke (real binary + fake Telegram API over HTTPS at a
public-looking address, browser form wire format): bot starts on
settings change (getMe), testTgBot delivers, panel restart re-arms the
bot, tgRunTime='@every 1m' cron really fires sendDocument carrying the
panel SQLite DB (magic verified) plus the report sendMessage, login
notification delivered, dead-endpoint failure is logged not silent.
13/13 PASS — see P9-REPORT.md.
2026-10-21 17:16:32 +00:00
Muse 5031a70ccb P9(4): remove local-core live-test trio — outbound speed test + egress probe, restart/stop xray endpoints
Per user decision 2026-10-21 (reverses the earlier keep call in
PANEL-LITE-SPEC.md, now amended): the lite panel never runs a local
core, so measuring/probing from the panel host is meaningless.

Backend:
- delete service/outbound probe implementation (probe_http.go and its
  tests) and the TestOutbound/TestOutbounds batch prober; outbound
  traffic accounting (AddTraffic/GetOutboundsTraffic/Reset) unchanged
- drop POST /panel/api/xray/testOutbound + testOutbounds routes and the
  outboundTestUrl setting (get/update plumbing removed; stored rows in
  existing DBs are inert)
- drop POST /panel/api/server/restartXrayService + stopXrayService
  routes/handlers and the node-sync allowlist entry; the service-level
  Stop/RestartXrayService stay for internal import/restore flows
- node-sync allowlist contract test updated to the new inventory

Frontend:
- remove test buttons/mode switch/test-all from outbounds tab, card
  list and table columns; delete TestResultPopover and CountryPill;
  drop the egress/country/latency columns fed by probe results
- remove outboundTestUrl state and save plumbing from useXraySetting
  and the Basics tab field; drop OutboundTestResult schemas
- delete the 15 now-dead i18n keys from all 13 locales (incl. the
  restart/stop keys orphaned since P6/P7 — i18n-dead-keys test green)
- tests: drop the test-URL hook test, re-probe the loopback index
  mapping through Move-to-top, regenerate API types (gen)
2026-10-21 16:35:53 +00:00
Muse 6772c97f8e P8.1: fix browser inbound re-homing — nodeId probe must parse form-encoded bodies
updateInbound detected an explicit nodeId by probing the raw request
body as JSON only (requestHasJSONKey). The panel frontend, however,
posts application/x-www-form-urlencoded by default (http-init.ts
form-encodes every POST without a declared JSON Content-Type), so the
probe missed on every real browser save and UpdateInbound silently kept
the stored assignment — the edit dialog's 部署到 picker never moved
anything, while JSON API callers (and the P8 E2E, which posted JSON)
worked.

requestHasKey is now content-type aware: JSON bodies are probed as
before; urlencoded bodies are parsed with url.ParseQuery, where the
browser's null encoding (a bare "nodeId=") also counts as provided —
it binds as *int(0) and the existing 0->nil normalisation turns it
into the move-to-local target.

Regression tests post the exact browser wire format through the real
handler stack: form move between nodes, form post without nodeId
(assignment kept), form post with nodeId= (move to local, no binding
error), plus the JSON move at HTTP level. The two form-move tests
fail on the unfixed code and pass with the fix.
2026-10-21 15:37:45 +00:00
Muse 7284fa6cf0 P8(2): inbound node reassignment (move) with backend re-homing
An inbound's 部署到 node can now be changed after creation; the row,
clients, client_traffics and subscription output stay untouched (same
inbound id throughout).

Contract: the update payload's nodeId counts only when the key was
explicitly sent — the controller probes the raw JSON body and sets
Inbound.NodeIDProvided; the wire adapter now always emits nodeId (null =
local) so clearing the picker is an explicit move-to-local, while
callers that omit nodeId keep the stored assignment (legacy behaviour).

UpdateInbound resolves the target before the port-conflict check (so
conflicts are scoped to the target node), rejects moves to a missing
node, re-derives auto tags under the target node's prefix, validates
the tag against the target node's namespace, and marks BOTH nodes
dirty: the source node's next reconcile sweeps the old tag (no silent
ghost — the flag persists until a reconcile succeeds, so an offline
side just defers), the target's pushes the inbound. Agent-bound nodes
converge via GetXrayConfigForAgent on the agent's next config poll.
A local side has no reconcile loop, so it is applied directly
post-commit (Del/Add on the local runtime, restart fallback).

Frontend: the deploy-to Select is no longer disabled in edit mode
(protocol stays locked); candidate rules unchanged (online nodes only).

Tests: panel->panel move with reconcile sweep/push assertions,
auto-tag prefix regeneration, agent-config flip in both directions,
omitted-nodeId legacy contract, same-node no-op, missing-node
rejection, node->local move.
2026-10-21 13:49:57 +00:00
Muse 261a1f6787 P8(1): restore homepage overview curves on a memory-only sampling ring
Backend: new overviewMetrics store — a single-tier (2s x 360 = 12min)
in-memory ring fed by ServerService.RefreshStatus for exactly the eight
overview series (cpu/mem/swap/diskUsage/netUp/netDown/tcpCount/udpCount).
No persistence, no gob snapshot, no system-history page: the only surface
is GET /panel/api/server/history/:metric/:bucket restricted to those
keys, which seeds the frontend curves. ~46KB bounded by construction;
the ring starts empty on every panel start.

Frontend: restore useOverviewHistory + the VitalTile/ThroughputCard/
ConnectionsCard sparklines and the IndexPage wiring exactly as they
were before P7 removed them along with the history module.
2026-10-21 13:49:43 +00:00
Muse 60ce5eab98 docs(spec): record scope decision — keep protocol range, IP check/speedtest, ACME, multi-user 2026-10-21 21:09:29 +08:00
Muse f887f47bb9 P7: restore agent node type, agent heartbeat expiry, build-version injection, remove log/history/xray-metrics modules, optional sub port
- nodes: port node-type (traditional/agent) picker back from web-src into
  the embedded frontend; backend annotates NodeView.nodeType from
  agent_nodes bindings; fix agent-node update path (skip reachability
  probe and apiToken requirement for agent-managed nodes); restore i18n
  keys in all 13 locales; install command now uses the Gitea mirror
- jobs: expire agent-bound nodes whose agent_nodes.last_seen is older
  than max(3x heartbeat interval, 120s) = 180s; last_seen=0 (never
  registered) is left untouched; transitions reuse UpdateHeartbeat +
  node event broadcast
- config: GetBaseVersion honors ldflags-injected buildVersion; release
  builds inject 3.7.0-agent.1 so the panel no longer reports a phantom
  update against the Gitea release tag
- logger/server: remove the three log viewers (panel/xray/amneziawg),
  their API endpoints and the 10240-entry in-memory log buffer; file
  logging via lumberjack unchanged; tests assert via a new optional
  logger hook instead of the removed buffer
- server: remove system history and xray metrics modules end to end
  (endpoints, sampling appends in RefreshStatus, per-minute persist
  cron, gob snapshot/restore, XrayMetricsService); realtime status and
  per-node history are untouched
- settings: subPort may be 0/unset - subscription links are generated
  without a port while the subscription service keeps binding the
  default 2096; the settings form declares the cleared state via
  onNumber's new onClear option instead of snapping back to 1
2026-10-21 06:44:00 +00:00
Rogue 2c85f85549 精简版第六轮补裁(P6): 摘除分组/API文档死入口与首页Xray状态徽标及重启/停止按钮, 清理死i18n键 2026-10-20 19:25:29 +00:00
Muse 0f0335e943 修复二开 agent 流量增量丢失: 基线改上报确认后推进并落盘持久化
- xray 新增快照/确认接口 GetTrafficSnapshot/CommitTrafficSnapshot/
  RestoreTrafficBaseline, 与面板 GetTraffic 的 StatsLastValues 完全隔离
- agent 改走快照: 仅主控 HTTP 200 后才推进基线, 失败轮增量由累计
  计数做差在下轮自动补齐; 已确认基线原子落盘, agent 重启恢复续差
- 核心重启计数归零的从零规则保留; Onlines 仍每轮新鲜采集直报
- 新增 11 个测试覆盖断网恢复/连续失败补齐/重启恢复/计数归零/
  面板语义隔离, xray 与 agent 两包全绿
2026-10-20 15:58:38 +00:00
Muse 4828f946b1 精简版第四轮补裁(P4): 页面层摘除 + Xray更新端点下线 + 本机核心监管下线
页面层(用户真机截图发现前两轮漏裁):
- 设置: 摘除 Telegram机器人/邮件菜单与页面, 及页内残留入口(通知页/外部流量/LDAP/2FA设置页)
- Xray配置: 摘除负载均衡/DNS/高级配置菜单与页面; 基础配置(出站+路由)完好
- 总览: 摘除 Xray更新弹窗(VersionModal+GeodataSection)全部入口, 版本号改为静态展示
- 13个locale同步摘除461个已删功能专属翻译键(逐键核查前后端引用为零; i18n-dead-keys测试全绿)

Xray更新后端(经调查确认仅服务本机bin/xray, 与agent下发/订阅无关):
- 删除 getXrayVersion/installXray/updateGeofile 路由与handler(访问返回404)
- 删除 ServerService 对应实现与校验和函数; 同步api-docs/monitor白名单/openapi

本机核心监管下线(设计: 主控永不运行本机xray, 入站全在agent):
- XrayService.RestartXray 降级为no-op(一次性Warning说明日志); StopXray无进程时幂等返回
- web.go 摘除启动拉起本机核心/CheckXrayRunning看门狗(1s)/ApplyPendingRestart cron(30s)/XrayTrafficJob/CheckClientIpJob 注册
- ApplyPendingRestart 降级为消费即清, 其测试更新为新语义
- XrayMetricsService.Sample 短路: 不再每2s探本机/debug/vars, 状态优雅置为不可用
- 配置生成(纯JSON)/agent链路/订阅/入站CRUD未动; 状态读数优雅归零(stop/Unknown)

注: TestGetXrayConfig_EnabledClientsStillEmitted 在基线945b3a5同样失败(既有问题, 非本轮引入)
2026-10-20 14:58:05 +00:00
Muse 945b3a56a2 链接迁移: 前端用户可见链接与 .github 元数据改指本仓 Gitea
CI / go-test (push) Canceled after 0s
CI / postgres-durable-first (push) Canceled after 0s
CI / codegen (push) Canceled after 0s
CI / govulncheck (push) Canceled after 0s
CI / race (push) Canceled after 0s
CI / fuzz-smoke (push) Canceled after 0s
CI / golangci (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CodeQL Advanced / Analyze (go) (push) Canceled after 0s
CodeQL Advanced / Analyze (actions) (push) Canceled after 0s
CodeQL Advanced / Analyze (javascript-typescript) (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Deploy Smoke Tests / noninteractive-install (ubuntu-24.04-arm) (push) Canceled after 0s
Deploy Smoke Tests / noninteractive-install (ubuntu-latest) (push) Canceled after 0s
Deploy Smoke Tests / release-tag-install (ubuntu-24.04-arm) (push) Canceled after 0s
Deploy Smoke Tests / release-tag-install (ubuntu-latest) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
- 前端: 侧边栏 REPO_URL 改指本仓 Gitea; 订阅设置帮助链接改指本仓
  Gitea 上的 docs/custom-subscription-templates.md (dist 产物未动, 下次构建自愈)
- FUNDING.yml: 删除上游作者的赞助句柄 (github/buy_me_a_coffee/custom 捐赠页),
  留注释说明; ISSUE_TEMPLATE: Wiki/搜索/最新版三个 contact_links 与
  question.yaml 的 Wiki 链接改指本仓 Gitea (仓库首页/Issues/Releases)
- .github/claude/repo-context.md: 安装命令一行改指本仓 install-master.sh
2026-10-20 12:41:56 +00:00
Muse b8e132fc0b 链接迁移: 6 个多语言 README 与 CONTRIBUTING 改指本仓 Gitea
- 快速开始主命令改指本仓 install-master.sh (Gitea raw); 无等价物的
  指定版本/dev 通道一键命令替换为指向主 README 的英文说明行 (小节结构保留)
- 删除 5 个绑定上游仓库的 shields/pkg.go.dev 徽章 (无 Gitea 等价物);
  Wiki 链接改指本仓首页; Docker 示例镜像由上游发布的 ghcr.io/mhsanaei/3x-ui
  改为本地构建的 3x-ui-agent:local (fork 不发布注册表镜像)
- 删除上游作者个人捐赠锚点 (buymeacoffee/nowpayments) 与 starchart 上游统计小节
- CONTRIBUTING: clone 地址与 Issues 链接改指本仓 Gitea
2026-10-20 12:40:52 +00:00
Muse c67f0cb0cf 链接迁移: fork 脚本复活指 Gitea、上游三件套中和、面板自更新链改指本仓
- install-master.sh/install-agent.sh: 二进制下载源由已封账号 aaaamoooo/3x-ui-diy
  改指本仓 Gitea Releases (tag 沿用 v3.7.0-agent.1); README 同步撤下'暂不可用'标注
- install.sh/update.sh: 未被 fork 部署链引用, 整文件替换为中英双语短桩 (exit 1),
  防旧习惯调用时静默装成/更新成上游原版
- x-ui.sh: 保留全部管理功能, 仅中和 install/update/update_dev/update_menu/
  legacy_version/update_shell 的上游下载分支与 uninstall 打印的上游命令,
  一律改为提示本仓 Gitea Releases 地址后退出该分支
- panel.go: 面板自更新运行时耦合处理 — panelUpdaterURL 与版本检查 API 由
  MHSanaei GitHub 改指本仓 Gitea (raw update.sh + /api/v1 releases, 响应字段
  tag_name/body/target_commitish 与原解析结构一致); 下载到的将是本仓 update.sh
  短桩, 面板更新会安全失败而非覆盖成原版
- deploy/cloud-init: curl 上游 install.sh 改为本仓 install-master.sh (Gitea raw);
  头部注明 XUI_* 非交互旋钮与 install-result.env 凭据回显在 fork 安装脚本下无等价物
2026-10-20 12:36:50 +00:00
Muse 8da3cde494 docs: README 改版为 fork 口径——删上游/已封 GitHub 的一键安装命令,改为 Gitea Releases 手动部署主控/agent 两模式,补卸载章节 2026-10-20 12:27:21 +00:00
1311 changed files with 57596 additions and 100938 deletions
+1 -1
View File
@@ -5,6 +5,6 @@ build
db
cert
pgdata
x-ui/
l-ui/
*.db
*.dump
+46 -46
View File
@@ -2,25 +2,25 @@
# 1. Developer Bootstrap: The active (uncommented) variables directly below
# configure a safe, unprivileged local environment for 'go run .'.
# This allows 'cp .env.example .env' to work out-of-the-box without root.
# 2. Production Reference: All available XUI_* configuration options are
# 2. Production Reference: All available LUI_* configuration options are
# documented and commented out in the reference section further below.
#
# 3x-ui reads its runtime configuration from XUI_* environment variables.
# L-UI reads its runtime configuration from LUI_* environment variables.
# On a script install, the installer writes them to the service environment file
# (/etc/default/x-ui, /etc/conf.d/x-ui, or /etc/sysconfig/x-ui depending on the distro).
# (/etc/default/l-ui, /etc/conf.d/l-ui, or /etc/sysconfig/l-ui depending on the distro).
# For Docker, you set them in docker-compose.yml or via 'docker run -e'.
#
# Defaults are sensible — set only what you need to change, then restart:
# systemctl restart x-ui
# systemctl restart l-ui
# ------------------------------------------------------------------------------
# LOCAL DEVELOPMENT OVERRIDES (ACTIVE BY DEFAULT)
# ------------------------------------------------------------------------------
XUI_DEBUG=true
XUI_DB_FOLDER=x-ui
XUI_LOG_FOLDER=x-ui
XUI_BIN_FOLDER=x-ui
XUI_INIT_WEB_BASE_PATH=/
LUI_DEBUG=true
LUI_DB_FOLDER=l-ui
LUI_LOG_FOLDER=l-ui
LUI_BIN_FOLDER=l-ui
LUI_INIT_WEB_BASE_PATH=/
# ==============================================================================
# REFERENCE CONFIGURATION (ALL OPTIONS)
@@ -31,21 +31,21 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Backend database type: sqlite, or postgres (also accepts postgresql / pg)
# Default: sqlite
#XUI_DB_TYPE=sqlite
#LUI_DB_TYPE=sqlite
# Folder for the SQLite database file (x-ui.db)
# Default: /etc/x-ui (Overridden to 'x-ui' in the development block above)
#XUI_DB_FOLDER=/etc/x-ui
# Folder for the SQLite database file (l-ui.db)
# Default: /etc/l-ui (Overridden to 'l-ui' in the development block above)
#LUI_DB_FOLDER=/etc/l-ui
# PostgreSQL connection string (used when XUI_DB_TYPE=postgres)
# PostgreSQL connection string (used when LUI_DB_TYPE=postgres)
# Example: postgres://user:password@localhost:5432/dbname?sslmode=disable
#XUI_DB_DSN=
#LUI_DB_DSN=
# Max open connections in the PostgreSQL pool
#XUI_DB_MAX_OPEN_CONNS=
#LUI_DB_MAX_OPEN_CONNS=
# Max idle connections in the PostgreSQL pool
#XUI_DB_MAX_IDLE_CONNS=
#LUI_DB_MAX_IDLE_CONNS=
# PostgreSQL Docker Container Settings
# Default credentials used if you are running PostgreSQL via docker-compose
@@ -58,19 +58,19 @@ XUI_INIT_WEB_BASE_PATH=/
# Panel
# ------------------------------------------------------------------------------
# Override the panel port (1–65535). Takes precedence over the stored setting.
#XUI_PORT=
#LUI_PORT=
# Initial web base path on FIRST launch (e.g., /panel)
# Default: /
#XUI_INIT_WEB_BASE_PATH=/
#LUI_INIT_WEB_BASE_PATH=/
# Enable Fail2ban-based IP-limit enforcement
# Default: true
#XUI_ENABLE_FAIL2BAN=true
#LUI_ENABLE_FAIL2BAN=true
# Skip the HSTS header — set true when TLS is terminated by a reverse proxy
# Default: false
#XUI_SKIP_HSTS=false
#LUI_SKIP_HSTS=false
# ------------------------------------------------------------------------------
@@ -78,26 +78,26 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Logging level: debug, info, notice, warning, or error
# Default: info
#XUI_LOG_LEVEL=info
#LUI_LOG_LEVEL=info
# Debug mode. Forces log level to debug, enables Gin debug mode,
# and ensures frontend assets are served directly from disk (see CLAUDE.md).
# Default: false (Overridden to 'true' in the development block at the top)
#XUI_DEBUG=false
#LUI_DEBUG=false
# Log output directory
# Default: /var/log/x-ui (Overridden to 'x-ui' in the development block above)
#XUI_LOG_FOLDER=/var/log/x-ui
# Default: /var/log/l-ui (Overridden to 'l-ui' in the development block above)
#LUI_LOG_FOLDER=/var/log/l-ui
# Folder for the Xray-core binary and geosite/geoip files
# Default: bin (Overridden to 'x-ui' in the development block above)
#XUI_BIN_FOLDER=bin
# Default: bin (Overridden to 'l-ui' in the development block above)
#LUI_BIN_FOLDER=bin
# Legacy Path Settings
# Main installation folder (Default: /usr/local/x-ui for Linux, /app for Docker)
#XUI_MAIN_FOLDER=/usr/local/x-ui
# Main installation folder (Default: /usr/local/l-ui for Linux, /app for Docker)
#LUI_MAIN_FOLDER=/usr/local/l-ui
# Path to the systemd service file (Default: /etc/systemd/system)
#XUI_SERVICE=/etc/systemd/system
#LUI_SERVICE=/etc/systemd/system
# ------------------------------------------------------------------------------
@@ -105,27 +105,27 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Go GC target percentage; lower = less RAM, slightly more CPU.
# Default: 75
#XUI_GOGC=
#LUI_GOGC=
# Minutes between FreeOSMemory calls; 0 disables.
# Default: 10
#XUI_MEMORY_RELEASE_INTERVAL=
#LUI_MEMORY_RELEASE_INTERVAL=
# Go soft memory limit in MiB
#XUI_MEMORY_LIMIT=
#LUI_MEMORY_LIMIT=
# Go-syntax soft limit (e.g., 400MiB); takes precedence over XUI_MEMORY_LIMIT
# Go-syntax soft limit (e.g., 400MiB); takes precedence over LUI_MEMORY_LIMIT
#GOMEMLIMIT=
# Expose pprof profiling on 127.0.0.1:6060
# Default: false
#XUI_PPROF=false
#LUI_PPROF=false
# Automatically set to 'true' inside the official Docker image.
# Consumed by internal scripts (x-ui.sh) to detect the environment.
# Consumed by internal scripts (l-ui.sh) to detect the environment.
# There is normally no need to set or toggle this variable manually.
# Default: false (automatically 'true' in Docker environments)
#XUI_IN_DOCKER=false
#LUI_IN_DOCKER=false
# ------------------------------------------------------------------------------
@@ -142,36 +142,36 @@ XUI_INIT_WEB_BASE_PATH=/
# Optional watchdog: probes a URL (optionally through a local Xray inbound)
# and restarts Xray after repeated failures. A restart drops all connected clients.
# Default: false
#XUI_TUNNEL_HEALTH_MONITOR=false
#LUI_TUNNEL_HEALTH_MONITOR=false
# Proxy to send the probe through, e.g., socks5://127.0.0.1:1080
# Empty = only checks host connectivity
#XUI_TUNNEL_HEALTH_PROXY=
#LUI_TUNNEL_HEALTH_PROXY=
# URL to probe
# Default: https://www.cloudflare.com/cdn-cgi/trace
#XUI_TUNNEL_HEALTH_URL=https://www.cloudflare.com/cdn-cgi/trace
#LUI_TUNNEL_HEALTH_URL=https://www.cloudflare.com/cdn-cgi/trace
# Interval between probes
# Default: 30s
#XUI_TUNNEL_HEALTH_INTERVAL=30s
#LUI_TUNNEL_HEALTH_INTERVAL=30s
# Per-probe timeout
# Default: 10s
#XUI_TUNNEL_HEALTH_TIMEOUT=10s
#LUI_TUNNEL_HEALTH_TIMEOUT=10s
# Consecutive failures before a restart
# Default: 3
#XUI_TUNNEL_HEALTH_FAILURES=3
#LUI_TUNNEL_HEALTH_FAILURES=3
# Minimum delay between restarts
# Default: 5m
#XUI_TUNNEL_HEALTH_COOLDOWN=5m
#LUI_TUNNEL_HEALTH_COOLDOWN=5m
# ------------------------------------------------------------------------------
# Unattended install
# ------------------------------------------------------------------------------
# Set to 1 (or run with no TTY) to install with zero prompts.
# Generated credentials will be written to /etc/x-ui/install-result.env
#XUI_NONINTERACTIVE=1
# Generated credentials will be written to /etc/l-ui/install-result.env
#LUI_NONINTERACTIVE=1
+5 -3
View File
@@ -1,6 +1,8 @@
# These are supported funding model platforms
# Fork note: the upstream author's funding handles (github / buy_me_a_coffee /
# custom donate page) were removed — they do not belong to this fork.
github: MHSanaei
github: # upstream author's handle removed in this fork
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
@@ -10,5 +12,5 @@ liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: mhsanaei
custom: https://donate.sanaei.dev/
buy_me_a_coffee: # upstream author's handle removed in this fork
custom: # upstream author's donation page removed in this fork
+4 -4
View File
@@ -54,7 +54,7 @@ body:
attributes:
label: Relevant logs
description: |
Panel logs (`journalctl -u x-ui -n 200`) and/or the browser DevTools
Panel logs (`journalctl -u l-ui -n 200`) and/or the browser DevTools
console output. **Redact** tokens, real domains, IPs, and client UUIDs.
render: shell
validations:
@@ -74,7 +74,7 @@ body:
- type: input
id: xui-version
attributes:
label: 3x-ui version
label: L-UI version
description: Shown at the top of the panel sidebar.
placeholder: 3.1.0
validations:
@@ -92,7 +92,7 @@ body:
- type: dropdown
id: install-method
attributes:
label: How did you install 3x-ui?
label: How did you install L-UI?
options:
- install.sh script
- Docker / Docker Compose
@@ -159,7 +159,7 @@ body:
options:
- label: I searched [existing issues](../issues?q=is%3Aissue) and this bug has not been reported.
required: true
- label: I am running the latest released version of 3x-ui (or have verified the bug still exists on it).
- label: I am running the latest released version of L-UI (or have verified the bug still exists on it).
required: true
- label: This bug report is written in English.
required: true
+4 -4
View File
@@ -1,11 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: 📖 Project Wiki
url: https://github.com/MHSanaei/3x-ui/wiki
- name: 📖 Project home (Gitea)
url: https://git.881218.xyz/rogue/l-ui
about: Setup, install, configuration, and "how do I…" guides live here. Please check before opening a question.
- name: 🔍 Search existing issues
url: https://github.com/MHSanaei/3x-ui/issues?q=is%3Aissue
url: https://git.881218.xyz/rogue/l-ui/issues
about: Your bug, feature, or question may already be tracked. Comment on the existing one rather than opening a duplicate.
- name: 🚀 Latest release
url: https://github.com/MHSanaei/3x-ui/releases/latest
url: https://git.881218.xyz/rogue/l-ui/releases
about: Reproduce on the latest version before reporting — many bugs are already fixed in the most recent release.
+1 -1
View File
@@ -1,5 +1,5 @@
name: Feature request
description: Suggest an idea or improvement for 3x-ui
description: Suggest an idea or improvement for L-UI
title: "[Feature]: "
labels: ["enhancement"]
+5 -5
View File
@@ -1,5 +1,5 @@
name: Question
description: Ask how to do something with 3x-ui
description: Ask how to do something with L-UI
title: "[Question]: "
labels: ["question"]
@@ -9,7 +9,7 @@ body:
value: |
Before opening a question, please:
- Read the [project Wiki](https://github.com/MHSanaei/3x-ui/wiki) —
- Read the [project home](https://git.881218.xyz/rogue/l-ui) —
most setup, install, and "how do I …" answers live there.
- Search [existing issues](../issues?q=is%3Aissue) — the question
may already have been asked.
@@ -43,7 +43,7 @@ body:
- type: input
id: xui-version
attributes:
label: 3x-ui version
label: L-UI version
description: Shown at the top of the panel sidebar.
placeholder: 3.1.0
validations:
@@ -52,7 +52,7 @@ body:
- type: dropdown
id: install-method
attributes:
label: How did you install 3x-ui?
label: How did you install L-UI?
options:
- install.sh script
- Docker / Docker Compose
@@ -85,7 +85,7 @@ body:
attributes:
label: Before submitting
options:
- label: I read the [Wiki](https://github.com/MHSanaei/3x-ui/wiki) and searched [existing issues](../issues?q=is%3Aissue).
- label: I read the [project home](https://git.881218.xyz/rogue/l-ui) and searched [existing issues](../issues?q=is%3Aissue).
required: true
- label: This is a usage question, not a bug report.
required: true
+17 -17
View File
@@ -13,7 +13,7 @@ question it already answers.
## Stack
3x-ui is an open-source web control panel for managing Xray-core servers.
L-UI is an open-source web control panel for managing Xray-core servers.
- Backend: Go 1.27, module `github.com/mhsanaei/3x-ui/v3`, Gin and GORM.
- It runs Xray-core as a managed child process (`internal/xray/process.go`) and
@@ -26,8 +26,8 @@ question it already answers.
per inbound. Client, ad-tag and quota/expiry edits are hot-applied through the
fork's management API (`PUT /secrets`) so connections survive, with a process
restart as the fallback on older binaries.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux, the executable
directory on Windows) or PostgreSQL (`XUI_DB_TYPE` / `XUI_DB_DSN`). The SQLite
- Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux, the executable
directory on Windows) or PostgreSQL (`LUI_DB_TYPE` / `LUI_DB_DSN`). The SQLite
driver is CGo, so `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, built
into `internal/web/dist/` (gitignored) and embedded with `embed.FS`.
@@ -36,7 +36,7 @@ question it already answers.
| area | path |
| --- | --- |
| entry point + `x-ui` CLI | `main.go` |
| entry point + `l-ui` CLI | `main.go` |
| env parsing | `internal/config/` |
| schema, migrations | `internal/database/`, `internal/database/model/` |
| Xray child process + config | `internal/xray/` |
@@ -48,7 +48,7 @@ question it already answers.
| master/sub-node over mTLS | `internal/web/runtime/` |
| i18n | `internal/web/locale/`, `internal/web/translation/` |
| UI source | `frontend/src/` |
| install / upgrade | `install.sh`, `x-ui.sh`, `DockerInit.sh` |
| install / upgrade | `install.sh`, `l-ui.sh`, `DockerInit.sh` |
## Hard rules a change must respect
@@ -93,7 +93,7 @@ question it already answers.
subtests and `t.Helper()` on helpers. An assertion must pin the exact value,
typed error or emitted string — `err != nil` and `len(x) > 0` are findings,
not nits. Prefer real dependencies: a throwaway DB via
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` with `t.Cleanup`, and
`database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` with `t.Cleanup`, and
`httptest` for HTTP. `internal/sub`'s `initSubDB(t)` is the template.
A test must FAIL without its fix; one that passes either way certifies
nothing and then gets cited as proof the fix works.
@@ -143,36 +143,36 @@ variable is set, and CI sets only the PostgreSQL ones above:
| gate | covers |
| --- | --- |
| `XUI_TEST_PG_DSN` | PostgreSQL-specific paths |
| `XUI_DB_TYPE` + `XUI_DB_DSN` | dialect-dependent behaviour |
| `LUI_TEST_PG_DSN` | PostgreSQL-specific paths |
| `LUI_DB_TYPE` + `LUI_DB_DSN` | dialect-dependent behaviour |
| `XRAY_E2E_BINARY` | the Xray gRPC end-to-end tests in `internal/xray/` |
| `XUI_SCALE_TEST` | scale tests in `internal/sub/`, `internal/web/job/`, `internal/web/service/` |
| `LUI_SCALE_TEST` | scale tests in `internal/sub/`, `internal/web/job/`, `internal/web/service/` |
Mutation testing (`mutation.yml`) runs nightly and never on a pull request, so a
test that cannot fail is invisible to CI. `make verify` is the local gate.
## Support facts reporters get wrong
- Linux install: `bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)`
- Linux install: `bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)`
- Install generates a RANDOM username, password and web base path — never
admin/admin. The `x-ui` menu on the server shows or resets them.
admin/admin. The `l-ui` menu on the server shows or resets them.
- The installer service environment file is DISTRO-DEPENDENT:
`/etc/default/x-ui` (Debian/Ubuntu), `/etc/conf.d/x-ui` (Arch),
`/etc/sysconfig/x-ui` (RHEL/Fedora). Naming the wrong one means the reporter's
`/etc/default/l-ui` (Debian/Ubuntu), `/etc/conf.d/l-ui` (Arch),
`/etc/sysconfig/l-ui` (RHEL/Fedora). Naming the wrong one means the reporter's
edit is silently never read by systemd — a common cause of "I set the variable
and nothing happened".
- Windows is supported. There the database sits next to the executable, not in
`/etc` — never quote the Linux path to a Windows user.
- SQLite to PostgreSQL: `x-ui migrate-db --dsn "postgres://..."`, then set
`XUI_DB_TYPE`/`XUI_DB_DSN` in that file and `systemctl restart x-ui`. The
- SQLite to PostgreSQL: `l-ui migrate-db --dsn "postgres://..."`, then set
`LUI_DB_TYPE`/`LUI_DB_DSN` in that file and `systemctl restart l-ui`. The
source SQLite file is left in place.
- Docker image `ghcr.io/mhsanaei/3x-ui`; PostgreSQL profile
`docker compose --profile postgres up -d`. Fail2ban IP-limit enforcement needs
`NET_ADMIN` + `NET_RAW` (compose grants them; a bare `docker run` must add
`--cap-add=NET_ADMIN --cap-add=NET_RAW`).
- Never state that a `XUI_*` variable does not exist without grepping
- Never state that a `LUI_*` variable does not exist without grepping
`internal/config/` and `internal/tunnelmonitor/` first. The
`XUI_TUNNEL_HEALTH_*` family is the usual answer to "the panel restarts Xray
`LUI_TUNNEL_HEALTH_*` family is the usual answer to "the panel restarts Xray
every few minutes".
- Security per inbound is none / tls / reality. XTLS is a VLESS *flow*
(`xtls-rprx-vision`), not a security setting — never tell anyone to pick XTLS
+2 -2
View File
@@ -58,8 +58,8 @@ jobs:
--health-timeout 5s
--health-retries 5
env:
XUI_DB_TYPE: postgres
XUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
LUI_DB_TYPE: postgres
LUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
+10 -10
View File
@@ -53,7 +53,7 @@ jobs:
--allowedTools "Bash(gh label list:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh issue comment ${{ github.event.issue.number }}:*),Bash(gh issue edit ${{ github.event.issue.number }} --add-label:*),Bash(gh issue edit ${{ github.event.issue.number }} --remove-label:*),Bash(gh issue edit ${{ github.event.issue.number }} --title:*),Bash(gh issue close ${{ github.event.issue.number }}:*),Bash(gh search issues:*),Bash(gh search commits:*),Bash(gh search prs:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh release list:*),Bash(gh release view:*),Bash(git log:*),Bash(git show:*),Bash(git blame:*),Bash(git ls-tree:*),Bash(git tag:*),Read,Glob,Grep,Write(//tmp/**),Edit(//tmp/**)"
--disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: |
You are the SENIOR GITHUB ISSUE ANALYST for the MHSanaei/3x-ui
You are the SENIOR GITHUB ISSUE ANALYST for the MHSanaei/L-UI
repository, an open-source web control panel for managing Xray-core
servers. You are the only automated reply an issue ever gets. Your
question is: IS THE REPORTED PROBLEM REAL, AND IF SO, WHY?
@@ -106,7 +106,7 @@ jobs:
reports, "enhancement" for feature requests, "question" for
questions - so a pre-applied type label is a template default to
verify, not the reporter's considered classification. The bug form
already REQUIRES the 3x-ui version, install method and OS, and also
already REQUIRES the L-UI version, install method and OS, and also
collects logs, the Xray version, affected areas and reverse-proxy
setup; the question form requires the version and install method. It
all arrives under "### <heading>" sections of the body. Read those
@@ -251,7 +251,7 @@ jobs:
question you could have answered by reading more code.
SECURITY EXCEPTION, which overrides everything else: if the report
describes what looks like an exploitable vulnerability in 3x-ui - an
describes what looks like an exploitable vulnerability in L-UI - an
authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation - do NOT investigate or
analyse it publicly. Post one short comment asking the reporter to
@@ -285,7 +285,7 @@ jobs:
- CLOSE AS INVALID when the body, judged exactly as written, is
empty or only whitespace, punctuation or emoji; pure gibberish;
advertising or unrelated links; a throwaway test ("test", "asdf");
or unrelated to 3x-ui and Xray. Then: post the comment, add the
or unrelated to L-UI and Xray. Then: post the comment, add the
`invalid` label, and
`gh issue close ${{ github.event.issue.number }} --reason "not planned"`.
A short, vague, badly formatted, machine-translated or low-quality
@@ -628,11 +628,11 @@ jobs:
--allowedTools "Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh issue comment ${{ github.event.issue.number }}:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh pr comment ${{ github.event.issue.number }}:*),Bash(gh search issues:*),Bash(gh search commits:*),Bash(gh release list:*),Bash(gh label list:*),Read,Glob,Grep,Write(//tmp/**),Edit(//tmp/**)"
--disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: |
You are replying to an @claude mention from a maintainer of the MHSanaei/3x-ui repository - its owner, or somebody invited to it with write access, an open-source web panel for managing Xray-core servers. This run investigates and explains; it never changes anything. You have no tool that can edit a file in the checkout, no git command that can write, and a token that cannot push, so no file is edited, no branch is created, no commit is made and no pull request is opened or merged - on an issue and on a pull request alike. The one exception in this repository lives in a separate workflow job that only the repository owner can start, so do not mention it or offer it. The full repo source is checked out in the working directory; use Read, Glob and Grep to open and verify the relevant files before stating any default, path, flag, option name, or behavior. Your file-writing tool is limited to /tmp: a long reply goes to /tmp/comment.md and is posted with gh issue comment <number> --body-file /tmp/comment.md (or gh pr comment for a pull request). If that write is refused for any reason, pass the body inline with --body instead - never leave the thread unanswered.
You are replying to an @claude mention from a maintainer of the MHSanaei/L-UI repository - its owner, or somebody invited to it with write access, an open-source web panel for managing Xray-core servers. This run investigates and explains; it never changes anything. You have no tool that can edit a file in the checkout, no git command that can write, and a token that cannot push, so no file is edited, no branch is created, no commit is made and no pull request is opened or merged - on an issue and on a pull request alike. The one exception in this repository lives in a separate workflow job that only the repository owner can start, so do not mention it or offer it. The full repo source is checked out in the working directory; use Read, Glob and Grep to open and verify the relevant files before stating any default, path, flag, option name, or behavior. Your file-writing tool is limited to /tmp: a long reply goes to /tmp/comment.md and is posted with gh issue comment <number> --body-file /tmp/comment.md (or gh pr comment for a pull request). If that write is refused for any reason, pass the body inline with --body instead - never leave the thread unanswered.
Key layout:
- main.go holds the entry point and the x-ui management CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert).
- internal/config/ parses env vars (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER, XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_FOLDER, XUI_DB_TYPE, XUI_DB_DSN).
- main.go holds the entry point and the l-ui management CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert).
- internal/config/ parses env vars (LUI_DEBUG, LUI_LOG_LEVEL, LUI_LOG_FOLDER, LUI_BIN_FOLDER, LUI_SKIP_HSTS, LUI_PORT, LUI_DB_FOLDER, LUI_DB_TYPE, LUI_DB_DSN).
- internal/database/ and internal/database/model/ hold the GORM schema (Inbound, Client, Setting, User) and the inbound protocol enum (vmess, vless, tunnel, http, trojan, shadowsocks, mixed, wireguard, hysteria, mtproto).
- internal/mtproto/ runs MTProto (Telegram) proxy inbounds via the bundled mtg binary.
- internal/web/controller/ has panel and REST API handlers with the OpenAPI spec served at /panel/api/openapi.json.
@@ -643,13 +643,13 @@ jobs:
- internal/sub/ is the subscription server.
- internal/eventbus/ is an in-process pub/sub event bus (outbound and node health, xray.crash, cpu.high, memory.high, login.attempt).
- internal/xray/ runs Xray-core as a managed child process and generates its config; internal/xray/geodata/ streams the geosite/geoip .dat files.
- internal/crypto/ (node-token encryption), internal/logger/, internal/util/ (link, ldap, sys, wireguard - leaf-only helpers) and internal/tunnelmonitor/ (the XUI_TUNNEL_HEALTH_* tunnel watchdog) are shared infrastructure.
- internal/crypto/ (node-token encryption), internal/logger/, internal/util/ (link, ldap, sys, wireguard - leaf-only helpers) and internal/tunnelmonitor/ (the LUI_TUNNEL_HEALTH_* tunnel watchdog) are shared infrastructure.
- frontend/ is the React 19 plus Ant Design 6 plus Vite 8 plus TypeScript source built into the embedded internal/web/dist/.
- tools/openapigen emits the frontend API types and Zod/JSON schemas; the OpenAPI document itself is assembled by frontend/scripts/build-openapi.mjs.
- docs/ is a separate Next.js docs site; docs/lib/xray/ holds a third independent implementation of link/subscription generation.
CLAUDE.md and docs/architecture.md in the checkout are the maintained maps; when they and this layout disagree, they win.
Stack and runtime facts: Backend is Go (module github.com/mhsanaei/3x-ui/v3) with Gin and GORM; storage is SQLite by default at /etc/x-ui/x-ui.db or PostgreSQL via XUI_DB_TYPE and XUI_DB_DSN; further env vars include XUI_DB_MAX_OPEN_CONNS, XUI_DB_MAX_IDLE_CONNS, XUI_INIT_WEB_BASE_PATH, XUI_ENABLE_FAIL2BAN, and the XUI_TUNNEL_HEALTH_* family in internal/tunnelmonitor/ - never say a XUI_* variable does not exist without grepping internal/config/ and internal/tunnelmonitor/ first; the installer's service env file is distro-dependent - /etc/default/x-ui (Debian/Ubuntu/Armbian), /etc/conf.d/x-ui (Arch/Alpine), /etc/sysconfig/x-ui (RHEL/Fedora and others); SQLite to PostgreSQL migration is x-ui migrate-db --dsn followed by a service restart; install uses install.sh and the x-ui menu, generating random initial credentials; Docker image is ghcr.io/mhsanaei/3x-ui and Fail2ban IP-limit enforcement needs NET_ADMIN and NET_RAW; Windows is a supported platform (the DB sits next to the executable there, not in /etc). Do not hardcode a version: for version or is-this-fixed questions, check the latest release and recent commits or closed PRs with gh. The same discipline applies to every fact in this prompt - the repo moves, so re-verify names, paths, flags, and enum values in the source before quoting them.
Stack and runtime facts: Backend is Go (module github.com/mhsanaei/3x-ui/v3) with Gin and GORM; storage is SQLite by default at /etc/l-ui/l-ui.db or PostgreSQL via LUI_DB_TYPE and LUI_DB_DSN; further env vars include LUI_DB_MAX_OPEN_CONNS, LUI_DB_MAX_IDLE_CONNS, LUI_INIT_WEB_BASE_PATH, LUI_ENABLE_FAIL2BAN, and the LUI_TUNNEL_HEALTH_* family in internal/tunnelmonitor/ - never say a LUI_* variable does not exist without grepping internal/config/ and internal/tunnelmonitor/ first; the installer's service env file is distro-dependent - /etc/default/l-ui (Debian/Ubuntu/Armbian), /etc/conf.d/l-ui (Arch/Alpine), /etc/sysconfig/l-ui (RHEL/Fedora and others); SQLite to PostgreSQL migration is l-ui migrate-db --dsn followed by a service restart; install uses install.sh and the l-ui menu, generating random initial credentials; Docker image is ghcr.io/mhsanaei/3x-ui and Fail2ban IP-limit enforcement needs NET_ADMIN and NET_RAW; Windows is a supported platform (the DB sits next to the executable there, not in /etc). Do not hardcode a version: for version or is-this-fixed questions, check the latest release and recent commits or closed PRs with gh. The same discipline applies to every fact in this prompt - the repo moves, so re-verify names, paths, flags, and enum values in the source before quoting them.
Style: lead with the answer in the first sentence; use fenced code blocks for commands and backtick formatting for paths and setting names; distinguish what you confirmed in the source (name the file) from what you infer; never promise fixes, timelines, or releases. Ground every claim in the code or the README and wiki; do not invent features, paths, flags, or commands, and do not stop at the first plausible match. Token cost is not a concern, so investigate as deeply as the question needs.
@@ -836,7 +836,7 @@ jobs:
--disallowedTools "Bash,WebFetch,WebSearch,Task,Edit(//**/.git/**),Read(//**/.git/**)"
prompt: |
The repository owner asked for the merge conflicts on pull request
#${{ github.event.issue.number }} of MHSanaei/3x-ui, an open-source
#${{ github.event.issue.number }} of MHSanaei/L-UI, an open-source
web panel for managing Xray-core servers, to be resolved. The merge
of `${{ steps.merge.outputs.base }}` into the pull request's branch
`${{ steps.merge.outputs.head }}` is already in progress in the
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
uses: docker/metadata-action@v6
with:
images: |
hsanaeii/3x-ui
hsanaeii/L-UI
ghcr.io/mhsanaei/3x-ui
tags: |
type=ref,event=branch
+29 -29
View File
@@ -13,9 +13,9 @@ on:
- "go.sum"
- "**.sh"
- "frontend/**"
- "x-ui.service.debian"
- "x-ui.service.arch"
- "x-ui.service.rhel"
- "l-ui.service.debian"
- "l-ui.service.arch"
- "l-ui.service.rhel"
- ".github/workflows/release.yml"
pull_request:
paths:
@@ -24,9 +24,9 @@ on:
- "go.sum"
- "**.sh"
- "frontend/**"
- "x-ui.service.debian"
- "x-ui.service.arch"
- "x-ui.service.rhel"
- "l-ui.service.debian"
- "l-ui.service.arch"
- "l-ui.service.rhel"
- ".github/workflows/release.yml"
jobs:
@@ -113,15 +113,15 @@ jobs:
file xui-release
ldd xui-release || echo "Static binary confirmed"
mkdir x-ui
cp xui-release x-ui/
cp x-ui.service.debian x-ui/
cp x-ui.service.arch x-ui/
cp x-ui.service.rhel x-ui/
cp x-ui.sh x-ui/
mv x-ui/xui-release x-ui/x-ui
mkdir x-ui/bin
cd x-ui/bin
mkdir l-ui
cp xui-release l-ui/
cp l-ui.service.debian l-ui/
cp l-ui.service.arch l-ui/
cp l-ui.service.rhel l-ui/
cp l-ui.sh l-ui/
mv l-ui/xui-release l-ui/l-ui
mkdir l-ui/bin
cd l-ui/bin
# Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -183,13 +183,13 @@ jobs:
cd ../..
- name: Package
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
run: tar -zcvf l-ui-linux-${{ matrix.platform }}.tar.gz l-ui
- name: Upload files to Artifacts
uses: actions/upload-artifact@v7
with:
name: x-ui-linux-${{ matrix.platform }}
path: ./x-ui-linux-${{ matrix.platform }}.tar.gz
name: l-ui-linux-${{ matrix.platform }}
path: ./l-ui-linux-${{ matrix.platform }}.tar.gz
- name: Upload files to GH release
uses: svenstaro/upload-release-action@v2
@@ -197,8 +197,8 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: x-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
file: l-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: l-ui-linux-${{ matrix.platform }}.tar.gz
overwrite: true
prerelease: true
@@ -277,10 +277,10 @@ jobs:
shell: pwsh
run: |
$retry = @{ MaximumRetryCount = 5; RetryIntervalSec = 10 }
mkdir x-ui
Copy-Item xui-release.exe x-ui\x-ui.exe
mkdir x-ui\bin
cd x-ui\bin
mkdir l-ui
Copy-Item xui-release.exe l-ui\l-ui.exe
mkdir l-ui\bin
cd l-ui\bin
# Download Xray for Windows
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -315,13 +315,13 @@ jobs:
- name: Package to Zip
shell: pwsh
run: |
Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
Compress-Archive -Path .\l-ui -DestinationPath "l-ui-windows-amd64.zip"
- name: Upload files to Artifacts
uses: actions/upload-artifact@v7
with:
name: x-ui-windows-amd64
path: ./x-ui-windows-amd64.zip
name: l-ui-windows-amd64
path: ./l-ui-windows-amd64.zip
- name: Upload files to GH release
uses: svenstaro/upload-release-action@v2
@@ -329,8 +329,8 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: x-ui-windows-amd64.zip
asset_name: x-ui-windows-amd64.zip
file: l-ui-windows-amd64.zip
asset_name: l-ui-windows-amd64.zip
overwrite: true
prerelease: true
+2 -2
View File
@@ -65,5 +65,5 @@ jobs:
- uses: actions/checkout@v7
- name: Pinned release install smoke test
env:
XUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }}
run: bash deploy/test/smoke-noninteractive.sh "$XUI_SMOKE_VERSION"
LUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }}
run: bash deploy/test/smoke-noninteractive.sh "$LUI_SMOKE_VERSION"
+7 -4
View File
@@ -17,8 +17,11 @@ tmp/
# Ignore build and distribution directories
backup/
bin/
x-ui/
l-ui/
dist/
# Exception: the vendored embedded fallback theme ships its dist/ as
# source (go:embed) — it is not a build output.
!/internal/web/service/probe_theme_default/dist/
release/
node_modules/
@@ -31,9 +34,9 @@ Thumbs.db
# Ignore Go build files
*.exe
x-ui.db
x-ui.db-shm
x-ui.db-wal
l-ui.db
l-ui.db-shm
l-ui.db-wal
system_metrics.gob
*.dump
+16 -16
View File
@@ -3,41 +3,41 @@
"version": "0.2.0",
"configurations": [
{
"name": "Run 3x-ui (Debug)",
"name": "Run L-UI (Debug)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui"
"LUI_DEBUG": "true",
"LUI_DB_FOLDER": "l-ui",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui"
},
"console": "integratedTerminal"
},
{
"name": "Run 3x-ui (Postgres)",
"name": "Run L-UI (Postgres)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable"
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable"
},
"windows": {
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
}
},
+3 -3
View File
@@ -8,14 +8,14 @@
"args": [
"build",
"-o",
"bin/3x-ui",
"bin/L-UI",
"./main.go"
],
"windows": {
"args": [
"build",
"-o",
"bin/3x-ui.exe",
"bin/L-UI.exe",
"./main.go"
]
},
@@ -41,7 +41,7 @@
"options": {
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true"
"LUI_DEBUG": "true"
}
},
"problemMatcher": [
+9 -9
View File
@@ -24,16 +24,16 @@ file locations when it can answer in one hop.
falls back to a process restart on older binaries. A client's panel-side
traffic reset also calls `POST /secrets/{name}/reset-quota` so a renewed client
is not re-blocked by the sidecar's quota counter.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux; the executable dir on
Windows), PostgreSQL optional (`XUI_DB_TYPE` / `XUI_DB_DSN`). The CGo SQLite
- Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux; the executable dir on
Windows), PostgreSQL optional (`LUI_DB_TYPE` / `LUI_DB_DSN`). The CGo SQLite
driver (`mattn/go-sqlite3`) needs a C compiler — `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`,
built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`.
## Repo map
- `main.go` — entry point + `x-ui` CLI (run, migrate, migrate-db, setting, cert).
- `internal/config/` — env parsing (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER,
XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_*).
- `main.go` — entry point + `l-ui` CLI (run, migrate, migrate-db, setting, cert).
- `internal/config/` — env parsing (LUI_DEBUG, LUI_LOG_LEVEL, LUI_LOG_FOLDER,
LUI_BIN_FOLDER, LUI_SKIP_HSTS, LUI_PORT, LUI_DB_*).
- `internal/database/` + `internal/database/model/` — GORM schema (~24 models;
Inbound, Client, Setting, User are the core), inbound Protocol enum,
AutoMigrate + hand-written migrations in `db.go`.
@@ -116,7 +116,7 @@ file locations when it can answer in one hop.
- Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests,
`t.Helper()` on helpers. Assert the exact value / typed error / emitted
string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` +
`database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` +
`t.Cleanup(func() { _ = database.CloseDB() })`; `httptest` for HTTP.
`internal/sub`'s `initSubDB(t)` is the template.
- A test must fail without its fix. Write it, revert the fix, watch it go red,
@@ -126,8 +126,8 @@ file locations when it can answer in one hop.
pure map lookup, or inputs the function can never receive. One real test that
drives the bug through the actual code path beats five that restate the code.
- Code must pass `golangci-lint run` (gofumpt + goimports formatting): `make lint`.
- Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `XUI_TEST_PG_DSN`,
`XUI_DB_TYPE`+`XUI_DB_DSN`, `XRAY_E2E_BINARY` or `XUI_SCALE_TEST` is set — a
- Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `LUI_TEST_PG_DSN`,
`LUI_DB_TYPE`+`LUI_DB_DSN`, `XRAY_E2E_BINARY` or `LUI_SCALE_TEST` is set — a
green `go test ./...` does not mean those paths ran.
## Frontend conventions (summary; full version in frontend/CLAUDE.md)
@@ -140,7 +140,7 @@ file locations when it can answer in one hop.
a headless-Chromium Storybook project, so run
`npx playwright install --with-deps chromium` once or `make verify` fails.
- Editing `frontend/src` does NOT change what users see until the Vite build is
regenerated into `internal/web/dist/`. In `XUI_DEBUG=true`, HTML is served from
regenerated into `internal/web/dist/`. In `LUI_DEBUG=true`, HTML is served from
the frozen embedded FS but JS/CSS off disk — after `npm run build` you MUST
restart `go run .` or you get a blank page with 404s.
- After touching share-link logic (`src/lib/xray/`), run `npm run test` (golden
+40 -40
View File
@@ -1,6 +1,6 @@
# Contributing
Thanks for taking the time to contribute to 3x-ui. This guide gets a development panel running locally and explains the conventions the project follows so changes land cleanly.
Thanks for taking the time to contribute to L-UI. This guide gets a development panel running locally and explains the conventions the project follows so changes land cleanly.
## Prerequisites
@@ -50,12 +50,12 @@ Cross-building the Linux SQLite target from Windows (or vice versa) requires a s
## First-time setup
```bash
git clone https://github.com/MHSanaei/3x-ui.git
cd 3x-ui
git clone https://git.881218.xyz/rogue/l-ui.git
cd L-UI
cp .env.example .env
mkdir x-ui
mkdir l-ui
go mod download
@@ -65,18 +65,18 @@ npm run build
cd ..
```
`.env.example` ships with defaults that keep the database, logs, and xray binary inside the local `x-ui/` folder so nothing escapes the project directory:
`.env.example` ships with defaults that keep the database, logs, and xray binary inside the local `l-ui/` folder so nothing escapes the project directory:
```
XUI_DEBUG=true
XUI_DB_FOLDER=x-ui
XUI_LOG_FOLDER=x-ui
XUI_BIN_FOLDER=x-ui
XUI_INIT_WEB_BASE_PATH=/
# XUI_PORT=8080
LUI_DEBUG=true
LUI_DB_FOLDER=l-ui
LUI_LOG_FOLDER=l-ui
LUI_BIN_FOLDER=l-ui
LUI_INIT_WEB_BASE_PATH=/
# LUI_PORT=8080
```
Drop the xray binary (`xray-windows-amd64.exe` on Windows, `xray-linux-amd64` on Linux, etc.) plus the matching `geoip.dat` and `geosite.dat` files into `x-ui/`. The easiest source is a [released Xray-core build](https://github.com/XTLS/Xray-core/releases). On Windows, `wintun.dll` is also required for testing TUN inbounds.
Drop the xray binary (`xray-windows-amd64.exe` on Windows, `xray-linux-amd64` on Linux, etc.) plus the matching `geoip.dat` and `geosite.dat` files into `l-ui/`. The easiest source is a [released Xray-core build](https://github.com/XTLS/Xray-core/releases). On Windows, `wintun.dll` is also required for testing TUN inbounds.
## Running
@@ -88,7 +88,7 @@ Open [http://localhost:2053](http://localhost:2053) and log in with `admin` / `a
### Inside VS Code
The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run 3x-ui (Debug)** for the default SQLite setup, and **Run 3x-ui (Postgres)** which points `XUI_DB_TYPE`/`XUI_DB_DSN` at a local PostgreSQL. The Postgres profile also prepends the PostgreSQL `bin` to `PATH` so the panel can find `pg_dump`/`pg_restore` (the `postgresql-client` tools used for DB backup/restore) — adjust the DSN and that path to your machine:
The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run L-UI (Debug)** for the default SQLite setup, and **Run L-UI (Postgres)** which points `LUI_DB_TYPE`/`LUI_DB_DSN` at a local PostgreSQL. The Postgres profile also prepends the PostgreSQL `bin` to `PATH` so the panel can find `pg_dump`/`pg_restore` (the `postgresql-client` tools used for DB backup/restore) — adjust the DSN and that path to your machine:
```jsonc
{
@@ -96,33 +96,33 @@ The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run 3
"version": "0.2.0",
"configurations": [
{
"name": "Run 3x-ui (Debug)",
"name": "Run L-UI (Debug)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui"
"LUI_DEBUG": "true",
"LUI_DB_FOLDER": "l-ui",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui"
},
"console": "integratedTerminal"
},
{
"name": "Run 3x-ui (Postgres)",
"name": "Run L-UI (Postgres)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
},
"console": "integratedTerminal"
@@ -167,7 +167,7 @@ Locale strings live in `internal/web/translation/<locale>.json`, **not** under `
The Vite dev proxy serves the admin SPA for any `/panel/*` URL — `bypassMigratedRoute` in `vite.config.js` rewrites those requests to `index.html` and lets React Router take over — while forwarding `/panel/api/*`, `/panel/api/setting/*`, `/panel/api/xray/*`, and the WebSocket to the Go panel. Because routing is now client-side, new panel routes need no proxy or allowlist changes.
> **`XUI_DEBUG=true` gotcha** — in debug mode the panel serves HTML from the embedded FS (frozen at the last `go build` / `go run`) but JS/CSS off disk. Re-running `npm run build` without restarting Go leaves the embedded HTML pointing at the *old* hashed asset names, producing a blank page with 404s in the console. Always restart `go run .` after a frontend rebuild.
> **`LUI_DEBUG=true` gotcha** — in debug mode the panel serves HTML from the embedded FS (frozen at the last `go build` / `go run`) but JS/CSS off disk. Re-running `npm run build` without restarting Go leaves the embedded HTML pointing at the *old* hashed asset names, producing a blank page with 404s in the console. Always restart `go run .` after a frontend rebuild.
### Adding a new page
@@ -237,7 +237,7 @@ For deeper notes on the frontend toolchain see [`frontend/README.md`](frontend/R
| `internal/xray/` | Xray-core process lifecycle and gRPC API client |
| `internal/sub/` | Subscription endpoints (raw, JSON, Clash) |
| `internal/config/` | Environment-variable helpers, paths, defaults |
| `x-ui/` | **Runtime data** — db, logs, xray binary, geo files (gitignored) |
| `l-ui/` | **Runtime data** — db, logs, xray binary, geo files (gitignored) |
## Testing
@@ -247,7 +247,7 @@ Tests live next to the code (`foo.go` ↔ `foo_test.go`); frontend specs and gol
- **Stdlib `testing` only** — no testify. Table-driven with `t.Run` subtests and `t.Helper()` on helpers.
- **Assert the contract, not internals.** Pin the exact value / typed error / emitted string — not `err != nil` or `len > 0`. A test that still passes when the behavior is broken is worse than no test.
- **Real dependencies over mocks.** Get a throwaway DB with `database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` + `t.Cleanup(func() { _ = database.CloseDB() })` (Windows-safe), and use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
- **Real dependencies over mocks.** Get a throwaway DB with `database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` + `t.Cleanup(func() { _ = database.CloseDB() })` (Windows-safe), and use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
### Running
@@ -297,24 +297,24 @@ CI runs this for you nightly (and on demand) via `.github/workflows/mutation.yml
| Variable | Default | Purpose |
|----------|---------|---------|
| `XUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk |
| `XUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` |
| `XUI_DB_FOLDER` | platform default | Where `x-ui.db` lives |
| `XUI_LOG_FOLDER` | platform default | Where `3xui.log` lives |
| `XUI_BIN_FOLDER` | `bin` | Where the xray binary, geo files, and xray `config.json` live |
| `XUI_INIT_WEB_BASE_PATH` | `/` | The initial URI path for the web panel |
| `XUI_PORT` | persisted `webPort` | Runtime-only web panel listener port override (`1` through `65535`) |
| `XUI_DB_TYPE` | `sqlite` | Set to `postgres` to use PostgreSQL via `XUI_DB_DSN` |
| `XUI_DB_DSN` | — | PostgreSQL DSN when `XUI_DB_TYPE=postgres` |
| `LUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk |
| `LUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` |
| `LUI_DB_FOLDER` | platform default | Where `l-ui.db` lives |
| `LUI_LOG_FOLDER` | platform default | Where `3xui.log` lives |
| `LUI_BIN_FOLDER` | `bin` | Where the xray binary, geo files, and xray `config.json` live |
| `LUI_INIT_WEB_BASE_PATH` | `/` | The initial URI path for the web panel |
| `LUI_PORT` | persisted `webPort` | Runtime-only web panel listener port override (`1` through `65535`) |
| `LUI_DB_TYPE` | `sqlite` | Set to `postgres` to use PostgreSQL via `LUI_DB_DSN` |
| `LUI_DB_DSN` | — | PostgreSQL DSN when `LUI_DB_TYPE=postgres` |
A valid `XUI_PORT` takes precedence over the database-backed `webPort` for the
A valid `LUI_PORT` takes precedence over the database-backed `webPort` for the
current process without changing the stored setting. Unset, empty, whitespace-only,
malformed, or out-of-range values fall back to `webPort`; invalid configured values
also produce a warning. With Docker bridge networking, the published container port
must match the override, for example `XUI_PORT: "8080"` with `ports: ["8080:8080"]`.
must match the override, for example `LUI_PORT: "8080"` with `ports: ["8080:8080"]`.
## Issues
- Bug reports and feature requests: [GitHub Issues](https://github.com/MHSanaei/3x-ui/issues)
- Bug reports and feature requests: [Issues](https://git.881218.xyz/rogue/l-ui/issues)
Before filing a bug, include the OS, Go version, panel version (`/panel/api/server/status` or the dashboard footer), and the relevant excerpt from `x-ui/3xui.log`.
Before filing a bug, include the OS, Go version, panel version (`/panel/api/server/status` or the dashboard footer), and the relevant excerpt from `l-ui/3xui.log`.
+5 -5
View File
@@ -1,8 +1,8 @@
#!/bin/sh
# Start fail2ban with the 3x-ipl jail
if [ "$XUI_ENABLE_FAIL2BAN" = "true" ]; then
LOG_FOLDER="${XUI_LOG_FOLDER:-/var/log/x-ui}"
if [ "$LUI_ENABLE_FAIL2BAN" = "true" ]; then
LOG_FOLDER="${LUI_LOG_FOLDER:-/var/log/l-ui}"
mkdir -p "$LOG_FOLDER"
touch "$LOG_FOLDER/3xipl.log" "$LOG_FOLDER/3xipl-banned.log"
@@ -33,7 +33,7 @@ EOF
# added later without regenerating these files.
SSH_PORTS=$(grep -oE '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null | grep -oE '[0-9]+' | paste -sd, -)
[ -z "$SSH_PORTS" ] && SSH_PORTS="22"
PANEL_PORT=$(/app/x-ui setting -show true 2>/dev/null | grep -Eo 'port: .+' | awk '{print $2}')
PANEL_PORT=$(/app/l-ui setting -show true 2>/dev/null | grep -Eo 'port: .+' | awk '{print $2}')
EXEMPT_PORTS="$SSH_PORTS"
[ -n "$PANEL_PORT" ] && EXEMPT_PORTS="$EXEMPT_PORTS,$PANEL_PORT"
@@ -78,5 +78,5 @@ if [ -f /root/.acme.sh/acme.sh ]; then
crond
fi
# Run x-ui
exec /app/x-ui
# Run l-ui
exec /app/l-ui
+12 -12
View File
@@ -27,11 +27,11 @@ COPY --from=frontend /src/internal/web/dist ./internal/web/dist
ENV CGO_ENABLED=1
ENV CGO_CFLAGS="-D_LARGEFILE64_SOURCE"
RUN go build -ldflags "-w -s" -o build/x-ui main.go
RUN go build -ldflags "-w -s" -o build/l-ui main.go
RUN ./DockerInit.sh "$TARGETARCH"
# ========================================================
# Stage: Final Image of 3x-ui
# Stage: Final Image of L-UI
# ========================================================
FROM alpine
ENV TZ=Asia/Tehran
@@ -47,7 +47,7 @@ RUN apk add --no-cache --update \
COPY --from=builder /app/build/ /app/
COPY --from=builder /app/DockerEntrypoint.sh /app/
COPY --from=builder /app/x-ui.sh /usr/bin/x-ui
COPY --from=builder /app/l-ui.sh /usr/bin/l-ui
COPY --from=builder /app/internal/web/translation /app/internal/web/translation
@@ -60,15 +60,15 @@ RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \
RUN chmod +x \
/app/DockerEntrypoint.sh \
/app/x-ui \
/usr/bin/x-ui
/app/l-ui \
/usr/bin/l-ui
ENV XUI_IN_DOCKER="true"
ENV XUI_MAIN_FOLDER="/app"
ENV XUI_ENABLE_FAIL2BAN="true"
ENV XUI_DB_TYPE=""
ENV XUI_DB_DSN=""
ENV LUI_IN_DOCKER="true"
ENV LUI_MAIN_FOLDER="/app"
ENV LUI_ENABLE_FAIL2BAN="true"
ENV LUI_DB_TYPE=""
ENV LUI_DB_DSN=""
EXPOSE 2053
VOLUME [ "/etc/x-ui" ]
CMD [ "./x-ui" ]
VOLUME [ "/etc/l-ui" ]
CMD [ "./l-ui" ]
ENTRYPOINT [ "/app/DockerEntrypoint.sh" ]
+10 -7
View File
@@ -1,7 +1,7 @@
# 3x-ui 路由器主控精简版 — 定版清单
# L-UI 路由器主控精简版 — 定版清单
> 2026-10-20 与用户逐项讨论中。本文档定版前不开工。
> 背景:AX6600 路由器 = **主控**(3x-ui 3.7.0,纯控制面,本机 xray 已 chmod -x 禁用,RSS ~130MB);
> 背景:AX6600 路由器 = **主控**(L-UI 3.7.0,纯控制面,本机 xray 已 chmod -x 禁用,RSS ~130MB);
> Alpine 主控 = 备用,趋于退役。精简目标:二开构建压内存,验收线 RSS ≤ 90MB。
## 保留(已定)
@@ -24,13 +24,16 @@
- 安全设置:双重验证(2FA,用户不用)
- 邮件模块(SMTP 发送:到期/流量提醒等,用户不用)
- 分组功能(客户端归类标签 + 按组批量操作/聚合订阅;用户从未用过,裁功能不影响已建客户端与订阅)
- 本地核心实测三件套(P9 第 4 条,用户 2026-10-21 晚改口):出站测速(临时 xray 实例批量探测 `testOutbound(s)` 接口 + 前端测试按钮/模式切换/结果弹层)、出口探测(同一动作的 egress IP/国家展示)、重启/停止核心接口(`restartXrayService`/`stopXrayService`,与首页已摘按钮同族);出站与路由的模板编辑(增删改存)保留不动
- 本地核心整条路径(P9 第 4b 条):进程管理/状态机、buildXrayConfig 本地分支与 local-only 注入(panel/node egress 桥、订阅出站合并、mtproto/amneziawg 桥)、本地核心专属接口(balancer 状态/override、routeTest、getXrayResult)与前端 RouteTester、本地核心三个 job(流量采集/存活看门狗/客户端 IP 限制)已整条删除;配置构建只剩 agent 一条线(模板 + 节点入站 + egress + 转发编译)。MTProto/AmneziaWG 随之退役:新建/编辑直接拒绝,存量行保留在库中可删除、不再被服务。金标准验证:同一种子库删除前后三台 agent 的生成配置逐字一致
## 待用户确认
## 范围确认(2026-10-21 用户拍板:四项全部保留,不裁)
- 协议范围:是否只留 VLESS + SS2022,裁其余协议模板(VMess、Trojan、WireGuard、TUIC、Hysteria、MTProto 等)——建议裁
- IP 检查 / 测速类后台任务——建议裁
- 面板内置 ACME 签证书(走 CF Tunnel,不直签)——建议裁
- 多用户功能(单管理员使用)——建议裁
- 协议范围:保留全部协议模板(VLESS、SS2022、VMess、Trojan、WireGuard、TUIC、Hysteria、MTProto 等),不收窄
- IP 检查 / 测速类后台任务:保留 → **2026-10-21 晚用户改口推翻本项**:出站测速 + 出口探测(同一动作,测的是主控本地网络位置;精简主控不跑本机核心、无本地出站,测速结果无意义)连同重启/停止核心控件与接口,已于 P9 第 4 条摘除。其余三项(协议范围 / ACME / 多用户)保留不变,不要再翻出来问。
- 面板内置 ACME 签证书:保留
- 多用户功能:保留
- 用户理由:这四块以静态代码为主,裁掉省不了多少内存。此节关闭,后续轮次不要再翻出来问。
## 修复(非裁剪,已定)
+36 -53
View File
@@ -2,18 +2,13 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI** هي لوحة تحكم ويب متقدمة ومفتوحة المصدر لإدارة خوادم [Xray-core](https://github.com/XTLS/Xray-core). توفّر واجهة نظيفة ومتعددة اللغات لنشر وتكوين ومراقبة مجموعة واسعة من بروتوكولات الوكيل وVPN — من خادم VPS واحد إلى عمليات النشر متعددة العقد.
@@ -69,31 +64,31 @@
## البدء السريع
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
لتثبيت إصدار محدد، أضِف وسمه (مثل `v3.4.0`):
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
لتثبيت بنية **dev** المتجددة (أحدث إصدار أولي لكل التزام (commit) من `main`، وليس إصدارًا مستقرًا)، مرّر `dev-latest`:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
أثناء التثبيت، يتم إنشاء اسم مستخدم وكلمة مرور ومسار وصول عشوائية. بعد التثبيت، شغّل `x-ui` لفتح قائمة الإدارة، حيث يمكنك بدء/إيقاف الخدمة، وعرض أو إعادة تعيين بيانات تسجيل الدخول، وإدارة شهادات SSL، والمزيد.
أثناء التثبيت، يتم إنشاء اسم مستخدم وكلمة مرور ومسار وصول عشوائية. بعد التثبيت، شغّل `l-ui` لفتح قائمة الإدارة، حيث يمكنك بدء/إيقاف الخدمة، وعرض أو إعادة تعيين بيانات تسجيل الدخول، وإدارة شهادات SSL، والمزيد.
للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://github.com/MHSanaei/3x-ui/wiki).
للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://git.881218.xyz/rogue/l-ui).
### التثبيت غير التفاعلي
يعمل المثبِّت أيضًا **بشكل غير تفاعلي** لـ cloud-init.
عيّن `XUI_NONINTERACTIVE=1` (أو مرّره عبر أنبوب دون TTY) وسيتولى التثبيت من البداية إلى النهاية
عيّن `LUI_NONINTERACTIVE=1` (أو مرّره عبر أنبوب دون TTY) وسيتولى التثبيت من البداية إلى النهاية
دون أي مطالبات، مُنشئًا بيانات اعتماد عشوائية وكاتبًا إياها في
`/etc/x-ui/install-result.env`. راجع [`deploy/`](deploy/) لـ:
`/etc/l-ui/install-result.env`. راجع [`deploy/`](deploy/) لـ:
- [بيانات مستخدم cloud-init](deploy/cloud-init/) — تثبيت غير تفاعلي على أي سحابة (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [ملاحظات Hetzner Cloud](deploy/marketplace/hetzner/) — نشر يعتمد على cloud-init على Hetzner
@@ -108,29 +103,29 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
يدعم 3X-UI خلفيتين (backends) يتم اختيارهما أثناء التثبيت:
- **SQLite** (افتراضي) — ملف واحد في `/etc/x-ui/x-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة.
- **SQLite** (افتراضي) — ملف واحد في `/etc/l-ui/l-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة.
- **PostgreSQL** — موصى به لأعداد العملاء الكبيرة أو الإعدادات متعددة العقد. يمكن للمثبِّت تثبيت PostgreSQL محليًا لك، أو قبول DSN لخادم موجود.
في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/x-ui`):
في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### ترحيل تثبيت SQLite موجود إلى PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ثم عيّن XUI_DB_TYPE و XUI_DB_DSN في /etc/default/x-ui وأعد التشغيل:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ثم عيّن LUI_DB_TYPE و LUI_DB_DSN في /etc/default/l-ui وأعد التشغيل:
systemctl restart l-ui
```
يبقى ملف SQLite الأصلي دون تغيير؛ احذفه يدويًا بعد التحقق من الخلفية الجديدة.
### Docker
يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `XUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل:
يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `LUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل:
```bash
docker compose --profile postgres up -d
@@ -139,29 +134,29 @@ docker compose --profile postgres up -d
تتضمن الصورة Fail2ban (مُفعَّل افتراضيًا) لفرض **حدود IP** لكل عميل. يحظر Fail2ban المخالفين باستخدام `iptables`، الذي يتطلب صلاحية `NET_ADMIN`. يمنح `docker-compose.yml` هذه الصلاحية مسبقًا عبر `cap_add`؛ إذا شغّلت الحاوية باستخدام `docker run` بدلاً من ذلك، فأضِف الصلاحيات بنفسك، وإلا فسيتم تسجيل عمليات الحظر دون تطبيقها أبدًا:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## متغيرات البيئة
| المتغير | الوصف | الافتراضي |
| --- | --- | --- |
| `XUI_DB_TYPE` | خلفية قاعدة البيانات: `sqlite` أو `postgres` | `sqlite` |
| `XUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` |
| `XUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` |
| `XUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | تفعيل وضع التصحيح | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — |
| `XUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | الحد الأدنى للتأخير بين عمليات إعادة التشغيل المتتالية | `5m` |
| `LUI_DB_TYPE` | خلفية قاعدة البيانات: `sqlite` أو `postgres` | `sqlite` |
| `LUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` |
| `LUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` |
| `LUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` |
| `LUI_DEBUG` | تفعيل وضع التصحيح | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — |
| `LUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | الحد الأدنى للتأخير بين عمليات إعادة التشغيل المتتالية | `5m` |
## اللغات المدعومة
@@ -184,22 +179,10 @@ English · فارسی · العربية · 中文(简体) · 中文(繁體
## أدوات المجتمع
أدوات وتكاملات بناها المجتمع حول 3x-ui.
أدوات وتكاملات بناها المجتمع حول L-UI.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (الترخيص: **MIT**): _إدارة الاتصالات الواردة والعملاء وإعدادات اللوحة وتكوين Xray كرمز باستخدام Terraform / OpenTofu._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (الترخيص: **MIT**): _إدارة الاتصالات الواردة والعملاء وإعدادات اللوحة وتكوين Xray كرمز باستخدام Terraform / OpenTofu._
## دعم المشروع
**إذا كان هذا المشروع مفيدًا لك، فقد ترغب في إعطائه**:star2:
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
</a>
## النجوم عبر الزمن
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+36 -54
View File
@@ -2,18 +2,13 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI** es un panel de control web avanzado y de código abierto para gestionar servidores [Xray-core](https://github.com/XTLS/Xray-core). Ofrece una interfaz limpia y multilingüe para desplegar, configurar y monitorear una amplia gama de protocolos de proxy y VPN — desde un único VPS hasta despliegues multinodo.
@@ -69,31 +64,31 @@ Construido como un fork mejorado del proyecto X-UI original, 3X-UI añade un sop
## Inicio Rápido
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
Para instalar una versión específica, añade su etiqueta (p. ej. `v3.4.0`):
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
Para instalar la versión **dev** continua (la última prelanzamiento por commit desde `main`, no una versión estable), pasa `dev-latest`:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
Durante la instalación se generan un nombre de usuario, una contraseña y una ruta de acceso aleatorios. Tras la instalación, ejecuta `x-ui` para abrir el menú de gestión, donde puedes iniciar/detener el servicio, ver o restablecer tus credenciales de acceso, gestionar certificados SSL y mucho más.
Durante la instalación se generan un nombre de usuario, una contraseña y una ruta de acceso aleatorios. Tras la instalación, ejecuta `l-ui` para abrir el menú de gestión, donde puedes iniciar/detener el servicio, ver o restablecer tus credenciales de acceso, gestionar certificados SSL y mucho más.
Para la documentación completa, visita la [Wiki del proyecto](https://github.com/MHSanaei/3x-ui/wiki).
Para la documentación completa, visita la [Wiki del proyecto](https://git.881218.xyz/rogue/l-ui).
### Instalación desatendida
El instalador también se ejecuta de forma **no interactiva** para cloud-init.
Define `XUI_NONINTERACTIVE=1` (o canalízalo sin TTY) y realizará la instalación de principio a fin sin
Define `LUI_NONINTERACTIVE=1` (o canalízalo sin TTY) y realizará la instalación de principio a fin sin
ninguna pregunta, generando credenciales aleatorias y escribiéndolas en
`/etc/x-ui/install-result.env`. Consulta [`deploy/`](deploy/) para:
`/etc/l-ui/install-result.env`. Consulta [`deploy/`](deploy/) para:
- [User-data de cloud-init](deploy/cloud-init/) — instalación desatendida en cualquier nube (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Notas de Hetzner Cloud](deploy/marketplace/hetzner/) — despliegue basado en cloud-init en Hetzner
@@ -108,29 +103,29 @@ ninguna pregunta, generando credenciales aleatorias y escribiéndolas en
3X-UI admite dos backends, que se eligen durante la instalación:
- **SQLite** (predeterminado) — un único archivo en `/etc/x-ui/x-ui.db`. Sin configuración, ideal para despliegues pequeños y medianos.
- **SQLite** (predeterminado) — un único archivo en `/etc/l-ui/l-ui.db`. Sin configuración, ideal para despliegues pequeños y medianos.
- **PostgreSQL** — recomendado para un gran número de clientes o configuraciones multinodo. El instalador puede instalar PostgreSQL localmente por ti, o aceptar un DSN a un servidor existente.
En tiempo de ejecución, el backend se selecciona mediante variables de entorno (el instalador las escribe por ti en `/etc/default/x-ui`):
En tiempo de ejecución, el backend se selecciona mediante variables de entorno (el instalador las escribe por ti en `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Migrar una instalación de SQLite existente a PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# luego define XUI_DB_TYPE y XUI_DB_DSN en /etc/default/x-ui y reinicia:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# luego define LUI_DB_TYPE y LUI_DB_DSN en /etc/default/l-ui y reinicia:
systemctl restart l-ui
```
El archivo SQLite de origen permanece intacto; elimínalo manualmente una vez que hayas verificado el nuevo backend.
### Docker
El comando predeterminado `docker compose up -d` sigue usando SQLite. Para ejecutarlo con el servicio PostgreSQL incluido, descomenta las dos líneas de variables de entorno `XUI_DB_*` en `docker-compose.yml` e inícialo con el perfil:
El comando predeterminado `docker compose up -d` sigue usando SQLite. Para ejecutarlo con el servicio PostgreSQL incluido, descomenta las dos líneas de variables de entorno `LUI_DB_*` en `docker-compose.yml` e inícialo con el perfil:
```bash
docker compose --profile postgres up -d
@@ -139,29 +134,29 @@ docker compose --profile postgres up -d
La imagen incluye Fail2ban (habilitado de forma predeterminada) para aplicar **límites de IP** por cliente. Fail2ban banea a los infractores con `iptables`, lo que requiere la capacidad `NET_ADMIN`. `docker-compose.yml` ya la concede mediante `cap_add`; si en su lugar inicias el contenedor con `docker run`, añade tú mismo las capacidades, de lo contrario los baneos se registran pero nunca se aplican:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Variables de Entorno
| Variable | Descripción | Predeterminado |
| --- | --- | --- |
| `XUI_DB_TYPE` | Backend de base de datos: `sqlite` o `postgres` | `sqlite` |
| `XUI_DB_DSN` | Cadena de conexión de PostgreSQL (cuando `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Máximo de conexiones abiertas (pool de PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Máximo de conexiones inactivas (pool de PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | La ruta URI inicial para el panel web | `/` |
| `XUI_ENABLE_FAIL2BAN` | Habilitar la aplicación de límites de IP basada en Fail2ban | `true` |
| `XUI_LOG_LEVEL` | Nivel de registro (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Habilitar el modo de depuración | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Habilitar el monitor de salud del túnel (sondea una URL y reinicia xray tras fallos repetidos; un reinicio desconecta a todos los clientes) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Proxy a través del cual se envía el sondeo; apúntalo a una entrada local de xray para que el sondeo pruebe el túnel (p. ej. `socks5://127.0.0.1:1080`). Vacío significa que el sondeo solo comprueba la conectividad del host | — |
| `XUI_TUNNEL_HEALTH_URL` | URL sondeada para verificar la salud del túnel | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Intervalo entre sondeos | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Fallos consecutivos antes de que se active un reinicio | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Retardo mínimo entre reinicios consecutivos | `5m` |
| `LUI_DB_TYPE` | Backend de base de datos: `sqlite` o `postgres` | `sqlite` |
| `LUI_DB_DSN` | Cadena de conexión de PostgreSQL (cuando `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Máximo de conexiones abiertas (pool de PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Máximo de conexiones inactivas (pool de PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | La ruta URI inicial para el panel web | `/` |
| `LUI_ENABLE_FAIL2BAN` | Habilitar la aplicación de límites de IP basada en Fail2ban | `true` |
| `LUI_LOG_LEVEL` | Nivel de registro (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Habilitar el modo de depuración | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Habilitar el monitor de salud del túnel (sondea una URL y reinicia xray tras fallos repetidos; un reinicio desconecta a todos los clientes) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Proxy a través del cual se envía el sondeo; apúntalo a una entrada local de xray para que el sondeo pruebe el túnel (p. ej. `socks5://127.0.0.1:1080`). Vacío significa que el sondeo solo comprueba la conectividad del host | — |
| `LUI_TUNNEL_HEALTH_URL` | URL sondeada para verificar la salud del túnel | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Intervalo entre sondeos | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Fallos consecutivos antes de que se active un reinicio | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Retardo mínimo entre reinicios consecutivos | `5m` |
## Idiomas Compatibles
@@ -184,23 +179,10 @@ Las contribuciones son bienvenidas. Por favor, lee la [Guía de contribución](/
## Herramientas de la Comunidad
Herramientas e integraciones construidas por la comunidad alrededor de 3x-ui.
Herramientas e integraciones construidas por la comunidad alrededor de L-UI.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Licencia: **MIT**): _Gestiona inbounds, clientes, configuración del panel y configuración de Xray como código con Terraform / OpenTofu._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (Licencia: **MIT**): _Gestiona inbounds, clientes, configuración del panel y configuración de Xray como código con Terraform / OpenTofu._
## Apoyar el Proyecto
**Si este proyecto te es útil, puedes darle una**:star2:
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
</a>
## Estrellas a lo Largo del Tiempo
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+36 -54
View File
@@ -2,18 +2,13 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI** یک پنل کنترل وب پیشرفته و متن‌باز برای مدیریت سرورهای [Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک رابط کاربری تمیز و چندزبانه برای استقرار، پیکربندی و نظارت بر طیف گسترده‌ای از پروتکل‌های پراکسی و VPN ارائه می‌دهد — از یک VPS تکی تا استقرارهای چندنودی.
@@ -69,31 +64,31 @@
## شروع سریع
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
برای نصب یک نسخه‌ی مشخص، تگ آن را در انتها اضافه کنید (مثلاً `v3.4.0`):
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
برای نصب نسخه‌ی غلتانِ **dev** (آخرین پیش‌انتشار به‌ازای هر کامیت از شاخه‌ی `main`، نه یک انتشار پایدار)، مقدار `dev-latest` را پاس دهید:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
در حین نصب، یک نام کاربری، رمز عبور و مسیر دسترسی تصادفی تولید می‌شود. پس از نصب، دستور `x-ui` را اجرا کنید تا منوی مدیریت باز شود؛ در آنجا می‌توانید سرویس را شروع/متوقف کنید، اطلاعات ورود خود را ببینید یا بازنشانی کنید، گواهی‌های SSL را مدیریت کنید و کارهای دیگری انجام دهید.
در حین نصب، یک نام کاربری، رمز عبور و مسیر دسترسی تصادفی تولید می‌شود. پس از نصب، دستور `l-ui` را اجرا کنید تا منوی مدیریت باز شود؛ در آنجا می‌توانید سرویس را شروع/متوقف کنید، اطلاعات ورود خود را ببینید یا بازنشانی کنید، گواهی‌های SSL را مدیریت کنید و کارهای دیگری انجام دهید.
برای مستندات کامل، لطفاً به [ویکی پروژه](https://github.com/MHSanaei/3x-ui/wiki) مراجعه کنید.
برای مستندات کامل، لطفاً به [ویکی پروژه](https://git.881218.xyz/rogue/l-ui) مراجعه کنید.
### نصب بدون نظارت
نصب‌کننده به‌صورت **غیرتعاملی** نیز برای cloud-init اجرا می‌شود.
‏`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY از طریق pipe اجرا کنید) تا نصب به‌صورت سرتاسری و بدون
‏`LUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY از طریق pipe اجرا کنید) تا نصب به‌صورت سرتاسری و بدون
هیچ پرسشی انجام شود، اطلاعات ورود تصادفی تولید کرده و آن‌ها را در
`/etc/x-ui/install-result.env` می‌نویسد. برای موارد زیر به [`deploy/`](deploy/) مراجعه کنید:
`/etc/l-ui/install-result.env` می‌نویسد. برای موارد زیر به [`deploy/`](deploy/) مراجعه کنید:
- [user-data مربوط به Cloud-init](deploy/cloud-init/) — نصب بدون نظارت روی هر ابری (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [یادداشت‌های Hetzner Cloud](deploy/marketplace/hetzner/) — استقرار مبتنی بر cloud-init روی Hetzner
@@ -108,29 +103,29 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
‏3X-UI از دو بک‌اند پشتیبانی می‌کند که در حین نصب انتخاب می‌شوند:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط.
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط.
- **PostgreSQL** — برای تعداد کلاینت بالا یا راه‌اندازی‌های چندنودی توصیه می‌شود. نصب‌کننده می‌تواند PostgreSQL را به‌صورت محلی برایتان نصب کند، یا یک DSN به یک سرور موجود را بپذیرد.
در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/x-ui` می‌نویسد):
در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/l-ui` می‌نویسد):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### انتقال یک نصب موجود SQLite به PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# سپس XUI_DB_TYPE و XUI_DB_DSN را در /etc/default/x-ui تنظیم کرده و ری‌استارت کنید:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# سپس LUI_DB_TYPE و LUI_DB_DSN را در /etc/default/l-ui تنظیم کرده و ری‌استارت کنید:
systemctl restart l-ui
```
فایل اصلی SQLite دست‌نخورده باقی می‌ماند؛ پس از اطمینان از صحت بک‌اند جدید، آن را به‌صورت دستی حذف کنید.
### Docker
دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `XUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید:
دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `LUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید:
```bash
docker compose --profile postgres up -d
@@ -139,29 +134,29 @@ docker compose --profile postgres up -d
این ایمیج، Fail2ban را (که به‌صورت پیش‌فرض فعال است) برای اعمال **محدودیت‌های IP** به‌ازای هر کلاینت همراه دارد. ‏Fail2ban متخلفان را با `iptables` مسدود می‌کند که به مجوز `NET_ADMIN` نیاز دارد. فایل `docker-compose.yml` این مجوز را از قبل از طریق `cap_add` می‌دهد؛ اگر به‌جای آن کانتینر را با `docker run` اجرا می‌کنید، خودتان مجوزها را اضافه کنید، در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند اما هرگز اعمال نمی‌شوند:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## متغیرهای محیطی
| متغیر | توضیحات | پیش‌فرض |
| --- | --- | --- |
| `XUI_DB_TYPE` | بک‌اند پایگاه‌داده: `sqlite` یا `postgres` | `sqlite` |
| `XUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` |
| `XUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` |
| `XUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — |
| `XUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | حداقل تأخیر بین ری‌استارت‌های متوالی | `5m` |
| `LUI_DB_TYPE` | بک‌اند پایگاه‌داده: `sqlite` یا `postgres` | `sqlite` |
| `LUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` |
| `LUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` |
| `LUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` |
| `LUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — |
| `LUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | حداقل تأخیر بین ری‌استارت‌های متوالی | `5m` |
## زبان‌های پشتیبانی‌شده
@@ -184,23 +179,10 @@ English · فارسی · العربية · 中文(简体) · 中文(繁體
## ابزارهای جامعه
ابزارها و یکپارچه‌سازی‌هایی که توسط جامعه پیرامون 3x-ui ساخته شده‌اند.
ابزارها و یکپارچه‌سازی‌هایی که توسط جامعه پیرامون L-UI ساخته شده‌اند.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (مجوز: **MIT**): _مدیریت اینباندها، کلاینت‌ها، تنظیمات پنل و پیکربندی Xray به‌صورت کد با Terraform / OpenTofu._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (مجوز: **MIT**): _مدیریت اینباندها، کلاینت‌ها، تنظیمات پنل و پیکربندی Xray به‌صورت کد با Terraform / OpenTofu._
## پشتیبانی از پروژه
**اگر این پروژه برای شما مفید است، می‌توانید به آن یک**:star2: بدهید
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
</a>
## ستاره‌ها در طول زمان
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+77 -16
View File
@@ -1,39 +1,98 @@
# 3x-ui-agent
# L-UI
基于 3x-ui v3.7.0 的二次开发:节点 agent 化。节点鸡不再跑完整面板,只跑一个轻量 agent(约 60MB 内存),由主控统一管理、下发 xray 配置。
基于上游 3x-ui v3.7.0 的二次开发 fork:节点 agent 化。节点鸡不再跑完整面板,只跑一个轻量 agent(约 60MB 内存),由主控统一管理、下发 xray 配置。
本仓库托管在自建 Gitea:<https://git.881218.xyz/rogue/l-ui>,二进制从本仓库的 Releases 下载。**不要**使用上游的一键安装脚本/命令(`install.sh`、`update.sh` 等仍指向原版,会装成上游原版,与本 fork 不兼容)。
## 架构
- **主控**:完整 3x-ui 面板,唯一的配置可信源。管理节点、入站、客户端,下发完整 xray 配置(含出站、路由)到各 agent。
- **Agent**:跑在节点鸡上,通过 token 向主控注册。定时拉取主控下发的 xray 配置并应用,上报心跳和流量。只提供 VLESS / SS2022 入站。
- **主控**:完整 L-UI 面板,唯一的配置可信源。管理节点、入站、客户端,下发完整 xray 配置(含出站、路由)到各 agent。
- **Agent**:跑在节点鸡上,通过注册 token 向主控注册。定时拉取主控下发的 xray 配置并应用,上报心跳和流量。节点下发仅支持 VLESS / SS2022 两类入站(本 fork 的取向)。
同一个二进制、两种角色:不带参数运行是主控面板,`l-ui agent --config /etc/l-ui/agent.json` 运行是 agent。
## 安装
二进制下载:本仓库 [Releases](https://git.881218.xyz/rogue/l-ui/releases),按架构选 `l-ui-linux-amd64` 或 `l-ui-linux-arm64`。
> 仓库根目录的 `install-master.sh` / `install-agent.sh` 是一键脚本,下载源已迁至本仓 Gitea Releases(tag `v3.7.0-agent.1`),可直接使用;也可按下面步骤手动部署。
### 主控
```bash
bash <(curl -fL https://raw.githubusercontent.com/aaaamoooo/3x-ui-diy/main/install-master.sh)
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放主控二进制(Releases 下载的 l-ui-linux-<架构>)
cp l-ui-linux-amd64 /usr/local/l-ui/l-ui && chmod +x /usr/local/l-ui/l-ui
# 2. 放 xray 二进制与 geo 文件到 bin/ 子目录
# 纯控制面部署(节点全走 agent)可禁用本机 xray:不放,或放了之后 chmod -x
cp xray-linux-amd64 /usr/local/l-ui/bin/
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
```
装完面板在 `http://主控IP:2053`,默认账号 `admin` / `admin`。
启动(二选一):
- Debian/Ubuntu(systemd):把仓库的 `l-ui.service.debian` 复制为 `/etc/systemd/system/l-ui.service`,然后 `systemctl daemon-reload && systemctl enable --now l-ui`。
- OpenWrt(procd):用 init 脚本以 `/usr/local/l-ui/l-ui` 为命令启动,工作目录 `/usr/local/l-ui`。
数据库在 `/etc/l-ui/l-ui.db`。面板端口按设置,默认 2053,首次登录默认账号 `admin` / `admin`,请登录后立即修改。
### Agent(节点鸡)
先在主控面板「节点管理」→「添加节点」→ 类型选 **Agent**,保存后弹窗会显示 token,复制下来。
然后在节点鸡上:
先在主控侧为该节点生成注册 token(建节点 → 用面板 API Token 签发绑定该节点的 agent token,完整步骤见 [docs/AGENT.md](docs/AGENT.md)),然后在节点鸡上:
```bash
bash <(curl -fL https://raw.githubusercontent.com/aaaamoooo/3x-ui-diy/main/install-agent.sh) \
--master http://主控IP:2053 --token 你的TOKEN --name 节点名
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放同一个二进制(与主控同版本),在节点上改名为 lui-agent(与主控进程区分、避免同机覆盖)
cp l-ui-linux-amd64 /usr/local/l-ui/lui-agent && chmod +x /usr/local/l-ui/lui-agent
# 2. 放 xray 二进制与 geo 文件(agent 不负责下载,需手动放置)
cp xray-linux-amd64 /usr/local/l-ui/bin/xray && chmod +x /usr/local/l-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
# 3. 写 agent 配置
cat > /etc/l-ui/agent.json <<'EOF'
{
"master_url": "http://主控地址:2053",
"token": "<主控签发的注册 token>",
"node_name": "节点名"
}
EOF
chmod 600 /etc/l-ui/agent.json
```
agent 约 30 秒后拉到配置并启动 xray,节点在面板显示在线。
- `master_url` 走内网用 `http://`;走 `https://` 需可信证书(自签连不上)。
- agent 另有独立的运行时配置 `config-agent.json`(生成于 `bin/`);`agent.json` 可选 `api_port` 指定 xray stats API 端口(部署口径 62790,metrics 端口为其下一位 62791)。
- 启动:Debian 把仓库的 `systemd/lui-agent.service` 复制到 `/etc/systemd/system/` 后 `systemctl enable --now lui-agent`;OpenRC 用仓库的 `openrc/lui-agent` 放到 `/etc/init.d/lui-agent`。
agent 约 30 秒后拉到配置并启动 xray,节点在面板显示在线。更细的 agent 说明(出站/路由下发、验证、故障排查)见 [docs/AGENT.md](docs/AGENT.md)。
## 卸载
### 主控
```bash
# 先停服务:systemctl disable --now l-ui(或 /etc/init.d/l-ui stop)
rm -f /etc/systemd/system/l-ui.service # 或删掉对应的 procd init 脚本
rm -rf /usr/local/l-ui /etc/l-ui
```
### Agent
```bash
# 先停服务:systemctl disable --now lui-agent(或 rc-service lui-agent stop)
rm -f /etc/systemd/system/lui-agent.service # 或 /etc/init.d/lui-agent
rm -rf /usr/local/l-ui /etc/l-ui
```
(`/etc/l-ui` 里含数据库与 token 配置,确认不再需要再删。)
## 使用流程
1. 主控面板添加 Agent 类型节点,拿到 token
2. 节点鸡一键安装 agent,填入主控地址和 token
1. 主控侧建节点并签发 agent 注册 token(见 docs/AGENT.md)
2. 节点鸡按上面步骤部署 agent,填入主控地址和 token
3. 在「入站列表」创建入站(VLESS / SS2022),「部署到」选择在线的 agent 节点
4. 主控自动把完整 xray 配置下发到节点,客户端即可连接
@@ -42,14 +101,16 @@ agent 约 30 秒后拉到配置并启动 xray,节点在面板显示在线。
| | 内存 |
|---|---|
| agent + xray | 约 63MB |
| 完整 3x-ui 面板 | 130–160MB |
| 完整 L-UI 面板 | 130–160MB |
另有路由器主控精简版构建(剥离 xray-core 库,见仓库内 PANEL-LITE-SPEC.md),面向纯控制面部署,内存显著更低。
## 与原版的区别
- 节点不再需要安装完整面板
- 主控是唯一可信源,节点配置全部由主控下发
- 节点在线状态由 agent 心跳维持
- 添加节点支持 Agent 类型,自动生成注册 token
- 添加节点支持 Agent 类型,使用注册 token 接入
## License
+36 -54
View File
@@ -2,18 +2,13 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI** — продвинутая веб-панель управления с открытым исходным кодом для управления серверами [Xray-core](https://github.com/XTLS/Xray-core). Она предоставляет аккуратный многоязычный интерфейс для развёртывания, настройки и мониторинга широкого спектра протоколов прокси и VPN — от одного VPS до развёртываний с несколькими узлами.
@@ -69,31 +64,31 @@
## Быстрый старт
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
Чтобы установить конкретную версию, добавьте её тег (например, `v3.4.0`):
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
Чтобы установить скользящую **dev**-сборку (новейший предварительный релиз по каждому коммиту из ветки `main`, а не стабильный релиз), передайте `dev-latest`:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
Во время установки генерируются случайные имя пользователя, пароль и путь доступа. После установки выполните `x-ui`, чтобы открыть меню управления, где можно запускать/останавливать сервис, просматривать или сбрасывать учётные данные для входа, управлять SSL-сертификатами и многое другое.
Во время установки генерируются случайные имя пользователя, пароль и путь доступа. После установки выполните `l-ui`, чтобы открыть меню управления, где можно запускать/останавливать сервис, просматривать или сбрасывать учётные данные для входа, управлять SSL-сертификатами и многое другое.
Полную документацию смотрите в [вики проекта](https://github.com/MHSanaei/3x-ui/wiki).
Полную документацию смотрите в [вики проекта](https://git.881218.xyz/rogue/l-ui).
### Автоматическая установка
Установщик также работает в **неинтерактивном** режиме для cloud-init.
Задайте `XUI_NONINTERACTIVE=1` (или передайте по конвейеру без TTY), и установка пройдёт от начала до конца
Задайте `LUI_NONINTERACTIVE=1` (или передайте по конвейеру без TTY), и установка пройдёт от начала до конца
без единого запроса: будут сгенерированы случайные учётные данные и записаны в
`/etc/x-ui/install-result.env`. Смотрите [`deploy/`](deploy/) для:
`/etc/l-ui/install-result.env`. Смотрите [`deploy/`](deploy/) для:
- [Cloud-init user-data](deploy/cloud-init/) — автоматическая установка в любом облаке (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Заметки по Hetzner Cloud](deploy/marketplace/hetzner/) — развёртывание на Hetzner на базе cloud-init
@@ -108,29 +103,29 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
3X-UI поддерживает два бэкенда, выбираемых при установке:
- **SQLite** (по умолчанию) — единый файл по пути `/etc/x-ui/x-ui.db`. Без настройки, идеально для небольших и средних развёртываний.
- **SQLite** (по умолчанию) — единый файл по пути `/etc/l-ui/l-ui.db`. Без настройки, идеально для небольших и средних развёртываний.
- **PostgreSQL** — рекомендуется при большом числе клиентов или конфигурациях с несколькими узлами. Установщик может установить PostgreSQL локально за вас или принять DSN к существующему серверу.
Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/x-ui`):
Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Перенос существующей установки SQLite в PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# затем задайте XUI_DB_TYPE и XUI_DB_DSN в /etc/default/x-ui и перезапустите:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# затем задайте LUI_DB_TYPE и LUI_DB_DSN в /etc/default/l-ui и перезапустите:
systemctl restart l-ui
```
Исходный файл SQLite остаётся нетронутым; удалите его вручную после проверки нового бэкенда.
### Docker
Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `XUI_DB_*` в `docker-compose.yml` и запустите с профилем:
Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `LUI_DB_*` в `docker-compose.yml` и запустите с профилем:
```bash
docker compose --profile postgres up -d
@@ -139,29 +134,29 @@ docker compose --profile postgres up -d
Образ включает Fail2ban (включён по умолчанию) для применения **лимитов IP** по каждому клиенту. Fail2ban блокирует нарушителей с помощью `iptables`, что требует возможности `NET_ADMIN`. `docker-compose.yml` уже предоставляет её через `cap_add`; если вы вместо этого запускаете контейнер через `docker run`, добавьте возможности самостоятельно, иначе блокировки будут регистрироваться, но никогда не применяться:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Переменные окружения
| Переменная | Описание | По умолчанию |
| --- | --- | --- |
| `XUI_DB_TYPE` | Бэкенд базы данных: `sqlite` или `postgres` | `sqlite` |
| `XUI_DB_DSN` | Строка подключения PostgreSQL (когда `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` |
| `XUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` |
| `XUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Включить режим отладки | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — |
| `XUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Минимальная задержка между последовательными перезапусками | `5m` |
| `LUI_DB_TYPE` | Бэкенд базы данных: `sqlite` или `postgres` | `sqlite` |
| `LUI_DB_DSN` | Строка подключения PostgreSQL (когда `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` |
| `LUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` |
| `LUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Включить режим отладки | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — |
| `LUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Минимальная задержка между последовательными перезапусками | `5m` |
## Поддерживаемые языки
@@ -184,23 +179,10 @@ English · فارسی · العربية · 中文(简体) · 中文(繁體
## Инструменты сообщества
Инструменты и интеграции, созданные сообществом вокруг 3x-ui.
Инструменты и интеграции, созданные сообществом вокруг L-UI.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Лицензия: **MIT**): _Управление входящими, клиентами, настройками панели и конфигурацией Xray через код с помощью Terraform / OpenTofu._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (Лицензия: **MIT**): _Управление входящими, клиентами, настройками панели и конфигурацией Xray через код с помощью Terraform / OpenTofu._
## Поддержка проекта
**Если этот проект полезен для вас, вы можете поставить ему**:star2:
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
</a>
## Звезды с течением времени
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+36 -54
View File
@@ -2,18 +2,13 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI**, [Xray-core](https://github.com/XTLS/Xray-core) sunucularını yönetmek için geliştirilmiş profesyonel, açık kaynaklı bir web kontrol panelidir. Tek bir sanal sunucudan (VPS) çok düğümlü (multi-node) dağıtımlara kadar çok çeşitli proxy ve VPN protokollerini kurmak, yapılandırmak ve izlemek için temiz, çok dilli bir arayüz sağlar.
@@ -69,31 +64,31 @@ Orijinal X-UI projesinin geliştirilmiş bir çatallaması (fork) olarak inşa e
## Hızlı Başlangıç
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
Belirli bir sürümü kurmak için, etiketini (ör. `v3.4.0`) ekleyin:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
Sürekli güncellenen **dev** sürümünü (kararlı bir sürüm değil; `main` dalından her commit'te oluşturulan en son ön sürüm) kurmak için `dev-latest` değerini geçirin:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
Kurulum sırasında rastgele bir kullanıcı adı, şifre ve erişim yolu oluşturulur. Kurulumdan sonra, hizmeti başlatabileceğiniz/durdurabileceğiniz, giriş bilgilerinizi görüntüleyebileceğiniz veya sıfırlayabileceğiniz, SSL sertifikalarını yönetebileceğiniz ve çok daha fazlasını yapabileceğiniz yönetim menüsünü açmak için terminalde `x-ui` komutunu çalıştırın.
Kurulum sırasında rastgele bir kullanıcı adı, şifre ve erişim yolu oluşturulur. Kurulumdan sonra, hizmeti başlatabileceğiniz/durdurabileceğiniz, giriş bilgilerinizi görüntüleyebileceğiniz veya sıfırlayabileceğiniz, SSL sertifikalarını yönetebileceğiniz ve çok daha fazlasını yapabileceğiniz yönetim menüsünü açmak için terminalde `l-ui` komutunu çalıştırın.
Tam dokümantasyon için lütfen [proje Wiki sayfasını](https://github.com/MHSanaei/3x-ui/wiki) ziyaret edin.
Tam dokümantasyon için lütfen [proje Wiki sayfasını](https://git.881218.xyz/rogue/l-ui) ziyaret edin.
### Etkileşimsiz kurulum
Yükleyici, cloud-init için **etkileşimsiz** olarak da çalışır.
`XUI_NONINTERACTIVE=1` ayarlayın (veya TTY olmadan boru hattına aktarın); kurulum baştan
`LUI_NONINTERACTIVE=1` ayarlayın (veya TTY olmadan boru hattına aktarın); kurulum baştan
sona hiçbir soru sormadan tamamlanır, rastgele kimlik bilgileri oluşturup bunları
`/etc/x-ui/install-result.env` dosyasına yazar. Şunlar için [`deploy/`](deploy/) klasörüne bakın:
`/etc/l-ui/install-result.env` dosyasına yazar. Şunlar için [`deploy/`](deploy/) klasörüne bakın:
- [Cloud-init user-data](deploy/cloud-init/) — herhangi bir bulutta etkileşimsiz kurulum (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Hetzner Cloud notları](deploy/marketplace/hetzner/) — Hetzner üzerinde cloud-init tabanlı dağıtım
@@ -108,29 +103,29 @@ sona hiçbir soru sormadan tamamlanır, rastgele kimlik bilgileri oluşturup bun
3X-UI kurulum sırasında seçilebilecek iki arka uç (backend) destekler:
- **SQLite** (varsayılan) — `/etc/x-ui/x-ui.db` konumunda tek bir dosya. Kurulum gerektirmez, küçük ve orta ölçekli dağıtımlar için idealdir.
- **SQLite** (varsayılan) — `/etc/l-ui/l-ui.db` konumunda tek bir dosya. Kurulum gerektirmez, küçük ve orta ölçekli dağıtımlar için idealdir.
- **PostgreSQL** — Yüksek kullanıcı sayıları veya çoklu düğüm (multi-node) kurulumları için önerilir. Yükleyici sizin için yerel olarak PostgreSQL kurabilir veya mevcut bir sunucuya DSN bağlantısı kabul edebilir.
Çalışma anında veritabanı türü ortam değişkenleri (environment variables) ile seçilir (yükleyici bunları sizin için `/etc/default/x-ui` dosyasına yazar):
Çalışma anında veritabanı türü ortam değişkenleri (environment variables) ile seçilir (yükleyici bunları sizin için `/etc/default/l-ui` dosyasına yazar):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Mevcut bir SQLite Kurulumunu PostgreSQL'e Taşıma
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ardından /etc/default/x-ui içindeki XUI_DB_TYPE ve XUI_DB_DSN değerlerini ayarlayıp yeniden başlatın:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ardından /etc/default/l-ui içindeki LUI_DB_TYPE ve LUI_DB_DSN değerlerini ayarlayıp yeniden başlatın:
systemctl restart l-ui
```
Kaynak SQLite dosyasına dokunulmaz; yeni veritabanının düzgün çalıştığını doğruladıktan sonra eski SQLite dosyasını manuel olarak silebilirsiniz.
### Docker
Varsayılan `docker compose up -d` komutu SQLite kullanmaya devam eder. Birlikte paketlenmiş PostgreSQL servisi ile çalıştırmak için, `docker-compose.yml` dosyasındaki iki `XUI_DB_*` değişken satırının yorumunu kaldırın ve profille başlatın:
Varsayılan `docker compose up -d` komutu SQLite kullanmaya devam eder. Birlikte paketlenmiş PostgreSQL servisi ile çalıştırmak için, `docker-compose.yml` dosyasındaki iki `LUI_DB_*` değişken satırının yorumunu kaldırın ve profille başlatın:
```bash
docker compose --profile postgres up -d
@@ -139,29 +134,29 @@ docker compose --profile postgres up -d
Docker imajı, kullanıcı başına **IP limitlerini** zorunlu kılmak için Fail2ban ile (varsayılan olarak etkindir) paketlenmiştir. Fail2ban, ihlalcileri `iptables` ile engeller ve bunun için `NET_ADMIN` yetkisine ihtiyaç duyar. `docker-compose.yml` bunu zaten `cap_add` üzerinden vermektedir; ancak konteyneri bunun yerine `docker run` ile başlatırsanız bu yetkileri kendiniz eklemelisiniz, aksi takdirde yasaklamalar günlüğe kaydedilir ancak uygulanmaz:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Ortam Değişkenleri (Environment Variables)
| Değişken | Açıklama | Varsayılan |
| --- | --- | --- |
| `XUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `XUI_DB_TYPE=postgres` ise) | — |
| `XUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Maksimum açık bağlantı sayısı (PostgreSQL havuzu) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Maksimum boşta bekleme bağlantısı (PostgreSQL havuzu) | — |
| `XUI_INIT_WEB_BASE_PATH` | Web paneli için başlangıç URI yolu | `/` |
| `XUI_ENABLE_FAIL2BAN` | Fail2ban tabanlı IP limit uygulamasını etkinleştir | `true` |
| `XUI_LOG_LEVEL` | Günlük (Log) ayrıntı seviyesi (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Hata ayıklama (debug) modunu etkinleştir | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Tünel sağlık izleyicisini etkinleştir (bir URL'yi yoklar ve tekrarlanan başarısızlıklardan sonra xray'i yeniden başlatır; yeniden başlatma tüm istemcilerin bağlantısını düşürür) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Yoklamanın gönderildiği proxy; yoklamanın tüneli test etmesi için bunu yerel bir xray gelen bağlantısına yönlendirin (ör. `socks5://127.0.0.1:1080`). Boş bırakılırsa yoklama yalnızca ana makine bağlantısını kontrol eder | — |
| `XUI_TUNNEL_HEALTH_URL` | Tünel sağlığı için yoklanan URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Yoklamalar arasındaki aralık | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Yoklama başına zaman aşımı | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Yeniden başlatma tetiklenmeden önceki ardışık başarısızlık sayısı | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Ardışık yeniden başlatmalar arasındaki minimum gecikme | `5m` |
| `LUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` |
| `LUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `LUI_DB_TYPE=postgres` ise) | — |
| `LUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Maksimum açık bağlantı sayısı (PostgreSQL havuzu) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Maksimum boşta bekleme bağlantısı (PostgreSQL havuzu) | — |
| `LUI_INIT_WEB_BASE_PATH` | Web paneli için başlangıç URI yolu | `/` |
| `LUI_ENABLE_FAIL2BAN` | Fail2ban tabanlı IP limit uygulamasını etkinleştir | `true` |
| `LUI_LOG_LEVEL` | Günlük (Log) ayrıntı seviyesi (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Hata ayıklama (debug) modunu etkinleştir | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Tünel sağlık izleyicisini etkinleştir (bir URL'yi yoklar ve tekrarlanan başarısızlıklardan sonra xray'i yeniden başlatır; yeniden başlatma tüm istemcilerin bağlantısını düşürür) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Yoklamanın gönderildiği proxy; yoklamanın tüneli test etmesi için bunu yerel bir xray gelen bağlantısına yönlendirin (ör. `socks5://127.0.0.1:1080`). Boş bırakılırsa yoklama yalnızca ana makine bağlantısını kontrol eder | — |
| `LUI_TUNNEL_HEALTH_URL` | Tünel sağlığı için yoklanan URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Yoklamalar arasındaki aralık | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Yoklama başına zaman aşımı | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Yeniden başlatma tetiklenmeden önceki ardışık başarısızlık sayısı | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Ardışık yeniden başlatmalar arasındaki minimum gecikme | `5m` |
## Desteklenen Diller
@@ -184,23 +179,10 @@ Katkılarınızı her zaman bekliyoruz. Bir sorun (issue) açmadan veya pull req
## Topluluk Araçları
3x-ui çevresindeki topluluk tarafından oluşturulmuş araçlar ve entegrasyonlar.
L-UI çevresindeki topluluk tarafından oluşturulmuş araçlar ve entegrasyonlar.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Lisans: **MIT**): _Gelen bağlantılarnı, kullanıcıları, panel ayarlarını ve Xray yapılandırmasını Terraform / OpenTofu ile kod olarak (as code) yönetin._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (Lisans: **MIT**): _Gelen bağlantılarnı, kullanıcıları, panel ayarlarını ve Xray yapılandırmasını Terraform / OpenTofu ile kod olarak (as code) yönetin._
## Projeyi Destekleyin
**Eğer bu proje size faydalı olduysa, bir yıldız verebilirsiniz**:star2:
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Bana Bir Kahve Ismarla" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="NOWPayments üzerinden Kripto Bağış Butonu">
</a>
## Yıldız Tablosu
[![Zaman içerisindeki yıldız sayısı](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+37 -54
View File
@@ -2,18 +2,14 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
<p align="center">
<a href="https://github.com/MHSanaei/3x-ui/releases"><img src="https://img.shields.io/github/v/release/mhsanaei/3x-ui" alt="Release"></a>
<a href="https://github.com/MHSanaei/3x-ui/actions"><img src="https://img.shields.io/github/actions/workflow/status/mhsanaei/3x-ui/release.yml.svg" alt="Build"></a>
<a href="#"><img src="https://img.shields.io/github/go-mod/go-version/mhsanaei/3x-ui.svg" alt="GO Version"></a>
<a href="https://github.com/MHSanaei/3x-ui/releases/latest"><img src="https://img.shields.io/github/downloads/mhsanaei/3x-ui/total.svg" alt="Downloads"></a>
<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img src="https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true" alt="License"></a>
<a href="https://pkg.go.dev/github.com/mhsanaei/3x-ui/v3"><img src="https://pkg.go.dev/badge/github.com/mhsanaei/3x-ui/v3.svg" alt="Go Reference"></a>
</p>
**3X-UI** 是一个先进的开源 Web 控制面板,用于管理 [Xray-core](https://github.com/XTLS/Xray-core) 服务器。它提供简洁、多语言的界面,用于部署、配置和监控各种代理与 VPN 协议——从单台 VPS 到多节点部署。
@@ -69,31 +65,31 @@
## 快速开始
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
若要安装特定版本,请在命令后附加对应的标签(例如 `v3.4.0`):
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
# This fork provides no pinned-version one-click install; see the main README (README.md).
```
若要安装滚动更新的 **dev** 版本(来自 `main` 的最新逐次提交预发布版本,而非稳定版本),请传入 `dev-latest`:
```bash
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
安装过程中会生成随机的用户名、密码和访问路径。安装完成后,运行 `x-ui` 打开管理菜单,您可以在其中启动/停止服务、查看或重置登录凭据、管理 SSL 证书等。
安装过程中会生成随机的用户名、密码和访问路径。安装完成后,运行 `l-ui` 打开管理菜单,您可以在其中启动/停止服务、查看或重置登录凭据、管理 SSL 证书等。
完整文档请参阅 [项目Wiki](https://github.com/MHSanaei/3x-ui/wiki)。
完整文档请参阅 [项目Wiki](https://git.881218.xyz/rogue/l-ui)。
### 无人值守安装
安装程序也可以**非交互式**运行,适用于 cloud-init。
设置 `XUI_NONINTERACTIVE=1`(或在无 TTY 的情况下通过管道传入),它就会全程
设置 `LUI_NONINTERACTIVE=1`(或在无 TTY 的情况下通过管道传入),它就会全程
零提示地完成端到端安装,生成随机凭据并写入
`/etc/x-ui/install-result.env`。请参阅 [`deploy/`](deploy/):
`/etc/l-ui/install-result.env`。请参阅 [`deploy/`](deploy/):
- [Cloud-init user-data](deploy/cloud-init/) — 在任意云平台上无人值守安装(Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Hetzner Cloud 说明](deploy/marketplace/hetzner/) — 在 Hetzner 上基于 cloud-init 的部署
@@ -108,29 +104,29 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
3X-UI 支持两种后端,可在安装时选择:
- **SQLite**(默认)— 位于 `/etc/x-ui/x-ui.db` 的单个文件。无需配置,适合中小型部署。
- **SQLite**(默认)— 位于 `/etc/l-ui/l-ui.db` 的单个文件。无需配置,适合中小型部署。
- **PostgreSQL** — 推荐用于大量客户端或多节点设置。安装程序可以为您在本地安装 PostgreSQL,或接受指向现有服务器的 DSN。
运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/x-ui`):
运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### 将现有的 SQLite 安装迁移到 PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# 然后在 /etc/default/x-ui 中设置 XUI_DB_TYPE 和 XUI_DB_DSN 并重启:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# 然后在 /etc/default/l-ui 中设置 LUI_DB_TYPE 和 LUI_DB_DSN 并重启:
systemctl restart l-ui
```
源 SQLite 文件保持不变;在确认新后端正常工作后,请手动删除它。
### Docker
默认的 `docker compose up -d` 仍使用 SQLite。若要使用捆绑的 PostgreSQL 服务运行,请取消注释 `docker-compose.yml` 中的两行 `XUI_DB_*` 环境变量,并使用该 profile 启动:
默认的 `docker compose up -d` 仍使用 SQLite。若要使用捆绑的 PostgreSQL 服务运行,请取消注释 `docker-compose.yml` 中的两行 `LUI_DB_*` 环境变量,并使用该 profile 启动:
```bash
docker compose --profile postgres up -d
@@ -139,29 +135,29 @@ docker compose --profile postgres up -d
该镜像捆绑了 Fail2ban(默认启用),用于强制执行按客户端的 **IP 限制**。Fail2ban 使用 `iptables` 封禁违规者,这需要 `NET_ADMIN` 权限。`docker-compose.yml` 已通过 `cap_add` 授予该权限;如果您改用 `docker run` 启动容器,请自行添加这些权限,否则封禁只会被记录而永远不会生效:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## 环境变量
| 变量 | 说明 | 默认值 |
| --- | --- | --- |
| `XUI_DB_TYPE` | 数据库后端:`sqlite` 或 `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL 连接字符串(当 `XUI_DB_TYPE=postgres` 时) | — |
| `XUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — |
| `XUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — |
| `XUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` |
| `XUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` |
| `XUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` |
| `XUI_DEBUG` | 启用调试模式 | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — |
| `XUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | 两次连续重启之间的最小间隔 | `5m` |
| `LUI_DB_TYPE` | 数据库后端:`sqlite` 或 `postgres` | `sqlite` |
| `LUI_DB_DSN` | PostgreSQL 连接字符串(当 `LUI_DB_TYPE=postgres` 时) | — |
| `LUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — |
| `LUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — |
| `LUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` |
| `LUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` |
| `LUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` |
| `LUI_DEBUG` | 启用调试模式 | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — |
| `LUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | 两次连续重启之间的最小间隔 | `5m` |
## 支持的语言
@@ -184,23 +180,10 @@ English · فارسی · العربية · 中文(简体) · 中文(繁體
## 社区工具
社区围绕 3x-ui 构建的工具和集成。
社区围绕 L-UI 构建的工具和集成。
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (许可证: **MIT**): _使用 Terraform / OpenTofu 通过代码管理入站、客户端、面板设置和 Xray 配置。_
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (许可证: **MIT**): _使用 Terraform / OpenTofu 通过代码管理入站、客户端、面板设置和 Xray 配置。_
## 支持项目
**如果这个项目对您有帮助,您可以给它一个**:star2:
<a href="https://www.buymeacoffee.com/MHSanaei" target="_blank">
<img src="./media/default-yellow.png" alt="Buy Me A Coffee" style="height: 70px !important;width: 277px !important;" >
</a>
</br>
<a href="https://nowpayments.io/donation/hsanaei" target="_blank" rel="noreferrer noopener">
<img src="./media/donation-button-black.svg" alt="Crypto donation button by NOWPayments">
</a>
## 随时间变化的星标数
[![Stargazers over time](https://starchart.cc/MHSanaei/3x-ui.svg?variant=adaptive)](https://starchart.cc/MHSanaei/3x-ui)
+195
View File
@@ -0,0 +1,195 @@
# Renaming: 3x-ui / x-ui → L-UI / l-ui / lui-agent
Base: `8158ced` (panel V2.6.0 / agent A2.5.0). This batch is a pure
rename: **no version bump, no feature change, no production change,
no Gitea change, no release**. Versions stay V2.6.0 / A2.5.0; the
version bump is left to the release step (see Pending below).
## Mapping (exact — do not invent other aliases)
| old | new | where it shows up |
| --- | --- | --- |
| display brand `3x-ui` / `x-ui` | `L-UI` | panel UI, i18n, README, docs |
| panel binary / process | `l-ui` | release asset, `ps`, `/usr/bin/l-ui` (Docker), `l-ui setting …` |
| agent binary / process | `lui-agent` | release asset, `ps`, `lui-agent agent …` |
| install dir | `/usr/local/l-ui` | panel + agent binaries |
| config / state dir | `/etc/l-ui` | `agent.json`, `node_token_key.json`, env files |
| panel DB | `/etc/l-ui/l-ui.db` | driven by `internal/config/name` (`l-ui`) via `GetName()` + `GetDBFolderPath()` — no separate DB-name constant |
| probe DB | `/etc/l-ui/probe.db` | name unchanged, directory moved (`probe/store.go` joins `GetDBFolderPath()`) |
| cert dir | `/etc/l-ui/cert` | panel + subscription share it |
| binary dir | `/usr/local/l-ui/bin` | `DefaultBinFolder`; sing-box live config `config-singbox.json` lives here |
| log dir | `/var/log/l-ui` | panel log, agent log, sing-box log |
| panel service | `l-ui.service` | systemd units `l-ui.service.{debian,arch,rhel}`, OpenRC `l-ui.rc` |
| agent service | `lui-agent.service` | `systemd/lui-agent.service`, OpenRC `openrc/lui-agent` |
| management CLI | `l-ui.sh` | was `x-ui.sh`; Docker copies it to `/usr/bin/l-ui` |
| panel release assets | `l-ui-linux-amd64`, `l-ui-linux-arm64` (+ `.sha256`) | `scripts/release-build.sh`, `selfupdate.AssetName` |
| agent release assets | `lui-agent-linux-amd64`, `lui-agent-linux-arm64` (+ `.sha256`) | `scripts/release-build.sh`, `selfupdate.AgentAssetName` |
| agent version marker | `agent-version.txt` | name unchanged |
| env prefix | `LUI_` | every `XUI_` variable, code + scripts + docs + tests (inventory below) |
| source dir (Linux agent) | `cmd/lui-agent` | was `cmd/xui-agent`; `release-build.sh` builds `./cmd/lui-agent` |
| Gitea repo (PLACEHOLDER) | `rogue/l-ui` | see Pending — **not yet real** |
## Environment variables renamed
Code reads **only** the new `LUI_` prefix. There is no dual-read
fallback in code: an old unit file that still exports `XUI_*` will
silently lose those settings, which is why the migration doc
(`docs/migration-l-ui.md`) has an explicit unit-env translation
table. Old units must be replaced, not edited in place.
Full inventory (from a whole-tree scan; `LUI_DB_*` below is a docs
glob, not a variable):
`LUI_ACCESS_URL`, `LUI_ACME_EMAIL`, `LUI_ACME_HTTP_PORT`,
`LUI_API_TOKEN`, `LUI_B1_OLD_BACKUP`, `LUI_B2_OLD_DB`,
`LUI_BIN_FOLDER`, `LUI_DB_CACHE_MB`, `LUI_DB_DSN`,
`LUI_DB_FOLDER`, `LUI_DB_JOURNAL_MODE`, `LUI_DB_MAX_IDLE_CONNS`,
`LUI_DB_MAX_OPEN_CONNS`, `LUI_DB_MMAP_MB`, `LUI_DB_SYNCHRONOUS`,
`LUI_DB_TYPE`, `LUI_DEBUG`, `LUI_DOMAIN`, `LUI_ENABLE_FAIL2BAN`,
`LUI_GOGC`, `LUI_HOME` (install-agent.sh only), `LUI_INIT_SYSTEM`
(install-agent.sh only), `LUI_INIT_WEB_BASE_PATH`, `LUI_IN_DOCKER`,
`LUI_LOG_FOLDER`, `LUI_LOG_LEVEL`, `LUI_MAIN_FOLDER`,
`LUI_MEMORY_LIMIT`, `LUI_MEMORY_RELEASE_INTERVAL`,
`LUI_NODE_TOKEN_KEY`, `LUI_NODE_TOKEN_KEY_FILE`,
`LUI_NODE_TOKEN_KEY_TEST`, `LUI_NONINTERACTIVE`,
`LUI_ORPHAN_DUMMY`, `LUI_PANEL_PORT`, `LUI_PASSWORD`, `LUI_PORT`,
`LUI_PPROF`, `LUI_RELEASE_BASE_URL`, `LUI_RELEASE_LATEST_URL`,
`LUI_ROOT` (install-agent.sh only), `LUI_SCALE_DB_PATH`,
`LUI_SCALE_SIZES`, `LUI_SCALE_TEST`, `LUI_SELFUPDATE_SYSTEMD`,
`LUI_SERVER_IP`, `LUI_SERVICE`, `LUI_SERVICE_NAME`,
`LUI_SINGBOX_BIN`, `LUI_SKIP_HSTS`, `LUI_SMOKE_VERSION`,
`LUI_SOURCEMAP`, `LUI_SSL_IPV6`, `LUI_SSL_MODE`,
`LUI_TEST_PG_DSN`, `LUI_TUNNEL_HEALTH_COOLDOWN`,
`LUI_TUNNEL_HEALTH_FAILURES`, `LUI_TUNNEL_HEALTH_INTERVAL`,
`LUI_TUNNEL_HEALTH_MONITOR`, `LUI_TUNNEL_HEALTH_PROXY`,
`LUI_TUNNEL_HEALTH_TIMEOUT`, `LUI_TUNNEL_HEALTH_URL`,
`LUI_UPDATE_RUN_ID`, `LUI_UPDATE_STATUS_FILE`, `LUI_UPDATE_TAG`,
`LUI_URL` (install scripts only), `LUI_USERNAME`,
`LUI_WEB_BASE_PATH`.
## sing-box orphan-core check (special re-verification)
The orphan scan (`internal/agent/singbox.go`,
`singboxCmdlineMatchesConfig`) matches a core process by the exact
argv triple `run -c <live config path>`. Both sides use the same
source: the live path is `filepath.Join(config.GetBinFolderPath(),
"config-singbox.json")`, and the agent sets `LUI_BIN_FOLDER` to
`DefaultBinFolder` (`/usr/local/l-ui/bin`) when unset. So the rename
propagates to both the writer and the matcher automatically; there
is no hardcoded old path in `singbox.go`. After migration the only
cores the new agent will reap are cores started with
`/usr/local/l-ui/bin/config-singbox.json` — a core still running
the old `/usr/local/x-ui/bin/config-singbox.json` is **not** matched
and must be killed by the migration step (see migration doc), or it
will hold the inbound ports and the new core will fail to bind.
This is the one place where "rename both sides" is not enough: the
old core has to be stopped, not re-adopted.
## Tianyi update badge (same batch, panel side only)
- Backend: `NodeView.agentOs` (from `AgentNode.ProbeOS`), overlaid
in `annotateAgentTelemetry` ahead of the telemetry early-exit,
like `ProbeOnly`.
- Frontend: both badge sites in `NodeList.tsx` (list column +
detail) now gate on `!isWindowsAgentOS(agentOs)`, where the
helper (in `panel-version.ts`) is a case-insensitive `windows`
prefix test. Empty OS fails open (badge as before).
- Backend: `requestAgentUpdate` refuses Windows rows up front
("not available on Windows … re-running install-agent.ps1")
instead of recording an intent that would only age out. The
one-click action button itself is unchanged; clicking it on a
Windows row now errors clearly.
- Why ProbeOS is reliable: the frozen A2.2.1 Windows agent reports
`probeFacts.os` = `winOSName()` — registry ProductName
("Windows 10", "Windows 11", …) with DisplayVersion appended,
falling back to bare "Windows" — on register and on heartbeat,
and the panel persists it to `probe_os` (pinned by
`TestAgentLegacyWindows221Contract`). No fake version, no
per-node freeze switch, no Windows agent change, no new win asset.
- Tianyi's machine itself is untouched; its agent stays A2.2.1.
## Intentionally kept (not omissions)
- **Go module path `github.com/mhsanaei/3x-ui/v3`** — the upstream
import path. Renaming it would break every import and the
`-ldflags -X` injection paths; it is not user-visible.
- **Upstream mentions** — sentences that name the upstream original
("upstream 3x-ui", "stock 3x-ui", "based on upstream 3x-ui",
`ghcr.io/mhsanaei/3x-ui`, `raw.githubusercontent.com/mhsanaei/3x-ui`)
stay, because that is the upstream project's actual name.
- **Windows agent, frozen** — `cmd/xui-agent-windows/` untouched:
service name `x-ui-agent`, `C:\x-ui\agent.json`, display name
"3x-ui Agent", `x-ui-agent-windows.exe`. The shipped A2.2.1
binary cannot change without a new win release, which this batch
explicitly does not ship. Renaming its source would only make
the source lie about the shipped binary.
- **`install-agent.ps1` untouched** — see Pending.
- **Log filenames `3xui.log`, `3xipl.log`, `3xipl-banned.log` and
the fail2ban jail name `3x-ipl`** — only their directory moves
(`/var/log/l-ui/`). Renaming the files would break external
fail2ban configs beyond the directory move the migration
already requires.
- **Docker Postgres user/DB `xui`** — renaming them would orphan
existing `pgdata` volumes (a fresh empty DB would appear and
the panel would start empty). Service/container names were
renamed (`l-ui`, `l-ui_app`, `l-ui_postgres`); credentials kept.
- **Windows-only DB copy in `internal/config/config.go` `init()`** —
its source is now explicitly `/etc/x-ui/x-ui.db` (the only
pre-rename path left in Go code, as a copy source only). Normal
operation never reads it; operator migration moves the DB by mv.
- **`install-agent.sh` legacy-process kill** — it now kills both
`/usr/local/l-ui/l-ui agent` and `/usr/local/x-ui/x-ui agent`.
The old form is a one-time migration cleanup, not a runtime
dual-path fallback; it can be deleted once old forms are gone.
- **`frontend/src/generated/schemas.ts`** — generated by
`tools/openapigen`, marked DO NOT EDIT. Its three "3x-ui panel"
descriptions come from Go model comments and will refresh on
the next regeneration; hand-editing a generated file would be
overwritten anyway.
- **Tracked test binaries `x-ui-agent-test-amd64`,
`x-ui-master-new-amd64`, `x-ui-with-ui-amd64`** — stale ELF
artifacts committed earlier, not referenced by any script or by
`release-build.sh`, not release assets. Left untouched (not
rebuilt, not renamed); deleting committed binaries is a separate
cleanup decision, not part of this rename.
- **`docs/release.md` version-table examples (V2.4.0 / A2.3.0)** —
pre-existing stale examples, not version constants; left as-is
so this diff stays a rename. The agent-change glob there now
reads `cmd/lui-agent*`, which correctly excludes the frozen
Windows dir (Windows-only changes must not move the agent line).
## Pending / must be decided before any release
1. **Gitea repo spelling (BLOCKER).** `rogue/l-ui` is a placeholder.
The Gitea repo has NOT been renamed in this batch and must not
be assumed renamed. Before any release: user confirms the exact
spelling, then update `internal/selfupdate/selfupdate.go`
(annotated in code), `internal/web/service/panel/panel.go`,
`scripts/release-build.sh`, `install-agent.sh`,
`install-master.sh`, `update.sh`, `install.sh`, `docs/release.md`
and every `rogue/l-ui` URL in the tree to the confirmed spelling.
Until then, the renamed update check points at a repo that does
not exist yet — this branch must not be released as-is.
2. **Version bump.** Panel stays V2.6.0, agent stays A2.5.0 in this
diff. The release step must bump the panel line (and the agent
line only if agent code changed in the release commit) and
`install-agent.sh`'s `RELEASE_BASE`.
3. **`install-agent.ps1` (Windows, frozen, TYYUN only).** Untouched
on purpose: it is pinned to the V2.4.0 release base and
downloads `x-ui-agent-windows-amd64.exe` into `C:\x-ui`.
After the Gitea repo is renamed, that download URL
(`rogue/3x-ui-agent/releases/download/V2.4.0/…`) will 404
unless one of these is chosen: (a) leave ps1 alone and accept
that a future Windows reinstall needs a manual exe (the frozen
line needs no reinstall by design); (b) update only its repo
segment to the confirmed spelling, keeping the V2.4.0 pin and
the old asset name (the V2.4.0 release's assets keep their old
names only if the repo is renamed without re-uploading them —
verify before choosing); (c) unfreeze Windows and ship a new
win asset (out of scope for this batch). Do NOT quietly bump
its pin to a release that has no win asset.
4. **Generated schemas regeneration** — run `tools/openapigen`
at release time so `frontend/src/generated/schemas.ts`
descriptions pick up the L-UI wording.
5. **Tracked test binaries** — decide separately whether to delete
the three stale ELF files from the repo.
+2 -2
View File
@@ -1,6 +1,6 @@
# Review instructions
3x-ui is a Go (Gin + GORM) web panel that generates configuration, share links
L-UI is a Go (Gin + GORM) web panel that generates configuration, share links
and subscriptions for other programs — Xray-core, mihomo, sing-box, mtg-multi —
and is deployed by operators who upgrade in place. Judge findings by what
breaks for those consumers and operators, not by style.
@@ -111,7 +111,7 @@ near-certain about and that actually breaks something:
- "CI passed" is a claim too, and needs the same evidence: say it only of a
run you actually read. A green one proves less here than it looks — only
`postgres-durable-first` runs against PostgreSQL, `go-test` and `race` are
SQLite, and `XRAY_E2E_BINARY` and `XUI_SCALE_TEST` are set by no job, so
SQLite, and `XRAY_E2E_BINARY` and `LUI_SCALE_TEST` are set by no job, so
those tests have never run in CI at all. Where a change touches dialect,
migration or Xray gRPC code that no job exercised, say it is unverified
rather than repeating a green tick as proof.
+2 -2
View File
@@ -5,11 +5,11 @@
Do not open a public issue for anything you believe is exploitable — an
authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation. A public report gives attackers
a head start against every 3x-ui deployment.
a head start against every L-UI deployment.
Instead, use GitHub's private vulnerability reporting: open this
repository's **Security** tab and click **Report a vulnerability**. Include
the affected 3x-ui version, reproduction steps, and the impact you see.
the affected L-UI version, reproduction steps, and the impact you see.
You will receive replies in the advisory thread.
There is no bug-bounty program. Fixes ship in the next release, and the
+4 -2
View File
@@ -125,7 +125,9 @@ func TestBotContextSkipGatesExist(t *testing.T) {
table := section(t, doc, "**What CI does NOT prove.**", "Mutation testing")
// [A-Z0-9_] and not [A-Z_]: XRAY_E2E_BINARY carries a digit, and excluding it
// silently dropped that gate from the check instead of failing.
gates := regexp.MustCompile("`((?:XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(table, -1)
// LUI_ joins XUI_ here because the rename changed the env prefix; the
// old prefix stays so a stray XUI_ gate still gets checked, not ignored.
gates := regexp.MustCompile("`((?:LUI|XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(table, -1)
if len(gates) < 5 {
t.Fatalf("expected at least 5 skip-gate variables in %s, found %d", botContextPath, len(gates))
}
@@ -171,7 +173,7 @@ func TestReviewNamesRealCIJobsAndGates(t *testing.T) {
}
})
}
for _, g := range regexp.MustCompile("`((?:XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(doc, -1) {
for _, g := range regexp.MustCompile("`((?:LUI|XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(doc, -1) {
t.Run(g[1], func(t *testing.T) {
if strings.Contains(ci, g[1]) {
t.Errorf("%s claims %s is never set in CI, but %s sets it", reviewPath, g[1], ciWorkflowPath)
+133
View File
@@ -0,0 +1,133 @@
// Command lui-agent is the standalone Linux build of the L-UI node
// agent (agent/panel split, phase 1). Until the split, nodes ran the
// panel binary under the "agent" subcommand, shipping the whole web
// panel and the embedded frontend to every node. This entry links only
// the agent's own dependency closure (internal/agent plus config,
// logger, selfupdate, xray-api types and a few util leaves), so the node
// artifact is a fraction of the panel binary while remaining a drop-in
// replacement for it:
//
// - invocation is unchanged: service units run
// "lui-agent agent [-config /etc/l-ui/agent.json]" (the bare
// "-config" form is also accepted for manual runs);
// - agent.json, the traffic baseline and the other state files keep
// their names, locations and formats;
// - the wire protocol with the master (register / heartbeat /
// config / traffic / probe-report / update intent) is byte-for-
// byte the internal/agent implementation the dual-mode binary ran.
//
// The agent lifecycle wiring below mirrors main.go's agent branch
// exactly — the same internal/agent package does the work either way,
// and cmd/xui-agent-windows is the Windows sibling of this entry.
package main
import (
"flag"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path/filepath"
"syscall"
"github.com/mhsanaei/3x-ui/v3/internal/agent"
"github.com/mhsanaei/3x-ui/v3/internal/config"
"github.com/mhsanaei/3x-ui/v3/internal/logger"
"github.com/mhsanaei/3x-ui/v3/internal/util/memtuning"
"github.com/op/go-logging"
)
func main() {
args := os.Args[1:]
// Version self-report: the agent's own display version (A-form),
// from the same build-time displayVersion injection the panel
// uses. Kept ahead of the subcommand so it works however the
// binary was invoked.
if len(args) > 0 {
switch args[0] {
case "-v", "--version", "version":
fmt.Println(config.GetAgentDisplayVersion())
return
}
}
// Service units (systemd / OpenRC / procd / nohup fallback in
// install-agent.sh) invoke the binary with the historical "agent"
// subcommand; consume it so those units keep working unchanged.
if len(args) > 0 && args[0] == "agent" {
args = args[1:]
} else if len(args) > 0 && args[0][0] != '-' {
fmt.Fprintf(os.Stderr, "lui-agent: unknown subcommand %q (this binary only runs the node agent)\n", args[0])
os.Exit(2)
}
runAgent(args)
}
// runAgent is main.go's agent branch, verbatim in behaviour: same
// flags, same defaults, same shutdown wiring.
func runAgent(args []string) {
agentCmd := flag.NewFlagSet("agent", flag.ExitOnError)
var configPath string
agentCmd.StringVar(&configPath, "config", "/etc/l-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("LUI_BIN_FOLDER") == "" {
_ = os.Setenv("LUI_BIN_FOLDER", agent.DefaultBinFolder)
}
cfg, err := agent.LoadConfig(configPath)
if err != nil {
log.Fatalf("Failed to load agent config from %s: %v", configPath, err)
}
// The acknowledged traffic baseline persists next to the agent
// config (its state home, e.g. /etc/l-ui), unless the config
// names a path.
if cfg.BaselinePath == "" {
cfg.BaselinePath = filepath.Join(filepath.Dir(configPath), "agent-traffic-baseline.json")
}
// Initialize logger
logger.InitLogger(logging.INFO)
log.Printf("Starting L-UI agent (node: %s)", cfg.NodeName)
// Agent memory profile (ITEM-P3 A1/M5): the same runtime tuning
// family as the panel, with the agent's tighter budget, plus the
// periodic release the panel runs through its job scheduler (the
// agent has no scheduler), plus the panel's LUI_PPROF gate.
for _, line := range memtuning.ApplyAgentMemoryTuning() {
log.Println(line)
}
memtuning.StartPeriodicMemoryRelease()
if os.Getenv("LUI_PPROF") == "true" {
go func() {
log.Println("pprof profiling server listening on 127.0.0.1:6060")
if err := http.ListenAndServe("127.0.0.1:6060", nil); err != nil {
log.Printf("pprof server stopped: %v", err)
}
}()
}
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)
}
}
+270
View File
@@ -0,0 +1,270 @@
//go:build windows
// Command xui-agent-windows is the standalone Windows build of the
// 3x-ui node agent. Windows nodes are probe-only by design: the agent
// reports host facts/metrics and runs latency probes, but no xray or
// sing-box core is ever fetched or started here (the agent core
// machinery stays the master's Linux fleet concern; the local
// agent.json carries "probeOnly": true, written by
// install-agent.ps1).
//
// Usage:
//
// xui-agent-windows.exe [-config C:\x-ui\agent.json] run (service or console)
// xui-agent-windows.exe install [-config <path>] register the service
// xui-agent-windows.exe uninstall remove the service
// xui-agent-windows.exe start | stop control the service
//
// The agent lifecycle wiring (config load, baseline derivation,
// logger init, graceful stop) mirrors main.go's agent branch — the
// same internal/agent package does the work either way.
package main
import (
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
"time"
"github.com/mhsanaei/3x-ui/v3/internal/agent"
"github.com/mhsanaei/3x-ui/v3/internal/logger"
"github.com/op/go-logging"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/mgr"
)
const (
serviceName = "x-ui-agent"
defaultCfgPath = `C:\x-ui\agent.json`
)
func main() {
log.SetPrefix("[x-ui-agent] ")
args := os.Args[1:]
// Management subcommands come first; anything else is a run.
if len(args) > 0 {
switch args[0] {
case "install", "uninstall", "start", "stop":
cfgPath := parseConfigFlag("xui-agent-windows "+args[0], args[1:])
if err := runControl(args[0], cfgPath); err != nil {
log.Fatalf("%s: %v", args[0], err)
}
return
}
}
cfgPath := parseConfigFlag("xui-agent-windows", args)
isService, err := svc.IsWindowsService()
if err != nil {
log.Fatalf("detect service environment: %v", err)
}
if isService {
if err := svc.Run(serviceName, &agentHandler{cfgPath: cfgPath}); err != nil {
log.Fatalf("service run: %v", err)
}
return
}
// Interactive run: console foreground, Ctrl+C stops gracefully.
running, err := startAgent(cfgPath)
if err != nil {
log.Fatalf("start agent: %v", err)
}
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
select {
case <-sigCh:
log.Println("Shutting down agent...")
running.Stop()
<-running.done
case err := <-running.done:
if err != nil {
log.Fatalf("Agent error: %v", err)
}
}
}
func parseConfigFlag(name string, args []string) string {
fs := flag.NewFlagSet(name, flag.ExitOnError)
cfg := fs.String("config", defaultCfgPath, "Path to agent config file")
_ = fs.Parse(args)
return *cfg
}
// runningAgent is one started agent plus its completion signal.
type runningAgent struct {
ag *agent.Agent
done chan error
}
func (r *runningAgent) Stop() { r.ag.Stop() }
// startAgent performs the same setup as main.go's agent branch and
// launches the agent loop in the background.
func startAgent(cfgPath string) (*runningAgent, error) {
// Agent mode uses the panel's directory layout for core binaries
// and configs; on a probe-only Windows node nothing consumes it,
// but keep the wiring identical to the Linux entry so behaviour
// cannot drift between the two.
if os.Getenv("XUI_BIN_FOLDER") == "" {
_ = os.Setenv("XUI_BIN_FOLDER", agent.DefaultBinFolder)
}
cfg, err := agent.LoadConfig(cfgPath)
if err != nil {
return nil, fmt.Errorf("load agent config from %s: %w", cfgPath, err)
}
// The acknowledged traffic baseline persists next to the agent
// config (its state home), unless the config names a path.
if cfg.BaselinePath == "" {
cfg.BaselinePath = filepath.Join(filepath.Dir(cfgPath), "agent-traffic-baseline.json")
}
logger.InitLogger(logging.INFO)
log.Printf("Starting 3x-ui agent (node: %s)", cfg.NodeName)
ag := agent.New(cfg)
r := &runningAgent{ag: ag, done: make(chan error, 1)}
go func() { r.done <- ag.Run() }()
return r, nil
}
// agentHandler adapts the agent loop to the SCM protocol.
type agentHandler struct {
cfgPath string
}
func (h *agentHandler) Execute(_ []string, r <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
const accepted = svc.AcceptStop | svc.AcceptShutdown
status <- svc.Status{State: svc.StartPending}
running, err := startAgent(h.cfgPath)
if err != nil {
log.Printf("start agent: %v", err)
return false, 1
}
status <- svc.Status{State: svc.Running, Accepts: accepted}
for {
select {
case err := <-running.done:
// The agent loop ended on its own (e.g. fatal run error).
if err != nil {
log.Printf("agent exited: %v", err)
return false, 1
}
return false, 0
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
status <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
status <- svc.Status{State: svc.StopPending}
running.Stop()
<-running.done
return false, 0
default:
log.Printf("unexpected service command: %v", c.Cmd)
}
}
}
}
// runControl implements the install/uninstall/start/stop subcommands
// through the service control manager.
func runControl(cmd, cfgPath string) error {
m, err := mgr.ConnectRemote("")
if err != nil {
return fmt.Errorf("connect to service manager: %w", err)
}
defer m.Disconnect()
switch cmd {
case "install":
exePath, err := os.Executable()
if err != nil {
return fmt.Errorf("locate own binary: %w", err)
}
absCfg, err := filepath.Abs(cfgPath)
if err != nil {
return fmt.Errorf("resolve config path: %w", err)
}
if s, err := m.OpenService(serviceName); err == nil {
s.Close()
return fmt.Errorf("service %s already exists (uninstall first)", serviceName)
}
s, err := m.CreateService(serviceName, exePath, mgr.Config{
DisplayName: "3x-ui Agent",
Description: "3x-ui probe-only node agent (facts, metrics and latency probes; runs no proxy core).",
StartType: mgr.StartAutomatic,
ErrorControl: mgr.ErrorNormal,
}, "-config", absCfg)
if err != nil {
return fmt.Errorf("create service: %w", err)
}
defer s.Close()
log.Printf("service %s installed (config: %s)", serviceName, absCfg)
return nil
case "uninstall":
s, err := openService(m)
if err != nil {
return err
}
defer s.Close()
// Stop first so the binary is not locked when the operator
// deletes or replaces it; an already-stopped service is fine.
_, _ = s.Control(svc.Stop)
deadline := time.Now().Add(15 * time.Second)
for time.Now().Before(deadline) {
st, err := s.Query()
if err != nil || st.State == svc.Stopped {
break
}
time.Sleep(300 * time.Millisecond)
}
if err := s.Delete(); err != nil {
return fmt.Errorf("delete service: %w", err)
}
log.Printf("service %s removed", serviceName)
return nil
case "start":
s, err := openService(m)
if err != nil {
return err
}
defer s.Close()
if err := s.Start(); err != nil {
return fmt.Errorf("start service: %w", err)
}
log.Printf("service %s started", serviceName)
return nil
case "stop":
s, err := openService(m)
if err != nil {
return err
}
defer s.Close()
if _, err := s.Control(svc.Stop); err != nil {
return fmt.Errorf("stop service: %w", err)
}
log.Printf("service %s stop requested", serviceName)
return nil
}
return fmt.Errorf("unknown subcommand %q", cmd)
}
func openService(m *mgr.Mgr) (*mgr.Service, error) {
s, err := m.OpenService(serviceName)
if err != nil {
return nil, fmt.Errorf("open service %s: %w", serviceName, err)
}
return s, nil
}
+9 -9
View File
@@ -1,6 +1,6 @@
# Cloud deployment (unattended install)
Tooling to ship the 3x-ui panel via unattended install, with **per-instance
Tooling to ship the L-UI panel via unattended install, with **per-instance
credentials generated on first boot** (never `admin/admin`, never a shared
session secret). Works on amd64 and arm64.
@@ -12,7 +12,7 @@ session secret). Works on amd64 and arm64.
## How it works
`install.sh` runs unattended when `XUI_NONINTERACTIVE=1` or stdin is not a TTY.
`install.sh` runs unattended when `LUI_NONINTERACTIVE=1` or stdin is not a TTY.
Each instance installs and configures itself with random credentials. See
[`cloud-init/README.md`](cloud-init/README.md).
@@ -21,11 +21,11 @@ Each instance installs and configures itself with random credentials. See
`install.sh` reads these env vars in non-interactive mode (all optional; unset ⇒
secure random / default):
`XUI_USERNAME`, `XUI_PASSWORD`, `XUI_PANEL_PORT`, `XUI_WEB_BASE_PATH`,
`XUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `XUI_DOMAIN`,
`XUI_ACME_EMAIL`, `XUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`),
`XUI_SSL_IPV6` (optional IPv6 address to add to an `ip`-mode cert),
`XUI_SERVER_IP` (fallback IP for the displayed access URL when auto-detection fails),
`XUI_DB_TYPE` (`sqlite`|`postgres`), `XUI_DB_DSN`.
`LUI_USERNAME`, `LUI_PASSWORD`, `LUI_PANEL_PORT`, `LUI_WEB_BASE_PATH`,
`LUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `LUI_DOMAIN`,
`LUI_ACME_EMAIL`, `LUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`),
`LUI_SSL_IPV6` (optional IPv6 address to add to an `ip`-mode cert),
`LUI_SERVER_IP` (fallback IP for the displayed access URL when auto-detection fails),
`LUI_DB_TYPE` (`sqlite`|`postgres`), `LUI_DB_DSN`.
The resulting credentials are written to `/etc/x-ui/install-result.env` (mode 600).
The resulting credentials are written to `/etc/l-ui/install-result.env` (mode 600).
+14 -14
View File
@@ -1,6 +1,6 @@
# 3x-ui via cloud-init
# L-UI via cloud-init
A single [`cloud-init.yaml`](cloud-init.yaml) user-data file that installs 3x-ui
A single [`cloud-init.yaml`](cloud-init.yaml) user-data file that installs L-UI
non-interactively on a fresh Ubuntu/Debian VM and generates **unique random
credentials per instance**. It works on any cloud-init platform.
@@ -8,35 +8,35 @@ credentials per instance**. It works on any cloud-init platform.
1. The VM boots a stock Ubuntu/Debian cloud image.
2. cloud-init writes and runs `/opt/xui-bootstrap.sh`, which exports
`XUI_NONINTERACTIVE=1` and pipes the project's `install.sh` into `bash`.
`LUI_NONINTERACTIVE=1` and pipes the project's `install.sh` into `bash`.
3. `install.sh` runs end-to-end with **zero prompts**, picking secure random
values for any credential you didn't pin.
4. The generated credentials are written to `/etc/x-ui/install-result.env`
4. The generated credentials are written to `/etc/l-ui/install-result.env`
(mode 600), echoed to the **serial console**, and appended to `/etc/motd`.
Retrieve them after boot with either:
```bash
sudo cat /etc/x-ui/install-result.env # over SSH
sudo cat /etc/l-ui/install-result.env # over SSH
```
…or read the provider's **serial console** output (handy before you have SSH).
## Customising
Edit the `export XUI_*` lines inside the `write_files` block of
Edit the `export LUI_*` lines inside the `write_files` block of
[`cloud-init.yaml`](cloud-init.yaml). All knobs are optional; unset ⇒ random/secure default.
| Env var | Default | Meaning |
| --- | --- | --- |
| `XUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` |
| `XUI_USERNAME` | random | Admin username |
| `XUI_PASSWORD` | random | Admin password |
| `XUI_PANEL_PORT` | random high port | Panel listen port |
| `XUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) |
| `XUI_DOMAIN` | — | Required when `XUI_SSL_MODE=domain` |
| `XUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) |
| `XUI_DB_TYPE` / `XUI_DB_DSN` | `sqlite` | Set `postgres` + DSN to use PostgreSQL |
| `LUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` |
| `LUI_USERNAME` | random | Admin username |
| `LUI_PASSWORD` | random | Admin password |
| `LUI_PANEL_PORT` | random high port | Panel listen port |
| `LUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) |
| `LUI_DOMAIN` | — | Required when `LUI_SSL_MODE=domain` |
| `LUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) |
| `LUI_DB_TYPE` / `LUI_DB_DSN` | `sqlite` | Set `postgres` + DSN to use PostgreSQL |
> **TLS note:** `none` serves the panel over plain HTTP on a random high port —
> fine behind a reverse proxy or an SSH tunnel, but put TLS in front of it before
+28 -25
View File
@@ -1,17 +1,20 @@
#cloud-config
# ---------------------------------------------------------------------------
# Generic 3x-ui unattended install via cloud-init user-data.
# Generic L-UI unattended install via cloud-init user-data.
#
# Works on any cloud-init platform: Hetzner, AWS, DigitalOcean, Vultr, GCP,
# Azure, Oracle. Paste the whole file as the instance "user data".
#
# It installs the latest 3x-ui release NON-INTERACTIVELY, generating unique
# It installs the latest L-UI release NON-INTERACTIVELY, generating unique
# random credentials per instance. Full credentials are surfaced ONLY on the
# serial console (owner-only); /etc/motd (world-readable) shows just the access
# URL + username. Nothing is baked in advance — every instance is unique.
#
# Requires the non-interactive install.sh (3x-ui with XUI_NONINTERACTIVE support).
# Edit the exported XUI_* knobs in /opt/xui-bootstrap.sh below to customise.
# Fork note (L-UI): the bootstrap below installs this fork's
# install-master.sh from its own Gitea repository. The fork installer does
# NOT consume the LUI_* non-interactive knobs and does NOT write
# /etc/l-ui/install-result.env, so the LUI_* exports and the credential-
# surfacing block below are inert leftovers from the upstream installer.
# ---------------------------------------------------------------------------
package_update: true
@@ -27,46 +30,46 @@ write_files:
export DEBIAN_FRONTEND=noninteractive
# --- Non-interactive install knobs --------------------------------------
export XUI_NONINTERACTIVE=1
export LUI_NONINTERACTIVE=1
# SSL mode: none (plain HTTP, default) | ip | domain
export XUI_SSL_MODE="${XUI_SSL_MODE:-none}"
export LUI_SSL_MODE="${LUI_SSL_MODE:-none}"
# Pin credentials instead of random (leave unset for secure random values):
# export XUI_USERNAME="admin2"
# export XUI_PASSWORD="change-me-please"
# export XUI_PANEL_PORT="2053"
# export XUI_WEB_BASE_PATH="panel"
# export LUI_USERNAME="admin2"
# export LUI_PASSWORD="change-me-please"
# export LUI_PANEL_PORT="2053"
# export LUI_WEB_BASE_PATH="panel"
# Let's Encrypt domain certificate instead of plain HTTP:
# export XUI_SSL_MODE="domain"
# export XUI_DOMAIN="panel.example.com"
# export XUI_ACME_EMAIL="you@example.com"
# export LUI_SSL_MODE="domain"
# export LUI_DOMAIN="panel.example.com"
# export LUI_ACME_EMAIL="you@example.com"
# PostgreSQL instead of SQLite:
# export XUI_DB_TYPE="postgres"
# export XUI_DB_DSN="postgres://user:pass@host:5432/db?sslmode=disable"
# export LUI_DB_TYPE="postgres"
# export LUI_DB_DSN="postgres://user:pass@host:5432/db?sslmode=disable"
# ------------------------------------------------------------------------
curl -fsSL https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh | bash
curl -fsSL https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh | bash
# Surface the generated credentials. Full creds (incl. password + API token)
# go ONLY to the serial console (/dev/console, owner-only). /etc/motd is
# world-readable, so it gets just the access URL + username and a pointer
# to the root-only env file.
if [ -r /etc/x-ui/install-result.env ]; then
if [ -r /etc/l-ui/install-result.env ]; then
{
echo
echo "=== 3x-ui panel credentials (generated on first boot) ==="
cat /etc/x-ui/install-result.env
echo "=== L-UI panel credentials (generated on first boot) ==="
cat /etc/l-ui/install-result.env
echo "========================================================"
echo "Change the password after first login."
} > /dev/console 2>/dev/null || true
# shellcheck disable=SC1091
. /etc/x-ui/install-result.env
. /etc/l-ui/install-result.env
{
echo
echo "=== 3x-ui panel (generated on first boot) ==="
echo "URL: ${XUI_ACCESS_URL:-unknown}"
echo "Username: ${XUI_USERNAME:-unknown}"
echo "Password + API token: sudo cat /etc/x-ui/install-result.env"
echo "=== L-UI panel (generated on first boot) ==="
echo "URL: ${LUI_ACCESS_URL:-unknown}"
echo "Username: ${LUI_USERNAME:-unknown}"
echo "Password + API token: sudo cat /etc/l-ui/install-result.env"
echo "============================================="
echo "Change the password after first login."
} >> /etc/motd 2>/dev/null || true
@@ -75,4 +78,4 @@ write_files:
runcmd:
- [bash, /opt/xui-bootstrap.sh]
final_message: "3x-ui installed — full credentials in /etc/x-ui/install-result.env (sudo); /etc/motd shows the URL + username only."
final_message: "L-UI installed — full credentials in /etc/l-ui/install-result.env (sudo); /etc/motd shows the URL + username only."
+5 -5
View File
@@ -1,13 +1,13 @@
# 3x-ui on Hetzner Cloud
# L-UI on Hetzner Cloud
Hetzner Cloud does **not** have a third-party image marketplace the way AWS does.
Ship 3x-ui via **cloud-init**: each instance installs non-interactively and
Ship L-UI via **cloud-init**: each instance installs non-interactively and
generates unique per-instance credentials (no `admin/admin`, no shared secret).
## cloud-init (no image build)
Use the generic user-data from [`../../cloud-init/`](../../cloud-init/). It installs
3x-ui non-interactively and generates unique per-instance credentials.
L-UI non-interactively and generates unique per-instance credentials.
Web console: **Create Server → Cloud config** → paste
[`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml).
@@ -25,13 +25,13 @@ hcloud server create \
After boot, fetch the generated credentials:
```bash
ssh root@<server-ip> 'cat /etc/x-ui/install-result.env'
ssh root@<server-ip> 'cat /etc/l-ui/install-result.env'
```
## "App"-style listing
Hetzner's curated apps live in the community repo
[`github.com/hetznercloud/apps`](https://github.com/hetznercloud/apps): each app
is essentially a documented cloud-init config plus metadata. To propose 3x-ui as
is essentially a documented cloud-init config plus metadata. To propose L-UI as
a Hetzner app, follow that repo's contribution pattern and base the app's
cloud-config on [`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml).
+31 -31
View File
@@ -3,8 +3,8 @@
# smoke-noninteractive.sh — verify the non-interactive install path.
#
# Runs install.sh inside an Ubuntu container with NO TTY (piped) and
# XUI_NONINTERACTIVE=1, then asserts:
# * /etc/x-ui/install-result.env exists (mode 600) with random, non-default creds
# LUI_NONINTERACTIVE=1, then asserts:
# * /etc/l-ui/install-result.env exists (mode 600) with random, non-default creds
# * the panel reports hasDefaultCredential: false (no admin/admin remains)
# * the panel HTTP server actually serves on the generated port/base path
# * with a [version] argument: the installed binary reports exactly that version
@@ -18,41 +18,41 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
IMAGE="${SMOKE_IMAGE:-ubuntu:24.04}"
XUI_SMOKE_VERSION="${1:-}"
LUI_SMOKE_VERSION="${1:-}"
if ! command -v docker > /dev/null 2>&1; then
echo "ERROR: docker is required for this smoke test." >&2
exit 1
fi
echo "== non-interactive install smoke test (image: $IMAGE, version: ${XUI_SMOKE_VERSION:-latest}) =="
echo "== non-interactive install smoke test (image: $IMAGE, version: ${LUI_SMOKE_VERSION:-latest}) =="
docker run --rm \
-v "${REPO_ROOT}/install.sh:/root/install.sh:ro" \
-e XUI_NONINTERACTIVE=1 \
-e XUI_SSL_MODE=none \
-e XUI_SMOKE_VERSION="$XUI_SMOKE_VERSION" \
-e LUI_NONINTERACTIVE=1 \
-e LUI_SSL_MODE=none \
-e LUI_SMOKE_VERSION="$LUI_SMOKE_VERSION" \
-e DEBIAN_FRONTEND=noninteractive \
"$IMAGE" bash -euo pipefail -c '
apt-get update -qq
apt-get install -y -qq curl tar openssl ca-certificates > /dev/null
echo "--- running install.sh piped (no TTY), version: ${XUI_SMOKE_VERSION:-latest} ---"
echo "--- running install.sh piped (no TTY), version: ${LUI_SMOKE_VERSION:-latest} ---"
# Piping guarantees stdin is not a TTY, exercising the auto non-interactive path.
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else
cat /root/install.sh | bash
fi
echo "--- assertions ---"
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
installed=$(/usr/local/x-ui/x-ui -v)
[ "$installed" = "${XUI_SMOKE_VERSION#v}" ] \
|| { echo "FAIL: installed version $installed, want ${XUI_SMOKE_VERSION#v}"; exit 1; }
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
installed=$(/usr/local/l-ui/l-ui -v)
[ "$installed" = "${LUI_SMOKE_VERSION#v}" ] \
|| { echo "FAIL: installed version $installed, want ${LUI_SMOKE_VERSION#v}"; exit 1; }
fi
RESULT=/etc/x-ui/install-result.env
RESULT=/etc/l-ui/install-result.env
test -f "$RESULT" || { echo "FAIL: $RESULT missing"; exit 1; }
perms=$(stat -c %a "$RESULT")
@@ -60,23 +60,23 @@ docker run --rm \
# shellcheck disable=SC1090
. "$RESULT"
[ -n "${XUI_USERNAME:-}" ] && [ "$XUI_USERNAME" != "admin" ] \
[ -n "${LUI_USERNAME:-}" ] && [ "$LUI_USERNAME" != "admin" ] \
|| { echo "FAIL: username missing or still admin"; exit 1; }
[ -n "${XUI_PASSWORD:-}" ] && [ "$XUI_PASSWORD" != "admin" ] \
[ -n "${LUI_PASSWORD:-}" ] && [ "$LUI_PASSWORD" != "admin" ] \
|| { echo "FAIL: password missing or still admin"; exit 1; }
[ -n "${XUI_PANEL_PORT:-}" ] || { echo "FAIL: port missing"; exit 1; }
[ -n "${LUI_PANEL_PORT:-}" ] || { echo "FAIL: port missing"; exit 1; }
# No default admin in the DB.
/usr/local/x-ui/x-ui setting -show | grep -q "hasDefaultCredential: false" \
/usr/local/l-ui/l-ui setting -show | grep -q "hasDefaultCredential: false" \
|| { echo "FAIL: hasDefaultCredential is not false"; exit 1; }
echo "--- verifying the panel serves HTTP ---"
cd /usr/local/x-ui
./x-ui > /tmp/xui.log 2>&1 &
cd /usr/local/l-ui
./l-ui > /tmp/lui.log 2>&1 &
xpid=$!
for _ in $(seq 1 15); do
code=$(curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1:${XUI_PANEL_PORT}/${XUI_WEB_BASE_PATH}/" 2>/dev/null || true)
"http://127.0.0.1:${LUI_PANEL_PORT}/${LUI_WEB_BASE_PATH}/" 2>/dev/null || true)
case "$code" in 200|301|302|307|308) break ;; esac
sleep 1
done
@@ -84,28 +84,28 @@ docker run --rm \
echo "panel HTTP status: ${code:-none}"
case "${code:-}" in
200|301|302|307|308) : ;;
*) echo "FAIL: panel did not serve (status ${code:-none})"; tail -n 30 /tmp/xui.log; exit 1 ;;
*) echo "FAIL: panel did not serve (status ${code:-none})"; tail -n 30 /tmp/lui.log; exit 1 ;;
esac
echo "--- verifying a second install preserves custom bin/ files ---"
echo "custom-sentinel" > /usr/local/x-ui/bin/geoip_custom.dat
geoip_sum_before=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
echo "custom-sentinel" > /usr/local/l-ui/bin/geoip_custom.dat
geoip_sum_before=$(sha256sum /usr/local/l-ui/bin/geoip.dat | cut -d" " -f1)
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else
cat /root/install.sh | bash
fi
test -f /usr/local/x-ui/bin/geoip_custom.dat \
test -f /usr/local/l-ui/bin/geoip_custom.dat \
|| { echo "FAIL: custom bin/ file did not survive a second install"; exit 1; }
[ "$(cat /usr/local/x-ui/bin/geoip_custom.dat)" = "custom-sentinel" ] \
[ "$(cat /usr/local/l-ui/bin/geoip_custom.dat)" = "custom-sentinel" ] \
|| { echo "FAIL: custom bin/ file content changed across a second install"; exit 1; }
geoip_sum_after=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
geoip_sum_after=$(sha256sum /usr/local/l-ui/bin/geoip.dat | cut -d" " -f1)
[ "$geoip_sum_after" = "$geoip_sum_before" ] \
|| { echo "FAIL: bundled geoip.dat changed across a same-version reinstall"; exit 1; }
echo "SMOKE_PASS: user=$XUI_USERNAME port=$XUI_PANEL_PORT path=$XUI_WEB_BASE_PATH"
echo "SMOKE_PASS: user=$LUI_USERNAME port=$LUI_PANEL_PORT path=$LUI_WEB_BASE_PATH"
'
echo "== non-interactive smoke test PASSED =="
+15 -15
View File
@@ -1,14 +1,14 @@
services:
3xui:
l-ui:
build:
context: .
dockerfile: ./Dockerfile
container_name: 3xui_app
container_name: l-ui_app
# hostname: yourhostname <- optional
# Optional hard memory cap. When set, the panel derives its Go soft limit
# (GOMEMLIMIT, ~90% of this cap) so it GCs before the OOM killer fires.
# mem_limit: 512m
# The bundled Fail2ban (XUI_ENABLE_FAIL2BAN below) enforces the IP limit
# The bundled Fail2ban (LUI_ENABLE_FAIL2BAN below) enforces the IP limit
# with iptables, which needs NET_ADMIN. Without these caps a ban is logged
# and shown in fail2ban status but never actually applied. NET_RAW covers
# ip6tables. If you disable Fail2ban, you can drop cap_add.
@@ -20,39 +20,39 @@ services:
- NET_ADMIN
- NET_RAW
volumes:
- $PWD/db/:/etc/x-ui/
- $PWD/db/:/etc/l-ui/
- $PWD/cert/:/root/cert/
# Persists acme.sh state so certificate auto-renewal survives container
# recreation (the entrypoint re-registers the renewal cron job from it).
- $PWD/acme/:/root/.acme.sh/
environment:
XRAY_VMESS_AEAD_FORCED: "false"
XUI_ENABLE_FAIL2BAN: "true"
LUI_ENABLE_FAIL2BAN: "true"
# Memory tuning. The panel keeps RAM low via GOGC + periodic release; it no
# longer sets a soft limit from total host RAM (no benefit, risks GC thrash).
# XUI_GOGC: "75" # lower = less RAM, slightly more CPU; GOGC env overrides
# XUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables
# LUI_GOGC: "75" # lower = less RAM, slightly more CPU; GOGC env overrides
# LUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables
# Go memory soft limit, only applied from an explicit budget below (or a
# real cgroup/mem_limit cap). Pin it with one of:
# XUI_MEMORY_LIMIT: "400" # in MiB
# LUI_MEMORY_LIMIT: "400" # in MiB
# GOMEMLIMIT: "400MiB" # Go syntax, takes precedence
# XUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling
# XUI_INIT_WEB_BASE_PATH: "/"
# XUI_PORT: "8080"
# LUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling
# LUI_INIT_WEB_BASE_PATH: "/"
# LUI_PORT: "8080"
# To use PostgreSQL instead of the default SQLite, run:
# docker compose --profile postgres up -d
# and uncomment the two lines below.
# XUI_DB_TYPE: "postgres"
# XUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable"
# LUI_DB_TYPE: "postgres"
# LUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable" # postgres user/db kept: renaming them would orphan existing pgdata
tty: true
ports:
# When XUI_PORT is set, publish the same container port (for example "8080:8080").
# When LUI_PORT is set, publish the same container port (for example "8080:8080").
- "2053:2053"
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: 3xui_postgres
container_name: l-ui_postgres
profiles: ["postgres"]
environment:
POSTGRES_USER: xui
+21 -21
View File
@@ -1,13 +1,13 @@
# 3x-ui Agent 模式安装说明
# L-UI Agent 模式安装说明
节点鸡不再跑完整 3x-ui 面板,只跑一个轻量 agent:用 token 向主控注册,
节点鸡不再跑完整 L-UI 面板,只跑一个轻量 agent:用 token 向主控注册,
主控下发完整 xray 配置(含入站、出站、路由规则),agent 写配置并管理 xray 进程,
每 60 秒向主控上报流量/在线数。
## 架构
- 主控:完整 3x-ui(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。
- 节点:`x-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。
- 主控:完整 L-UI(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。
- 节点:`l-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。
- 出站/路由规则只能在主控上建和改(面板是唯一可信源),agent 只管应用下发
的完整配置,不上报本地配置。
@@ -35,24 +35,24 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
## 二、节点安装
```bash
mkdir -p /usr/local/x-ui/bin /etc/x-ui
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放 x-ui 二进制(agent 补丁版,与主控同版本)
cp x-ui /usr/local/x-ui/x-ui && chmod +x /usr/local/x-ui/x-ui
# 1. 放 l-ui 二进制(agent 补丁版,与主控同版本),在节点上改名为 lui-agent(与主控进程区分)
cp l-ui /usr/local/l-ui/lui-agent && chmod +x /usr/local/l-ui/lui-agent
# 2. 放 xray 二进制与 geo 文件(agent 不负责下载,手动放置)
cp xray-linux-amd64 /usr/local/x-ui/bin/xray && chmod +x /usr/local/x-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/x-ui/bin/
cp xray-linux-amd64 /usr/local/l-ui/bin/xray && chmod +x /usr/local/l-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
# 3. 写 agent 配置
cat > /etc/x-ui/agent.json <<'EOF'
cat > /etc/l-ui/agent.json <<'EOF'
{
"master_url": "http://主控内网地址:2053",
"token": "<上一步生成的 token>",
"node_name": "hk-node-1"
}
EOF
chmod 600 /etc/x-ui/agent.json
chmod 600 /etc/l-ui/agent.json
```
说明:
@@ -60,27 +60,27 @@ chmod 600 /etc/x-ui/agent.json
- `master_url` 用 `http://`(内网)或 `https://`(需可信证书;自签证书连不上,
agent 默认校验 TLS)。
- `poll_interval` 可省略,默认 30 秒轮询一次配置。
- 不要在节点上再启动完整面板(`x-ui` 不带 `agent` 参数的模式)。
- 不要在节点上再启动完整面板(`l-ui` 不带 `agent` 参数的模式)。
## 三、启动 agent
systemd(Debian/Ubuntu):
```bash
cp systemd/x-ui-agent.service /etc/systemd/system/
cp systemd/lui-agent.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now x-ui-agent
journalctl -u x-ui-agent -f
systemctl enable --now lui-agent
journalctl -u lui-agent -f
```
OpenWrt(procd):
```bash
cp openrc/x-ui-agent /etc/init.d/x-ui-agent
chmod +x /etc/init.d/x-ui-agent
/etc/init.d/x-ui-agent enable
/etc/init.d/x-ui-agent start
logread -f | grep x-ui-agent
cp openrc/lui-agent /etc/init.d/lui-agent
chmod +x /etc/init.d/lui-agent
/etc/init.d/lui-agent enable
/etc/init.d/lui-agent start
logread -f | grep lui-agent
```
## 四、主控管理该节点的出站与路由规则
@@ -120,6 +120,6 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
|---|---|
| `register failed ... 401` | token 贴错,或 token 没在主控生成 |
| `config fetch failed ... 409` | token 未绑定节点(生成时没传 `node_id`) |
| xray 起不来 | `/usr/local/x-ui/bin/xray` 是否存在可执行;`xray -test -c /usr/local/x-ui/bin/config.json` 看配置报错 |
| xray 起不来 | `/usr/local/l-ui/bin/xray` 是否存在可执行;`xray -test -c /usr/local/l-ui/bin/config.json` 看配置报错 |
| 流量不上报 | xray 的 api 入站端口是否被占用;agent 日志看 `Traffic report failed` |
| 主控连不上 | `master_url` 拼错;https 自签证书改走 `http://` 内网地址 |
+2 -2
View File
@@ -1,6 +1,6 @@
# Contributing to 3x-ui-docs
# Contributing to L-UI-docs
Thanks for helping improve the 3x-ui documentation and product site!
Thanks for helping improve the L-UI documentation and product site!
## Prerequisites
+6 -6
View File
@@ -2,22 +2,22 @@
<a href="https://docs.sanaei.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="public/logo-dark.png" />
<img src="public/logo-light.png" alt="3x-ui" width="180" />
<img src="public/logo-light.png" alt="L-UI" width="180" />
</picture>
</a>
</p>
<h1 align="center">3x-ui Documentation</h1>
<h1 align="center">L-UI Documentation</h1>
<p align="center">
The official documentation and product site for
<a href="https://github.com/MHSanaei/3x-ui"><b>3x-ui</b></a> —
<a href="https://github.com/MHSanaei/L-UI"><b>L-UI</b></a> —
an advanced web panel for managing Xray-core servers.
</p>
<p align="center">
<a href="https://docs.sanaei.dev"><img src="https://img.shields.io/badge/docs-docs.sanaei.dev-22d3ee?style=flat-square" alt="Live site" /></a>
<a href="https://github.com/MHSanaei/3x-ui/actions/workflows/docs-ci.yml"><img src="https://github.com/MHSanaei/3x-ui/actions/workflows/docs-ci.yml/badge.svg" alt="CI" /></a>
<a href="https://github.com/MHSanaei/L-UI/actions/workflows/docs-ci.yml"><img src="https://github.com/MHSanaei/L-UI/actions/workflows/docs-ci.yml/badge.svg" alt="CI" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-GPL--3.0-blue?style=flat-square" alt="License: GPL-3.0" /></a>
<img src="https://img.shields.io/badge/Next.js-16-black?style=flat-square&logo=next.js" alt="Next.js 16" />
<img src="https://img.shields.io/badge/Fumadocs-16-0ea5e9?style=flat-square" alt="Fumadocs 16" />
@@ -31,7 +31,7 @@
## Overview
This directory (`docs/` in the [3x-ui](https://github.com/MHSanaei/3x-ui) monorepo) contains
This directory (`docs/` in the [L-UI](https://github.com/MHSanaei/L-UI) monorepo) contains
the source for [docs.sanaei.dev](https://docs.sanaei.dev) — a static-first documentation and
marketing site built with [Fumadocs](https://fumadocs.dev) on Next.js. It has **no backend,
no database, and no auth**: every page is prerendered and every tool runs entirely in the
@@ -39,7 +39,7 @@ browser.
## What's inside
The documentation walks you through 3x-ui from first install to day-to-day operation:
The documentation walks you through L-UI from first install to day-to-day operation:
- **Getting Started** — installation, first login, and updating or uninstalling the panel.
- **Configuration** — the panel, inbounds, REALITY, transports, clients, subscriptions, and share links.
+1 -1
View File
@@ -2,7 +2,7 @@
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* 3x-ui brand: cyan / turquoise accent (matches the panel logo). */
/* L-UI brand: cyan / turquoise accent (matches the panel logo). */
:root {
--color-fd-primary: hsl(190, 95%, 39%);
--color-fd-primary-foreground: hsl(0, 0%, 100%);
+19 -22
View File
@@ -1,4 +1,4 @@
# 3x-ui — Architecture & Code Map
# L-UI — Architecture & Code Map
> Navigation map for contributors and AI coding agents (referenced from `CLAUDE.md`).
> Goal: jump to the right file in one hop instead of grepping the whole tree.
@@ -13,7 +13,7 @@
## 1. Mental model (the 30-second version)
3x-ui is a **web control panel for [Xray-core](https://github.com/XTLS/Xray-core)**. The Go
L-UI is a **web control panel for [Xray-core](https://github.com/XTLS/Xray-core)**. The Go
backend is the source of truth: it stores inbounds/clients/settings in a DB, renders an
Xray JSON config from that state, supervises the Xray child process, and exposes a REST +
WebSocket API. A React SPA (built by Vite, embedded into the Go binary) is the UI. A second,
@@ -41,7 +41,7 @@ Two key ideas that explain most of the complexity:
1. **The DB → Xray config pipeline.** Inbounds/clients live in the DB. On every change the
backend regenerates the Xray config and applies it — preferring a _hot diff_ (live gRPC
API mutation) over a full process restart. See §5.1.
2. **The Runtime abstraction (multi-node).** A panel can manage remote "nodes" (other 3x-ui
2. **The Runtime abstraction (multi-node).** A panel can manage remote "nodes" (other L-UI
instances). Every state-changing inbound/client operation is dispatched through a
`runtime.Runtime` interface that is either **`Local`** (this box's Xray gRPC API) or
**`Remote`** (HTTPS call to a child node, with `verify`/`skip`/`pin`/`mtls` TLS modes).
@@ -54,7 +54,7 @@ Two key ideas that explain most of the complexity:
**Backend (Go 1.27):**
- Web framework: **Gin** (`gin-gonic/gin`) + sessions (cookie store), gzip.
- ORM: **GORM** with **SQLite** (default) or **PostgreSQL** (`XUI_DB_TYPE=postgres`).
- ORM: **GORM** with **SQLite** (default) or **PostgreSQL** (`LUI_DB_TYPE=postgres`).
- Scheduler: **robfig/cron/v3** (seconds-precision) for all background jobs.
- Xray: **xtls/xray-core** vendored as a library; the panel talks to the running core over
its **gRPC API** and also shells out to manage the process.
@@ -85,7 +85,7 @@ Browser (React, fetch)
→ POST {basePath}/panel/api/...
→ Gin engine (internal/web/web.go: initRouter)
→ middleware chain: SecurityHeaders → MaxBodyBytes (10 MiB; importDB exempt)
→ [DomainValidator, if webDomain set] → gzip → sessions("3x-ui")
→ [DomainValidator, if webDomain set] → gzip → sessions("L-UI")
→ base-path/cache-control context → Localizer
→ API routes add: ConfigEnvelope (zstd + SHA-256) → CSRF
→ Controller (internal/web/controller/*.go) // HTTP concerns only: bind, validate, respond
@@ -120,14 +120,14 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
## 4. Directory map (what lives where)
```
3x-ui/
L-UI/
├── main.go # Entry point: CLI (run / migrate / migrate-db / setting / cert),
│ # bootstrap, signal handling, restart loop
├── go.mod / go.sum # Go deps (module path ends in /v3)
│
├── internal/ # ALL backend Go code (private packages)
│ ├── config/ # Env-var config: paths, DB kind/DSN, log level, version
│ │ # Every XUI_* env var is read here (config.go)
│ │ # Every LUI_* env var is read here (config.go)
│ ├── database/
│ │ ├── db.go # InitDB: connect, AutoMigrate, seeders (~1.4k lines). DB hotspot.
│ │ ├── migrate_data.go # Data migrations (seeders/normalizers beyond AutoMigrate)
@@ -139,7 +139,7 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ ├── pia/ # PIA WireGuard protocol client (auth, signed server list, /addKey)
│ ├── eventbus/ # In-process pub/sub (buffered channel): outbound.down|up,
│ │ # xray.crash, node.down|up, cpu.high, memory.high, login.attempt
│ ├── tunnelmonitor/ # Optional tunnel health probe (XUI_TUNNEL_HEALTH_* env vars):
│ ├── tunnelmonitor/ # Optional tunnel health probe (LUI_TUNNEL_HEALTH_* env vars):
│ │ # HTTP probe (default Cloudflare trace); repeated failures
│ │ # trigger an Xray restart hook. Independent of panel settings.
│ ├── xray/ # Xray-core integration (the proxy engine wrapper)
@@ -163,9 +163,9 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ │ │ ├── node.go # /panel/api/nodes (multi-node management)
│ │ │ ├── host.go # /panel/api/hosts (per-inbound subscription host overrides)
│ │ │ ├── server.go # /panel/api/server (status, xray version, certs, logs, DB import/export)
│ │ │ ├── setting.go # /panel/api/setting (settings + API tokens)
│ │ │ ├── setting.go # /panel/api/setting (settings)
│ │ │ ├── xray_setting.go # /panel/api/xray (raw Xray config editor, WARP/Nord/PIA, geodata)
│ │ │ ├── api.go # /panel/api gateway (token auth, envelope + CSRF wiring)
│ │ │ ├── api.go # /panel/api gateway (envelope + CSRF wiring)
│ │ │ ├── index.go # login/logout/csrf/2FA
│ │ │ ├── spa.go # SPA fallback for /panel UI routes
│ │ │ └── websocket.go # WS upgrade endpoint
@@ -203,12 +203,11 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ │ │ ├── port_conflict.go # Detect inbound port collisions
│ │ │ ├── fallback.go # Xray fallback (SNI/ALPN routing on shared port)
│ │ │ ├── email/ # Email notification service (SMTP)
│ │ │ ├── integration/ # External providers: warp.go, nord.go, pia.go
│ │ │ ├── integration/ # External providers: warp.go
│ │ │ ├── outbound/ # Outbound config service
│ │ │ ├── panel/ # Cross-cutting panel services:
│ │ │ │ ├── panel.go # panel-level helpers
│ │ │ │ ├── user.go # admin user auth (bcrypt)
│ │ │ │ ├── api_token.go # API token CRUD (SHA-256 hashed)
│ │ │ │ └── websocket.go # WS hub / push service
│ │ │ └── tgbot/ # Telegram bot command handlers
│ │ ├── runtime/ # ⭐⭐ The Local/Remote node abstraction (see §5.2)
@@ -281,8 +280,8 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
├── media/ # README images
│
├── Dockerfile / docker-compose.yml / DockerEntrypoint.sh / DockerInit.sh # Container build/run
├── install.sh / update.sh / x-ui.sh # VPS install + management CLI
├── x-ui.service.* / x-ui.rc # systemd units (debian/rhel/arch) + rc script
├── install.sh / update.sh / l-ui.sh # VPS install + management CLI
├── l-ui.service.* / l-ui.rc # systemd units (debian/rhel/arch) + rc script
├── windows_files/ # Windows service support
└── .github/workflows/ # CI: ci.yml, codeql.yml, docker.yml, release.yml, smoke.yml,
# mutation.yml, cleanup_caches.yml, claude-bot.yml
@@ -314,7 +313,7 @@ Restart is debounced via an atomic "need restart" flag (`SetToNeedRestart` /
### 5.2 Runtime abstraction — Local vs Remote (multi-node) ⭐ most important
A "node" (`model.Node`) is another 3x-ui instance this panel controls. Every state-changing
A "node" (`model.Node`) is another L-UI instance this panel controls. Every state-changing
inbound/client operation goes through the `runtime.Runtime` interface so the _same service
code_ works whether the target is the local Xray or a remote node.
@@ -327,7 +326,7 @@ code_ works whether the target is the local Xray or a remote node.
- **TLS modes** (`tls_client.go`, per-node `TlsVerifyMode`):
`verify` (system CAs, default) / `skip` (no validation) / `pin` (leaf cert SHA-256 must
match `PinnedCertSha256`) / `mtls` (master presents a client certificate; node cert checked
against system roots; API token optional). Master-side cert management:
against system roots). Master-side cert management:
`service/node_mtls.go` + `service/setting_mtls.go`.
- **Dispatch:** `manager.go` → `Manager.RuntimeFor(nodeID *int)`; `nil` nodeID → `Local`,
otherwise a cached/lazy-loaded `Remote`. `InvalidateNode(id)` drops a cached remote client.
@@ -431,7 +430,7 @@ notifications instead of importing notification services into producers.
### 5.8 Tunnel health monitor
`internal/tunnelmonitor/` is an optional watchdog configured **only via env vars**
(`XUI_TUNNEL_HEALTH_*`, read in `internal/config/`), deliberately independent of panel
(`LUI_TUNNEL_HEALTH_*`, read in `internal/config/`), deliberately independent of panel
settings so it can be enabled from a systemd `EnvironmentFile` even when the panel is
unreachable. It periodically probes an HTTP URL (default: Cloudflare trace endpoint) through
the tunnel; after N successive failures (default 3) it fires a recovery callback wired to an
@@ -462,7 +461,6 @@ for AutoMigrate in `internal/database/db.go`.
| `OutboundTraffics` | Outbound counters | per outbound tag |
| `OutboundSubscription` | External provider subs | Warp/Nord style |
| `Setting` | Key/value panel settings | everything configurable |
| `ApiToken` | REST API tokens | SHA-256 hash (plaintext shown once) |
| `InboundFallback` | Fallback routing on a shared port | SNI/ALPN/path → dest |
| `HistoryOfSeeders` | Seeder bookkeeping | prevents re-running one-off migrations |
@@ -490,7 +488,6 @@ for AutoMigrate in `internal/database/db.go`.
| **External subscription** import/aggregation | `sub/external_subscription.go`, `sub/external_config.go` | `sub/clash_external.go` |
| **Settings** not saving / defaults | `service/setting.go`, `controller/setting.go` | model `Setting` |
| **Login / 2FA / sessions / CSRF** | `controller/index.go`, `service/panel/user.go`, `middleware/` | `session/` |
| **API tokens** | `service/panel/api_token.go`, `controller/setting.go` | model `ApiToken` |
| **Port conflict** on inbound add | `service/port_conflict.go` | `controller/inbound.go` |
| **Fallbacks** (shared 443, SNI routing) | `service/fallback.go`, `controller/inbound.go` | model `InboundFallback` |
| **Geo category browser** empty / won't open | `xray/geodata/` (`Store`, `reader.go`), `service/geodata.go` | `controller/xray_setting.go` (`/panel/api/xray/geodata/*`), asset dir = `config.GetBinFolderPath()` |
@@ -498,7 +495,7 @@ for AutoMigrate in `internal/database/db.go`.
| **Telegram bot** commands | `service/tgbot/` | `job/stats_notify_job.go` |
| **Email notifications** | `service/email/` | `internal/eventbus/` (consumers) |
| **CPU / memory alerts** not firing | `job/check_cpu_usage.go`, `job/check_memory_usage.go` | `internal/eventbus/`, notifier settings in `service/setting.go` |
| Xray auto-restart on **dead tunnel** | `internal/tunnelmonitor/` | `XUI_TUNNEL_HEALTH_*` in `internal/config/` |
| Xray auto-restart on **dead tunnel** | `internal/tunnelmonitor/` | `LUI_TUNNEL_HEALTH_*` in `internal/config/` |
| **WARP / Nord / PIA** outbound integration | `service/integration/warp.go` / `nord.go` / `pia.go` | `internal/pia/`, `frontend/src/pages/xray/overrides/` |
| **MTProto** proxy issues | `internal/mtproto/manager.go`, `mtproto/process*.go` | `job/mtproto_job.go` |
| **DB migration** / new column | `internal/database/db.go` (AutoMigrate list), `migrate_data.go` | `model/model.go` |
@@ -580,8 +577,8 @@ root → `go build ./...` / `go run main.go`.
## 10. Gotchas & conventions
- **Module path is `.../v3`.** Internal imports use `github.com/mhsanaei/3x-ui/v3/internal/...`.
- **SQLite vs Postgres.** Default is SQLite at `{XUI_DB_FOLDER}/x-ui.db`. Postgres via
`XUI_DB_TYPE=postgres` + `XUI_DB_DSN`. Some SQL paths are dialect-aware (`database/dialect.go`);
- **SQLite vs Postgres.** Default is SQLite at `{LUI_DB_FOLDER}/l-ui.db`. Postgres via
`LUI_DB_TYPE=postgres` + `LUI_DB_DSN`. Some SQL paths are dialect-aware (`database/dialect.go`);
test both when touching raw queries (there are `*_scale_postgres_test.go` suites).
- **`Inbound.Settings` / `StreamSettings` / `Sniffing` are raw JSON strings**, not structured
columns. Parsing/validation happens in services and the `xray` package, not in GORM.
+3 -3
View File
@@ -1,15 +1,15 @@
import { cn } from '@/lib/cn';
// Official 3x-ui logo (media/3x-ui-{light,dark}.png from the upstream repo).
// Official L-UI logo (media/L-UI-{light,dark}.png from the upstream repo).
// Theme-aware via Tailwind's `dark:` variant. Pass a height class (e.g. `h-6`);
// width scales automatically (the artwork is 2:1).
export function Logo({ className }: { className?: string }) {
return (
<>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/logo-light.png" alt="3x-ui" className={cn('w-auto dark:hidden', className)} />
<img src="/logo-light.png" alt="L-UI" className={cn('w-auto dark:hidden', className)} />
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/logo-dark.png" alt="3x-ui" className={cn('hidden w-auto dark:block', className)} />
<img src="/logo-dark.png" alt="L-UI" className={cn('hidden w-auto dark:block', className)} />
</>
);
}
@@ -35,7 +35,7 @@ export function ApiRequestBuilder() {
return (
<ToolFrame
title="API request builder"
description="Build an authenticated cURL command or fetch() snippet for any 3x-ui panel API endpoint under /panel/api/*."
description="Build an authenticated cURL command or fetch() snippet for any L-UI panel API endpoint under /panel/api/*."
onReset={reset}
>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: AmneziaWG
description: Set up an AmneziaWG inbound in 3x-ui — obfuscation parameters, native IPv6, per-client port-forwarding, and routing client traffic through Xray.
description: Set up an AmneziaWG inbound in L-UI — obfuscation parameters, native IPv6, per-client port-forwarding, and routing client traffic through Xray.
icon: Lock
---
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Clients
description: Manage 3x-ui clients — credentials, traffic and expiry limits, IP limits, groups, bulk actions, external links, and online status.
description: Manage L-UI clients — credentials, traffic and expiry limits, IP limits, groups, bulk actions, external links, and online status.
icon: Users
---
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Inbounds & Protocols
description: Create inbounds in 3x-ui — protocols, transports, traffic reset and expiry, and fallbacks that serve multiple protocols on one port.
description: Create inbounds in L-UI — protocols, transports, traffic reset and expiry, and fallbacks that serve multiple protocols on one port.
icon: ArrowDownToLine
---
@@ -75,7 +75,7 @@ The inbound editor accepts these protocols:
Fallbacks let a single TLS port (e.g. `443`) serve more than one protocol — for
example VLESS **and** Trojan — by routing unmatched handshakes to a child
inbound. In 3x-ui, fallbacks are managed in the panel (a master inbound's
inbound. In L-UI, fallbacks are managed in the panel (a master inbound's
**Fallbacks** list) rather than hand-written into JSON.
Fallbacks are available only when the master inbound is:
+4 -4
View File
@@ -1,6 +1,6 @@
---
title: Panel Settings
description: Every 3x-ui panel setting — web server, TLS, display, security, and notifications — with defaults from the source.
description: Every L-UI panel setting — web server, TLS, display, security, and notifications — with defaults from the source.
icon: SlidersHorizontal
---
@@ -14,7 +14,7 @@ browser in full.
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | Panel port (1–65535). The `XUI_PORT` env var overrides it at runtime. |
| `webPort` | `2053` | Panel port (1–65535). The `LUI_PORT` env var overrides it at runtime. |
| `webListen` | _(all interfaces)_ | Bind the panel to a specific IP. |
| `webBasePath` | `/` | URL path the panel is served under (always normalized to `/…/`). |
| `webCertFile` / `webKeyFile` | _(none)_ | TLS certificate + key. When both are set, the panel serves **HTTPS**. |
@@ -24,12 +24,12 @@ browser in full.
After changing the port or base path, the panel URL becomes
`http(s)://<server>:<port><web-base-path>`. You can preset the base path on first
launch with [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
launch with [`LUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
### TLS
Serving the panel over HTTPS protects your credentials in transit. Either set
`webCertFile` + `webKeyFile` — the [`x-ui` SSL menu](/docs/config/ssl-certificates)
`webCertFile` + `webKeyFile` — the [`l-ui` SSL menu](/docs/config/ssl-certificates)
can obtain a Let's Encrypt certificate for you — or terminate TLS at a
[reverse proxy](/docs/operations/reverse-proxy).
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: REALITY
description: Set up a VLESS + REALITY inbound with XTLS-Vision in 3x-ui — keys, short IDs, SNI, fingerprints, and common pitfalls.
description: Set up a VLESS + REALITY inbound with XTLS-Vision in L-UI — keys, short IDs, SNI, fingerprints, and common pitfalls.
icon: ShieldCheck
---
@@ -15,7 +15,7 @@ REALITY is used with **VLESS** (and Trojan). The recommended flow is
## Key settings
When you choose **REALITY** as the security mode on a VLESS inbound, 3x-ui
When you choose **REALITY** as the security mode on a VLESS inbound, L-UI
exposes these fields:
| Field | What it is |
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: Share Links
description: 3x-ui share-link formats (vless, vmess, trojan, ss, hysteria2, mtproto), the remark template variables, and an in-browser link inspector.
description: L-UI share-link formats (vless, vmess, trojan, ss, hysteria2, mtproto), the remark template variables, and an in-browser link inspector.
icon: Link
---
3x-ui generates a **share link** (and QR code) for each client. Client apps such
L-UI generates a **share link** (and QR code) for each client. Client apps such
as v2rayNG, Hiddify, and Mihomo import these links to configure themselves.
## Link formats
@@ -1,6 +1,6 @@
---
title: SSL Certificates
description: Get and renew TLS certificates for the 3x-ui panel and inbounds — with the x-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot.
description: Get and renew TLS certificates for the L-UI panel and inbounds — with the l-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot.
icon: ShieldCheck
---
@@ -8,7 +8,7 @@ A TLS certificate lets you serve the **panel** over HTTPS (so your login and API
traffic are encrypted) and terminate TLS on **inbounds** (VLESS-TLS, Trojan,
Shadowsocks-TLS, and friends). There are three ways to obtain one:
- **The `x-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
- **The `l-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
client. Easiest for a single domain or a bare IP.
- **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or
when port 80 is blocked / the server sits behind Cloudflare's proxy.
@@ -22,9 +22,9 @@ Shadowsocks-TLS, and friends). There are three ways to obtain one:
inbounds.
</Callout>
## The `x-ui` SSL menu (Let's Encrypt)
## The `l-ui` SSL menu (Let's Encrypt)
Run `x-ui` and choose **`20` — SSL Certificate Management**. It drives
Run `l-ui` and choose **`20` — SSL Certificate Management**. It drives
[acme.sh](https://github.com/acmesh-official/acme.sh) and offers:
| Option | What it does |
@@ -58,7 +58,7 @@ use. Stop anything bound to it for the duration, and allow it through the
<Step>
### Run the issuer
`x-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests
`l-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests
the certificate and saves it under `/root/cert/<domain>/` as `fullchain.pem`
(the certificate chain) and `privkey.pem` (the private key).
</Step>
@@ -105,7 +105,7 @@ it. Copy the token — it's shown only once.
<Step>
### Run the Cloudflare issuer
`x-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an
`l-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an
API token (the default) or **`g`** for the Global API Key, then enter your
domain (and, for the Global API Key, your account email and key). acme.sh creates
the TXT record, validates, and cleans it up.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Subscription
description: Run the 3x-ui subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
description: Run the L-UI subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
icon: Rss
---
@@ -58,7 +58,7 @@ page instead of the raw body.
The **Base64** body is just the newline-joined share links, standard-base64
encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a
complete Xray client config — a fixed skeleton (local mixed/HTTP inbounds, DNS,
routing, policy) plus a `proxy` outbound pointing at the inbound. 3x-ui emits a
routing, policy) plus a `proxy` outbound pointing at the inbound. L-UI emits a
**single config object for one client and an array for several**, uses the flat
outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips
`sockopt` from `streamSettings`.
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Transports & Security
description: Every transport 3x-ui exposes — TCP, mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, Hysteria — with their settings, plus FinalMask obfuscation, sockopt, TLS/REALITY, XTLS-Vision, and VLESS encryption.
description: Every transport L-UI exposes — TCP, mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, Hysteria — with their settings, plus FinalMask obfuscation, sockopt, TLS/REALITY, XTLS-Vision, and VLESS encryption.
icon: Network
---
+16 -16
View File
@@ -1,6 +1,6 @@
---
title: First Login
description: Find your generated 3x-ui credentials, reach the panel, enable two-factor auth, and harden it before exposing anything.
description: Find your generated L-UI credentials, reach the panel, enable two-factor auth, and harden it before exposing anything.
icon: KeyRound
---
@@ -24,25 +24,25 @@ path, so check your actual values.
A script install prints a credential summary when it finishes and also writes it
to a root-only file:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```bash title="/etc/l-ui/install-result.env (mode 600)"
LUI_USERNAME=...
LUI_PASSWORD=...
LUI_PANEL_PORT=...
LUI_WEB_BASE_PATH=...
LUI_ACCESS_URL=...
LUI_API_TOKEN=...
LUI_DB_TYPE=sqlite
```
If you missed them, use the management tools:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
l-ui # menu → 11 (View Current Settings)
l-ui settings # or the one-shot form
```
For **Docker**, read the generated credentials from the container logs, or run
`docker exec -it <container> x-ui setting -show`.
`docker exec -it <container> l-ui setting -show`.
<Callout type="warn">
If your panel still uses the default `admin` / `admin` (the panel warns when it
@@ -53,7 +53,7 @@ For **Docker**, read the generated credentials from the container logs, or run
A non-default port and a long, random **web base path** make the panel much
harder to find. Change them from **Panel Settings** in the UI, or from the
`x-ui` menu:
`l-ui` menu:
- **7 — Reset Username & Password** (optionally disabling 2FA at the same time)
- **8 — Reset Web Base Path** (randomizes it)
@@ -64,11 +64,11 @@ two-factor auth was on, disables it.
## Two-factor authentication (2FA)
3x-ui supports TOTP two-factor auth (compatible with Google Authenticator, Aegis,
L-UI supports TOTP two-factor auth (compatible with Google Authenticator, Aegis,
etc.). Enable it in **Panel Settings** — once enabled, the login page asks for a
6-digit code in addition to your password, and turning it on forces everyone to
log in again. You can disable it from the menu's **Reset Username & Password**
step or with `x-ui setting -resetTwoFactor`.
step or with `l-ui setting -resetTwoFactor`.
## Built-in login protection
@@ -105,7 +105,7 @@ Turn on 2FA so a leaked password alone can't grant access.
<Step>
### Put the panel behind TLS
Use a valid certificate (via the `x-ui` menu's SSL management, or a reverse
Use a valid certificate (via the `l-ui` menu's SSL management, or a reverse
proxy) so the panel is only reachable over HTTPS.
</Step>
+6 -6
View File
@@ -1,10 +1,10 @@
---
title: Meet 3x-ui
title: Meet L-UI
description: A web panel for Xray-core — manage inbounds, protocols, clients, and subscriptions from your browser instead of editing JSON by hand.
icon: Info
---
**3x-ui** is a web control panel that sits on top of
**L-UI** is a web control panel that sits on top of
[Xray-core](https://github.com/XTLS/Xray-core), the proxy engine that actually
moves your traffic. Instead of writing and reloading Xray's JSON configuration
by hand, you manage everything — inbounds, protocols, clients, certificates,
@@ -15,7 +15,7 @@ subscriptions — from a browser dashboard.
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Admin["Admin browser"] -->|HTTPS panel| Panel["L-UI panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -52,18 +52,18 @@ flowchart LR
| Database | SQLite (default) or PostgreSQL |
| Proxy engine | Xray-core (bundled and managed by the panel) |
The default SQLite database lives at `/etc/x-ui/x-ui.db`, and the panel listens
The default SQLite database lives at `/etc/l-ui/l-ui.db`, and the panel listens
on port **2053** by default. Both are configurable — see
[First login](/docs/guide/first-login) and the environment variable reference.
## Who it's for
3x-ui is aimed at anyone running their own Xray server: from a single personal
L-UI is aimed at anyone running their own Xray server: from a single personal
VPS to operators managing many nodes and clients. If you want the power of
Xray-core without living in JSON config files, this is for you.
<Callout type="info">
3x-ui is an enhanced fork of the original X-UI project, adding broader protocol
L-UI is an enhanced fork of the original X-UI project, adding broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, and many quality-of-life features.
</Callout>
+18 -18
View File
@@ -1,17 +1,17 @@
---
title: Installation
description: Install 3x-ui via the official script (stable, pinned, or dev-latest), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
description: Install L-UI via the official script (stable, pinned, or dev-latest), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
icon: Download
---
3x-ui runs on a wide range of Linux distributions — Ubuntu, Debian, Armbian,
L-UI runs on a wide range of Linux distributions — Ubuntu, Debian, Armbian,
Fedora, CentOS, RHEL, AlmaLinux, Rocky Linux, Oracle Linux, Amazon Linux,
Virtuozzo, Arch, Manjaro, openSUSE (Tumbleweed/Leap), Alpine — and Windows,
across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`.
<Callout type="warn">
Run the script installer as **root** (or with `sudo`). It installs a service,
sets up the `x-ui` management command, and enables the panel on boot.
sets up the `l-ui` management command, and enables the panel on boot.
</Callout>
<Tabs items={['Script', 'Docker', 'Manual']}>
@@ -20,7 +20,7 @@ across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`.
The official script is the recommended path. During installation it generates a
**random** username, password, and access (web base) path, sets up the service,
and installs the `x-ui` management command.
and installs the `l-ui` management command.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
@@ -39,8 +39,8 @@ Install the rolling **dev** build (the latest per-commit pre-release from `main`
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
When it finishes, note the printed login details and run `x-ui` to open the
[management menu](/docs/guide/update-uninstall#the-x-ui-management-menu), then
When it finishes, note the printed login details and run `l-ui` to open the
[management menu](/docs/guide/update-uninstall#the-l-ui-management-menu), then
continue to [First login](/docs/guide/first-login).
</Tab>
@@ -54,7 +54,7 @@ The default Compose setup uses SQLite. Clone the repo (or copy its
docker compose up -d
```
To run with the bundled **PostgreSQL** service, uncomment the two `XUI_DB_*`
To run with the bundled **PostgreSQL** service, uncomment the two `LUI_DB_*`
lines in `docker-compose.yml` and start with the profile:
```bash
@@ -70,16 +70,16 @@ otherwise bans are logged but never applied:
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-e LUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/l-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
--name L-UI \
ghcr.io/mhsanaei/3x-ui:latest
```
The `db/` volume holds the SQLite database (`/etc/x-ui/x-ui.db`) and `cert/`
The `db/` volume holds the SQLite database (`/etc/l-ui/l-ui.db`) and `cert/`
holds TLS certificates, so your data survives upgrades.
</Tab>
@@ -87,7 +87,7 @@ holds TLS certificates, so your data survives upgrades.
<Tab value="Manual">
For advanced users, download a release archive for your architecture from the
[releases page](https://github.com/MHSanaei/3x-ui/releases), extract it, and run
[releases page](https://github.com/MHSanaei/L-UI/releases), extract it, and run
the binary as a systemd service. The install script automates exactly these
steps, so it's preferred unless you have a specific reason to install by hand.
@@ -105,7 +105,7 @@ Tailor the command to your setup:
You pick the storage backend at install time:
- **SQLite** (default) — a single file at `/etc/x-ui/x-ui.db`. Zero setup.
- **SQLite** (default) — a single file at `/etc/l-ui/l-ui.db`. Zero setup.
- **PostgreSQL** — for high client counts or multi-node setups. The installer
can install it locally or use a DSN you provide.
@@ -115,15 +115,15 @@ migration.
## Unattended / cloud-init
The installer also runs **non-interactively** for automation. Set
`XUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero
`LUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero
prompts, generating random credentials and writing them to
`/etc/x-ui/install-result.env`:
`/etc/l-ui/install-result.env`:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
LUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
The repo's [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy)
The repo's [`deploy/`](https://github.com/MHSanaei/L-UI/tree/main/deploy)
directory has ready-made **cloud-init** user-data for unattended installs on any
cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
@@ -138,7 +138,7 @@ cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
<Card
title="Update & uninstall"
href="/docs/guide/update-uninstall"
description="The x-ui menu, updates, and removal."
description="The l-ui menu, updates, and removal."
/>
<Card
title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
---
title: Update & Uninstall
description: Manage 3x-ui with the x-ui menu and CLI — update (stable, dev, or legacy), change settings, and uninstall cleanly.
description: Manage L-UI with the l-ui menu and CLI — update (stable, dev, or legacy), change settings, and uninstall cleanly.
icon: RefreshCw
---
After a script install, the `x-ui` command is your control center. Run it with
After a script install, the `l-ui` command is your control center. Run it with
no arguments for the interactive menu, or pass a subcommand for a one-shot action.
```bash
x-ui
l-ui
```
## The `x-ui` management menu
## The `l-ui` management menu
The menu (items `0`–`28`) shows the panel/Xray status at the top, then:
@@ -20,9 +20,9 @@ The menu (items `0`–`28`) shows the panel/Xray status at the top, then:
| 1 | Install | (Re)install from the remote script |
| 2 | Update | Update to the latest **stable** release |
| 3 | Update to Dev Channel (latest commit) | Update to the rolling `dev-latest` build |
| 4 | Update Menu | Update just the `x-ui` menu script |
| 4 | Update Menu | Update just the `l-ui` menu script |
| 5 | Legacy Version | Install a specific older version (prompts for a tag) |
| 6 | Uninstall | Remove 3x-ui (see below) |
| 6 | Uninstall | Remove L-UI (see below) |
| 7 | Reset Username & Password | Set new credentials; optionally disable 2FA |
| 8 | Reset Web Base Path | Randomize the web base path |
| 9 | Reset Settings | Reset panel settings (your account is preserved) |
@@ -51,29 +51,29 @@ Some of these have their own pages: [SSL certificates](/docs/config/ssl-certific
## CLI subcommands
For scripts and quick actions, `x-ui` also takes a subcommand directly:
For scripts and quick actions, `l-ui` also takes a subcommand directly:
| Command | Action |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | Control the service |
| `x-ui restart-xray` | Reload only Xray-core |
| `x-ui status` | Show status |
| `x-ui settings` | Show current settings |
| `x-ui enable` / `disable` | Toggle autostart on boot |
| `x-ui log` | Tail the debug log |
| `x-ui banlog` | Show Fail2ban ban log |
| `x-ui update` | Update to the latest stable release |
| `x-ui update-dev` | Update to the rolling `dev-latest` build |
| `x-ui legacy` | Install a specific older version (prompts) |
| `x-ui update-all-geofiles` | Update all geo files, restart if changed |
| `x-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `x-ui install` / `uninstall` | Install / uninstall |
| `l-ui start` / `stop` / `restart` | Control the service |
| `l-ui restart-xray` | Reload only Xray-core |
| `l-ui status` | Show status |
| `l-ui settings` | Show current settings |
| `l-ui enable` / `disable` | Toggle autostart on boot |
| `l-ui log` | Tail the debug log |
| `l-ui banlog` | Show Fail2ban ban log |
| `l-ui update` | Update to the latest stable release |
| `l-ui update-dev` | Update to the rolling `dev-latest` build |
| `l-ui legacy` | Install a specific older version (prompts) |
| `l-ui update-all-geofiles` | Update all geo files, restart if changed |
| `l-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `l-ui install` / `uninstall` | Install / uninstall |
## Updating
- **Stable:** menu option **2** or `x-ui update`. Re-running the install script
- **Stable:** menu option **2** or `l-ui update`. Re-running the install script
also updates in place.
- **Dev channel:** menu option **3** or `x-ui update-dev` — the rolling
- **Dev channel:** menu option **3** or `l-ui update-dev` — the rolling
`dev-latest` per-commit build (not a stable release).
- **A specific older version:** menu option **5** (Legacy Version).
@@ -83,17 +83,17 @@ Updating preserves your database and settings. Take a
<Callout type="info">
Docker users update differently — pull the new image and recreate the
container (`docker compose pull && docker compose up -d`) rather than using the
`x-ui` update commands.
`l-ui` update commands.
</Callout>
## Uninstalling
Menu option **6** or `x-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/x-ui/` and the install folder. If the panel
Menu option **6** or `l-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/l-ui/` and the install folder. If the panel
used a locally-installed PostgreSQL, it offers to purge that too (a separate,
irreversible confirmation).
<Callout type="warn">
Uninstalling removes the database (`/etc/x-ui/x-ui.db`) and your configuration.
Uninstalling removes the database (`/etc/l-ui/l-ui.db`) and your configuration.
[Back up](/docs/operations/backup-restore) first if you might need it.
</Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
---
title: Contributing
description: How to contribute to 3x-ui and to translate this documentation.
description: How to contribute to L-UI and to translate this documentation.
icon: GitPullRequestArrow
---
3x-ui is community-driven. Contributions to the panel and to these docs are
L-UI is community-driven. Contributions to the panel and to these docs are
welcome.
## Support the developer
3x-ui is free and open source, built and maintained in the open. If it's useful
L-UI is free and open source, built and maintained in the open. If it's useful
to you, consider supporting continued development:
- **Donate** at [donate.sanaei.dev](https://donate.sanaei.dev/) — the page shows
current funding **goals and targets** you can help reach.
- **Star** the [repository](https://github.com/MHSanaei/3x-ui) and share the
- **Star** the [repository](https://github.com/MHSanaei/L-UI) and share the
project.
- **Join** the Telegram channel [@XrayUI](https://t.me/XrayUI) to follow news and
help others.
## Contribute to 3x-ui
## Contribute to L-UI
- Read the project's `CONTRIBUTING.md` in the
[repository](https://github.com/MHSanaei/3x-ui).
[repository](https://github.com/MHSanaei/L-UI).
- Open issues for bugs and feature requests with clear reproduction steps.
- Use Conventional Commits and keep pull requests focused.
+9 -9
View File
@@ -1,13 +1,13 @@
---
title: FAQ
description: Frequently asked questions about 3x-ui — licensing, supported systems, databases, and clients.
description: Frequently asked questions about L-UI — licensing, supported systems, databases, and clients.
icon: CircleQuestionMark
---
## Is 3x-ui free and open source?
## Is L-UI free and open source?
Yes. 3x-ui is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/3x-ui).
Yes. L-UI is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/L-UI).
## What systems does it run on?
@@ -18,7 +18,7 @@ It also runs as a Docker container. See [Installation](/docs/guide/installation)
## SQLite or PostgreSQL?
SQLite is the default and is fine for most deployments. PostgreSQL is available
for larger setups via `XUI_DB_TYPE=postgres` and `XUI_DB_DSN` — see the
for larger setups via `LUI_DB_TYPE=postgres` and `LUI_DB_DSN` — see the
[environment variables](/docs/reference/env-vars).
## Which client apps work with it?
@@ -27,9 +27,9 @@ Any Xray-compatible client — for example v2rayNG, Hiddify, and Clash/Mihomo.
Import a client's share link or QR code, or use a
[subscription](/docs/config/subscription).
## How is 3x-ui different from x-ui?
## How is L-UI different from l-ui?
3x-ui is an enhanced fork of the original X-UI project. It adds broader protocol
L-UI is an enhanced fork of the original X-UI project. It adds broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, a 13-language UI, and many quality-of-life features.
@@ -37,11 +37,11 @@ management, a 13-language UI, and many quality-of-life features.
Re-run the install script (it updates in place), or pull the new Docker image.
See [Installation](/docs/guide/installation) and the
[releases page](https://github.com/MHSanaei/3x-ui/releases).
[releases page](https://github.com/MHSanaei/L-UI/releases).
## Where can I get help?
Join the official Telegram channel [@XrayUI](https://t.me/XrayUI) for
announcements and community support, or open an issue on
[GitHub](https://github.com/MHSanaei/3x-ui/issues). For common problems, start
[GitHub](https://github.com/MHSanaei/L-UI/issues). For common problems, start
with [Troubleshooting](/docs/help/troubleshooting).
+8 -8
View File
@@ -1,6 +1,6 @@
---
title: Migration
description: Migrate to 3x-ui from x-ui, between servers, or between 3x-ui versions.
description: Migrate to L-UI from l-ui, between servers, or between L-UI versions.
icon: ArrowRightLeft
---
@@ -13,12 +13,12 @@ Moving to a new server is a database move:
<Step>
### Back up the old server
Copy the database (default `/etc/x-ui/x-ui.db`) and your certificates. See
Copy the database (default `/etc/l-ui/l-ui.db`) and your certificates. See
[Backup & restore](/docs/operations/backup-restore).
</Step>
<Step>
### Install 3x-ui on the new server
### Install L-UI on the new server
Use the same install method and a compatible version. See
[Installation](/docs/guide/installation).
@@ -33,17 +33,17 @@ panel. Update any IP/domain-specific settings.
</Steps>
## Between 3x-ui versions
## Between L-UI versions
Within the same backend, upgrading is usually just re-running the installer or
pulling a new image — the panel migrates its own database. Across **major**
versions, read the [release notes](https://github.com/MHSanaei/3x-ui/releases)
versions, read the [release notes](https://github.com/MHSanaei/L-UI/releases)
first and take a backup.
## From x-ui
## From l-ui
Importing an older x-ui panel's database directly into 3x-ui is **not
supported** — the schemas differ. Install 3x-ui fresh and recreate
Importing an older l-ui panel's database directly into L-UI is **not
supported** — the schemas differ. Install L-UI fresh and recreate
inbounds/clients, exporting share links from the old panel as you go.
<Callout type="warn">
@@ -1,17 +1,17 @@
---
title: Troubleshooting
description: Fix common 3x-ui problems — the panel won't start, 502 errors, certificate issues, and clients that can't connect.
description: Fix common L-UI problems — the panel won't start, 502 errors, certificate issues, and clients that can't connect.
icon: Wrench
---
A checklist for the most common issues. When in doubt, raise the log level
(`XUI_LOG_LEVEL=debug`) and check the panel and Xray logs.
(`LUI_LOG_LEVEL=debug`) and check the panel and Xray logs.
## The panel won't start
- Check the service status and logs (`x-ui` menu → status/logs).
- Check the service status and logs (`l-ui` menu → status/logs).
- Make sure the **panel port isn't already in use** by another service.
- Verify the database path is writable (default `/etc/x-ui/x-ui.db`).
- Verify the database path is writable (default `/etc/l-ui/l-ui.db`).
## 502 / panel unreachable behind a proxy
@@ -37,6 +37,6 @@ A checklist for the most common issues. When in doubt, raise the log level
<Callout type="info">
Still stuck? Search the
[GitHub issues](https://github.com/MHSanaei/3x-ui/issues) — your symptom has
[GitHub issues](https://github.com/MHSanaei/L-UI/issues) — your symptom has
probably been seen before.
</Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
---
title: 3x-ui Documentation
description: Official documentation for 3x-ui — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
title: L-UI Documentation
description: Official documentation for L-UI — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
icon: House
---
**3x-ui** is an open-source web panel for deploying and managing
**L-UI** is an open-source web panel for deploying and managing
[Xray-core](https://github.com/XTLS/Xray-core) servers. It gives you a modern
dashboard for inbounds, protocols, clients, traffic accounting, subscriptions,
and more — without hand-editing Xray JSON on the command line.
@@ -17,7 +17,7 @@ leaves the page.
<Cards>
<Card
title="What is 3x-ui?"
title="What is L-UI?"
href="/docs/guide"
description="The big picture: Xray-core, the panel, and who it's for."
/>
@@ -49,6 +49,6 @@ leaves the page.
- **Operations** — multi-node management, Telegram bot, backups, and a REST API.
<Callout type="info">
New to Xray? Read [What is 3x-ui?](/docs/guide) first — it explains how the panel, Xray-core, and
New to Xray? Read [What is L-UI?](/docs/guide) first — it explains how the panel, Xray-core, and
your client apps fit together.
</Callout>
@@ -1,6 +1,6 @@
---
title: Backup & Restore
description: Back up and restore your 3x-ui database and certificates, manually or via the Telegram bot.
description: Back up and restore your L-UI database and certificates, manually or via the Telegram bot.
icon: DatabaseBackup
---
@@ -9,7 +9,7 @@ database. Back it up regularly so you can recover or migrate.
## What to back up
- **The database** — SQLite at `/etc/x-ui/x-ui.db` by default (or your
- **The database** — SQLite at `/etc/l-ui/l-ui.db` by default (or your
PostgreSQL database if you use that backend).
- **Certificates** — anything under `/root/cert/` (or wherever you store TLS
certs).
@@ -20,7 +20,7 @@ You can download a backup from the panel's overview, or copy the database file
directly from the server:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
cp /etc/l-ui/l-ui.db /root/l-ui-backup-$(date +%F).db
```
To restore, stop the panel, put the database back in place, and start it again.
@@ -41,12 +41,12 @@ can also request a backup on demand from the bot's menu.
## SQLite dump / restore
The `x-ui migrate-db` command converts the SQLite database to and from a plain
The `l-ui migrate-db` command converts the SQLite database to and from a plain
SQL text dump (handy for inspection or transferring between machines):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
l-ui migrate-db --dump /root/l-ui.sql # SQLite -> SQL text
l-ui migrate-db --restore /root/l-ui.sql # SQL text -> SQLite
```
To move to PostgreSQL instead, see [Database](/docs/reference/database).
@@ -1,15 +1,15 @@
---
title: Multi-node & Managed Hosts
description: Manage multiple 3x-ui panels from one master, with API-token or mTLS trust, heartbeats, and per-inbound host overrides for subscriptions.
description: Manage multiple L-UI panels from one master, with API-token or mTLS trust, heartbeats, and per-inbound host overrides for subscriptions.
icon: Boxes
---
3x-ui can manage **multiple servers** from a single master panel, and override
L-UI can manage **multiple servers** from a single master panel, and override
how each inbound is advertised in subscriptions with **managed hosts**.
## Nodes
A **node** is another 3x-ui panel that your master panel manages over the node's
A **node** is another L-UI panel that your master panel manages over the node's
API. The master polls each node and shows its status, versions, CPU/memory,
uptime, and traffic in one place.
@@ -1,11 +1,11 @@
---
title: Outbounds & Routing
description: Shape egress in 3x-ui — WARP, NordVPN, PIA WireGuard, outbound subscriptions, routing rules, and load balancers.
description: Shape egress in L-UI — WARP, NordVPN, PIA WireGuard, outbound subscriptions, routing rules, and load balancers.
icon: Route
---
Inbounds accept clients; **outbounds** decide where their traffic goes next.
3x-ui can route traffic through Cloudflare WARP, NordVPN, Private Internet Access
L-UI can route traffic through Cloudflare WARP, NordVPN, Private Internet Access
(WireGuard), or arbitrary outbound pools imported from a subscription,
and select between them with routing rules and balancers.
@@ -39,7 +39,7 @@ inbound's transport and security. Two outbounds are almost always present:
A **proxy** outbound (VLESS, VMess, Trojan, Shadowsocks) forwards to another
server — handy for chaining or sending select traffic abroad. Mind the wire
shapes 3x-ui uses: **VLESS is the flat form** (`address`/`port`/`id`/`flow`/
shapes L-UI uses: **VLESS is the flat form** (`address`/`port`/`id`/`flow`/
`encryption`), **VMess uses `settings.vnext[]`**, and **Trojan/Shadowsocks use
`settings.servers[]`**. The `streamSettings` must mirror the destination's
[transport and security](/docs/config/transports).
@@ -50,7 +50,7 @@ Assemble any outbound below and paste the JSON into **Xray Settings → Outbound
## Cloudflare WARP
WARP lets your server egress through Cloudflare's network. 3x-ui can register a
WARP lets your server egress through Cloudflare's network. L-UI can register a
WARP account for you and wire it into a WireGuard outbound tagged **`warp`**:
<Steps>
@@ -64,7 +64,7 @@ Create a WireGuard outbound with the tag `warp` in your Xray config.
<Step>
### Register WARP
From the panel's WARP controls, register an account. 3x-ui fills the outbound's
From the panel's WARP controls, register an account. L-UI fills the outbound's
keys, addresses, reserved bytes, and peer endpoint automatically.
</Step>
@@ -82,13 +82,13 @@ with a routing rule.
## NordVPN
3x-ui can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
L-UI can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
accept a private key directly) and list countries/servers, so you can build a
NordVPN outbound.
## PIA WireGuard
3x-ui can sign in with a PIA username and password, list countries/regions/servers
L-UI can sign in with a PIA username and password, list countries/regions/servers
from the signed PIA server list, and build a WireGuard outbound. Open
**Xray → Outbounds → More → PIA**, sign in, pick a server, and add the outbound.
You can add several servers (one outbound per hostname). The tag is
@@ -100,7 +100,7 @@ revoke the WireGuard peer on the PIA account.
The password is not stored. The PIA API token is stored with the same
`NODE_TOKEN_ENCRYPTION` setting as node API tokens. If you retire an old
`XUI_NODE_TOKEN_KEY` without signing into PIA again, Add/Reset fail until you
`LUI_NODE_TOKEN_KEY` without signing into PIA again, Add/Reset fail until you
re-login. Peer `allowedIPs` is IPv4-only (`0.0.0.0/0`).
## Outbound subscriptions (server pools)
@@ -1,13 +1,13 @@
---
title: Reverse Proxy
description: Put the 3x-ui panel and subscription behind Nginx or Caddy with Let's Encrypt TLS.
description: Put the L-UI panel and subscription behind Nginx or Caddy with Let's Encrypt TLS.
icon: Waypoints
---
A reverse proxy lets you serve the panel and subscription on a clean domain with
automatic HTTPS, and hide the real ports behind ports 80/443. Prefer to let the
panel terminate TLS directly? Get a certificate with the
[`x-ui` SSL menu](/docs/config/ssl-certificates) instead.
[`l-ui` SSL menu](/docs/config/ssl-certificates) instead.
## Generate a config
@@ -45,7 +45,7 @@ panel.example.com {
## Tips
- Keep the panel's **web base path** even behind a proxy; defense in depth.
- If you terminate TLS at the proxy, you may want `XUI_SKIP_HSTS=true` on the
- If you terminate TLS at the proxy, you may want `LUI_SKIP_HSTS=true` on the
panel — see the [environment variables reference](/docs/reference/env-vars).
- Proxy the [subscription](/docs/config/subscription) server too, so its contents
are served over HTTPS.
+10 -10
View File
@@ -1,6 +1,6 @@
---
title: Security
description: Harden 3x-ui — panel auth and 2FA, Fail2ban IP limits, firewall rules, BBR, and staying current.
description: Harden L-UI — panel auth and 2FA, Fail2ban IP limits, firewall rules, BBR, and staying current.
icon: ShieldCheck
---
@@ -21,15 +21,15 @@ See [First login](/docs/guide/first-login) for the full checklist.
Set an **IP limit** per client (see [Clients](/docs/config/clients)) to cap the
number of simultaneous source IPs. Enforcement is handled by **Fail2ban**, which
3x-ui installs and configures for you (enabled by default on script installs, and
on Docker via `XUI_ENABLE_FAIL2BAN=true`).
L-UI installs and configures for you (enabled by default on script installs, and
on Docker via `LUI_ENABLE_FAIL2BAN=true`).
Manage it from the `x-ui` menu (**22 — IP Limit Management**): install/configure,
Manage it from the `l-ui` menu (**22 — IP Limit Management**): install/configure,
change the ban duration (default **30 minutes**), ban/unban an IP, view ban logs,
and check status. Under the hood:
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/x-ui/3xipl.log` and
`/var/log/x-ui/3xipl-banned.log` (also via `x-ui banlog`).
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/l-ui/3xipl.log` and
`/var/log/l-ui/3xipl-banned.log` (also via `l-ui banlog`).
- Bans cover all TCP/UDP **except** your SSH and panel ports, so a ban can't lock
you out of the server or panel.
@@ -43,7 +43,7 @@ and check status. Under the hood:
## Firewall
Open only the ports you actually use: SSH, the panel port, the subscription
port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) wraps
port, and your inbound ports. The `l-ui` menu (**23 — Firewall Management**) wraps
`ufw`, or generate rules here:
<FirewallRulesGenerator />
@@ -55,12 +55,12 @@ port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) w
## Network tuning (BBR)
The `x-ui` menu (**26 — Enable BBR**) toggles Google's BBR congestion control
The `l-ui` menu (**26 — Enable BBR**) toggles Google's BBR congestion control
(`net.ipv4.tcp_congestion_control = bbr`, `net.core.default_qdisc = fq`), which
often improves throughput on congested links.
## Keep current
Update 3x-ui and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/3x-ui/releases) and see
Update L-UI and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/L-UI/releases) and see
[Update & uninstall](/docs/guide/update-uninstall).
@@ -1,10 +1,10 @@
---
title: Telegram Bot
description: Connect a Telegram bot to 3x-ui for commands, periodic reports, event alerts (login, CPU, node up/down), backups, and client self-service.
description: Connect a Telegram bot to L-UI for commands, periodic reports, event alerts (login, CPU, node up/down), backups, and client self-service.
icon: Send
---
3x-ui can drive a Telegram bot for monitoring, alerts, backups, and remote
L-UI can drive a Telegram bot for monitoring, alerts, backups, and remote
management. Admins get full control; regular users (linked by Telegram ID) can
check their own usage and links.
@@ -1,56 +0,0 @@
---
title: API Tokens
description: Manage scoped Bearer tokens for programmatic auth. Tokens grant
admin, monitor, or node-sync access, may expire, and are stored as SHA-256
hashes. The plaintext is returned only once at creation.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: List every API token, enabled or not. The token value is never returned —
only metadata.
url: '#list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata'
- depth: 2
title: Mint a scoped API token. The server-generated plaintext is returned only
once and stored as a hash.
url: '#mint-a-scoped-api-token-the-server-generated-plaintext-is-returned-only-once-and-stored-as-a-hash'
- depth: 2
title: Permanently delete a token. Any caller using it stops authenticating
immediately.
url: '#permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately'
- depth: 2
title: Toggle a token enabled/disabled without deleting it. Disabled tokens are
rejected by checkAPIAuth on the next request.
url: '#toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request'
structuredData:
headings:
- content: List every API token, enabled or not. The token value is never returned
— only metadata.
id: list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- content: Mint a scoped API token. The server-generated plaintext is returned
only once and stored as a hash.
id: mint-a-scoped-api-token-the-server-generated-plaintext-is-returned-only-once-and-stored-as-a-hash
- content: Permanently delete a token. Any caller using it stops authenticating
immediately.
id: permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- content: Toggle a token enabled/disabled without deleting it. Disabled tokens
are rejected by checkAPIAuth on the next request.
id: toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/apiTokens","method":"get"},{"path":"/panel/api/setting/apiTokens/create","method":"post"},{"path":"/panel/api/setting/apiTokens/delete/{id}","method":"post"},{"path":"/panel/api/setting/apiTokens/setEnabled/{id}","method":"post"}]} showTitle />
</>
);
}
@@ -54,7 +54,7 @@ export default function Layout(props) {
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/login","method":"post"},{"path":"/logout","method":"post"},{"path":"/csrf-token","method":"get"},{"path":"/getTwoFactorEnable","method":"post"}]} showTitle />
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/login","method":"post"},{"path":"/logout","method":"post"},{"path":"/csrf-token","method":"get"}]} showTitle />
</>
);
}
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: API Reference
description: The 3x-ui panel REST API — authentication, inbounds, clients, server stats, and more, generated from the OpenAPI spec.
description: The L-UI panel REST API — authentication, inbounds, clients, server stats, and more, generated from the OpenAPI spec.
icon: Webhook
---
The 3x-ui panel exposes a REST API for automation. These pages are generated from
The L-UI panel exposes a REST API for automation. These pages are generated from
the panel's OpenAPI specification, so they always match the documented schema.
## Authentication
@@ -4,7 +4,6 @@
"pages": [
"index",
"authentication",
"api-tokens",
"inbounds",
"clients",
"server",
+11 -17
View File
@@ -1,6 +1,6 @@
---
title: Nodes
description: Manage remote 3x-ui panels acting as nodes for a central panel. All
description: Manage remote L-UI panels acting as nodes for a central panel. All
endpoints under /panel/api/nodes.
full: true
_openapi:
@@ -37,15 +37,12 @@ _openapi:
panel.
url: '#fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel'
- depth: 2
title: Register a new remote node. Provide its URL, write-only apiToken, and
optional remark / allowPrivateAddress flag. Responses expose hasApiToken
only.
url: '#register-a-new-remote-node-provide-its-url-write-only-apitoken-and-optional-remark--allowprivateaddress-flag-responses-expose-hasapitoken-only'
title: Register a new remote node. Provide its URL and optional remark /
allowPrivateAddress flag.
url: '#register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag'
- depth: 2
title: 'Replace a node’s connection details. apiToken is write-only: omit it or
send an empty string to keep the stored token; set clearApiToken=true to
clear it.'
url: '#replace-a-nodes-connection-details-apitoken-is-write-only-omit-it-or-send-an-empty-string-to-keep-the-stored-token-set-clearapitokentrue-to-clear-it'
title: Replace a node’s connection details.
url: '#replace-a-nodes-connection-details'
- depth: 2
title: Delete a node. Inbounds bound to it are not auto-migrated.
url: '#delete-a-node-inbounds-bound-to-it-are-not-auto-migrated'
@@ -105,14 +102,11 @@ _openapi:
node-assigned inbound gets paths that exist on the node, not the
central panel.
id: fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- content: Register a new remote node. Provide its URL, write-only apiToken, and
optional remark / allowPrivateAddress flag. Responses expose
hasApiToken only.
id: register-a-new-remote-node-provide-its-url-write-only-apitoken-and-optional-remark--allowprivateaddress-flag-responses-expose-hasapitoken-only
- content: 'Replace a node’s connection details. apiToken is write-only: omit it
or send an empty string to keep the stored token; set
clearApiToken=true to clear it.'
id: replace-a-nodes-connection-details-apitoken-is-write-only-omit-it-or-send-an-empty-string-to-keep-the-stored-token-set-clearapitokentrue-to-clear-it
- content: Register a new remote node. Provide its URL and optional remark /
allowPrivateAddress flag.
id: register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag
- content: Replace a node’s connection details.
id: replace-a-nodes-connection-details
- content: Delete a node. Inbounds bound to it are not auto-migrated.
id: delete-a-node-inbounds-bound-to-it-are-not-auto-migrated
- content: Pause or resume traffic sync with this node.
@@ -53,8 +53,8 @@ _openapi:
title: List Xray binary versions available for install on this host.
url: '#list-xray-binary-versions-available-for-install-on-this-host'
- depth: 2
title: Check whether a newer 3x-ui release is available on GitHub.
url: '#check-whether-a-newer-3x-ui-release-is-available-on-github'
title: Check whether a newer L-UI release is available on GitHub.
url: '#check-whether-a-newer-L-UI-release-is-available-on-github'
- depth: 2
title: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one
@@ -218,8 +218,8 @@ _openapi:
id: time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- content: List Xray binary versions available for install on this host.
id: list-xray-binary-versions-available-for-install-on-this-host
- content: Check whether a newer 3x-ui release is available on GitHub.
id: check-whether-a-newer-3x-ui-release-is-available-on-github
- content: Check whether a newer L-UI release is available on GitHub.
id: check-whether-a-newer-L-UI-release-is-available-on-github
- content: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one
updatePanel returned to tell this run apart from a stale result.
@@ -36,10 +36,10 @@ _openapi:
values on success.
url: '#change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success'
- depth: 2
title: Restart the entire 3x-ui process after a 3-second grace period. The
title: Restart the entire L-UI process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10 seconds
later.
url: '#restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later'
url: '#restart-the-entire-L-UI-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later'
- depth: 2
title: Test SMTP connection with stage-by-stage reporting (connect, auth, send).
Returns structured result with stage and message.
@@ -76,10 +76,10 @@ _openapi:
credentials for verification. The session is refreshed with the new
values on success.
id: change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- content: Restart the entire 3x-ui process after a 3-second grace period. The
- content: Restart the entire L-UI process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10
seconds later.
id: restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
id: restart-the-entire-L-UI-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- content: Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
id: test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
+14 -14
View File
@@ -1,17 +1,17 @@
---
title: Database
description: 3x-ui storage backends — SQLite (default) and PostgreSQL — the database path, connection pool, and SQLite-to-PostgreSQL migration.
description: L-UI storage backends — SQLite (default) and PostgreSQL — the database path, connection pool, and SQLite-to-PostgreSQL migration.
icon: Database
---
3x-ui stores everything — inbounds, clients, settings — in a database. You choose
L-UI stores everything — inbounds, clients, settings — in a database. You choose
the backend at install time; both are first-class.
## SQLite (default)
A single file at `/etc/x-ui/x-ui.db`. Zero setup, ideal for small and medium
A single file at `/etc/l-ui/l-ui.db`. Zero setup, ideal for small and medium
deployments. The folder is configurable with
[`XUI_DB_FOLDER`](/docs/reference/env-vars#database) (on Windows it defaults next
[`LUI_DB_FOLDER`](/docs/reference/env-vars#database) (on Windows it defaults next
to the binary).
## PostgreSQL
@@ -19,20 +19,20 @@ to the binary).
Recommended for high client counts or multi-node setups. The installer can
install PostgreSQL locally for you, or accept a DSN to an existing server. At
runtime the backend is selected via environment variables, which the installer
writes to `/etc/default/x-ui`:
writes to `/etc/default/l-ui`:
```bash title="/etc/default/x-ui"
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```bash title="/etc/default/l-ui"
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
Tune the connection pool with `XUI_DB_MAX_OPEN_CONNS` and
`XUI_DB_MAX_IDLE_CONNS`.
Tune the connection pool with `LUI_DB_MAX_OPEN_CONNS` and
`LUI_DB_MAX_IDLE_CONNS`.
### Docker
`docker compose up -d` keeps using SQLite. To run with the bundled PostgreSQL
service, uncomment the two `XUI_DB_*` lines in `docker-compose.yml` and start
service, uncomment the two `LUI_DB_*` lines in `docker-compose.yml` and start
with the profile:
```bash
@@ -44,13 +44,13 @@ docker compose --profile postgres up -d
Move an existing SQLite install to PostgreSQL with the built-in command:
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
```
Then set `XUI_DB_TYPE` and `XUI_DB_DSN` in `/etc/default/x-ui` and restart:
Then set `LUI_DB_TYPE` and `LUI_DB_DSN` in `/etc/default/l-ui` and restart:
```bash
systemctl restart x-ui
systemctl restart l-ui
```
<Callout type="info">
+30 -30
View File
@@ -1,46 +1,46 @@
---
title: Environment Variables
description: Complete reference for 3x-ui's XUI_* environment variables — database, panel, logging, memory, and the tunnel health monitor.
description: Complete reference for L-UI's LUI_* environment variables — database, panel, logging, memory, and the tunnel health monitor.
icon: Variable
---
3x-ui reads its runtime configuration from `XUI_*` environment variables. On a
L-UI reads its runtime configuration from `LUI_*` environment variables. On a
script install the installer writes them to the service environment file
(`/etc/default/x-ui`, or `/etc/conf.d/x-ui` / `/etc/sysconfig/x-ui` depending on
(`/etc/default/l-ui`, or `/etc/conf.d/l-ui` / `/etc/sysconfig/l-ui` depending on
the distro); for Docker you set them in `docker-compose.yml` or `docker run -e`.
Defaults are sensible — set only what you need to change, then restart:
`systemctl restart x-ui`.
`systemctl restart l-ui`.
## Database
| Variable | Default | Description |
| ------------------------ | ----------- | -------------------------------------------------------------------- |
| `XUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). |
| `XUI_DB_FOLDER` | `/etc/x-ui` | Folder for the SQLite database file (`x-ui.db`). |
| `XUI_DB_DSN` | — | PostgreSQL connection string (used when `XUI_DB_TYPE=postgres`). |
| `XUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. |
| `XUI_DB_MAX_IDLE_CONNS` | — | Max idle connections in the PostgreSQL pool. |
| `LUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). |
| `LUI_DB_FOLDER` | `/etc/l-ui` | Folder for the SQLite database file (`l-ui.db`). |
| `LUI_DB_DSN` | — | PostgreSQL connection string (used when `LUI_DB_TYPE=postgres`). |
| `LUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. |
| `LUI_DB_MAX_IDLE_CONNS` | — | Max idle connections in the PostgreSQL pool. |
The default SQLite database path is `/etc/x-ui/x-ui.db`. See
The default SQLite database path is `/etc/l-ui/l-ui.db`. See
[Database](/docs/reference/database) for the SQLite ↔ PostgreSQL details.
## Panel
| Variable | Default | Description |
| ------------------------ | ------- | ------------------------------------------------------------------------ |
| `XUI_PORT` | — | Override the panel port (1–65535). Takes precedence over the stored setting. |
| `XUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. |
| `XUI_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
| `LUI_PORT` | — | Override the panel port (1–65535). Takes precedence over the stored setting. |
| `LUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `LUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. |
| `LUI_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
## Logging & binaries
| Variable | Default | Description |
| ---------------- | ---------------- | ----------------------------------------------------------- |
| `XUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `XUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `XUI_LOG_FOLDER` | `/var/log/x-ui` | Log output directory. |
| `XUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
| `LUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `LUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `LUI_LOG_FOLDER` | `/var/log/l-ui` | Log output directory. |
| `LUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
## Memory & profiling
@@ -49,11 +49,11 @@ knobs — leave them unset unless you're tuning a constrained host.
| Variable | Default | Description |
| ----------------------------- | ------- | ----------------------------------------------------------------- |
| `XUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `XUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `XUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `LUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `LUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `LUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `GOMEMLIMIT` | — | Go-syntax soft limit (e.g. `400MiB`); takes precedence over above.|
| `XUI_PPROF` | `false` | Expose pprof profiling on `127.0.0.1:6060`. |
| `LUI_PPROF` | `false` | Expose pprof profiling on `127.0.0.1:6060`. |
## Xray
@@ -69,16 +69,16 @@ clients, so enable it deliberately.
| Variable | Default | Description |
| ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| `XUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. |
| `XUI_TUNNEL_HEALTH_PROXY` | — | Proxy to send the probe through, e.g. `socks5://127.0.0.1:1080`. Empty = only checks host connectivity. |
| `XUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `XUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `XUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
| `LUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. |
| `LUI_TUNNEL_HEALTH_PROXY` | — | Proxy to send the probe through, e.g. `socks5://127.0.0.1:1080`. Empty = only checks host connectivity. |
| `LUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `LUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `LUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
## Unattended install
| Variable | Description |
| -------------------- | -------------------------------------------------------------------------------------------- |
| `XUI_NONINTERACTIVE` | Set to `1` (or run with no TTY) to install with zero prompts; generated credentials are written to `/etc/x-ui/install-result.env`. See [Installation](/docs/guide/installation#unattended--cloud-init). |
| `LUI_NONINTERACTIVE` | Set to `1` (or run with no TTY) to install with zero prompts; generated credentials are written to `/etc/l-ui/install-result.env`. See [Installation](/docs/guide/installation#unattended--cloud-init). |
@@ -1,6 +1,6 @@
---
title: Ports & Firewall
description: The ports 3x-ui uses by default and ready-made ufw / nftables rules to open them.
description: The ports L-UI uses by default and ready-made ufw / nftables rules to open them.
icon: Network
---
@@ -32,5 +32,5 @@ Your actual inbound ports depend on the inbounds you create.
<Cards>
<Card title="Security" href="/docs/operations/security" description="Fail2ban, IP limits, and hardening." />
<Card title="Environment variables" href="/docs/reference/env-vars" description="XUI_PORT and friends." />
<Card title="Environment variables" href="/docs/reference/env-vars" description="LUI_PORT and friends." />
</Cards>
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: کلاینت‌ها
description: مدیریت کلاینت‌های 3x-ui — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
description: مدیریت کلاینت‌های L-UI — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
icon: Users
---
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: ورودی‌ها و پروتکل‌ها
description: ساخت ورودی‌ها در 3x-ui — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
description: ساخت ورودی‌ها در L-UI — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
icon: ArrowDownToLine
---
@@ -74,7 +74,7 @@ TLS یا REALITY) را انتخاب کنید. به [انتقال‌ها](/docs/c
Fallbackها به یک پورت TLS واحد (مثلاً `443`) اجازه می‌دهند بیش از یک پروتکل را
سرویس دهد — برای مثال VLESS **و** Trojan — با هدایت دست‌دادن‌های (handshake)
ناهماهنگ به یک ورودی فرزند. در 3x-ui، fallbackها در پنل مدیریت می‌شوند (لیست
ناهماهنگ به یک ورودی فرزند. در L-UI، fallbackها در پنل مدیریت می‌شوند (لیست
**Fallbacks** یک ورودی اصلی) به‌جای آنکه به‌صورت دستی در JSON نوشته شوند.
Fallbackها تنها زمانی در دسترس‌اند که ورودی اصلی این‌گونه باشد:
+4 -4
View File
@@ -1,6 +1,6 @@
---
title: تنظیمات پنل
description: تمام تنظیمات پنل 3x-ui — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
description: تمام تنظیمات پنل L-UI — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
icon: SlidersHorizontal
---
@@ -14,7 +14,7 @@ icon: SlidersHorizontal
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `XUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `LUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webListen` | _(همه‌ی واسط‌ها)_ | پنل را به یک IP مشخص مقید کنید. |
| `webBasePath` | `/` | مسیر URLی که پنل زیر آن ارائه می‌شود (همیشه به شکل `/…/` نرمال‌سازی می‌شود). |
| `webCertFile` / `webKeyFile` | _(هیچ‌کدام)_ | گواهی + کلید TLS. وقتی هر دو تنظیم شوند، پنل با **HTTPS** ارائه می‌شود. |
@@ -24,12 +24,12 @@ icon: SlidersHorizontal
پس از تغییر پورت یا مسیر پایه، آدرس پنل به‌صورت
`http(s)://<server>:<port><web-base-path>` درمی‌آید. می‌توانید مسیر پایه را در
نخستین اجرا با [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars) از پیش تعیین کنید.
نخستین اجرا با [`LUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars) از پیش تعیین کنید.
### TLS
ارائه‌ی پنل روی HTTPS از اطلاعات احراز هویت شما در حین انتقال محافظت می‌کند. یا
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `x-ui`](/docs/config/ssl-certificates)
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `l-ui`](/docs/config/ssl-certificates)
می‌تواند یک گواهی Let's Encrypt برای شما تهیه کند — یا TLS را روی یک
[پروکسی معکوس](/docs/operations/reverse-proxy) خاتمه دهید.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: REALITY
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در 3x-ui — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در L-UI — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
icon: ShieldCheck
---
@@ -15,7 +15,7 @@ REALITY همراه با **VLESS** (و Trojan) به‌کار می‌رود. جر
## تنظیمات کلیدی
وقتی **REALITY** را به‌عنوان حالت امنیتی روی یک ورودی VLESS انتخاب می‌کنید، 3x-ui
وقتی **REALITY** را به‌عنوان حالت امنیتی روی یک ورودی VLESS انتخاب می‌کنید، L-UI
این فیلدها را نمایش می‌دهد:
| فیلد | چیست |
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: لینک‌های اشتراک‌گذاری
description: قالب‌های لینک اشتراک‌گذاری 3x-ui (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
description: قالب‌های لینک اشتراک‌گذاری L-UI (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
icon: Link
---
3x-ui برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
L-UI برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
مانند v2rayNG، Hiddify و Mihomo این لینک‌ها را برای پیکربندی خودشان وارد می‌کنند.
## قالب‌های لینک
@@ -1,6 +1,6 @@
---
title: گواهی‌های SSL
description: دریافت و تمدید گواهی‌های TLS برای پنل و ورودی‌های 3x-ui — با منوی ACME در x-ui (دامنه یا IP خام)، گواهی wildcard از طریق Cloudflare DNS-01، یا Certbot دستی.
description: دریافت و تمدید گواهی‌های TLS برای پنل و ورودی‌های L-UI — با منوی ACME در l-ui (دامنه یا IP خام)، گواهی wildcard از طریق Cloudflare DNS-01، یا Certbot دستی.
icon: ShieldCheck
---
@@ -8,7 +8,7 @@ icon: ShieldCheck
API شما رمزگذاری شود) و TLS را روی **ورودی‌ها** خاتمه دهید (VLESS-TLS، Trojan،
Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌آوردن گواهی وجود دارد:
- **منوی `x-ui`** — کلاینت داخلی [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment).
- **منوی `l-ui`** — کلاینت داخلی [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment).
آسان‌ترین گزینه برای یک دامنه‌ی واحد یا یک IP خام.
- **Cloudflare DNS-01** — این هم از همان منو؛ برای گواهی‌های **wildcard** یا
زمانی که پورت 80 مسدود است / سرور پشت پراکسی Cloudflare قرار دارد لازم است.
@@ -21,9 +21,9 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
TLS یک سایت واقعی را قرض می‌گیرند. این صفحه برای پنل و برای ورودی‌های کلاسیک TLS است.
</Callout>
## منوی SSL در `x-ui` (Let's Encrypt)
## منوی SSL در `l-ui` (Let's Encrypt)
`x-ui` را اجرا کنید و **`20` — SSL Certificate Management** را انتخاب کنید. این گزینه
`l-ui` را اجرا کنید و **`20` — SSL Certificate Management** را انتخاب کنید. این گزینه
[acme.sh](https://github.com/acmesh-official/acme.sh) را به کار می‌گیرد و موارد زیر را ارائه می‌دهد:
| گزینه | کاری که انجام می‌دهد |
@@ -57,7 +57,7 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
<Step>
### صادرکننده را اجرا کنید
`x-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
`l-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
درخواست می‌کند و آن را زیر `/root/cert/<domain>/` به‌صورت `fullchain.pem`
(زنجیره‌ی گواهی) و `privkey.pem` (کلید خصوصی) ذخیره می‌کند.
</Step>
@@ -104,7 +104,7 @@ DNS دامنه‌ی شما باید توسط Cloudflare مدیریت شود و
<Step>
### صادرکننده‌ی Cloudflare را اجرا کنید
`x-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
`l-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
توکن API (پیش‌فرض) یا **`g`** را برای Global API Key انتخاب کنید، سپس دامنه‌ی خود را
وارد کنید (و برای Global API Key، ایمیل حساب و کلید خود را). acme.sh رکورد TXT را
می‌سازد، اعتبارسنجی می‌کند و آن را پاک‌سازی می‌کند.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Subscription
description: راه‌اندازی سرور اشتراک 3x-ui — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
description: راه‌اندازی سرور اشتراک L-UI — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
icon: Rss
---
@@ -59,7 +59,7 @@ https://<sub-host>:<sub-port>/sub/<sub-id>
با standard-base64 رمزگذاری شده‌اند (با `subEncrypt` قابل تغییر است). بدنه‌ی **JSON**
هر کلاینت را در یک پیکربندی کامل کلاینت Xray می‌پیچد — یک اسکلت ثابت (ورودی‌های محلی
mixed/HTTP، DNS، مسیریابی، policy) به‌علاوه‌ی یک outbound از نوع `proxy` که به ورودی
اشاره می‌کند. 3x-ui **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
اشاره می‌کند. L-UI **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
تولید می‌کند، از فرم تخت `settings` در outbound استفاده می‌کند
(`address`/`port`/`id`، `level: 8`) و `sockopt` را از `streamSettings` حذف می‌کند.
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: انتقال‌ها و امنیت
description: هر انتقالی که 3x-ui ارائه می‌دهد — TCP، mKCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، Hysteria — به‌همراه تنظیماتشان، و نیز مبهم‌سازی FinalMask، sockopt، TLS/REALITY، XTLS-Vision و رمزنگاری VLESS.
description: هر انتقالی که L-UI ارائه می‌دهد — TCP، mKCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، Hysteria — به‌همراه تنظیماتشان، و نیز مبهم‌سازی FinalMask، sockopt، TLS/REALITY، XTLS-Vision و رمزنگاری VLESS.
icon: Network
---
+16 -16
View File
@@ -1,6 +1,6 @@
---
title: نخستین ورود
description: مشخصات ورود تولیدشدهٔ 3x-ui را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
description: مشخصات ورود تولیدشدهٔ L-UI را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
icon: KeyRound
---
@@ -24,25 +24,25 @@ http://<your-server-ip>:<port>/<web-base-path>
نصب با اسکریپت پس از پایان، خلاصه‌ای از مشخصات ورود را چاپ می‌کند و آن را در یک
فایل ویژهٔ root نیز می‌نویسد:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```bash title="/etc/l-ui/install-result.env (mode 600)"
LUI_USERNAME=...
LUI_PASSWORD=...
LUI_PANEL_PORT=...
LUI_WEB_BASE_PATH=...
LUI_ACCESS_URL=...
LUI_API_TOKEN=...
LUI_DB_TYPE=sqlite
```
اگر آن‌ها را از دست دادید، از ابزارهای مدیریتی استفاده کنید:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
l-ui # menu → 11 (View Current Settings)
l-ui settings # or the one-shot form
```
برای **Docker**، مشخصات ورود تولیدشده را از لاگ‌های کانتینر بخوانید، یا دستور
`docker exec -it <container> x-ui setting -show` را اجرا کنید.
`docker exec -it <container> l-ui setting -show` را اجرا کنید.
<Callout type="warn">
اگر پنل شما هنوز از مقادیر پیش‌فرض `admin` / `admin` استفاده می‌کند (پنل در این
@@ -53,7 +53,7 @@ x-ui settings # or the one-shot form
یک پورت غیرپیش‌فرض و یک **مسیر پایهٔ وب** طولانی و تصادفی، یافتن پنل را بسیار
دشوارتر می‌کند. آن‌ها را از بخش **Panel Settings** در رابط کاربری، یا از منوی
`x-ui` تغییر دهید:
`l-ui` تغییر دهید:
- **7 — Reset Username & Password** (با امکان غیرفعال‌سازی همزمان 2FA)
- **8 — Reset Web Base Path** (آن را تصادفی می‌کند)
@@ -64,11 +64,11 @@ x-ui settings # or the one-shot form
## احراز هویت دومرحله‌ای (2FA)
‏3x-ui از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
‏L-UI از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
Authenticator، Aegis و غیره). آن را در بخش **Panel Settings** فعال کنید — پس از
فعال‌سازی، صفحهٔ ورود علاوه بر رمز عبور، یک کد ۶ رقمی نیز درخواست می‌کند و
فعال کردن آن همه را وادار به ورود مجدد می‌کند. می‌توانید آن را از مرحلهٔ **Reset
Username & Password** در منو یا با دستور `x-ui setting -resetTwoFactor` غیرفعال
Username & Password** در منو یا با دستور `l-ui setting -resetTwoFactor` غیرفعال
کنید.
## محافظت داخلی از ورود
@@ -106,7 +106,7 @@ Username & Password** در منو یا با دستور `x-ui setting -resetTwoFa
<Step>
### پنل را پشت TLS قرار دهید
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `x-ui` یا یک reverse proxy)
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `l-ui` یا یک reverse proxy)
استفاده کنید تا پنل تنها از طریق HTTPS در دسترس باشد.
</Step>
+6 -6
View File
@@ -1,10 +1,10 @@
---
title: آشنایی با 3x-ui
title: آشنایی با L-UI
description: یک پنل تحت وب برای Xray-core — ورودی‌ها، پروتکل‌ها، کلاینت‌ها و اشتراک‌ها را به‌جای ویرایش دستی JSON، از مرورگر خود مدیریت کنید.
icon: Info
---
**3x-ui** یک پنل کنترل تحت وب است که روی
**L-UI** یک پنل کنترل تحت وب است که روی
[Xray-core](https://github.com/XTLS/Xray-core)، همان موتور پروکسی که در واقع
ترافیک شما را جابه‌جا می‌کند، قرار می‌گیرد. به‌جای نوشتن و بارگذاری مجدد پیکربندی
JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها، پروتکل‌ها، کلاینت‌ها، گواهی‌ها،
@@ -15,7 +15,7 @@ JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها،
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Admin["Admin browser"] -->|HTTPS panel| Panel["L-UI panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -53,19 +53,19 @@ flowchart LR
| پایگاه‌داده | SQLite (پیش‌فرض) یا PostgreSQL |
| موتور پروکسی | Xray-core (همراه و مدیریت‌شده توسط پنل) |
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/x-ui/x-ui.db` قرار دارد و پنل به‌صورت
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/l-ui/l-ui.db` قرار دارد و پنل به‌صورت
پیش‌فرض روی پورت **2053** گوش می‌دهد. هر دو قابل پیکربندی هستند — به
[نخستین ورود](/docs/guide/first-login) و مرجع متغیرهای محیطی مراجعه کنید.
## برای چه کسانی است
3x-ui برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
L-UI برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
VPS شخصی منفرد تا اپراتورهایی که نودها و کلاینت‌های فراوانی را مدیریت می‌کنند. اگر
قدرت Xray-core را می‌خواهید بدون اینکه در فایل‌های پیکربندی JSON زندگی کنید، این
برای شماست.
<Callout type="info">
3x-ui یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
L-UI یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت
چندنودی و بسیاری از قابلیت‌های راحتی‌بخش را اضافه می‌کند.
</Callout>
+18 -18
View File
@@ -1,17 +1,17 @@
---
title: نصب
description: نصب 3x-ui با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
description: نصب L-UI با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
icon: Download
---
‏3x-ui روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
‏L-UI روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
Fedora، CentOS، RHEL، AlmaLinux، Rocky Linux، Oracle Linux، Amazon Linux،
Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچنین Windows،
روی معماری‌های `amd64`، `386`، `arm64`، `armv7`، `armv6`، `armv5` و `s390x`.
<Callout type="warn">
نصب‌کنندهٔ اسکریپتی را به‌صورت **root** (یا با `sudo`) اجرا کنید. این اسکریپت یک
سرویس نصب می‌کند، دستور مدیریتی `x-ui` را راه‌اندازی می‌کند و پنل را در زمان
سرویس نصب می‌کند، دستور مدیریتی `l-ui` را راه‌اندازی می‌کند و پنل را در زمان
بوت فعال می‌سازد.
</Callout>
@@ -21,7 +21,7 @@ Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچن
اسکریپت رسمی مسیر توصیه‌شده است. این اسکریپت در طول نصب یک نام کاربری، رمز عبور و
مسیر دسترسی (مسیر پایهٔ وب) **تصادفی** تولید می‌کند، سرویس را راه‌اندازی می‌کند و
دستور مدیریتی `x-ui` را نصب می‌کند.
دستور مدیریتی `l-ui` را نصب می‌کند.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
@@ -40,8 +40,8 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `x-ui` را اجرا کنید تا
[منوی مدیریت](/docs/guide/update-uninstall#the-x-ui-management-menu) باز شود، سپس
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `l-ui` را اجرا کنید تا
[منوی مدیریت](/docs/guide/update-uninstall#the-l-ui-management-menu) باز شود، سپس
به [نخستین ورود](/docs/guide/first-login) ادامه دهید.
</Tab>
@@ -55,7 +55,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
docker compose up -d
```
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `XUI_DB_*` را در
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `LUI_DB_*` را در
`docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل مربوطه اجرا کنید:
```bash
@@ -71,16 +71,16 @@ docker compose --profile postgres up -d
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-e LUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/l-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
--name L-UI \
ghcr.io/mhsanaei/3x-ui:latest
```
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/x-ui/x-ui.db`) را نگه می‌دارد و `cert/`
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/l-ui/l-ui.db`) را نگه می‌دارد و `cert/`
گواهی‌های TLS را، بنابراین داده‌های شما در ارتقاها حفظ می‌شوند.
</Tab>
@@ -88,7 +88,7 @@ docker run -d \
<Tab value="Manual">
برای کاربران پیشرفته، یک آرشیو انتشار متناسب با معماری خود را از
[صفحهٔ releases](https://github.com/MHSanaei/3x-ui/releases) دانلود کنید، آن را
[صفحهٔ releases](https://github.com/MHSanaei/L-UI/releases) دانلود کنید، آن را
استخراج کنید و باینری را به‌عنوان یک سرویس systemd اجرا کنید. اسکریپت نصب دقیقاً
همین مراحل را خودکار می‌کند، بنابراین مگر اینکه دلیل خاصی برای نصب دستی داشته
باشید، روش اسکریپتی ترجیح داده می‌شود.
@@ -107,7 +107,7 @@ docker run -d \
شما بک‌اند ذخیره‌سازی را در زمان نصب انتخاب می‌کنید:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **PostgreSQL** — برای تعداد کلاینت بالا یا پیکربندی‌های چندنودی. نصب‌کننده
می‌تواند آن را به‌صورت محلی نصب کند یا از یک DSN که شما ارائه می‌دهید استفاده کند.
@@ -117,15 +117,15 @@ docker run -d \
## نصب خودکار / cloud-init
نصب‌کننده برای خودکارسازی به‌صورت **غیرتعاملی** نیز اجرا می‌شود.
`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
`LUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
سرتاسری و بدون هیچ پرسشی انجام شود، مشخصات تصادفی تولید کند و آن‌ها را در
`/etc/x-ui/install-result.env` بنویسد:
`/etc/l-ui/install-result.env` بنویسد:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
LUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
دایرکتوری [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy) در مخزن
دایرکتوری [`deploy/`](https://github.com/MHSanaei/L-UI/tree/main/deploy) در مخزن
یک user-data آمادهٔ **cloud-init** برای نصب‌های خودکار روی هر ابری (Hetzner، AWS،
DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
@@ -140,7 +140,7 @@ DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
<Card
title="به‌روزرسانی و حذف نصب"
href="/docs/guide/update-uninstall"
description="منوی x-ui، به‌روزرسانی‌ها و حذف."
description="منوی l-ui، به‌روزرسانی‌ها و حذف."
/>
<Card
title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
---
title: به‌روزرسانی و حذف
description: مدیریت 3x-ui با منوی x-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
description: مدیریت L-UI با منوی l-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
icon: RefreshCw
---
پس از نصب با اسکریپت، دستور `x-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
پس از نصب با اسکریپت، دستور `l-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
کنید تا منوی تعاملی باز شود، یا یک زیردستور به آن بدهید تا یک عملیات تک‌مرحله‌ای انجام شود.
```bash
x-ui
l-ui
```
## منوی مدیریت `x-ui`
## منوی مدیریت `l-ui`
منو (آیتم‌های `0`–`28`) وضعیت پنل/Xray را در بالا نشان می‌دهد و سپس:
@@ -20,9 +20,9 @@ x-ui
| 1 | Install | (دوباره) نصب از روی اسکریپت راه دور |
| 2 | Update | به‌روزرسانی به آخرین نسخهٔ **پایدار** |
| 3 | Update to Dev Channel (latest commit) | به‌روزرسانی به بیلد غلتان `dev-latest` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `x-ui` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `l-ui` |
| 5 | Legacy Version | نصب یک نسخهٔ قدیمی مشخص (تگ را می‌پرسد) |
| 6 | Uninstall | حذف 3x-ui (در ادامه ببینید) |
| 6 | Uninstall | حذف L-UI (در ادامه ببینید) |
| 7 | Reset Username & Password | تنظیم مشخصات جدید؛ اختیاراً غیرفعال‌کردن 2FA |
| 8 | Reset Web Base Path | تصادفی‌کردن مسیر پایهٔ وب |
| 9 | Reset Settings | بازنشانی تنظیمات پنل (حساب شما حفظ می‌شود) |
@@ -51,29 +51,29 @@ x-ui
## زیردستورهای خط فرمان
برای اسکریپت‌ها و اقدام‌های سریع، `x-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
برای اسکریپت‌ها و اقدام‌های سریع، `l-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
| دستور | عملیات |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | کنترل سرویس |
| `x-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `x-ui status` | نمایش وضعیت |
| `x-ui settings` | نمایش تنظیمات فعلی |
| `x-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `x-ui log` | دنبال‌کردن لاگ دیباگ |
| `x-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `x-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `x-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `x-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `x-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `x-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `x-ui install` / `uninstall` | نصب / حذف |
| `l-ui start` / `stop` / `restart` | کنترل سرویس |
| `l-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `l-ui status` | نمایش وضعیت |
| `l-ui settings` | نمایش تنظیمات فعلی |
| `l-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `l-ui log` | دنبال‌کردن لاگ دیباگ |
| `l-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `l-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `l-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `l-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `l-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `l-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `l-ui install` / `uninstall` | نصب / حذف |
## به‌روزرسانی
- **پایدار:** گزینهٔ منوی **۲** یا `x-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
- **پایدار:** گزینهٔ منوی **۲** یا `l-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
در همان محل به‌روزرسانی می‌کند.
- **کانال dev:** گزینهٔ منوی **۳** یا `x-ui update-dev` — بیلد غلتان
- **کانال dev:** گزینهٔ منوی **۳** یا `l-ui update-dev` — بیلد غلتان
`dev-latest` به‌ازای هر کامیت (نه یک نسخهٔ پایدار).
- **یک نسخهٔ قدیمی مشخص:** گزینهٔ منوی **۵** (Legacy Version).
@@ -82,18 +82,18 @@ x-ui
<Callout type="info">
کاربران Docker به شیوهٔ دیگری به‌روزرسانی می‌کنند — به‌جای استفاده از دستورهای
به‌روزرسانی `x-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
به‌روزرسانی `l-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
(`docker compose pull && docker compose up -d`).
</Callout>
## حذف
گزینهٔ منوی **۶** یا `x-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/x-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
گزینهٔ منوی **۶** یا `l-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/l-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
نصب‌شده به‌صورت محلی استفاده می‌کرده، پیشنهاد می‌دهد آن را هم پاک‌سازی کند (یک تأیید
جداگانه و برگشت‌ناپذیر).
<Callout type="warn">
حذف، پایگاه‌داده (`/etc/x-ui/x-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
حذف، پایگاه‌داده (`/etc/l-ui/l-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
بعداً به آن نیاز داشته باشید، ابتدا [پشتیبان بگیرید](/docs/operations/backup-restore).
</Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
---
title: مشارکت
description: چگونه در توسعه 3x-ui مشارکت کنید و این مستندات را ترجمه کنید.
description: چگونه در توسعه L-UI مشارکت کنید و این مستندات را ترجمه کنید.
icon: GitPullRequestArrow
---
3x-ui یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
L-UI یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
می‌شود.
## حمایت از توسعه‌دهنده
3x-ui رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
L-UI رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
مفید بوده است، حمایت از ادامه توسعه را در نظر بگیرید:
- در [donate.sanaei.dev](https://donate.sanaei.dev/) **کمک مالی** کنید — این صفحه
**اهداف و سقف‌های** جاری تأمین مالی را که می‌توانید در رسیدن به آن‌ها کمک کنید نشان می‌دهد.
- به [مخزن](https://github.com/MHSanaei/3x-ui) **ستاره** بدهید و پروژه را به اشتراک
- به [مخزن](https://github.com/MHSanaei/L-UI) **ستاره** بدهید و پروژه را به اشتراک
بگذارید.
- به کانال Telegram یعنی [@XrayUI](https://t.me/XrayUI) **بپیوندید** تا اخبار را
دنبال کنید و به دیگران کمک کنید.
## مشارکت در 3x-ui
## مشارکت در L-UI
- فایل `CONTRIBUTING.md` پروژه را در
[مخزن](https://github.com/MHSanaei/3x-ui) بخوانید.
[مخزن](https://github.com/MHSanaei/L-UI) بخوانید.
- برای باگ‌ها و درخواست‌های امکانات جدید، با گام‌های بازتولید روشن، issue باز کنید.
- از Conventional Commits استفاده کنید و pull requestها را متمرکز نگه دارید.
+9 -9
View File
@@ -1,13 +1,13 @@
---
title: سؤالات متداول
description: پرسش‌های پرتکرار درباره 3x-ui — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
description: پرسش‌های پرتکرار درباره L-UI — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
icon: CircleQuestionMark
---
## آیا 3x-ui رایگان و متن‌باز است؟
## آیا L-UI رایگان و متن‌باز است؟
بله. 3x-ui تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/3x-ui) در دسترس است.
بله. L-UI تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/L-UI) در دسترس است.
## روی چه سیستم‌هایی اجرا می‌شود؟
@@ -18,7 +18,7 @@ Fedora، Arch، Alpine و موارد دیگر) روی معماری‌های `amd
## SQLite یا PostgreSQL؟
SQLite گزینه پیش‌فرض است و برای بیشتر استقرارها مناسب است. PostgreSQL برای
راه‌اندازی‌های بزرگ‌تر از طریق `XUI_DB_TYPE=postgres` و `XUI_DB_DSN` در دسترس است — به
راه‌اندازی‌های بزرگ‌تر از طریق `LUI_DB_TYPE=postgres` و `LUI_DB_DSN` در دسترس است — به
[متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
## کدام اپلیکیشن‌های کلاینت با آن کار می‌کنند؟
@@ -27,9 +27,9 @@ SQLite گزینه پیش‌فرض است و برای بیشتر استقراره
لینک اشتراک‌گذاری یا کد QR یک کلاینت را وارد کنید، یا از
[سابسکریپشن](/docs/config/subscription) استفاده کنید.
## 3x-ui چه تفاوتی با x-ui دارد؟
## L-UI چه تفاوتی با l-ui دارد؟
3x-ui یک فورک ارتقایافته از پروژه اصلی X-UI است. این پروژه پشتیبانی گسترده‌تری از
L-UI یک فورک ارتقایافته از پروژه اصلی X-UI است. این پروژه پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت چندنودی،
یک رابط کاربری ۱۳ زبانه و بسیاری از امکانات رفاهی را اضافه می‌کند.
@@ -37,11 +37,11 @@ SQLite گزینه پیش‌فرض است و برای بیشتر استقراره
اسکریپت نصب را دوباره اجرا کنید (به‌صورت درجا به‌روزرسانی می‌شود)، یا ایمیج جدید Docker را دریافت کنید.
به [نصب](/docs/guide/installation) و
[صفحه نسخه‌ها](https://github.com/MHSanaei/3x-ui/releases) مراجعه کنید.
[صفحه نسخه‌ها](https://github.com/MHSanaei/L-UI/releases) مراجعه کنید.
## از کجا می‌توانم کمک بگیرم؟
به کانال رسمی Telegram با نشانی [@XrayUI](https://t.me/XrayUI) برای
اطلاعیه‌ها و پشتیبانی انجمن بپیوندید، یا یک ایشو روی
[GitHub](https://github.com/MHSanaei/3x-ui/issues) باز کنید. برای مشکلات رایج، با
[GitHub](https://github.com/MHSanaei/L-UI/issues) باز کنید. برای مشکلات رایج، با
[عیب‌یابی](/docs/help/troubleshooting) شروع کنید.
+8 -8
View File
@@ -1,6 +1,6 @@
---
title: مهاجرت
description: مهاجرت به 3x-ui از x-ui، بین سرورها یا بین نسخه‌های 3x-ui.
description: مهاجرت به L-UI از l-ui، بین سرورها یا بین نسخه‌های L-UI.
icon: ArrowRightLeft
---
@@ -13,12 +13,12 @@ icon: ArrowRightLeft
<Step>
### از سرور قدیمی نسخه پشتیبان بگیرید
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/x-ui/x-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/l-ui/l-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
[پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) را ببینید.
</Step>
<Step>
### 3x-ui را روی سرور جدید نصب کنید
### L-UI را روی سرور جدید نصب کنید
از همان روش نصب و یک نسخهٔ سازگار استفاده کنید.
[نصب](/docs/guide/installation) را ببینید.
@@ -32,17 +32,17 @@ icon: ArrowRightLeft
</Steps>
## بین نسخه‌های 3x-ui
## بین نسخه‌های L-UI
در محدودهٔ یک backend یکسان، ارتقا معمولاً تنها به اجرای دوبارهٔ نصب‌کننده یا
کشیدن یک image جدید خلاصه می‌شود — پنل خودش پایگاه‌داده‌اش را مهاجرت می‌دهد. هنگام تغییر بین نسخه‌های **اصلی**،
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/3x-ui/releases)
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/L-UI/releases)
را بخوانید و یک نسخهٔ پشتیبان تهیه کنید.
## از x-ui
## از l-ui
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی x-ui به 3x-ui **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. 3x-ui را از نو نصب کنید و inboundها/کلاینت‌ها را
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی l-ui به L-UI **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. L-UI را از نو نصب کنید و inboundها/کلاینت‌ها را
دوباره بسازید و در همین حین لینک‌های اشتراک‌گذاری را از پنل قدیمی خروجی بگیرید.
<Callout type="warn">
@@ -1,17 +1,17 @@
---
title: عیب‌یابی
description: رفع مشکلات رایج 3x-ui — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
description: رفع مشکلات رایج L-UI — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
icon: Wrench
---
فهرستی برای رسیدگی به رایج‌ترین مشکلات. هرگاه مطمئن نبودید، سطح لاگ را بالا ببرید
(`XUI_LOG_LEVEL=debug`) و لاگ‌های پنل و Xray را بررسی کنید.
(`LUI_LOG_LEVEL=debug`) و لاگ‌های پنل و Xray را بررسی کنید.
## پنل اجرا نمی‌شود
- وضعیت سرویس و لاگ‌ها را بررسی کنید (منوی `x-ui` ← وضعیت/لاگ‌ها).
- وضعیت سرویس و لاگ‌ها را بررسی کنید (منوی `l-ui` ← وضعیت/لاگ‌ها).
- مطمئن شوید که **پورت پنل از قبل توسط سرویس دیگری اشغال نشده** باشد.
- بررسی کنید که مسیر دیتابیس قابل نوشتن باشد (پیش‌فرض `/etc/x-ui/x-ui.db`).
- بررسی کنید که مسیر دیتابیس قابل نوشتن باشد (پیش‌فرض `/etc/l-ui/l-ui.db`).
## خطای 502 / در دسترس نبودن پنل پشت یک پروکسی
@@ -37,6 +37,6 @@ icon: Wrench
<Callout type="info">
همچنان به مشکل خورده‌اید؟ در میان
[مسائل GitHub](https://github.com/MHSanaei/3x-ui/issues) جست‌وجو کنید — احتمالاً
[مسائل GitHub](https://github.com/MHSanaei/L-UI/issues) جست‌وجو کنید — احتمالاً
علامت مشکل شما قبلاً دیده شده است.
</Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
---
title: مستندات 3x-ui
description: مستندات رسمی 3x-ui — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
title: مستندات L-UI
description: مستندات رسمی L-UI — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
icon: House
---
**3x-ui** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
**L-UI** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
[Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک داشبورد مدرن برای
اینباندها، پروتکل‌ها، کلاینت‌ها، حسابداری ترافیک، سابسکریپشن‌ها و موارد دیگر در
اختیار شما می‌گذارد — بدون نیاز به ویرایش دستی JSON مربوط به Xray از طریق خط فرمان.
@@ -17,7 +17,7 @@ icon: House
<Cards>
<Card
title="3x-ui چیست؟"
title="L-UI چیست؟"
href="/docs/guide"
description="نمای کلی: Xray-core، پنل، و اینکه برای چه کسانی مناسب است."
/>
@@ -49,6 +49,6 @@ icon: House
- **عملیات** — مدیریت چندنودی، ربات Telegram، پشتیبان‌گیری و یک REST API.
<Callout type="info">
با Xray تازه آشنا شده‌اید؟ ابتدا [3x-ui چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
با Xray تازه آشنا شده‌اید؟ ابتدا [L-UI چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
اپلیکیشن‌های کلاینت شما چگونه در کنار هم کار می‌کنند.
</Callout>
@@ -1,6 +1,6 @@
---
title: پشتیبان‌گیری و بازیابی
description: از پایگاه‌داده و گواهی‌های 3x-ui خود به‌صورت دستی یا از طریق ربات Telegram پشتیبان بگیرید و آن‌ها را بازیابی کنید.
description: از پایگاه‌داده و گواهی‌های L-UI خود به‌صورت دستی یا از طریق ربات Telegram پشتیبان بگیرید و آن‌ها را بازیابی کنید.
icon: DatabaseBackup
---
@@ -9,7 +9,7 @@ icon: DatabaseBackup
## از چه چیزی پشتیبان بگیریم
- **پایگاه‌داده** — به‌صورت پیش‌فرض یک SQLite در `/etc/x-ui/x-ui.db` (یا پایگاه‌داده‌ی
- **پایگاه‌داده** — به‌صورت پیش‌فرض یک SQLite در `/etc/l-ui/l-ui.db` (یا پایگاه‌داده‌ی
PostgreSQL شما اگر از آن backend استفاده می‌کنید).
- **گواهی‌ها** — هر چیزی که زیر `/root/cert/` (یا هر جایی که گواهی‌های TLS را نگه می‌دارید)
قرار دارد.
@@ -20,7 +20,7 @@ icon: DatabaseBackup
مستقیماً از سرور کپی نمایید:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
cp /etc/l-ui/l-ui.db /root/l-ui-backup-$(date +%F).db
```
برای بازیابی، پنل را متوقف کنید، پایگاه‌داده را سر جای خود برگردانید و دوباره آن را اجرا کنید.
@@ -41,12 +41,12 @@ cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
## دامپ / بازیابی SQLite
دستور `x-ui migrate-db` پایگاه‌داده‌ی SQLite را به یک دامپ متنی SQL ساده و بالعکس تبدیل
دستور `l-ui migrate-db` پایگاه‌داده‌ی SQLite را به یک دامپ متنی SQL ساده و بالعکس تبدیل
می‌کند (برای بررسی یا انتقال میان دستگاه‌ها کاربردی است):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
l-ui migrate-db --dump /root/l-ui.sql # SQLite -> SQL text
l-ui migrate-db --restore /root/l-ui.sql # SQL text -> SQLite
```
برای مهاجرت به PostgreSQL، به [پایگاه‌داده](/docs/reference/database) مراجعه کنید.
@@ -1,14 +1,14 @@
---
title: چندنودی و میزبان‌های مدیریت‌شده
description: مدیریت چند پنل 3x-ui از یک مستر، با اعتماد مبتنی بر توکن API یا mTLS، ضربان قلب، و بازنویسی میزبان برای هر inbound جهت اشتراک‌ها.
description: مدیریت چند پنل L-UI از یک مستر، با اعتماد مبتنی بر توکن API یا mTLS، ضربان قلب، و بازنویسی میزبان برای هر inbound جهت اشتراک‌ها.
icon: Boxes
---
3x-ui می‌تواند **چندین سرور** را از یک پنل مستر واحد مدیریت کند و با **میزبان‌های مدیریت‌شده** نحوهٔ معرفی هر inbound در اشتراک‌ها را بازنویسی کند.
L-UI می‌تواند **چندین سرور** را از یک پنل مستر واحد مدیریت کند و با **میزبان‌های مدیریت‌شده** نحوهٔ معرفی هر inbound در اشتراک‌ها را بازنویسی کند.
## نودها
یک **نود** پنل 3x-ui دیگری است که پنل مستر شما آن را از طریق API نود مدیریت می‌کند. مستر هر نود را فراخوانی (poll) می‌کند و وضعیت، نسخه‌ها، CPU/حافظه، آپ‌تایم و ترافیک آن را در یک مکان نمایش می‌دهد.
یک **نود** پنل L-UI دیگری است که پنل مستر شما آن را از طریق API نود مدیریت می‌کند. مستر هر نود را فراخوانی (poll) می‌کند و وضعیت، نسخه‌ها، CPU/حافظه، آپ‌تایم و ترافیک آن را در یک مکان نمایش می‌دهد.
### افزودن یک نود

Some files were not shown because too many files have changed in this diff Show More