204 Commits
Author SHA1 Message Date
Muse f51e70cb17 release: panel V2.7.7 (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
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
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
2026-10-24 20:37:32 +00:00
Muse 419999dbf6 Merge branch 'fix/inbound-drag-sort' 2026-10-24 20:37:24 +00:00
Muse e8e154773f feat(inbounds): manual drag sort for panel inbound list
Table and mobile-card views get a grip column (HTML5 native drag, no
new dependency); only the grip is draggable, never the whole row. Drop
persists the full displayed order in one POST /panel/api/inbounds/reorder
call (single transaction, unknown ids rejected with no writes).

Order stored on model.Inbound.SortOrder (default:0;column:sort_order,
AutoMigrate backfills); only the panel list read path
(GetInboundsSlim) moves from id ASC to (sort_order, id). Subscription
generation keeps its own sub_sort_index order, the fallback tables keep
their own sort_order, and every other inbound consumer is untouched.

Cross-node by design: the order is global, not per node. The page holds
the full list and filters client-side, so a drop inside a node-filtered
or searched view computes the new order against the FULL list and sends
full ids; unlisted rows keep their relative order.
2026-10-24 20:35:43 +00:00
Muse eea1e17c35 fix(nodes): send node reorder as JSON and toast once
Without a JSON Content-Type, performFetch form-encodes {ids} to
ids=1&ids=2 and the backend ShouldBindJSON fails with "invalid
character 'i' looking for beginning of value"; the failure was also
toasted twice (HttpUtil plus this callback). Same JSON_HEADERS shape
as the host reorder call, plus silent so only this callback toasts.
2026-10-24 20:15:14 +00:00
Muse fbb296ca3d release: panel V2.7.6 (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 19:46:58 +00:00
Muse 9253c0016d Merge branch 'fix/node-manual-drag-sort' 2026-10-24 19:46:47 +00:00
Muse c29206aba2 Merge branch 'fix/inbound-node-filter-remove-local' 2026-10-24 19:46:46 +00:00
Muse 09855c7b23 feat(nodes): manual drag sort for panel node list
Panel node list rows get a grip column (HTML5 native drag, no new dependency); drop persists the full displayed order in one POST /panel/api/nodes/reorder call (single transaction, unknown ids rejected with no writes).

Order stored on model.Node.SortOrder (default 0, AutoMigrate backfills); the nodes page sorts by (sortOrder, id), so an untouched list renders exactly as before. The list read path keeps id order: the inbound filter dropdown, public page sort, and every other node consumer are untouched.

Table and card views share the same order; a failed save toasts and the display rolls back to server data on refetch.
2026-10-24 19:45:21 +00:00
Muse 9e0926be96 Merge branch 'fix/docs-l-ui-install-uninstall'
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
2026-10-24 19:24:56 +00:00
Muse 0d0a4b32ae docs: rewrite install/uninstall instructions for l-ui (drop upstream 3x-ui commands) 2026-10-24 19:24:50 +00:00
Muse c662fdc8b9 fix(clients): remove local-panel option from client node filter 2026-10-24 19:06:25 +00:00
Muse 84b91c4349 fix(inbounds): remove local-panel option from inbound node filter 2026-10-24 19:01:20 +00:00
Muse 9c6b594328 release: panel V2.7.5 (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 18:58:51 +00:00
Muse 4000be75e0 Merge branch 'fix/probe-meta-date-row' 2026-10-24 18:58:39 +00:00
Muse ad3e70d59b fix(nodes): probe meta date picker and single-row date/traffic fields 2026-10-24 18:56:48 +00:00
Muse f45a6f626f release: panel V2.7.4 (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 18:44:49 +00:00
Muse d65f86ae8e Merge branch 'fix/node-meta-hooks-order' 2026-10-24 18:44:42 +00:00
Muse 9cb985640a fix(nodes): call probe meta hooks before early return 2026-10-24 18:43:59 +00:00
Muse 2ae3f7aa15 release: panel V2.7.3 (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 18:29:23 +00:00
Muse 5f76f9b58e Merge branch 'merge/v273-combined' 2026-10-24 18:29:11 +00:00
Muse 51bb2a7e5b Merge branch 'fix/host-dialog-fields-remove' 2026-10-24 18:04:01 +00:00
Muse 1dc1924664 Merge branch 'fix/node-table-expand-remove' 2026-10-24 18:04:01 +00:00
Muse 908eda5844 Merge branch 'fix/node-dialog-hint-remove' 2026-10-24 18:04:00 +00:00
Muse abc232ae11 Merge branch 'fix/settings-topbar-hide' 2026-10-24 18:04:00 +00:00
Muse 19755418cf Merge branch 'fix/node-create-probe-meta' 2026-10-24 18:04:00 +00:00
Muse 607c37044e fix(hosts): remove tags and node fields from host dialog 2026-10-24 17:59:19 +00:00
Muse 4606708a56 fix(nodes): show probe meta draft in add-node dialog 2026-10-24 17:56:40 +00:00
Muse d8227ca06f fix(nodes): remove probe section title and hint from node dialog 2026-10-24 17:50:07 +00:00
Muse 72bdce8743 fix(nodes): reorder probe meta fields and pack group/sort/price/currency/cycle in one row 2026-10-24 17:47:26 +00:00
Muse a27e98ed24 fix(nodes): remove node table expand column and expanded history 2026-10-24 17:44:07 +00:00
Muse 346001567c fix(nodes): remove agent hint alert from node dialog 2026-10-24 17:43:03 +00:00
Muse cf2e543eb6 fix(settings): hide top save/restart bar on theme store and probe pages 2026-10-24 17:40:24 +00:00
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
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 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) 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: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) 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 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
1317 changed files with 58274 additions and 101256 deletions
+1 -1
View File
@@ -5,6 +5,6 @@ build
db db
cert cert
pgdata pgdata
x-ui/ l-ui/
*.db *.db
*.dump *.dump
+46 -46
View File
@@ -2,25 +2,25 @@
# 1. Developer Bootstrap: The active (uncommented) variables directly below # 1. Developer Bootstrap: The active (uncommented) variables directly below
# configure a safe, unprivileged local environment for 'go run .'. # configure a safe, unprivileged local environment for 'go run .'.
# This allows 'cp .env.example .env' to work out-of-the-box without root. # 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. # 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 # 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'. # 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: # 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) # LOCAL DEVELOPMENT OVERRIDES (ACTIVE BY DEFAULT)
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
XUI_DEBUG=true LUI_DEBUG=true
XUI_DB_FOLDER=x-ui LUI_DB_FOLDER=l-ui
XUI_LOG_FOLDER=x-ui LUI_LOG_FOLDER=l-ui
XUI_BIN_FOLDER=x-ui LUI_BIN_FOLDER=l-ui
XUI_INIT_WEB_BASE_PATH=/ LUI_INIT_WEB_BASE_PATH=/
# ============================================================================== # ==============================================================================
# REFERENCE CONFIGURATION (ALL OPTIONS) # REFERENCE CONFIGURATION (ALL OPTIONS)
@@ -31,21 +31,21 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Backend database type: sqlite, or postgres (also accepts postgresql / pg) # Backend database type: sqlite, or postgres (also accepts postgresql / pg)
# Default: sqlite # Default: sqlite
#XUI_DB_TYPE=sqlite #LUI_DB_TYPE=sqlite
# Folder for the SQLite database file (x-ui.db) # Folder for the SQLite database file (l-ui.db)
# Default: /etc/x-ui (Overridden to 'x-ui' in the development block above) # Default: /etc/l-ui (Overridden to 'l-ui' in the development block above)
#XUI_DB_FOLDER=/etc/x-ui #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 # Example: postgres://user:password@localhost:5432/dbname?sslmode=disable
#XUI_DB_DSN= #LUI_DB_DSN=
# Max open connections in the PostgreSQL pool # Max open connections in the PostgreSQL pool
#XUI_DB_MAX_OPEN_CONNS= #LUI_DB_MAX_OPEN_CONNS=
# Max idle connections in the PostgreSQL pool # Max idle connections in the PostgreSQL pool
#XUI_DB_MAX_IDLE_CONNS= #LUI_DB_MAX_IDLE_CONNS=
# PostgreSQL Docker Container Settings # PostgreSQL Docker Container Settings
# Default credentials used if you are running PostgreSQL via docker-compose # Default credentials used if you are running PostgreSQL via docker-compose
@@ -58,19 +58,19 @@ XUI_INIT_WEB_BASE_PATH=/
# Panel # Panel
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Override the panel port (1–65535). Takes precedence over the stored setting. # 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) # Initial web base path on FIRST launch (e.g., /panel)
# Default: / # Default: /
#XUI_INIT_WEB_BASE_PATH=/ #LUI_INIT_WEB_BASE_PATH=/
# Enable Fail2ban-based IP-limit enforcement # Enable Fail2ban-based IP-limit enforcement
# Default: true # Default: true
#XUI_ENABLE_FAIL2BAN=true #LUI_ENABLE_FAIL2BAN=true
# Skip the HSTS header — set true when TLS is terminated by a reverse proxy # Skip the HSTS header — set true when TLS is terminated by a reverse proxy
# Default: false # 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 # Logging level: debug, info, notice, warning, or error
# Default: info # Default: info
#XUI_LOG_LEVEL=info #LUI_LOG_LEVEL=info
# Debug mode. Forces log level to debug, enables Gin debug mode, # Debug mode. Forces log level to debug, enables Gin debug mode,
# and ensures frontend assets are served directly from disk (see CLAUDE.md). # and ensures frontend assets are served directly from disk (see CLAUDE.md).
# Default: false (Overridden to 'true' in the development block at the top) # Default: false (Overridden to 'true' in the development block at the top)
#XUI_DEBUG=false #LUI_DEBUG=false
# Log output directory # Log output directory
# Default: /var/log/x-ui (Overridden to 'x-ui' in the development block above) # Default: /var/log/l-ui (Overridden to 'l-ui' in the development block above)
#XUI_LOG_FOLDER=/var/log/x-ui #LUI_LOG_FOLDER=/var/log/l-ui
# Folder for the Xray-core binary and geosite/geoip files # Folder for the Xray-core binary and geosite/geoip files
# Default: bin (Overridden to 'x-ui' in the development block above) # Default: bin (Overridden to 'l-ui' in the development block above)
#XUI_BIN_FOLDER=bin #LUI_BIN_FOLDER=bin
# Legacy Path Settings # Legacy Path Settings
# Main installation folder (Default: /usr/local/x-ui for Linux, /app for Docker) # Main installation folder (Default: /usr/local/l-ui for Linux, /app for Docker)
#XUI_MAIN_FOLDER=/usr/local/x-ui #LUI_MAIN_FOLDER=/usr/local/l-ui
# Path to the systemd service file (Default: /etc/systemd/system) # 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. # Go GC target percentage; lower = less RAM, slightly more CPU.
# Default: 75 # Default: 75
#XUI_GOGC= #LUI_GOGC=
# Minutes between FreeOSMemory calls; 0 disables. # Minutes between FreeOSMemory calls; 0 disables.
# Default: 10 # Default: 10
#XUI_MEMORY_RELEASE_INTERVAL= #LUI_MEMORY_RELEASE_INTERVAL=
# Go soft memory limit in MiB # 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= #GOMEMLIMIT=
# Expose pprof profiling on 127.0.0.1:6060 # Expose pprof profiling on 127.0.0.1:6060
# Default: false # Default: false
#XUI_PPROF=false #LUI_PPROF=false
# Automatically set to 'true' inside the official Docker image. # 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. # There is normally no need to set or toggle this variable manually.
# Default: false (automatically 'true' in Docker environments) # 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) # Optional watchdog: probes a URL (optionally through a local Xray inbound)
# and restarts Xray after repeated failures. A restart drops all connected clients. # and restarts Xray after repeated failures. A restart drops all connected clients.
# Default: false # 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 # Proxy to send the probe through, e.g., socks5://127.0.0.1:1080
# Empty = only checks host connectivity # Empty = only checks host connectivity
#XUI_TUNNEL_HEALTH_PROXY= #LUI_TUNNEL_HEALTH_PROXY=
# URL to probe # URL to probe
# Default: https://www.cloudflare.com/cdn-cgi/trace # 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 # Interval between probes
# Default: 30s # Default: 30s
#XUI_TUNNEL_HEALTH_INTERVAL=30s #LUI_TUNNEL_HEALTH_INTERVAL=30s
# Per-probe timeout # Per-probe timeout
# Default: 10s # Default: 10s
#XUI_TUNNEL_HEALTH_TIMEOUT=10s #LUI_TUNNEL_HEALTH_TIMEOUT=10s
# Consecutive failures before a restart # Consecutive failures before a restart
# Default: 3 # Default: 3
#XUI_TUNNEL_HEALTH_FAILURES=3 #LUI_TUNNEL_HEALTH_FAILURES=3
# Minimum delay between restarts # Minimum delay between restarts
# Default: 5m # Default: 5m
#XUI_TUNNEL_HEALTH_COOLDOWN=5m #LUI_TUNNEL_HEALTH_COOLDOWN=5m
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Unattended install # Unattended install
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Set to 1 (or run with no TTY) to install with zero prompts. # 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 # Generated credentials will be written to /etc/l-ui/install-result.env
#XUI_NONINTERACTIVE=1 #LUI_NONINTERACTIVE=1
+5 -3
View File
@@ -1,6 +1,8 @@
# These are supported funding model platforms # 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 patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi 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 issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username polar: # Replace with a single Polar username
buy_me_a_coffee: mhsanaei buy_me_a_coffee: # upstream author's handle removed in this fork
custom: https://donate.sanaei.dev/ custom: # upstream author's donation page removed in this fork
+4 -4
View File
@@ -54,7 +54,7 @@ body:
attributes: attributes:
label: Relevant logs label: Relevant logs
description: | 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. console output. **Redact** tokens, real domains, IPs, and client UUIDs.
render: shell render: shell
validations: validations:
@@ -74,7 +74,7 @@ body:
- type: input - type: input
id: xui-version id: xui-version
attributes: attributes:
label: 3x-ui version label: L-UI version
description: Shown at the top of the panel sidebar. description: Shown at the top of the panel sidebar.
placeholder: 3.1.0 placeholder: 3.1.0
validations: validations:
@@ -92,7 +92,7 @@ body:
- type: dropdown - type: dropdown
id: install-method id: install-method
attributes: attributes:
label: How did you install 3x-ui? label: How did you install L-UI?
options: options:
- install.sh script - install.sh script
- Docker / Docker Compose - Docker / Docker Compose
@@ -159,7 +159,7 @@ body:
options: options:
- label: I searched [existing issues](../issues?q=is%3Aissue) and this bug has not been reported. - label: I searched [existing issues](../issues?q=is%3Aissue) and this bug has not been reported.
required: true 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 required: true
- label: This bug report is written in English. - label: This bug report is written in English.
required: true required: true
+4 -4
View File
@@ -1,11 +1,11 @@
blank_issues_enabled: false blank_issues_enabled: false
contact_links: contact_links:
- name: 📖 Project Wiki - name: 📖 Project home (Gitea)
url: https://github.com/MHSanaei/3x-ui/wiki 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. about: Setup, install, configuration, and "how do I…" guides live here. Please check before opening a question.
- name: 🔍 Search existing issues - 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. about: Your bug, feature, or question may already be tracked. Comment on the existing one rather than opening a duplicate.
- name: 🚀 Latest release - 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. 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 name: Feature request
description: Suggest an idea or improvement for 3x-ui description: Suggest an idea or improvement for L-UI
title: "[Feature]: " title: "[Feature]: "
labels: ["enhancement"] labels: ["enhancement"]
+5 -5
View File
@@ -1,5 +1,5 @@
name: Question name: Question
description: Ask how to do something with 3x-ui description: Ask how to do something with L-UI
title: "[Question]: " title: "[Question]: "
labels: ["question"] labels: ["question"]
@@ -9,7 +9,7 @@ body:
value: | value: |
Before opening a question, please: 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. most setup, install, and "how do I …" answers live there.
- Search [existing issues](../issues?q=is%3Aissue) — the question - Search [existing issues](../issues?q=is%3Aissue) — the question
may already have been asked. may already have been asked.
@@ -43,7 +43,7 @@ body:
- type: input - type: input
id: xui-version id: xui-version
attributes: attributes:
label: 3x-ui version label: L-UI version
description: Shown at the top of the panel sidebar. description: Shown at the top of the panel sidebar.
placeholder: 3.1.0 placeholder: 3.1.0
validations: validations:
@@ -52,7 +52,7 @@ body:
- type: dropdown - type: dropdown
id: install-method id: install-method
attributes: attributes:
label: How did you install 3x-ui? label: How did you install L-UI?
options: options:
- install.sh script - install.sh script
- Docker / Docker Compose - Docker / Docker Compose
@@ -85,7 +85,7 @@ body:
attributes: attributes:
label: Before submitting label: Before submitting
options: 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 required: true
- label: This is a usage question, not a bug report. - label: This is a usage question, not a bug report.
required: true required: true
+17 -17
View File
@@ -13,7 +13,7 @@ question it already answers.
## Stack ## 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. - 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 - 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 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 fork's management API (`PUT /secrets`) so connections survive, with a process
restart as the fallback on older binaries. restart as the fallback on older binaries.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux, the executable - Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux, the executable
directory on Windows) or PostgreSQL (`XUI_DB_TYPE` / `XUI_DB_DSN`). The SQLite directory on Windows) or PostgreSQL (`LUI_DB_TYPE` / `LUI_DB_DSN`). The SQLite
driver is CGo, so `CGO_ENABLED=0` builds fail. driver is CGo, so `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, built - Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, built
into `internal/web/dist/` (gitignored) and embedded with `embed.FS`. into `internal/web/dist/` (gitignored) and embedded with `embed.FS`.
@@ -36,7 +36,7 @@ question it already answers.
| area | path | | area | path |
| --- | --- | | --- | --- |
| entry point + `x-ui` CLI | `main.go` | | entry point + `l-ui` CLI | `main.go` |
| env parsing | `internal/config/` | | env parsing | `internal/config/` |
| schema, migrations | `internal/database/`, `internal/database/model/` | | schema, migrations | `internal/database/`, `internal/database/model/` |
| Xray child process + config | `internal/xray/` | | Xray child process + config | `internal/xray/` |
@@ -48,7 +48,7 @@ question it already answers.
| master/sub-node over mTLS | `internal/web/runtime/` | | master/sub-node over mTLS | `internal/web/runtime/` |
| i18n | `internal/web/locale/`, `internal/web/translation/` | | i18n | `internal/web/locale/`, `internal/web/translation/` |
| UI source | `frontend/src/` | | 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 ## 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, 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, typed error or emitted string — `err != nil` and `len(x) > 0` are findings,
not nits. Prefer real dependencies: a throwaway DB via 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. `httptest` for HTTP. `internal/sub`'s `initSubDB(t)` is the template.
A test must FAIL without its fix; one that passes either way certifies A test must FAIL without its fix; one that passes either way certifies
nothing and then gets cited as proof the fix works. 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 | | gate | covers |
| --- | --- | | --- | --- |
| `XUI_TEST_PG_DSN` | PostgreSQL-specific paths | | `LUI_TEST_PG_DSN` | PostgreSQL-specific paths |
| `XUI_DB_TYPE` + `XUI_DB_DSN` | dialect-dependent behaviour | | `LUI_DB_TYPE` + `LUI_DB_DSN` | dialect-dependent behaviour |
| `XRAY_E2E_BINARY` | the Xray gRPC end-to-end tests in `internal/xray/` | | `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 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. test that cannot fail is invisible to CI. `make verify` is the local gate.
## Support facts reporters get wrong ## 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 - 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: - The installer service environment file is DISTRO-DEPENDENT:
`/etc/default/x-ui` (Debian/Ubuntu), `/etc/conf.d/x-ui` (Arch), `/etc/default/l-ui` (Debian/Ubuntu), `/etc/conf.d/l-ui` (Arch),
`/etc/sysconfig/x-ui` (RHEL/Fedora). Naming the wrong one means the reporter's `/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 edit is silently never read by systemd — a common cause of "I set the variable
and nothing happened". and nothing happened".
- Windows is supported. There the database sits next to the executable, not in - Windows is supported. There the database sits next to the executable, not in
`/etc` — never quote the Linux path to a Windows user. `/etc` — never quote the Linux path to a Windows user.
- SQLite to PostgreSQL: `x-ui migrate-db --dsn "postgres://..."`, then set - SQLite to PostgreSQL: `l-ui migrate-db --dsn "postgres://..."`, then set
`XUI_DB_TYPE`/`XUI_DB_DSN` in that file and `systemctl restart x-ui`. The `LUI_DB_TYPE`/`LUI_DB_DSN` in that file and `systemctl restart l-ui`. The
source SQLite file is left in place. source SQLite file is left in place.
- Docker image `ghcr.io/mhsanaei/3x-ui`; PostgreSQL profile - Docker image `ghcr.io/mhsanaei/3x-ui`; PostgreSQL profile
`docker compose --profile postgres up -d`. Fail2ban IP-limit enforcement needs `docker compose --profile postgres up -d`. Fail2ban IP-limit enforcement needs
`NET_ADMIN` + `NET_RAW` (compose grants them; a bare `docker run` must add `NET_ADMIN` + `NET_RAW` (compose grants them; a bare `docker run` must add
`--cap-add=NET_ADMIN --cap-add=NET_RAW`). `--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 `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". every few minutes".
- Security per inbound is none / tls / reality. XTLS is a VLESS *flow* - 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 (`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-timeout 5s
--health-retries 5 --health-retries 5
env: env:
XUI_DB_TYPE: postgres LUI_DB_TYPE: postgres
XUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable" LUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
steps: steps:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
- uses: actions/setup-go@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/**)" --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/**)" --disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: | 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 repository, an open-source web control panel for managing Xray-core
servers. You are the only automated reply an issue ever gets. Your servers. You are the only automated reply an issue ever gets. Your
question is: IS THE REPORTED PROBLEM REAL, AND IF SO, WHY? question is: IS THE REPORTED PROBLEM REAL, AND IF SO, WHY?
@@ -106,7 +106,7 @@ jobs:
reports, "enhancement" for feature requests, "question" for reports, "enhancement" for feature requests, "question" for
questions - so a pre-applied type label is a template default to questions - so a pre-applied type label is a template default to
verify, not the reporter's considered classification. The bug form 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 collects logs, the Xray version, affected areas and reverse-proxy
setup; the question form requires the version and install method. It setup; the question form requires the version and install method. It
all arrives under "### <heading>" sections of the body. Read those all arrives under "### <heading>" sections of the body. Read those
@@ -251,7 +251,7 @@ jobs:
question you could have answered by reading more code. question you could have answered by reading more code.
SECURITY EXCEPTION, which overrides everything else: if the report 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 authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation - do NOT investigate or credential exposure, privilege escalation - do NOT investigate or
analyse it publicly. Post one short comment asking the reporter to 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 - CLOSE AS INVALID when the body, judged exactly as written, is
empty or only whitespace, punctuation or emoji; pure gibberish; empty or only whitespace, punctuation or emoji; pure gibberish;
advertising or unrelated links; a throwaway test ("test", "asdf"); 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 `invalid` label, and
`gh issue close ${{ github.event.issue.number }} --reason "not planned"`. `gh issue close ${{ github.event.issue.number }} --reason "not planned"`.
A short, vague, badly formatted, machine-translated or low-quality 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/**)" --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/**)" --disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: | 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: Key layout:
- main.go holds the entry point and the x-ui management CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert). - 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 (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). - 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/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/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. - 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/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/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/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/. - 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. - 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. - 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. 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. 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/**)" --disallowedTools "Bash,WebFetch,WebSearch,Task,Edit(//**/.git/**),Read(//**/.git/**)"
prompt: | prompt: |
The repository owner asked for the merge conflicts on pull request 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 web panel for managing Xray-core servers, to be resolved. The merge
of `${{ steps.merge.outputs.base }}` into the pull request's branch of `${{ steps.merge.outputs.base }}` into the pull request's branch
`${{ steps.merge.outputs.head }}` is already in progress in the `${{ steps.merge.outputs.head }}` is already in progress in the
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
uses: docker/metadata-action@v6 uses: docker/metadata-action@v6
with: with:
images: | images: |
hsanaeii/3x-ui hsanaeii/L-UI
ghcr.io/mhsanaei/3x-ui ghcr.io/mhsanaei/3x-ui
tags: | tags: |
type=ref,event=branch type=ref,event=branch
+29 -29
View File
@@ -13,9 +13,9 @@ on:
- "go.sum" - "go.sum"
- "**.sh" - "**.sh"
- "frontend/**" - "frontend/**"
- "x-ui.service.debian" - "l-ui.service.debian"
- "x-ui.service.arch" - "l-ui.service.arch"
- "x-ui.service.rhel" - "l-ui.service.rhel"
- ".github/workflows/release.yml" - ".github/workflows/release.yml"
pull_request: pull_request:
paths: paths:
@@ -24,9 +24,9 @@ on:
- "go.sum" - "go.sum"
- "**.sh" - "**.sh"
- "frontend/**" - "frontend/**"
- "x-ui.service.debian" - "l-ui.service.debian"
- "x-ui.service.arch" - "l-ui.service.arch"
- "x-ui.service.rhel" - "l-ui.service.rhel"
- ".github/workflows/release.yml" - ".github/workflows/release.yml"
jobs: jobs:
@@ -113,15 +113,15 @@ jobs:
file xui-release file xui-release
ldd xui-release || echo "Static binary confirmed" ldd xui-release || echo "Static binary confirmed"
mkdir x-ui mkdir l-ui
cp xui-release x-ui/ cp xui-release l-ui/
cp x-ui.service.debian x-ui/ cp l-ui.service.debian l-ui/
cp x-ui.service.arch x-ui/ cp l-ui.service.arch l-ui/
cp x-ui.service.rhel x-ui/ cp l-ui.service.rhel l-ui/
cp x-ui.sh x-ui/ cp l-ui.sh l-ui/
mv x-ui/xui-release x-ui/x-ui mv l-ui/xui-release l-ui/l-ui
mkdir x-ui/bin mkdir l-ui/bin
cd x-ui/bin cd l-ui/bin
# Download dependencies # Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.7.28/" Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -183,13 +183,13 @@ jobs:
cd ../.. cd ../..
- name: Package - 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 - name: Upload files to Artifacts
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: x-ui-linux-${{ matrix.platform }} name: l-ui-linux-${{ matrix.platform }}
path: ./x-ui-linux-${{ matrix.platform }}.tar.gz path: ./l-ui-linux-${{ matrix.platform }}.tar.gz
- name: Upload files to GH release - name: Upload files to GH release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
@@ -197,8 +197,8 @@ jobs:
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
file: x-ui-linux-${{ matrix.platform }}.tar.gz file: l-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz asset_name: l-ui-linux-${{ matrix.platform }}.tar.gz
overwrite: true overwrite: true
prerelease: true prerelease: true
@@ -277,10 +277,10 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
$retry = @{ MaximumRetryCount = 5; RetryIntervalSec = 10 } $retry = @{ MaximumRetryCount = 5; RetryIntervalSec = 10 }
mkdir x-ui mkdir l-ui
Copy-Item xui-release.exe x-ui\x-ui.exe Copy-Item xui-release.exe l-ui\l-ui.exe
mkdir x-ui\bin mkdir l-ui\bin
cd x-ui\bin cd l-ui\bin
# Download Xray for Windows # Download Xray for Windows
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.7.28/" $Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -315,13 +315,13 @@ jobs:
- name: Package to Zip - name: Package to Zip
shell: pwsh shell: pwsh
run: | 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 - name: Upload files to Artifacts
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: x-ui-windows-amd64 name: l-ui-windows-amd64
path: ./x-ui-windows-amd64.zip path: ./l-ui-windows-amd64.zip
- name: Upload files to GH release - name: Upload files to GH release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
@@ -329,8 +329,8 @@ jobs:
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }} tag: ${{ github.ref_name }}
file: x-ui-windows-amd64.zip file: l-ui-windows-amd64.zip
asset_name: x-ui-windows-amd64.zip asset_name: l-ui-windows-amd64.zip
overwrite: true overwrite: true
prerelease: true prerelease: true
+2 -2
View File
@@ -65,5 +65,5 @@ jobs:
- uses: actions/checkout@v7 - uses: actions/checkout@v7
- name: Pinned release install smoke test - name: Pinned release install smoke test
env: env:
XUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }} LUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }}
run: bash deploy/test/smoke-noninteractive.sh "$XUI_SMOKE_VERSION" run: bash deploy/test/smoke-noninteractive.sh "$LUI_SMOKE_VERSION"
+7 -4
View File
@@ -17,8 +17,11 @@ tmp/
# Ignore build and distribution directories # Ignore build and distribution directories
backup/ backup/
bin/ bin/
x-ui/ l-ui/
dist/ 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/ release/
node_modules/ node_modules/
@@ -31,9 +34,9 @@ Thumbs.db
# Ignore Go build files # Ignore Go build files
*.exe *.exe
x-ui.db l-ui.db
x-ui.db-shm l-ui.db-shm
x-ui.db-wal l-ui.db-wal
system_metrics.gob system_metrics.gob
*.dump *.dump
+16 -16
View File
@@ -3,41 +3,41 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Run 3x-ui (Debug)", "name": "Run L-UI (Debug)",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}", "program": "${workspaceFolder}",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": { "env": {
"XUI_DEBUG": "true", "LUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui", "LUI_DB_FOLDER": "l-ui",
"XUI_LOG_FOLDER": "x-ui", "LUI_LOG_FOLDER": "l-ui",
"XUI_BIN_FOLDER": "x-ui" "LUI_BIN_FOLDER": "l-ui"
}, },
"console": "integratedTerminal" "console": "integratedTerminal"
}, },
{ {
"name": "Run 3x-ui (Postgres)", "name": "Run L-UI (Postgres)",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}", "program": "${workspaceFolder}",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": { "env": {
"XUI_DEBUG": "true", "LUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui", "LUI_LOG_FOLDER": "l-ui",
"XUI_BIN_FOLDER": "x-ui", "LUI_BIN_FOLDER": "l-ui",
"XUI_DB_TYPE": "postgres", "LUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable" "LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable"
}, },
"windows": { "windows": {
"env": { "env": {
"XUI_DEBUG": "true", "LUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui", "LUI_LOG_FOLDER": "l-ui",
"XUI_BIN_FOLDER": "x-ui", "LUI_BIN_FOLDER": "l-ui",
"XUI_DB_TYPE": "postgres", "LUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable", "LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}" "PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
} }
}, },
+3 -3
View File
@@ -8,14 +8,14 @@
"args": [ "args": [
"build", "build",
"-o", "-o",
"bin/3x-ui", "bin/L-UI",
"./main.go" "./main.go"
], ],
"windows": { "windows": {
"args": [ "args": [
"build", "build",
"-o", "-o",
"bin/3x-ui.exe", "bin/L-UI.exe",
"./main.go" "./main.go"
] ]
}, },
@@ -41,7 +41,7 @@
"options": { "options": {
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": { "env": {
"XUI_DEBUG": "true" "LUI_DEBUG": "true"
} }
}, },
"problemMatcher": [ "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 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 traffic reset also calls `POST /secrets/{name}/reset-quota` so a renewed client
is not re-blocked by the sidecar's quota counter. 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 - Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux; the executable dir on
Windows), PostgreSQL optional (`XUI_DB_TYPE` / `XUI_DB_DSN`). The CGo SQLite 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. driver (`mattn/go-sqlite3`) needs a C compiler — `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, - Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`,
built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`. built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`.
## Repo map ## Repo map
- `main.go` — entry point + `x-ui` CLI (run, migrate, migrate-db, setting, cert). - `main.go` — entry point + `l-ui` CLI (run, migrate, migrate-db, setting, cert).
- `internal/config/` — env parsing (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER, - `internal/config/` — env parsing (LUI_DEBUG, LUI_LOG_LEVEL, LUI_LOG_FOLDER,
XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_*). LUI_BIN_FOLDER, LUI_SKIP_HSTS, LUI_PORT, LUI_DB_*).
- `internal/database/` + `internal/database/model/` — GORM schema (~24 models; - `internal/database/` + `internal/database/model/` — GORM schema (~24 models;
Inbound, Client, Setting, User are the core), inbound Protocol enum, Inbound, Client, Setting, User are the core), inbound Protocol enum,
AutoMigrate + hand-written migrations in `db.go`. 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, - Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests,
`t.Helper()` on helpers. Assert the exact value / typed error / emitted `t.Helper()` on helpers. Assert the exact value / typed error / emitted
string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via 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. `t.Cleanup(func() { _ = database.CloseDB() })`; `httptest` for HTTP.
`internal/sub`'s `initSubDB(t)` is the template. `internal/sub`'s `initSubDB(t)` is the template.
- A test must fail without its fix. Write it, revert the fix, watch it go red, - 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 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. 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`. - 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`, - Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `LUI_TEST_PG_DSN`,
`XUI_DB_TYPE`+`XUI_DB_DSN`, `XRAY_E2E_BINARY` or `XUI_SCALE_TEST` is set — a `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. green `go test ./...` does not mean those paths ran.
## Frontend conventions (summary; full version in frontend/CLAUDE.md) ## 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 a headless-Chromium Storybook project, so run
`npx playwright install --with-deps chromium` once or `make verify` fails. `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 - 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 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. restart `go run .` or you get a blank page with 404s.
- After touching share-link logic (`src/lib/xray/`), run `npm run test` (golden - After touching share-link logic (`src/lib/xray/`), run `npm run test` (golden
+40 -40
View File
@@ -1,6 +1,6 @@
# Contributing # 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 ## Prerequisites
@@ -50,12 +50,12 @@ Cross-building the Linux SQLite target from Windows (or vice versa) requires a s
## First-time setup ## First-time setup
```bash ```bash
git clone https://github.com/MHSanaei/3x-ui.git git clone https://git.881218.xyz/rogue/l-ui.git
cd 3x-ui cd L-UI
cp .env.example .env cp .env.example .env
mkdir x-ui mkdir l-ui
go mod download go mod download
@@ -65,18 +65,18 @@ npm run build
cd .. 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 LUI_DEBUG=true
XUI_DB_FOLDER=x-ui LUI_DB_FOLDER=l-ui
XUI_LOG_FOLDER=x-ui LUI_LOG_FOLDER=l-ui
XUI_BIN_FOLDER=x-ui LUI_BIN_FOLDER=l-ui
XUI_INIT_WEB_BASE_PATH=/ LUI_INIT_WEB_BASE_PATH=/
# XUI_PORT=8080 # 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 ## Running
@@ -88,7 +88,7 @@ Open [http://localhost:2053](http://localhost:2053) and log in with `admin` / `a
### Inside VS Code ### 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 ```jsonc
{ {
@@ -96,33 +96,33 @@ The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run 3
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Run 3x-ui (Debug)", "name": "Run L-UI (Debug)",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}", "program": "${workspaceFolder}",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": { "env": {
"XUI_DEBUG": "true", "LUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui", "LUI_DB_FOLDER": "l-ui",
"XUI_LOG_FOLDER": "x-ui", "LUI_LOG_FOLDER": "l-ui",
"XUI_BIN_FOLDER": "x-ui" "LUI_BIN_FOLDER": "l-ui"
}, },
"console": "integratedTerminal" "console": "integratedTerminal"
}, },
{ {
"name": "Run 3x-ui (Postgres)", "name": "Run L-UI (Postgres)",
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"program": "${workspaceFolder}", "program": "${workspaceFolder}",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"env": { "env": {
"XUI_DEBUG": "true", "LUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui", "LUI_LOG_FOLDER": "l-ui",
"XUI_BIN_FOLDER": "x-ui", "LUI_BIN_FOLDER": "l-ui",
"XUI_DB_TYPE": "postgres", "LUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable", "LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}" "PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
}, },
"console": "integratedTerminal" "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. 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 ### 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/xray/` | Xray-core process lifecycle and gRPC API client |
| `internal/sub/` | Subscription endpoints (raw, JSON, Clash) | | `internal/sub/` | Subscription endpoints (raw, JSON, Clash) |
| `internal/config/` | Environment-variable helpers, paths, defaults | | `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 ## 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. - **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. - **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 ### Running
@@ -297,24 +297,24 @@ CI runs this for you nightly (and on demand) via `.github/workflows/mutation.yml
| Variable | Default | Purpose | | Variable | Default | Purpose |
|----------|---------|---------| |----------|---------|---------|
| `XUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk | | `LUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk |
| `XUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` | | `LUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` |
| `XUI_DB_FOLDER` | platform default | Where `x-ui.db` lives | | `LUI_DB_FOLDER` | platform default | Where `l-ui.db` lives |
| `XUI_LOG_FOLDER` | platform default | Where `3xui.log` lives | | `LUI_LOG_FOLDER` | platform default | Where `3xui.log` lives |
| `XUI_BIN_FOLDER` | `bin` | Where the xray binary, geo files, and xray `config.json` live | | `LUI_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 | | `LUI_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`) | | `LUI_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` | | `LUI_DB_TYPE` | `sqlite` | Set to `postgres` to use PostgreSQL via `LUI_DB_DSN` |
| `XUI_DB_DSN` | — | PostgreSQL DSN when `XUI_DB_TYPE=postgres` | | `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, current process without changing the stored setting. Unset, empty, whitespace-only,
malformed, or out-of-range values fall back to `webPort`; invalid configured values 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 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 ## 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 #!/bin/sh
# Start fail2ban with the 3x-ipl jail # Start fail2ban with the 3x-ipl jail
if [ "$XUI_ENABLE_FAIL2BAN" = "true" ]; then if [ "$LUI_ENABLE_FAIL2BAN" = "true" ]; then
LOG_FOLDER="${XUI_LOG_FOLDER:-/var/log/x-ui}" LOG_FOLDER="${LUI_LOG_FOLDER:-/var/log/l-ui}"
mkdir -p "$LOG_FOLDER" mkdir -p "$LOG_FOLDER"
touch "$LOG_FOLDER/3xipl.log" "$LOG_FOLDER/3xipl-banned.log" touch "$LOG_FOLDER/3xipl.log" "$LOG_FOLDER/3xipl-banned.log"
@@ -33,7 +33,7 @@ EOF
# added later without regenerating these files. # 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, -) 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" [ -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" EXEMPT_PORTS="$SSH_PORTS"
[ -n "$PANEL_PORT" ] && EXEMPT_PORTS="$EXEMPT_PORTS,$PANEL_PORT" [ -n "$PANEL_PORT" ] && EXEMPT_PORTS="$EXEMPT_PORTS,$PANEL_PORT"
@@ -78,5 +78,5 @@ if [ -f /root/.acme.sh/acme.sh ]; then
crond crond
fi fi
# Run x-ui # Run l-ui
exec /app/x-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_ENABLED=1
ENV CGO_CFLAGS="-D_LARGEFILE64_SOURCE" 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" RUN ./DockerInit.sh "$TARGETARCH"
# ======================================================== # ========================================================
# Stage: Final Image of 3x-ui # Stage: Final Image of L-UI
# ======================================================== # ========================================================
FROM alpine FROM alpine
ENV TZ=Asia/Tehran ENV TZ=Asia/Tehran
@@ -47,7 +47,7 @@ RUN apk add --no-cache --update \
COPY --from=builder /app/build/ /app/ COPY --from=builder /app/build/ /app/
COPY --from=builder /app/DockerEntrypoint.sh /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 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 \ RUN chmod +x \
/app/DockerEntrypoint.sh \ /app/DockerEntrypoint.sh \
/app/x-ui \ /app/l-ui \
/usr/bin/x-ui /usr/bin/l-ui
ENV XUI_IN_DOCKER="true" ENV LUI_IN_DOCKER="true"
ENV XUI_MAIN_FOLDER="/app" ENV LUI_MAIN_FOLDER="/app"
ENV XUI_ENABLE_FAIL2BAN="true" ENV LUI_ENABLE_FAIL2BAN="true"
ENV XUI_DB_TYPE="" ENV LUI_DB_TYPE=""
ENV XUI_DB_DSN="" ENV LUI_DB_DSN=""
EXPOSE 2053 EXPOSE 2053
VOLUME [ "/etc/x-ui" ] VOLUME [ "/etc/l-ui" ]
CMD [ "./x-ui" ] CMD [ "./l-ui" ]
ENTRYPOINT [ "/app/DockerEntrypoint.sh" ] ENTRYPOINT [ "/app/DockerEntrypoint.sh" ]
+10 -7
View File
@@ -1,7 +1,7 @@
# 3x-ui 路由器主控精简版 — 定版清单 # L-UI 路由器主控精简版 — 定版清单
> 2026-10-20 与用户逐项讨论中。本文档定版前不开工。 > 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。 > Alpine 主控 = 备用,趋于退役。精简目标:二开构建压内存,验收线 RSS ≤ 90MB。
## 保留(已定) ## 保留(已定)
@@ -24,13 +24,16 @@
- 安全设置:双重验证(2FA,用户不用) - 安全设置:双重验证(2FA,用户不用)
- 邮件模块(SMTP 发送:到期/流量提醒等,用户不用) - 邮件模块(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 等)——建议裁 - 协议范围:保留全部协议模板(VLESS、SS2022、VMess、Trojan、WireGuard、TUIC、Hysteria、MTProto 等),不收窄
- IP 检查 / 测速类后台任务——建议裁 - IP 检查 / 测速类后台任务:保留 → **2026-10-21 晚用户改口推翻本项**:出站测速 + 出口探测(同一动作,测的是主控本地网络位置;精简主控不跑本机核心、无本地出站,测速结果无意义)连同重启/停止核心控件与接口,已于 P9 第 4 条摘除。其余三项(协议范围 / ACME / 多用户)保留不变,不要再翻出来问。
- 面板内置 ACME 签证书(走 CF Tunnel,不直签)——建议裁 - 面板内置 ACME 签证书:保留
- 多用户功能(单管理员使用)——建议裁 - 多用户功能:保留
- 用户理由:这四块以静态代码为主,裁掉省不了多少内存。此节关闭,后续轮次不要再翻出来问。
## 修复(非裁剪,已定) ## 修复(非裁剪,已定)
+36 -53
View File
@@ -2,18 +2,13 @@
<p align="center"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </p>
**3X-UI** هي لوحة تحكم ويب متقدمة ومفتوحة المصدر لإدارة خوادم [Xray-core](https://github.com/XTLS/Xray-core). توفّر واجهة نظيفة ومتعددة اللغات لنشر وتكوين ومراقبة مجموعة واسعة من بروتوكولات الوكيل وVPN — من خادم VPS واحد إلى عمليات النشر متعددة العقد. **3X-UI** هي لوحة تحكم ويب متقدمة ومفتوحة المصدر لإدارة خوادم [Xray-core](https://github.com/XTLS/Xray-core). توفّر واجهة نظيفة ومتعددة اللغات لنشر وتكوين ومراقبة مجموعة واسعة من بروتوكولات الوكيل وVPN — من خادم VPS واحد إلى عمليات النشر متعددة العقد.
@@ -69,31 +64,31 @@
## البدء السريع ## البدء السريع
```bash ```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`): لتثبيت إصدار محدد، أضِف وسمه (مثل `v3.4.0`):
```bash ```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`: لتثبيت بنية **dev** المتجددة (أحدث إصدار أولي لكل التزام (commit) من `main`، وليس إصدارًا مستقرًا)، مرّر `dev-latest`:
```bash ```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. يعمل المثبِّت أيضًا **بشكل غير تفاعلي** لـ 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) - [بيانات مستخدم cloud-init](deploy/cloud-init/) — تثبيت غير تفاعلي على أي سحابة (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [ملاحظات Hetzner Cloud](deploy/marketplace/hetzner/) — نشر يعتمد على cloud-init على Hetzner - [ملاحظات 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) يتم اختيارهما أثناء التثبيت: يدعم 3X-UI خلفيتين (backends) يتم اختيارهما أثناء التثبيت:
- **SQLite** (افتراضي) — ملف واحد في `/etc/x-ui/x-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة. - **SQLite** (افتراضي) — ملف واحد في `/etc/l-ui/l-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة.
- **PostgreSQL** — موصى به لأعداد العملاء الكبيرة أو الإعدادات متعددة العقد. يمكن للمثبِّت تثبيت PostgreSQL محليًا لك، أو قبول DSN لخادم موجود. - **PostgreSQL** — موصى به لأعداد العملاء الكبيرة أو الإعدادات متعددة العقد. يمكن للمثبِّت تثبيت PostgreSQL محليًا لك، أو قبول DSN لخادم موجود.
في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/x-ui`): في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/l-ui`):
``` ```
XUI_DB_TYPE=postgres LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### ترحيل تثبيت SQLite موجود إلى PostgreSQL ### ترحيل تثبيت SQLite موجود إلى PostgreSQL
```bash ```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"
# ثم عيّن XUI_DB_TYPE و XUI_DB_DSN في /etc/default/x-ui وأعد التشغيل: # ثم عيّن LUI_DB_TYPE و LUI_DB_DSN في /etc/default/l-ui وأعد التشغيل:
systemctl restart x-ui systemctl restart l-ui
``` ```
يبقى ملف SQLite الأصلي دون تغيير؛ احذفه يدويًا بعد التحقق من الخلفية الجديدة. يبقى ملف SQLite الأصلي دون تغيير؛ احذفه يدويًا بعد التحقق من الخلفية الجديدة.
### Docker ### Docker
يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `XUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل: يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `LUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل:
```bash ```bash
docker compose --profile postgres up -d 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` بدلاً من ذلك، فأضِف الصلاحيات بنفسك، وإلا فسيتم تسجيل عمليات الحظر دون تطبيقها أبدًا: تتضمن الصورة Fail2ban (مُفعَّل افتراضيًا) لفرض **حدود IP** لكل عميل. يحظر Fail2ban المخالفين باستخدام `iptables`، الذي يتطلب صلاحية `NET_ADMIN`. يمنح `docker-compose.yml` هذه الصلاحية مسبقًا عبر `cap_add`؛ إذا شغّلت الحاوية باستخدام `docker run` بدلاً من ذلك، فأضِف الصلاحيات بنفسك، وإلا فسيتم تسجيل عمليات الحظر دون تطبيقها أبدًا:
```bash ```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` | | `LUI_DB_TYPE` | خلفية قاعدة البيانات: `sqlite` أو `postgres` | `sqlite` |
| `XUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `XUI_DB_TYPE=postgres`) | — | | `LUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `LUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/x-ui` | | `LUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — | | `LUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — | | `LUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` | | `LUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` |
| `XUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` | | `LUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` |
| `XUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` | | `LUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | تفعيل وضع التصحيح | `false` | | `LUI_DEBUG` | تفعيل وضع التصحيح | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` | | `LUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — | | `LUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — |
| `XUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` | | `LUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` | | `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` | | `LUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | الحد الأدنى للتأخير بين عمليات إعادة التشغيل المتتالية | `5m` | | `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: **إذا كان هذا المشروع مفيدًا لك، فقد ترغب في إعطائه**: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"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </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. **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 ## Inicio Rápido
```bash ```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`): Para instalar una versión específica, añade su etiqueta (p. ej. `v3.4.0`):
```bash ```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`: Para instalar la versión **dev** continua (la última prelanzamiento por commit desde `main`, no una versión estable), pasa `dev-latest`:
```bash ```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 ### Instalación desatendida
El instalador también se ejecuta de forma **no interactiva** para cloud-init. 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 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) - [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 - [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: 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. - **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 LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### Migrar una instalación de SQLite existente a PostgreSQL ### Migrar una instalación de SQLite existente a PostgreSQL
```bash ```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"
# luego define XUI_DB_TYPE y XUI_DB_DSN en /etc/default/x-ui y reinicia: # luego define LUI_DB_TYPE y LUI_DB_DSN en /etc/default/l-ui y reinicia:
systemctl restart x-ui systemctl restart l-ui
``` ```
El archivo SQLite de origen permanece intacto; elimínalo manualmente una vez que hayas verificado el nuevo backend. El archivo SQLite de origen permanece intacto; elimínalo manualmente una vez que hayas verificado el nuevo backend.
### Docker ### 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 ```bash
docker compose --profile postgres up -d 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: 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 ```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 ## Variables de Entorno
| Variable | Descripción | Predeterminado | | Variable | Descripción | Predeterminado |
| --- | --- | --- | | --- | --- | --- |
| `XUI_DB_TYPE` | Backend de base de datos: `sqlite` o `postgres` | `sqlite` | | `LUI_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`) | — | | `LUI_DB_DSN` | Cadena de conexión de PostgreSQL (cuando `LUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/x-ui` | | `LUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Máximo de conexiones abiertas (pool de PostgreSQL) | — | | `LUI_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) | — | | `LUI_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 | `/` | | `LUI_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` | | `LUI_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` | | `LUI_LOG_LEVEL` | Nivel de registro (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Habilitar el modo de depuración | `false` | | `LUI_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` | | `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` |
| `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 | — | | `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 | — |
| `XUI_TUNNEL_HEALTH_URL` | URL sondeada para verificar la salud del túnel | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_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` | | `LUI_TUNNEL_HEALTH_INTERVAL` | Intervalo entre sondeos | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` | | `LUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Fallos consecutivos antes de que se active un reinicio | `3` | | `LUI_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_TUNNEL_HEALTH_COOLDOWN` | Retardo mínimo entre reinicios consecutivos | `5m` |
## Idiomas Compatibles ## Idiomas Compatibles
@@ -184,23 +179,10 @@ Las contribuciones son bienvenidas. Por favor, lee la [Guía de contribución](/
## Herramientas de la Comunidad ## 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 ## Apoyar el Proyecto
**Si este proyecto te es útil, puedes darle una**:star2: **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"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </p>
**3X-UI** یک پنل کنترل وب پیشرفته و متن‌باز برای مدیریت سرورهای [Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک رابط کاربری تمیز و چندزبانه برای استقرار، پیکربندی و نظارت بر طیف گسترده‌ای از پروتکل‌های پراکسی و VPN ارائه می‌دهد — از یک VPS تکی تا استقرارهای چندنودی. **3X-UI** یک پنل کنترل وب پیشرفته و متن‌باز برای مدیریت سرورهای [Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک رابط کاربری تمیز و چندزبانه برای استقرار، پیکربندی و نظارت بر طیف گسترده‌ای از پروتکل‌های پراکسی و VPN ارائه می‌دهد — از یک VPS تکی تا استقرارهای چندنودی.
@@ -69,31 +64,31 @@
## شروع سریع ## شروع سریع
```bash ```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`): برای نصب یک نسخه‌ی مشخص، تگ آن را در انتها اضافه کنید (مثلاً `v3.4.0`):
```bash ```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` را پاس دهید: برای نصب نسخه‌ی غلتانِ **dev** (آخرین پیش‌انتشار به‌ازای هر کامیت از شاخه‌ی `main`، نه یک انتشار پایدار)، مقدار `dev-latest` را پاس دهید:
```bash ```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 اجرا می‌شود. نصب‌کننده به‌صورت **غیرتعاملی** نیز برای 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) - [user-data مربوط به Cloud-init](deploy/cloud-init/) — نصب بدون نظارت روی هر ابری (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [یادداشت‌های Hetzner Cloud](deploy/marketplace/hetzner/) — استقرار مبتنی بر cloud-init روی Hetzner - [یادداشت‌های 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 از دو بک‌اند پشتیبانی می‌کند که در حین نصب انتخاب می‌شوند: ‏3X-UI از دو بک‌اند پشتیبانی می‌کند که در حین نصب انتخاب می‌شوند:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط. - **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط.
- **PostgreSQL** — برای تعداد کلاینت بالا یا راه‌اندازی‌های چندنودی توصیه می‌شود. نصب‌کننده می‌تواند PostgreSQL را به‌صورت محلی برایتان نصب کند، یا یک DSN به یک سرور موجود را بپذیرد. - **PostgreSQL** — برای تعداد کلاینت بالا یا راه‌اندازی‌های چندنودی توصیه می‌شود. نصب‌کننده می‌تواند PostgreSQL را به‌صورت محلی برایتان نصب کند، یا یک DSN به یک سرور موجود را بپذیرد.
در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/x-ui` می‌نویسد): در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/l-ui` می‌نویسد):
``` ```
XUI_DB_TYPE=postgres LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### انتقال یک نصب موجود SQLite به PostgreSQL ### انتقال یک نصب موجود SQLite به PostgreSQL
```bash ```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"
# سپس XUI_DB_TYPE و XUI_DB_DSN را در /etc/default/x-ui تنظیم کرده و ری‌استارت کنید: # سپس LUI_DB_TYPE و LUI_DB_DSN را در /etc/default/l-ui تنظیم کرده و ری‌استارت کنید:
systemctl restart x-ui systemctl restart l-ui
``` ```
فایل اصلی SQLite دست‌نخورده باقی می‌ماند؛ پس از اطمینان از صحت بک‌اند جدید، آن را به‌صورت دستی حذف کنید. فایل اصلی SQLite دست‌نخورده باقی می‌ماند؛ پس از اطمینان از صحت بک‌اند جدید، آن را به‌صورت دستی حذف کنید.
### Docker ### Docker
دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `XUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید: دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `LUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید:
```bash ```bash
docker compose --profile postgres up -d 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` اجرا می‌کنید، خودتان مجوزها را اضافه کنید، در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند اما هرگز اعمال نمی‌شوند: این ایمیج، Fail2ban را (که به‌صورت پیش‌فرض فعال است) برای اعمال **محدودیت‌های IP** به‌ازای هر کلاینت همراه دارد. ‏Fail2ban متخلفان را با `iptables` مسدود می‌کند که به مجوز `NET_ADMIN` نیاز دارد. فایل `docker-compose.yml` این مجوز را از قبل از طریق `cap_add` می‌دهد؛ اگر به‌جای آن کانتینر را با `docker run` اجرا می‌کنید، خودتان مجوزها را اضافه کنید، در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند اما هرگز اعمال نمی‌شوند:
```bash ```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` | | `LUI_DB_TYPE` | بک‌اند پایگاه‌داده: `sqlite` یا `postgres` | `sqlite` |
| `XUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `XUI_DB_TYPE=postgres`) | — | | `LUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `LUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/x-ui` | | `LUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — | | `LUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — | | `LUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` | | `LUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` |
| `XUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` | | `LUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` |
| `XUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` | | `LUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` | | `LUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` | | `LUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — | | `LUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — |
| `XUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` | | `LUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` | | `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` | | `LUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | حداقل تأخیر بین ری‌استارت‌های متوالی | `5m` | | `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: بدهید **اگر این پروژه برای شما مفید است، می‌توانید به آن یک**: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。 - **主控**:完整 L-UI 面板,唯一的配置可信源。管理节点、入站、客户端,下发完整 xray 配置(含出站、路由)到各 agent。
- **Agent**:跑在节点鸡上,通过 token 向主控注册。定时拉取主控下发的 xray 配置并应用,上报心跳和流量。只提供 VLESS / SS2022 入站。 - **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,可直接使用;主控一键安装:`bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)`;也可按下面步骤手动部署。
### 主控 ### 主控
```bash ```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(节点鸡)
先在主控面板「节点管理」→「添加节点」→ 类型选 **Agent**,保存后弹窗会显示 token,复制下来。 先在主控侧建节点,面板会生成绑定该节点的注册 token 与安装命令,然后在节点鸡上:
然后在节点鸡上:
```bash ```bash
bash <(curl -fL https://raw.githubusercontent.com/aaaamoooo/3x-ui-diy/main/install-agent.sh) \ mkdir -p /usr/local/l-ui/bin /etc/l-ui
--master http://主控IP:2053 --token 你的TOKEN --name 节点名
# 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 1. 主控侧建节点并签发 agent 注册 token(见 docs/AGENT.md)
2. 节点鸡一键安装 agent,填入主控地址和 token 2. 节点鸡按上面步骤部署 agent,填入主控地址和 token
3. 在「入站列表」创建入站(VLESS / SS2022),「部署到」选择在线的 agent 节点 3. 在「入站列表」创建入站(VLESS / SS2022),「部署到」选择在线的 agent 节点
4. 主控自动把完整 xray 配置下发到节点,客户端即可连接 4. 主控自动把完整 xray 配置下发到节点,客户端即可连接
@@ -42,14 +101,16 @@ agent 约 30 秒后拉到配置并启动 xray,节点在面板显示在线。
| | 内存 | | | 内存 |
|---|---| |---|---|
| agent + xray | 约 63MB | | agent + xray | 约 63MB |
| 完整 3x-ui 面板 | 130–160MB | | 完整 L-UI 面板 | 130–160MB |
另有路由器主控精简版构建(剥离 xray-core 库,见仓库内 PANEL-LITE-SPEC.md),面向纯控制面部署,内存显著更低。
## 与原版的区别 ## 与原版的区别
- 节点不再需要安装完整面板 - 节点不再需要安装完整面板
- 主控是唯一可信源,节点配置全部由主控下发 - 主控是唯一可信源,节点配置全部由主控下发
- 节点在线状态由 agent 心跳维持 - 节点在线状态由 agent 心跳维持
- 添加节点支持 Agent 类型,自动生成注册 token - 添加节点支持 Agent 类型,使用注册 token 接入
## License ## License
+36 -54
View File
@@ -2,18 +2,13 @@
<p align="center"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </p>
**3X-UI** — продвинутая веб-панель управления с открытым исходным кодом для управления серверами [Xray-core](https://github.com/XTLS/Xray-core). Она предоставляет аккуратный многоязычный интерфейс для развёртывания, настройки и мониторинга широкого спектра протоколов прокси и VPN — от одного VPS до развёртываний с несколькими узлами. **3X-UI** — продвинутая веб-панель управления с открытым исходным кодом для управления серверами [Xray-core](https://github.com/XTLS/Xray-core). Она предоставляет аккуратный многоязычный интерфейс для развёртывания, настройки и мониторинга широкого спектра протоколов прокси и VPN — от одного VPS до развёртываний с несколькими узлами.
@@ -69,31 +64,31 @@
## Быстрый старт ## Быстрый старт
```bash ```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`): Чтобы установить конкретную версию, добавьте её тег (например, `v3.4.0`):
```bash ```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`: Чтобы установить скользящую **dev**-сборку (новейший предварительный релиз по каждому коммиту из ветки `main`, а не стабильный релиз), передайте `dev-latest`:
```bash ```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. Установщик также работает в **неинтерактивном** режиме для 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) - [Cloud-init user-data](deploy/cloud-init/) — автоматическая установка в любом облаке (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Заметки по Hetzner Cloud](deploy/marketplace/hetzner/) — развёртывание на Hetzner на базе cloud-init - [Заметки по 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 поддерживает два бэкенда, выбираемых при установке: 3X-UI поддерживает два бэкенда, выбираемых при установке:
- **SQLite** (по умолчанию) — единый файл по пути `/etc/x-ui/x-ui.db`. Без настройки, идеально для небольших и средних развёртываний. - **SQLite** (по умолчанию) — единый файл по пути `/etc/l-ui/l-ui.db`. Без настройки, идеально для небольших и средних развёртываний.
- **PostgreSQL** — рекомендуется при большом числе клиентов или конфигурациях с несколькими узлами. Установщик может установить PostgreSQL локально за вас или принять DSN к существующему серверу. - **PostgreSQL** — рекомендуется при большом числе клиентов или конфигурациях с несколькими узлами. Установщик может установить PostgreSQL локально за вас или принять DSN к существующему серверу.
Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/x-ui`): Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/l-ui`):
``` ```
XUI_DB_TYPE=postgres LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### Перенос существующей установки SQLite в PostgreSQL ### Перенос существующей установки SQLite в PostgreSQL
```bash ```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"
# затем задайте XUI_DB_TYPE и XUI_DB_DSN в /etc/default/x-ui и перезапустите: # затем задайте LUI_DB_TYPE и LUI_DB_DSN в /etc/default/l-ui и перезапустите:
systemctl restart x-ui systemctl restart l-ui
``` ```
Исходный файл SQLite остаётся нетронутым; удалите его вручную после проверки нового бэкенда. Исходный файл SQLite остаётся нетронутым; удалите его вручную после проверки нового бэкенда.
### Docker ### Docker
Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `XUI_DB_*` в `docker-compose.yml` и запустите с профилем: Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `LUI_DB_*` в `docker-compose.yml` и запустите с профилем:
```bash ```bash
docker compose --profile postgres up -d 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`, добавьте возможности самостоятельно, иначе блокировки будут регистрироваться, но никогда не применяться: Образ включает Fail2ban (включён по умолчанию) для применения **лимитов IP** по каждому клиенту. Fail2ban блокирует нарушителей с помощью `iptables`, что требует возможности `NET_ADMIN`. `docker-compose.yml` уже предоставляет её через `cap_add`; если вы вместо этого запускаете контейнер через `docker run`, добавьте возможности самостоятельно, иначе блокировки будут регистрироваться, но никогда не применяться:
```bash ```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` | | `LUI_DB_TYPE` | Бэкенд базы данных: `sqlite` или `postgres` | `sqlite` |
| `XUI_DB_DSN` | Строка подключения PostgreSQL (когда `XUI_DB_TYPE=postgres`) | — | | `LUI_DB_DSN` | Строка подключения PostgreSQL (когда `LUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/x-ui` | | `LUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — | | `LUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — | | `LUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` | | `LUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` |
| `XUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` | | `LUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` |
| `XUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` | | `LUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Включить режим отладки | `false` | | `LUI_DEBUG` | Включить режим отладки | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` | | `LUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — | | `LUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — |
| `XUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` | | `LUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` | | `LUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` | | `LUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Минимальная задержка между последовательными перезапусками | `5m` | | `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: **Если этот проект полезен для вас, вы можете поставить ему**: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"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </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. **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ıç ## Hızlı Başlangıç
```bash ```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: Belirli bir sürümü kurmak için, etiketini (ör. `v3.4.0`) ekleyin:
```bash ```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: 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
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 ### Etkileşimsiz kurulum
Yükleyici, cloud-init için **etkileşimsiz** olarak da çalışır. 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ı 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) - [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 - [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: 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. - **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 LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### Mevcut bir SQLite Kurulumunu PostgreSQL'e Taşıma ### Mevcut bir SQLite Kurulumunu PostgreSQL'e Taşıma
```bash ```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"
# ardından /etc/default/x-ui içindeki XUI_DB_TYPE ve XUI_DB_DSN değerlerini ayarlayıp yeniden başlatın: # 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 x-ui 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. 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 ### 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 ```bash
docker compose --profile postgres up -d 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: 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 ```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) ## Ortam Değişkenleri (Environment Variables)
| Değişken | Açıklama | Varsayılan | | Değişken | Açıklama | Varsayılan |
| --- | --- | --- | | --- | --- | --- |
| `XUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` | | `LUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `XUI_DB_TYPE=postgres` ise) | — | | `LUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `LUI_DB_TYPE=postgres` ise) | — |
| `XUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/x-ui` | | `LUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Maksimum açık bağlantı sayısı (PostgreSQL havuzu) | — | | `LUI_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) | — | | `LUI_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 | `/` | | `LUI_INIT_WEB_BASE_PATH` | Web paneli için başlangıç URI yolu | `/` |
| `XUI_ENABLE_FAIL2BAN` | Fail2ban tabanlı IP limit uygulamasını etkinleştir | `true` | | `LUI_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` | | `LUI_LOG_LEVEL` | Günlük (Log) ayrıntı seviyesi (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Hata ayıklama (debug) modunu etkinleştir | `false` | | `LUI_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` | | `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` |
| `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 | — | | `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 | — |
| `XUI_TUNNEL_HEALTH_URL` | Tünel sağlığı için yoklanan URL | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_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` | | `LUI_TUNNEL_HEALTH_INTERVAL` | Yoklamalar arasındaki aralık | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Yoklama başına zaman aşımı | `10s` | | `LUI_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` | | `LUI_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_TUNNEL_HEALTH_COOLDOWN` | Ardışık yeniden başlatmalar arasındaki minimum gecikme | `5m` |
## Desteklenen Diller ## Desteklenen Diller
@@ -184,23 +179,10 @@ Katkılarınızı her zaman bekliyoruz. Bir sorun (issue) açmadan veya pull req
## Topluluk Araçları ## 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 ## Projeyi Destekleyin
**Eğer bu proje size faydalı olduysa, bir yıldız verebilirsiniz**:star2: **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"> <p align="center">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png"> <source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png"> <img alt="L-UI" src="./media/L-UI-light.png">
</picture> </picture>
</p> </p>
<p align="center"> <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://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> </p>
**3X-UI** 是一个先进的开源 Web 控制面板,用于管理 [Xray-core](https://github.com/XTLS/Xray-core) 服务器。它提供简洁、多语言的界面,用于部署、配置和监控各种代理与 VPN 协议——从单台 VPS 到多节点部署。 **3X-UI** 是一个先进的开源 Web 控制面板,用于管理 [Xray-core](https://github.com/XTLS/Xray-core) 服务器。它提供简洁、多语言的界面,用于部署、配置和监控各种代理与 VPN 协议——从单台 VPS 到多节点部署。
@@ -69,31 +65,31 @@
## 快速开始 ## 快速开始
```bash ```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`): 若要安装特定版本,请在命令后附加对应的标签(例如 `v3.4.0`):
```bash ```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`: 若要安装滚动更新的 **dev** 版本(来自 `main` 的最新逐次提交预发布版本,而非稳定版本),请传入 `dev-latest`:
```bash ```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。 安装程序也可以**非交互式**运行,适用于 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) - [Cloud-init user-data](deploy/cloud-init/) — 在任意云平台上无人值守安装(Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Hetzner Cloud 说明](deploy/marketplace/hetzner/) — 在 Hetzner 上基于 cloud-init 的部署 - [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 支持两种后端,可在安装时选择: 3X-UI 支持两种后端,可在安装时选择:
- **SQLite**(默认)— 位于 `/etc/x-ui/x-ui.db` 的单个文件。无需配置,适合中小型部署。 - **SQLite**(默认)— 位于 `/etc/l-ui/l-ui.db` 的单个文件。无需配置,适合中小型部署。
- **PostgreSQL** — 推荐用于大量客户端或多节点设置。安装程序可以为您在本地安装 PostgreSQL,或接受指向现有服务器的 DSN。 - **PostgreSQL** — 推荐用于大量客户端或多节点设置。安装程序可以为您在本地安装 PostgreSQL,或接受指向现有服务器的 DSN。
运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/x-ui`): 运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/l-ui`):
``` ```
XUI_DB_TYPE=postgres LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
``` ```
### 将现有的 SQLite 安装迁移到 PostgreSQL ### 将现有的 SQLite 安装迁移到 PostgreSQL
```bash ```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"
# 然后在 /etc/default/x-ui 中设置 XUI_DB_TYPE 和 XUI_DB_DSN 并重启: # 然后在 /etc/default/l-ui 中设置 LUI_DB_TYPE 和 LUI_DB_DSN 并重启:
systemctl restart x-ui systemctl restart l-ui
``` ```
源 SQLite 文件保持不变;在确认新后端正常工作后,请手动删除它。 源 SQLite 文件保持不变;在确认新后端正常工作后,请手动删除它。
### Docker ### 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 ```bash
docker compose --profile postgres up -d 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` 启动容器,请自行添加这些权限,否则封禁只会被记录而永远不会生效: 该镜像捆绑了 Fail2ban(默认启用),用于强制执行按客户端的 **IP 限制**。Fail2ban 使用 `iptables` 封禁违规者,这需要 `NET_ADMIN` 权限。`docker-compose.yml` 已通过 `cap_add` 授予该权限;如果您改用 `docker run` 启动容器,请自行添加这些权限,否则封禁只会被记录而永远不会生效:
```bash ```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` | | `LUI_DB_TYPE` | 数据库后端:`sqlite` 或 `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL 连接字符串(当 `XUI_DB_TYPE=postgres` 时) | — | | `LUI_DB_DSN` | PostgreSQL 连接字符串(当 `LUI_DB_TYPE=postgres` 时) | — |
| `XUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/x-ui` | | `LUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/l-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — | | `LUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — |
| `XUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — | | `LUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — |
| `XUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` | | `LUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` |
| `XUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` | | `LUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` |
| `XUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` | | `LUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` |
| `XUI_DEBUG` | 启用调试模式 | `false` | | `LUI_DEBUG` | 启用调试模式 | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` | | `LUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — | | `LUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — |
| `XUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` | | `LUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` | | `LUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` | | `LUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` | | `LUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | 两次连续重启之间的最小间隔 | `5m` | | `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: **如果这个项目对您有帮助,您可以给它一个**: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 # 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 subscriptions for other programs — Xray-core, mihomo, sing-box, mtg-multi —
and is deployed by operators who upgrade in place. Judge findings by what and is deployed by operators who upgrade in place. Judge findings by what
breaks for those consumers and operators, not by style. 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 - "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 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 `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, 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 migration or Xray gRPC code that no job exercised, say it is unverified
rather than repeating a green tick as proof. 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 Do not open a public issue for anything you believe is exploitable — an
authentication bypass, remote code execution, injection, secret or authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation. A public report gives attackers 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 Instead, use GitHub's private vulnerability reporting: open this
repository's **Security** tab and click **Report a vulnerability**. Include 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. You will receive replies in the advisory thread.
There is no bug-bounty program. Fixes ship in the next release, and the 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") 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 // [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. // 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 { if len(gates) < 5 {
t.Fatalf("expected at least 5 skip-gate variables in %s, found %d", botContextPath, len(gates)) 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) { t.Run(g[1], func(t *testing.T) {
if strings.Contains(ci, g[1]) { if strings.Contains(ci, g[1]) {
t.Errorf("%s claims %s is never set in CI, but %s sets it", reviewPath, g[1], ciWorkflowPath) 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) # 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 credentials generated on first boot** (never `admin/admin`, never a shared
session secret). Works on amd64 and arm64. session secret). Works on amd64 and arm64.
@@ -12,7 +12,7 @@ session secret). Works on amd64 and arm64.
## How it works ## 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 Each instance installs and configures itself with random credentials. See
[`cloud-init/README.md`](cloud-init/README.md). [`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 ⇒ `install.sh` reads these env vars in non-interactive mode (all optional; unset ⇒
secure random / default): secure random / default):
`XUI_USERNAME`, `XUI_PASSWORD`, `XUI_PANEL_PORT`, `XUI_WEB_BASE_PATH`, `LUI_USERNAME`, `LUI_PASSWORD`, `LUI_PANEL_PORT`, `LUI_WEB_BASE_PATH`,
`XUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `XUI_DOMAIN`, `LUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `LUI_DOMAIN`,
`XUI_ACME_EMAIL`, `XUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`), `LUI_ACME_EMAIL`, `LUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`),
`XUI_SSL_IPV6` (optional IPv6 address to add to an `ip`-mode cert), `LUI_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), `LUI_SERVER_IP` (fallback IP for the displayed access URL when auto-detection fails),
`XUI_DB_TYPE` (`sqlite`|`postgres`), `XUI_DB_DSN`. `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 non-interactively on a fresh Ubuntu/Debian VM and generates **unique random
credentials per instance**. It works on any cloud-init platform. 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. 1. The VM boots a stock Ubuntu/Debian cloud image.
2. cloud-init writes and runs `/opt/xui-bootstrap.sh`, which exports 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 3. `install.sh` runs end-to-end with **zero prompts**, picking secure random
values for any credential you didn't pin. 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`. (mode 600), echoed to the **serial console**, and appended to `/etc/motd`.
Retrieve them after boot with either: Retrieve them after boot with either:
```bash ```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). …or read the provider's **serial console** output (handy before you have SSH).
## Customising ## 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. [`cloud-init.yaml`](cloud-init.yaml). All knobs are optional; unset ⇒ random/secure default.
| Env var | Default | Meaning | | Env var | Default | Meaning |
| --- | --- | --- | | --- | --- | --- |
| `XUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` | | `LUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` |
| `XUI_USERNAME` | random | Admin username | | `LUI_USERNAME` | random | Admin username |
| `XUI_PASSWORD` | random | Admin password | | `LUI_PASSWORD` | random | Admin password |
| `XUI_PANEL_PORT` | random high port | Panel listen port | | `LUI_PANEL_PORT` | random high port | Panel listen port |
| `XUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) | | `LUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) |
| `XUI_DOMAIN` | — | Required when `XUI_SSL_MODE=domain` | | `LUI_DOMAIN` | — | Required when `LUI_SSL_MODE=domain` |
| `XUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) | | `LUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) |
| `XUI_DB_TYPE` / `XUI_DB_DSN` | `sqlite` | Set `postgres` + DSN to use PostgreSQL | | `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 — > **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 > 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 #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, # Works on any cloud-init platform: Hetzner, AWS, DigitalOcean, Vultr, GCP,
# Azure, Oracle. Paste the whole file as the instance "user data". # 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 # random credentials per instance. Full credentials are surfaced ONLY on the
# serial console (owner-only); /etc/motd (world-readable) shows just the access # serial console (owner-only); /etc/motd (world-readable) shows just the access
# URL + username. Nothing is baked in advance — every instance is unique. # URL + username. Nothing is baked in advance — every instance is unique.
# #
# Requires the non-interactive install.sh (3x-ui with XUI_NONINTERACTIVE support). # Fork note (L-UI): the bootstrap below installs this fork's
# Edit the exported XUI_* knobs in /opt/xui-bootstrap.sh below to customise. # 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 package_update: true
@@ -27,46 +30,46 @@ write_files:
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
# --- Non-interactive install knobs -------------------------------------- # --- Non-interactive install knobs --------------------------------------
export XUI_NONINTERACTIVE=1 export LUI_NONINTERACTIVE=1
# SSL mode: none (plain HTTP, default) | ip | domain # 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): # Pin credentials instead of random (leave unset for secure random values):
# export XUI_USERNAME="admin2" # export LUI_USERNAME="admin2"
# export XUI_PASSWORD="change-me-please" # export LUI_PASSWORD="change-me-please"
# export XUI_PANEL_PORT="2053" # export LUI_PANEL_PORT="2053"
# export XUI_WEB_BASE_PATH="panel" # export LUI_WEB_BASE_PATH="panel"
# Let's Encrypt domain certificate instead of plain HTTP: # Let's Encrypt domain certificate instead of plain HTTP:
# export XUI_SSL_MODE="domain" # export LUI_SSL_MODE="domain"
# export XUI_DOMAIN="panel.example.com" # export LUI_DOMAIN="panel.example.com"
# export XUI_ACME_EMAIL="you@example.com" # export LUI_ACME_EMAIL="you@example.com"
# PostgreSQL instead of SQLite: # PostgreSQL instead of SQLite:
# export XUI_DB_TYPE="postgres" # export LUI_DB_TYPE="postgres"
# export XUI_DB_DSN="postgres://user:pass@host:5432/db?sslmode=disable" # 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) # Surface the generated credentials. Full creds (incl. password + API token)
# go ONLY to the serial console (/dev/console, owner-only). /etc/motd is # 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 # world-readable, so it gets just the access URL + username and a pointer
# to the root-only env file. # 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
echo "=== 3x-ui panel credentials (generated on first boot) ===" echo "=== L-UI panel credentials (generated on first boot) ==="
cat /etc/x-ui/install-result.env cat /etc/l-ui/install-result.env
echo "========================================================" echo "========================================================"
echo "Change the password after first login." echo "Change the password after first login."
} > /dev/console 2>/dev/null || true } > /dev/console 2>/dev/null || true
# shellcheck disable=SC1091 # shellcheck disable=SC1091
. /etc/x-ui/install-result.env . /etc/l-ui/install-result.env
{ {
echo echo
echo "=== 3x-ui panel (generated on first boot) ===" echo "=== L-UI panel (generated on first boot) ==="
echo "URL: ${XUI_ACCESS_URL:-unknown}" echo "URL: ${LUI_ACCESS_URL:-unknown}"
echo "Username: ${XUI_USERNAME:-unknown}" echo "Username: ${LUI_USERNAME:-unknown}"
echo "Password + API token: sudo cat /etc/x-ui/install-result.env" echo "Password + API token: sudo cat /etc/l-ui/install-result.env"
echo "=============================================" echo "============================================="
echo "Change the password after first login." echo "Change the password after first login."
} >> /etc/motd 2>/dev/null || true } >> /etc/motd 2>/dev/null || true
@@ -75,4 +78,4 @@ write_files:
runcmd: runcmd:
- [bash, /opt/xui-bootstrap.sh] - [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. 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). generates unique per-instance credentials (no `admin/admin`, no shared secret).
## cloud-init (no image build) ## cloud-init (no image build)
Use the generic user-data from [`../../cloud-init/`](../../cloud-init/). It installs 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 Web console: **Create Server → Cloud config** → paste
[`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml). [`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml).
@@ -25,13 +25,13 @@ hcloud server create \
After boot, fetch the generated credentials: After boot, fetch the generated credentials:
```bash ```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 ## "App"-style listing
Hetzner's curated apps live in the community repo Hetzner's curated apps live in the community repo
[`github.com/hetznercloud/apps`](https://github.com/hetznercloud/apps): each app [`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 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). 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. # smoke-noninteractive.sh — verify the non-interactive install path.
# #
# Runs install.sh inside an Ubuntu container with NO TTY (piped) and # Runs install.sh inside an Ubuntu container with NO TTY (piped) and
# XUI_NONINTERACTIVE=1, then asserts: # LUI_NONINTERACTIVE=1, then asserts:
# * /etc/x-ui/install-result.env exists (mode 600) with random, non-default creds # * /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 reports hasDefaultCredential: false (no admin/admin remains)
# * the panel HTTP server actually serves on the generated port/base path # * the panel HTTP server actually serves on the generated port/base path
# * with a [version] argument: the installed binary reports exactly that version # * with a [version] argument: the installed binary reports exactly that version
@@ -18,41 +18,41 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
IMAGE="${SMOKE_IMAGE:-ubuntu:24.04}" IMAGE="${SMOKE_IMAGE:-ubuntu:24.04}"
XUI_SMOKE_VERSION="${1:-}" LUI_SMOKE_VERSION="${1:-}"
if ! command -v docker > /dev/null 2>&1; then if ! command -v docker > /dev/null 2>&1; then
echo "ERROR: docker is required for this smoke test." >&2 echo "ERROR: docker is required for this smoke test." >&2
exit 1 exit 1
fi 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 \ docker run --rm \
-v "${REPO_ROOT}/install.sh:/root/install.sh:ro" \ -v "${REPO_ROOT}/install.sh:/root/install.sh:ro" \
-e XUI_NONINTERACTIVE=1 \ -e LUI_NONINTERACTIVE=1 \
-e XUI_SSL_MODE=none \ -e LUI_SSL_MODE=none \
-e XUI_SMOKE_VERSION="$XUI_SMOKE_VERSION" \ -e LUI_SMOKE_VERSION="$LUI_SMOKE_VERSION" \
-e DEBIAN_FRONTEND=noninteractive \ -e DEBIAN_FRONTEND=noninteractive \
"$IMAGE" bash -euo pipefail -c ' "$IMAGE" bash -euo pipefail -c '
apt-get update -qq apt-get update -qq
apt-get install -y -qq curl tar openssl ca-certificates > /dev/null 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. # Piping guarantees stdin is not a TTY, exercising the auto non-interactive path.
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION" cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else else
cat /root/install.sh | bash cat /root/install.sh | bash
fi fi
echo "--- assertions ---" echo "--- assertions ---"
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
installed=$(/usr/local/x-ui/x-ui -v) installed=$(/usr/local/l-ui/l-ui -v)
[ "$installed" = "${XUI_SMOKE_VERSION#v}" ] \ [ "$installed" = "${LUI_SMOKE_VERSION#v}" ] \
|| { echo "FAIL: installed version $installed, want ${XUI_SMOKE_VERSION#v}"; exit 1; } || { echo "FAIL: installed version $installed, want ${LUI_SMOKE_VERSION#v}"; exit 1; }
fi fi
RESULT=/etc/x-ui/install-result.env RESULT=/etc/l-ui/install-result.env
test -f "$RESULT" || { echo "FAIL: $RESULT missing"; exit 1; } test -f "$RESULT" || { echo "FAIL: $RESULT missing"; exit 1; }
perms=$(stat -c %a "$RESULT") perms=$(stat -c %a "$RESULT")
@@ -60,23 +60,23 @@ docker run --rm \
# shellcheck disable=SC1090 # shellcheck disable=SC1090
. "$RESULT" . "$RESULT"
[ -n "${XUI_USERNAME:-}" ] && [ "$XUI_USERNAME" != "admin" ] \ [ -n "${LUI_USERNAME:-}" ] && [ "$LUI_USERNAME" != "admin" ] \
|| { echo "FAIL: username missing or still admin"; exit 1; } || { 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; } || { 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. # 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 "FAIL: hasDefaultCredential is not false"; exit 1; }
echo "--- verifying the panel serves HTTP ---" echo "--- verifying the panel serves HTTP ---"
cd /usr/local/x-ui cd /usr/local/l-ui
./x-ui > /tmp/xui.log 2>&1 & ./l-ui > /tmp/lui.log 2>&1 &
xpid=$! xpid=$!
for _ in $(seq 1 15); do for _ in $(seq 1 15); do
code=$(curl -s -o /dev/null -w "%{http_code}" \ 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 case "$code" in 200|301|302|307|308) break ;; esac
sleep 1 sleep 1
done done
@@ -84,28 +84,28 @@ docker run --rm \
echo "panel HTTP status: ${code:-none}" echo "panel HTTP status: ${code:-none}"
case "${code:-}" in case "${code:-}" in
200|301|302|307|308) : ;; 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 esac
echo "--- verifying a second install preserves custom bin/ files ---" echo "--- verifying a second install preserves custom bin/ files ---"
echo "custom-sentinel" > /usr/local/x-ui/bin/geoip_custom.dat echo "custom-sentinel" > /usr/local/l-ui/bin/geoip_custom.dat
geoip_sum_before=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1) geoip_sum_before=$(sha256sum /usr/local/l-ui/bin/geoip.dat | cut -d" " -f1)
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION" cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else else
cat /root/install.sh | bash cat /root/install.sh | bash
fi 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; } || { 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; } || { 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" ] \ [ "$geoip_sum_after" = "$geoip_sum_before" ] \
|| { echo "FAIL: bundled geoip.dat changed across a same-version reinstall"; exit 1; } || { 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 ==" echo "== non-interactive smoke test PASSED =="
+15 -15
View File
@@ -1,14 +1,14 @@
services: services:
3xui: l-ui:
build: build:
context: . context: .
dockerfile: ./Dockerfile dockerfile: ./Dockerfile
container_name: 3xui_app container_name: l-ui_app
# hostname: yourhostname <- optional # hostname: yourhostname <- optional
# Optional hard memory cap. When set, the panel derives its Go soft limit # 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. # (GOMEMLIMIT, ~90% of this cap) so it GCs before the OOM killer fires.
# mem_limit: 512m # 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 # 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 # and shown in fail2ban status but never actually applied. NET_RAW covers
# ip6tables. If you disable Fail2ban, you can drop cap_add. # ip6tables. If you disable Fail2ban, you can drop cap_add.
@@ -20,39 +20,39 @@ services:
- NET_ADMIN - NET_ADMIN
- NET_RAW - NET_RAW
volumes: volumes:
- $PWD/db/:/etc/x-ui/ - $PWD/db/:/etc/l-ui/
- $PWD/cert/:/root/cert/ - $PWD/cert/:/root/cert/
# Persists acme.sh state so certificate auto-renewal survives container # Persists acme.sh state so certificate auto-renewal survives container
# recreation (the entrypoint re-registers the renewal cron job from it). # recreation (the entrypoint re-registers the renewal cron job from it).
- $PWD/acme/:/root/.acme.sh/ - $PWD/acme/:/root/.acme.sh/
environment: environment:
XRAY_VMESS_AEAD_FORCED: "false" 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 # 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). # 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 # LUI_GOGC: "75" # lower = less RAM, slightly more CPU; GOGC env overrides
# XUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables # LUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables
# Go memory soft limit, only applied from an explicit budget below (or a # Go memory soft limit, only applied from an explicit budget below (or a
# real cgroup/mem_limit cap). Pin it with one of: # 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 # GOMEMLIMIT: "400MiB" # Go syntax, takes precedence
# XUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling # LUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling
# XUI_INIT_WEB_BASE_PATH: "/" # LUI_INIT_WEB_BASE_PATH: "/"
# XUI_PORT: "8080" # LUI_PORT: "8080"
# To use PostgreSQL instead of the default SQLite, run: # To use PostgreSQL instead of the default SQLite, run:
# docker compose --profile postgres up -d # docker compose --profile postgres up -d
# and uncomment the two lines below. # and uncomment the two lines below.
# XUI_DB_TYPE: "postgres" # LUI_DB_TYPE: "postgres"
# XUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable" # LUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable" # postgres user/db kept: renaming them would orphan existing pgdata
tty: true tty: true
ports: 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" - "2053:2053"
restart: unless-stopped restart: unless-stopped
postgres: postgres:
image: postgres:16-alpine image: postgres:16-alpine
container_name: 3xui_postgres container_name: l-ui_postgres
profiles: ["postgres"] profiles: ["postgres"]
environment: environment:
POSTGRES_USER: xui 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 进程, 主控下发完整 xray 配置(含入站、出站、路由规则),agent 写配置并管理 xray 进程,
每 60 秒向主控上报流量/在线数。 每 60 秒向主控上报流量/在线数。
## 架构 ## 架构
- 主控:完整 3x-ui(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。 - 主控:完整 L-UI(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。
- 节点:`x-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。 - 节点:`l-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。
- 出站/路由规则只能在主控上建和改(面板是唯一可信源),agent 只管应用下发 - 出站/路由规则只能在主控上建和改(面板是唯一可信源),agent 只管应用下发
的完整配置,不上报本地配置。 的完整配置,不上报本地配置。
@@ -35,24 +35,24 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
## 二、节点安装 ## 二、节点安装
```bash ```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 补丁版,与主控同版本) # 1. 放 l-ui 二进制(agent 补丁版,与主控同版本),在节点上改名为 lui-agent(与主控进程区分)
cp x-ui /usr/local/x-ui/x-ui && chmod +x /usr/local/x-ui/x-ui cp l-ui /usr/local/l-ui/lui-agent && chmod +x /usr/local/l-ui/lui-agent
# 2. 放 xray 二进制与 geo 文件(agent 不负责下载,手动放置) # 2. 放 xray 二进制与 geo 文件(agent 不负责下载,手动放置)
cp xray-linux-amd64 /usr/local/x-ui/bin/xray && chmod +x /usr/local/x-ui/bin/xray 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/x-ui/bin/ cp geoip.dat geosite.dat /usr/local/l-ui/bin/
# 3. 写 agent 配置 # 3. 写 agent 配置
cat > /etc/x-ui/agent.json <<'EOF' cat > /etc/l-ui/agent.json <<'EOF'
{ {
"master_url": "http://主控内网地址:2053", "master_url": "http://主控内网地址:2053",
"token": "<上一步生成的 token>", "token": "<上一步生成的 token>",
"node_name": "hk-node-1" "node_name": "hk-node-1"
} }
EOF 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://`(需可信证书;自签证书连不上, - `master_url` 用 `http://`(内网)或 `https://`(需可信证书;自签证书连不上,
agent 默认校验 TLS)。 agent 默认校验 TLS)。
- `poll_interval` 可省略,默认 30 秒轮询一次配置。 - `poll_interval` 可省略,默认 30 秒轮询一次配置。
- 不要在节点上再启动完整面板(`x-ui` 不带 `agent` 参数的模式)。 - 不要在节点上再启动完整面板(`l-ui` 不带 `agent` 参数的模式)。
## 三、启动 agent ## 三、启动 agent
systemd(Debian/Ubuntu): systemd(Debian/Ubuntu):
```bash ```bash
cp systemd/x-ui-agent.service /etc/systemd/system/ cp systemd/lui-agent.service /etc/systemd/system/
systemctl daemon-reload systemctl daemon-reload
systemctl enable --now x-ui-agent systemctl enable --now lui-agent
journalctl -u x-ui-agent -f journalctl -u lui-agent -f
``` ```
OpenWrt(procd): OpenWrt(procd):
```bash ```bash
cp openrc/x-ui-agent /etc/init.d/x-ui-agent cp openrc/lui-agent /etc/init.d/lui-agent
chmod +x /etc/init.d/x-ui-agent chmod +x /etc/init.d/lui-agent
/etc/init.d/x-ui-agent enable /etc/init.d/lui-agent enable
/etc/init.d/x-ui-agent start /etc/init.d/lui-agent start
logread -f | grep x-ui-agent logread -f | grep lui-agent
``` ```
## 四、主控管理该节点的出站与路由规则 ## 四、主控管理该节点的出站与路由规则
@@ -120,6 +120,6 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
|---|---| |---|---|
| `register failed ... 401` | token 贴错,或 token 没在主控生成 | | `register failed ... 401` | token 贴错,或 token 没在主控生成 |
| `config fetch failed ... 409` | token 未绑定节点(生成时没传 `node_id`) | | `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` | | 流量不上报 | xray 的 api 入站端口是否被占用;agent 日志看 `Traffic report failed` |
| 主控连不上 | `master_url` 拼错;https 自签证书改走 `http://` 内网地址 | | 主控连不上 | `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 ## Prerequisites
+6 -6
View File
@@ -2,22 +2,22 @@
<a href="https://docs.sanaei.dev"> <a href="https://docs.sanaei.dev">
<picture> <picture>
<source media="(prefers-color-scheme: dark)" srcset="public/logo-dark.png" /> <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> </picture>
</a> </a>
</p> </p>
<h1 align="center">3x-ui Documentation</h1> <h1 align="center">L-UI Documentation</h1>
<p align="center"> <p align="center">
The official documentation and product site for 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. an advanced web panel for managing Xray-core servers.
</p> </p>
<p align="center"> <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://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> <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/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" /> <img src="https://img.shields.io/badge/Fumadocs-16-0ea5e9?style=flat-square" alt="Fumadocs 16" />
@@ -31,7 +31,7 @@
## Overview ## 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 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, 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 no database, and no auth**: every page is prerendered and every tool runs entirely in the
@@ -39,7 +39,7 @@ browser.
## What's inside ## 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. - **Getting Started** — installation, first login, and updating or uninstalling the panel.
- **Configuration** — the panel, inbounds, REALITY, transports, clients, subscriptions, and share links. - **Configuration** — the panel, inbounds, REALITY, transports, clients, subscriptions, and share links.
+1 -1
View File
@@ -15,7 +15,7 @@ export function generateStaticParams() {
} }
const INSTALL_COMMAND = const INSTALL_COMMAND =
'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)';
export default async function HomePage({ params }: PageProps<'/[lang]'>) { export default async function HomePage({ params }: PageProps<'/[lang]'>) {
const { lang } = await params; const { lang } = await params;
+1 -1
View File
@@ -2,7 +2,7 @@
@import 'fumadocs-ui/css/neutral.css'; @import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.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 { :root {
--color-fd-primary: hsl(190, 95%, 39%); --color-fd-primary: hsl(190, 95%, 39%);
--color-fd-primary-foreground: hsl(0, 0%, 100%); --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`). > 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. > 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) ## 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 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 + 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, 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 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 backend regenerates the Xray config and applies it — preferring a _hot diff_ (live gRPC
API mutation) over a full process restart. See §5.1. 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 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 `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). **`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):** **Backend (Go 1.27):**
- Web framework: **Gin** (`gin-gonic/gin`) + sessions (cookie store), gzip. - 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. - 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 - 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. its **gRPC API** and also shells out to manage the process.
@@ -85,7 +85,7 @@ Browser (React, fetch)
→ POST {basePath}/panel/api/... → POST {basePath}/panel/api/...
→ Gin engine (internal/web/web.go: initRouter) → Gin engine (internal/web/web.go: initRouter)
→ middleware chain: SecurityHeaders → MaxBodyBytes (10 MiB; importDB exempt) → 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 → base-path/cache-control context → Localizer
→ API routes add: ConfigEnvelope (zstd + SHA-256) → CSRF → API routes add: ConfigEnvelope (zstd + SHA-256) → CSRF
→ Controller (internal/web/controller/*.go) // HTTP concerns only: bind, validate, respond → 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) ## 4. Directory map (what lives where)
``` ```
3x-ui/ L-UI/
├── main.go # Entry point: CLI (run / migrate / migrate-db / setting / cert), ├── main.go # Entry point: CLI (run / migrate / migrate-db / setting / cert),
│ # bootstrap, signal handling, restart loop │ # bootstrap, signal handling, restart loop
├── go.mod / go.sum # Go deps (module path ends in /v3) ├── go.mod / go.sum # Go deps (module path ends in /v3)
│ │
├── internal/ # ALL backend Go code (private packages) ├── internal/ # ALL backend Go code (private packages)
│ ├── config/ # Env-var config: paths, DB kind/DSN, log level, version │ ├── 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/ │ ├── database/
│ │ ├── db.go # InitDB: connect, AutoMigrate, seeders (~1.4k lines). DB hotspot. │ │ ├── db.go # InitDB: connect, AutoMigrate, seeders (~1.4k lines). DB hotspot.
│ │ ├── migrate_data.go # Data migrations (seeders/normalizers beyond AutoMigrate) │ │ ├── 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) │ ├── pia/ # PIA WireGuard protocol client (auth, signed server list, /addKey)
│ ├── eventbus/ # In-process pub/sub (buffered channel): outbound.down|up, │ ├── eventbus/ # In-process pub/sub (buffered channel): outbound.down|up,
│ │ # xray.crash, node.down|up, cpu.high, memory.high, login.attempt │ │ # 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 │ │ # HTTP probe (default Cloudflare trace); repeated failures
│ │ # trigger an Xray restart hook. Independent of panel settings. │ │ # trigger an Xray restart hook. Independent of panel settings.
│ ├── xray/ # Xray-core integration (the proxy engine wrapper) │ ├── 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) │ │ │ ├── node.go # /panel/api/nodes (multi-node management)
│ │ │ ├── host.go # /panel/api/hosts (per-inbound subscription host overrides) │ │ │ ├── host.go # /panel/api/hosts (per-inbound subscription host overrides)
│ │ │ ├── server.go # /panel/api/server (status, xray version, certs, logs, DB import/export) │ │ │ ├── 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) │ │ │ ├── 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 │ │ │ ├── index.go # login/logout/csrf/2FA
│ │ │ ├── spa.go # SPA fallback for /panel UI routes │ │ │ ├── spa.go # SPA fallback for /panel UI routes
│ │ │ └── websocket.go # WS upgrade endpoint │ │ │ └── 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 │ │ │ ├── port_conflict.go # Detect inbound port collisions
│ │ │ ├── fallback.go # Xray fallback (SNI/ALPN routing on shared port) │ │ │ ├── fallback.go # Xray fallback (SNI/ALPN routing on shared port)
│ │ │ ├── email/ # Email notification service (SMTP) │ │ │ ├── email/ # Email notification service (SMTP)
│ │ │ ├── integration/ # External providers: warp.go, nord.go, pia.go │ │ │ ├── integration/ # External providers: warp.go
│ │ │ ├── outbound/ # Outbound config service │ │ │ ├── outbound/ # Outbound config service
│ │ │ ├── panel/ # Cross-cutting panel services: │ │ │ ├── panel/ # Cross-cutting panel services:
│ │ │ │ ├── panel.go # panel-level helpers │ │ │ │ ├── panel.go # panel-level helpers
│ │ │ │ ├── user.go # admin user auth (bcrypt) │ │ │ │ ├── user.go # admin user auth (bcrypt)
│ │ │ │ ├── api_token.go # API token CRUD (SHA-256 hashed)
│ │ │ │ └── websocket.go # WS hub / push service │ │ │ │ └── websocket.go # WS hub / push service
│ │ │ └── tgbot/ # Telegram bot command handlers │ │ │ └── tgbot/ # Telegram bot command handlers
│ │ ├── runtime/ # ⭐⭐ The Local/Remote node abstraction (see §5.2) │ │ ├── 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 ├── media/ # README images
│ │
├── Dockerfile / docker-compose.yml / DockerEntrypoint.sh / DockerInit.sh # Container build/run ├── Dockerfile / docker-compose.yml / DockerEntrypoint.sh / DockerInit.sh # Container build/run
├── install.sh / update.sh / x-ui.sh # VPS install + management CLI ├── install.sh / update.sh / l-ui.sh # VPS install + management CLI
├── x-ui.service.* / x-ui.rc # systemd units (debian/rhel/arch) + rc script ├── l-ui.service.* / l-ui.rc # systemd units (debian/rhel/arch) + rc script
├── windows_files/ # Windows service support ├── windows_files/ # Windows service support
└── .github/workflows/ # CI: ci.yml, codeql.yml, docker.yml, release.yml, smoke.yml, └── .github/workflows/ # CI: ci.yml, codeql.yml, docker.yml, release.yml, smoke.yml,
# mutation.yml, cleanup_caches.yml, claude-bot.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 ### 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 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. 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`): - **TLS modes** (`tls_client.go`, per-node `TlsVerifyMode`):
`verify` (system CAs, default) / `skip` (no validation) / `pin` (leaf cert SHA-256 must `verify` (system CAs, default) / `skip` (no validation) / `pin` (leaf cert SHA-256 must
match `PinnedCertSha256`) / `mtls` (master presents a client certificate; node cert checked 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`. `service/node_mtls.go` + `service/setting_mtls.go`.
- **Dispatch:** `manager.go` → `Manager.RuntimeFor(nodeID *int)`; `nil` nodeID → `Local`, - **Dispatch:** `manager.go` → `Manager.RuntimeFor(nodeID *int)`; `nil` nodeID → `Local`,
otherwise a cached/lazy-loaded `Remote`. `InvalidateNode(id)` drops a cached remote client. 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 ### 5.8 Tunnel health monitor
`internal/tunnelmonitor/` is an optional watchdog configured **only via env vars** `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 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 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 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 | | `OutboundTraffics` | Outbound counters | per outbound tag |
| `OutboundSubscription` | External provider subs | Warp/Nord style | | `OutboundSubscription` | External provider subs | Warp/Nord style |
| `Setting` | Key/value panel settings | everything configurable | | `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 | | `InboundFallback` | Fallback routing on a shared port | SNI/ALPN/path → dest |
| `HistoryOfSeeders` | Seeder bookkeeping | prevents re-running one-off migrations | | `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` | | **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` | | **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/` | | **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` | | **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` | | **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()` | | **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` | | **Telegram bot** commands | `service/tgbot/` | `job/stats_notify_job.go` |
| **Email notifications** | `service/email/` | `internal/eventbus/` (consumers) | | **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` | | **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/` | | **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` | | **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` | | **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 ## 10. Gotchas & conventions
- **Module path is `.../v3`.** Internal imports use `github.com/mhsanaei/3x-ui/v3/internal/...`. - **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 - **SQLite vs Postgres.** Default is SQLite at `{LUI_DB_FOLDER}/l-ui.db`. Postgres via
`XUI_DB_TYPE=postgres` + `XUI_DB_DSN`. Some SQL paths are dialect-aware (`database/dialect.go`); `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). test both when touching raw queries (there are `*_scale_postgres_test.go` suites).
- **`Inbound.Settings` / `StreamSettings` / `Sniffing` are raw JSON strings**, not structured - **`Inbound.Settings` / `StreamSettings` / `Sniffing` are raw JSON strings**, not structured
columns. Parsing/validation happens in services and the `xray` package, not in GORM. 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'; 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`); // Theme-aware via Tailwind's `dark:` variant. Pass a height class (e.g. `h-6`);
// width scales automatically (the artwork is 2:1). // width scales automatically (the artwork is 2:1).
export function Logo({ className }: { className?: string }) { export function Logo({ className }: { className?: string }) {
return ( return (
<> <>
{/* eslint-disable-next-line @next/next/no-img-element */} {/* 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 */} {/* 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 ( return (
<ToolFrame <ToolFrame
title="API request builder" 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} onReset={reset}
> >
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2"> <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
@@ -44,7 +44,7 @@ export function InstallCommandBuilder() {
value={version} value={version}
onChange={setVersion} onChange={setVersion}
placeholder="latest" placeholder="latest"
hint="blank = latest stable · a tag like v3.4.0 · or dev-latest for the rolling dev build" hint="blank = latest release · a tag like V2.7.5 (script at that tag) · or dev-latest for the main-branch script"
/> />
{method === 'docker' ? ( {method === 'docker' ? (
<> <>
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: AmneziaWG 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 icon: Lock
--- ---
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: Clients 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 icon: Users
--- ---
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: Inbounds & Protocols 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 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 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 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** list) rather than hand-written into JSON.
Fallbacks are available only when the master inbound is: Fallbacks are available only when the master inbound is:
+4 -4
View File
@@ -1,6 +1,6 @@
--- ---
title: Panel Settings 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 icon: SlidersHorizontal
--- ---
@@ -14,7 +14,7 @@ browser in full.
| Setting | Default | Meaning | | 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. | | `webListen` | _(all interfaces)_ | Bind the panel to a specific IP. |
| `webBasePath` | `/` | URL path the panel is served under (always normalized to `/…/`). | | `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**. | | `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 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 `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 ### TLS
Serving the panel over HTTPS protects your credentials in transit. Either set 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 can obtain a Let's Encrypt certificate for you — or terminate TLS at a
[reverse proxy](/docs/operations/reverse-proxy). [reverse proxy](/docs/operations/reverse-proxy).
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: REALITY 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 icon: ShieldCheck
--- ---
@@ -15,7 +15,7 @@ REALITY is used with **VLESS** (and Trojan). The recommended flow is
## Key settings ## 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: exposes these fields:
| Field | What it is | | Field | What it is |
+2 -2
View File
@@ -1,10 +1,10 @@
--- ---
title: Share Links 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 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. as v2rayNG, Hiddify, and Mihomo import these links to configure themselves.
## Link formats ## Link formats
@@ -1,6 +1,6 @@
--- ---
title: SSL Certificates 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 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, traffic are encrypted) and terminate TLS on **inbounds** (VLESS-TLS, Trojan,
Shadowsocks-TLS, and friends). There are three ways to obtain one: 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. client. Easiest for a single domain or a bare IP.
- **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or - **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or
when port 80 is blocked / the server sits behind Cloudflare's proxy. 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. inbounds.
</Callout> </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: [acme.sh](https://github.com/acmesh-official/acme.sh) and offers:
| Option | What it does | | Option | What it does |
@@ -58,7 +58,7 @@ use. Stop anything bound to it for the duration, and allow it through the
<Step> <Step>
### Run the issuer ### 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 and saves it under `/root/cert/<domain>/` as `fullchain.pem`
(the certificate chain) and `privkey.pem` (the private key). (the certificate chain) and `privkey.pem` (the private key).
</Step> </Step>
@@ -105,7 +105,7 @@ it. Copy the token — it's shown only once.
<Step> <Step>
### Run the Cloudflare issuer ### 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 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 domain (and, for the Global API Key, your account email and key). acme.sh creates
the TXT record, validates, and cleans it up. the TXT record, validates, and cleans it up.
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: Subscription 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 icon: Rss
--- ---
@@ -58,7 +58,7 @@ page instead of the raw body.
The **Base64** body is just the newline-joined share links, standard-base64 The **Base64** body is just the newline-joined share links, standard-base64
encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a
complete Xray client config — a fixed skeleton (local mixed/HTTP inbounds, DNS, 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 **single config object for one client and an array for several**, uses the flat
outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips
`sockopt` from `streamSettings`. `sockopt` from `streamSettings`.
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: Transports & Security 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 icon: Network
--- ---
+16 -16
View File
@@ -1,6 +1,6 @@
--- ---
title: First Login 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 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 A script install prints a credential summary when it finishes and also writes it
to a root-only file: to a root-only file:
```bash title="/etc/x-ui/install-result.env (mode 600)" ```bash title="/etc/l-ui/install-result.env (mode 600)"
XUI_USERNAME=... LUI_USERNAME=...
XUI_PASSWORD=... LUI_PASSWORD=...
XUI_PANEL_PORT=... LUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=... LUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=... LUI_ACCESS_URL=...
XUI_API_TOKEN=... LUI_API_TOKEN=...
XUI_DB_TYPE=sqlite LUI_DB_TYPE=sqlite
``` ```
If you missed them, use the management tools: If you missed them, use the management tools:
```bash ```bash
x-ui # menu → 11 (View Current Settings) l-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form l-ui settings # or the one-shot form
``` ```
For **Docker**, read the generated credentials from the container logs, or run 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"> <Callout type="warn">
If your panel still uses the default `admin` / `admin` (the panel warns when it 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 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 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) - **7 — Reset Username & Password** (optionally disabling 2FA at the same time)
- **8 — Reset Web Base Path** (randomizes it) - **8 — Reset Web Base Path** (randomizes it)
@@ -64,11 +64,11 @@ two-factor auth was on, disables it.
## Two-factor authentication (2FA) ## 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 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 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** 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 ## Built-in login protection
@@ -105,7 +105,7 @@ Turn on 2FA so a leaked password alone can't grant access.
<Step> <Step>
### Put the panel behind TLS ### 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. proxy) so the panel is only reachable over HTTPS.
</Step> </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. description: A web panel for Xray-core — manage inbounds, protocols, clients, and subscriptions from your browser instead of editing JSON by hand.
icon: Info 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 [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 moves your traffic. Instead of writing and reloading Xray's JSON configuration
by hand, you manage everything — inbounds, protocols, clients, certificates, by hand, you manage everything — inbounds, protocols, clients, certificates,
@@ -15,7 +15,7 @@ subscriptions — from a browser dashboard.
<Mermaid <Mermaid
chart={` chart={`
flowchart LR 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 -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")] Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -52,18 +52,18 @@ flowchart LR
| Database | SQLite (default) or PostgreSQL | | Database | SQLite (default) or PostgreSQL |
| Proxy engine | Xray-core (bundled and managed by the panel) | | 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 on port **2053** by default. Both are configurable — see
[First login](/docs/guide/first-login) and the environment variable reference. [First login](/docs/guide/first-login) and the environment variable reference.
## Who it's for ## 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 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. Xray-core without living in JSON config files, this is for you.
<Callout type="info"> <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 support, improved stability, per-client traffic accounting, multi-node
management, and many quality-of-life features. management, and many quality-of-life features.
</Callout> </Callout>
+28 -57
View File
@@ -1,47 +1,43 @@
--- ---
title: Installation 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 (panel, node agent, or pinned), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
icon: Download 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, Fedora, CentOS, RHEL, AlmaLinux, Rocky Linux, Oracle Linux, Amazon Linux,
Virtuozzo, Arch, Manjaro, openSUSE (Tumbleweed/Leap), Alpine — and Windows, Virtuozzo, Arch, Manjaro, openSUSE (Tumbleweed/Leap), Alpine — and Windows,
across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`. across `amd64` and `arm64`.
<Callout type="warn"> <Callout type="warn">
Run the script installer as **root** (or with `sudo`). It installs a service, Run the script installer as **root** (or with `sudo`). One-click scripts support `amd64`/`arm64` only.
sets up the `x-ui` management command, and enables the panel on boot.
</Callout> </Callout>
<Tabs items={['Script', 'Docker', 'Manual']}> <Tabs items={['Script', 'Docker', 'Manual']}>
<Tab value="Script"> <Tab value="Script">
The official script is the recommended path. During installation it generates a The official script is the recommended path. Panel one-click install:
**random** username, password, and access (web base) path, sets up the service,
and installs the `x-ui` management command.
```bash title="latest stable" ```bash title="panel"
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)
``` ```
Install a **specific version** by appending its tag: It downloads the panel binary, xray, and geo files from this repo's Gitea Releases and starts the panel (default port 2053). Log in with the default `admin` / `admin` and change the password immediately.
Node agent install: create the node in the panel first — the panel generates the install command with the registration token; run it as root on the node, for example:
```bash title="node agent"
bash <(curl -fL https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-agent.sh) --master http://MASTER:2053 --token <token> --name <node-name>
```
Install a specific panel version: fetch the script at that tag (the script's default download URL is that version), for example:
```bash title="pinned version" ```bash title="pinned version"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0 bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/tag/V2.7.5/install-master.sh)
``` ```
Install the rolling **dev** build (the latest per-commit pre-release from `main` There is no dev-channel one-click install; the main-branch script tracks the latest release. When it finishes, continue to [First login](/docs/guide/first-login).
— not a stable release) by passing `dev-latest`:
```bash title="rolling dev build"
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
continue to [First login](/docs/guide/first-login).
</Tab> </Tab>
@@ -54,41 +50,25 @@ The default Compose setup uses SQLite. Clone the repo (or copy its
docker compose up -d 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: lines in `docker-compose.yml` and start with the profile:
```bash ```bash
docker compose --profile postgres up -d docker compose --profile postgres up -d
``` ```
Prefer the prebuilt image? It's published to the GitHub Container Registry. The No prebuilt image is published for this fork — build locally as above. The locally built image also bundles Fail2ban (for [IP limits](/docs/operations/security)); its bans work through `iptables` and therefore need `NET_ADMIN` (`NET_RAW` for IPv6) — the Compose file already includes both; otherwise bans are only logged, never applied.
image bundles Fail2ban (for [IP limits](/docs/operations/security)), which bans
with `iptables` and therefore needs `NET_ADMIN` (and `NET_RAW` for IPv6) —
otherwise bans are logged but never applied:
```bash title="docker run" The `db/` volume holds the SQLite database (`/etc/l-ui/l-ui.db`) and `cert/`
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
ghcr.io/mhsanaei/3x-ui:latest
```
The `db/` volume holds the SQLite database (`/etc/x-ui/x-ui.db`) and `cert/`
holds TLS certificates, so your data survives upgrades. holds TLS certificates, so your data survives upgrades.
</Tab> </Tab>
<Tab value="Manual"> <Tab value="Manual">
For advanced users, download a release archive for your architecture from the For advanced users, download a release binary for your architecture from the
[releases page](https://github.com/MHSanaei/3x-ui/releases), extract it, and run [releases page](https://git.881218.xyz/rogue/l-ui/releases) (`l-ui-linux-amd64` or `l-ui-linux-arm64`),
the binary as a systemd service. The install script automates exactly these place it at `/usr/local/l-ui/l-ui`, and run it as a systemd service following the repo root README. The install script automates exactly these
steps, so it's preferred unless you have a specific reason to install by hand. steps, so it's preferred unless you have a specific reason to install by hand.
</Tab> </Tab>
@@ -105,7 +85,7 @@ Tailor the command to your setup:
You pick the storage backend at install time: 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 - **PostgreSQL** — for high client counts or multi-node setups. The installer
can install it locally or use a DSN you provide. can install it locally or use a DSN you provide.
@@ -114,17 +94,8 @@ migration.
## Unattended / cloud-init ## Unattended / cloud-init
The installer also runs **non-interactively** for automation. Set The install script itself takes no interactive input, so it can be used directly for automation. The repo's [`deploy/cloud-init/`](https://git.881218.xyz/rogue/l-ui/src/branch/main/deploy/cloud-init)
`XUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero provides ready-made **cloud-init** user-data for unattended installs on any
prompts, generating random credentials and writing them to
`/etc/x-ui/install-result.env`:
```bash
XUI_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)
directory has ready-made **cloud-init** user-data for unattended installs on any
cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle). cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
## Next steps ## Next steps
@@ -138,7 +109,7 @@ cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
<Card <Card
title="Update & uninstall" title="Update & uninstall"
href="/docs/guide/update-uninstall" href="/docs/guide/update-uninstall"
description="The x-ui menu, updates, and removal." description="The l-ui menu, updates, and removal."
/> />
<Card <Card
title="REALITY" title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
--- ---
title: Update & Uninstall 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 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. no arguments for the interactive menu, or pass a subcommand for a one-shot action.
```bash ```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: 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 | | 1 | Install | (Re)install from the remote script |
| 2 | Update | Update to the latest **stable** release | | 2 | Update | Update to the latest **stable** release |
| 3 | Update to Dev Channel (latest commit) | Update to the rolling `dev-latest` build | | 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) | | 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 | | 7 | Reset Username & Password | Set new credentials; optionally disable 2FA |
| 8 | Reset Web Base Path | Randomize the web base path | | 8 | Reset Web Base Path | Randomize the web base path |
| 9 | Reset Settings | Reset panel settings (your account is preserved) | | 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 ## 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 | | Command | Action |
| -------------------------- | --------------------------------------------------- | | -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | Control the service | | `l-ui start` / `stop` / `restart` | Control the service |
| `x-ui restart-xray` | Reload only Xray-core | | `l-ui restart-xray` | Reload only Xray-core |
| `x-ui status` | Show status | | `l-ui status` | Show status |
| `x-ui settings` | Show current settings | | `l-ui settings` | Show current settings |
| `x-ui enable` / `disable` | Toggle autostart on boot | | `l-ui enable` / `disable` | Toggle autostart on boot |
| `x-ui log` | Tail the debug log | | `l-ui log` | Tail the debug log |
| `x-ui banlog` | Show Fail2ban ban log | | `l-ui banlog` | Show Fail2ban ban log |
| `x-ui update` | Update to the latest stable release | | `l-ui update` | Update to the latest stable release |
| `x-ui update-dev` | Update to the rolling `dev-latest` build | | `l-ui update-dev` | Update to the rolling `dev-latest` build |
| `x-ui legacy` | Install a specific older version (prompts) | | `l-ui legacy` | Install a specific older version (prompts) |
| `x-ui update-all-geofiles` | Update all geo files, restart if changed | | `l-ui update-all-geofiles` | Update all geo files, restart if changed |
| `x-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) | | `l-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `x-ui install` / `uninstall` | Install / uninstall | | `l-ui install` / `uninstall` | Install / uninstall |
## Updating ## 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. 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). `dev-latest` per-commit build (not a stable release).
- **A specific older version:** menu option **5** (Legacy Version). - **A specific older version:** menu option **5** (Legacy Version).
@@ -83,17 +83,17 @@ Updating preserves your database and settings. Take a
<Callout type="info"> <Callout type="info">
Docker users update differently — pull the new image and recreate the Docker users update differently — pull the new image and recreate the
container (`docker compose pull && docker compose up -d`) rather than using the container (`docker compose pull && docker compose up -d`) rather than using the
`x-ui` update commands. `l-ui` update commands.
</Callout> </Callout>
## Uninstalling ## Uninstalling
Menu option **6** or `x-ui uninstall`. It stops and disables the service, removes Menu option **6** or `l-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/x-ui/` and the install folder. If the panel 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, used a locally-installed PostgreSQL, it offers to purge that too (a separate,
irreversible confirmation). irreversible confirmation).
<Callout type="warn"> <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. [Back up](/docs/operations/backup-restore) first if you might need it.
</Callout> </Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
--- ---
title: Contributing 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 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. welcome.
## Support the developer ## 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: to you, consider supporting continued development:
- **Donate** at [donate.sanaei.dev](https://donate.sanaei.dev/) — the page shows - **Donate** at [donate.sanaei.dev](https://donate.sanaei.dev/) — the page shows
current funding **goals and targets** you can help reach. 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. project.
- **Join** the Telegram channel [@XrayUI](https://t.me/XrayUI) to follow news and - **Join** the Telegram channel [@XrayUI](https://t.me/XrayUI) to follow news and
help others. help others.
## Contribute to 3x-ui ## Contribute to L-UI
- Read the project's `CONTRIBUTING.md` in the - 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. - Open issues for bugs and feature requests with clear reproduction steps.
- Use Conventional Commits and keep pull requests focused. - Use Conventional Commits and keep pull requests focused.
+9 -9
View File
@@ -1,13 +1,13 @@
--- ---
title: FAQ 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 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 Yes. L-UI is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/3x-ui). [GitHub](https://github.com/MHSanaei/L-UI).
## What systems does it run on? ## 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 or PostgreSQL?
SQLite is the default and is fine for most deployments. PostgreSQL is available 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). [environment variables](/docs/reference/env-vars).
## Which client apps work with it? ## 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 Import a client's share link or QR code, or use a
[subscription](/docs/config/subscription). [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 support, improved stability, per-client traffic accounting, multi-node
management, a 13-language UI, and many quality-of-life features. 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. Re-run the install script (it updates in place), or pull the new Docker image.
See [Installation](/docs/guide/installation) and the 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? ## Where can I get help?
Join the official Telegram channel [@XrayUI](https://t.me/XrayUI) for Join the official Telegram channel [@XrayUI](https://t.me/XrayUI) for
announcements and community support, or open an issue on 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). with [Troubleshooting](/docs/help/troubleshooting).
+8 -8
View File
@@ -1,6 +1,6 @@
--- ---
title: Migration 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 icon: ArrowRightLeft
--- ---
@@ -13,12 +13,12 @@ Moving to a new server is a database move:
<Step> <Step>
### Back up the old server ### 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). [Backup & restore](/docs/operations/backup-restore).
</Step> </Step>
<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 Use the same install method and a compatible version. See
[Installation](/docs/guide/installation). [Installation](/docs/guide/installation).
@@ -33,17 +33,17 @@ panel. Update any IP/domain-specific settings.
</Steps> </Steps>
## Between 3x-ui versions ## Between L-UI versions
Within the same backend, upgrading is usually just re-running the installer or 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** 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. 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 Importing an older l-ui panel's database directly into L-UI is **not
supported** — the schemas differ. Install 3x-ui fresh and recreate supported** — the schemas differ. Install L-UI fresh and recreate
inbounds/clients, exporting share links from the old panel as you go. inbounds/clients, exporting share links from the old panel as you go.
<Callout type="warn"> <Callout type="warn">
@@ -1,17 +1,17 @@
--- ---
title: Troubleshooting 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 icon: Wrench
--- ---
A checklist for the most common issues. When in doubt, raise the log level 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 ## 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. - 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 ## 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"> <Callout type="info">
Still stuck? Search the 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. probably been seen before.
</Callout> </Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
--- ---
title: 3x-ui Documentation title: L-UI Documentation
description: Official documentation for 3x-ui — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions. description: Official documentation for L-UI — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
icon: House 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 [Xray-core](https://github.com/XTLS/Xray-core) servers. It gives you a modern
dashboard for inbounds, protocols, clients, traffic accounting, subscriptions, dashboard for inbounds, protocols, clients, traffic accounting, subscriptions,
and more — without hand-editing Xray JSON on the command line. and more — without hand-editing Xray JSON on the command line.
@@ -17,7 +17,7 @@ leaves the page.
<Cards> <Cards>
<Card <Card
title="What is 3x-ui?" title="What is L-UI?"
href="/docs/guide" href="/docs/guide"
description="The big picture: Xray-core, the panel, and who it's for." 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. - **Operations** — multi-node management, Telegram bot, backups, and a REST API.
<Callout type="info"> <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. your client apps fit together.
</Callout> </Callout>
@@ -1,6 +1,6 @@
--- ---
title: Backup & Restore 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 icon: DatabaseBackup
--- ---
@@ -9,7 +9,7 @@ database. Back it up regularly so you can recover or migrate.
## What to back up ## 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). PostgreSQL database if you use that backend).
- **Certificates** — anything under `/root/cert/` (or wherever you store TLS - **Certificates** — anything under `/root/cert/` (or wherever you store TLS
certs). certs).
@@ -20,7 +20,7 @@ You can download a backup from the panel's overview, or copy the database file
directly from the server: directly from the server:
```bash title="copy the SQLite database" ```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. 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 ## 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): SQL text dump (handy for inspection or transferring between machines):
```bash ```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text l-ui migrate-db --dump /root/l-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite l-ui migrate-db --restore /root/l-ui.sql # SQL text -> SQLite
``` ```
To move to PostgreSQL instead, see [Database](/docs/reference/database). To move to PostgreSQL instead, see [Database](/docs/reference/database).
@@ -1,15 +1,15 @@
--- ---
title: Multi-node & Managed Hosts 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 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**. how each inbound is advertised in subscriptions with **managed hosts**.
## Nodes ## 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, API. The master polls each node and shows its status, versions, CPU/memory,
uptime, and traffic in one place. uptime, and traffic in one place.
@@ -1,11 +1,11 @@
--- ---
title: Outbounds & Routing 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 icon: Route
--- ---
Inbounds accept clients; **outbounds** decide where their traffic goes next. 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, (WireGuard), or arbitrary outbound pools imported from a subscription,
and select between them with routing rules and balancers. 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 A **proxy** outbound (VLESS, VMess, Trojan, Shadowsocks) forwards to another
server — handy for chaining or sending select traffic abroad. Mind the wire 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 `encryption`), **VMess uses `settings.vnext[]`**, and **Trojan/Shadowsocks use
`settings.servers[]`**. The `streamSettings` must mirror the destination's `settings.servers[]`**. The `streamSettings` must mirror the destination's
[transport and security](/docs/config/transports). [transport and security](/docs/config/transports).
@@ -50,7 +50,7 @@ Assemble any outbound below and paste the JSON into **Xray Settings → Outbound
## Cloudflare WARP ## 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`**: WARP account for you and wire it into a WireGuard outbound tagged **`warp`**:
<Steps> <Steps>
@@ -64,7 +64,7 @@ Create a WireGuard outbound with the tag `warp` in your Xray config.
<Step> <Step>
### Register WARP ### 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. keys, addresses, reserved bytes, and peer endpoint automatically.
</Step> </Step>
@@ -82,13 +82,13 @@ with a routing rule.
## NordVPN ## 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 accept a private key directly) and list countries/servers, so you can build a
NordVPN outbound. NordVPN outbound.
## PIA WireGuard ## 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 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. **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 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 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 `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`). re-login. Peer `allowedIPs` is IPv4-only (`0.0.0.0/0`).
## Outbound subscriptions (server pools) ## Outbound subscriptions (server pools)
@@ -1,13 +1,13 @@
--- ---
title: Reverse Proxy 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 icon: Waypoints
--- ---
A reverse proxy lets you serve the panel and subscription on a clean domain with 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 automatic HTTPS, and hide the real ports behind ports 80/443. Prefer to let the
panel terminate TLS directly? Get a certificate with 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 ## Generate a config
@@ -45,7 +45,7 @@ panel.example.com {
## Tips ## Tips
- Keep the panel's **web base path** even behind a proxy; defense in depth. - 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). panel — see the [environment variables reference](/docs/reference/env-vars).
- Proxy the [subscription](/docs/config/subscription) server too, so its contents - Proxy the [subscription](/docs/config/subscription) server too, so its contents
are served over HTTPS. are served over HTTPS.
+10 -10
View File
@@ -1,6 +1,6 @@
--- ---
title: Security 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 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 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 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 L-UI installs and configures for you (enabled by default on script installs, and
on Docker via `XUI_ENABLE_FAIL2BAN=true`). 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, change the ban duration (default **30 minutes**), ban/unban an IP, view ban logs,
and check status. Under the hood: and check status. Under the hood:
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/x-ui/3xipl.log` and - The jail is named **`3x-ipl`**; ban logs live at `/var/log/l-ui/3xipl.log` and
`/var/log/x-ui/3xipl-banned.log` (also via `x-ui banlog`). `/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 - Bans cover all TCP/UDP **except** your SSH and panel ports, so a ban can't lock
you out of the server or panel. you out of the server or panel.
@@ -43,7 +43,7 @@ and check status. Under the hood:
## Firewall ## Firewall
Open only the ports you actually use: SSH, the panel port, the subscription 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: `ufw`, or generate rules here:
<FirewallRulesGenerator /> <FirewallRulesGenerator />
@@ -55,12 +55,12 @@ port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) w
## Network tuning (BBR) ## 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 (`net.ipv4.tcp_congestion_control = bbr`, `net.core.default_qdisc = fq`), which
often improves throughput on congested links. often improves throughput on congested links.
## Keep current ## Keep current
Update 3x-ui and Xray-core regularly — security fixes land in new releases. Watch Update L-UI and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/3x-ui/releases) and see the [releases page](https://github.com/MHSanaei/L-UI/releases) and see
[Update & uninstall](/docs/guide/update-uninstall). [Update & uninstall](/docs/guide/update-uninstall).
@@ -1,10 +1,10 @@
--- ---
title: Telegram Bot 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 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 management. Admins get full control; regular users (linked by Telegram ID) can
check their own usage and links. 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 ( return (
<> <>
{props.children} {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 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 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. the panel's OpenAPI specification, so they always match the documented schema.
## Authentication ## Authentication
@@ -4,7 +4,6 @@
"pages": [ "pages": [
"index", "index",
"authentication", "authentication",
"api-tokens",
"inbounds", "inbounds",
"clients", "clients",
"server", "server",
+11 -17
View File
@@ -1,6 +1,6 @@
--- ---
title: Nodes 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. endpoints under /panel/api/nodes.
full: true full: true
_openapi: _openapi:
@@ -37,15 +37,12 @@ _openapi:
panel. 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' 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 - depth: 2
title: Register a new remote node. Provide its URL, write-only apiToken, and title: Register a new remote node. Provide its URL and optional remark /
optional remark / allowPrivateAddress flag. Responses expose hasApiToken allowPrivateAddress flag.
only. url: '#register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag'
url: '#register-a-new-remote-node-provide-its-url-write-only-apitoken-and-optional-remark--allowprivateaddress-flag-responses-expose-hasapitoken-only'
- depth: 2 - depth: 2
title: 'Replace a node’s connection details. apiToken is write-only: omit it or title: Replace a node’s connection details.
send an empty string to keep the stored token; set clearApiToken=true to url: '#replace-a-nodes-connection-details'
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'
- depth: 2 - depth: 2
title: Delete a node. Inbounds bound to it are not auto-migrated. title: Delete a node. Inbounds bound to it are not auto-migrated.
url: '#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 node-assigned inbound gets paths that exist on the node, not the
central panel. 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 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 - content: Register a new remote node. Provide its URL and optional remark /
optional remark / allowPrivateAddress flag. Responses expose allowPrivateAddress flag.
hasApiToken only. id: register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag
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.
- content: 'Replace a node’s connection details. apiToken is write-only: omit it id: replace-a-nodes-connection-details
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: Delete a node. Inbounds bound to it are not auto-migrated. - content: Delete a node. Inbounds bound to it are not auto-migrated.
id: 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. - 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. title: List Xray binary versions available for install on this host.
url: '#list-xray-binary-versions-available-for-install-on-this-host' url: '#list-xray-binary-versions-available-for-install-on-this-host'
- depth: 2 - depth: 2
title: 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-3x-ui-release-is-available-on-github' url: '#check-whether-a-newer-L-UI-release-is-available-on-github'
- depth: 2 - depth: 2
title: Report the outcome of the most recently launched panel self-update (see title: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one 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 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. - content: List Xray binary versions available for install on this host.
id: 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. - content: Check whether a newer L-UI release is available on GitHub.
id: check-whether-a-newer-3x-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 - content: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one POST updatePanel). Compare the returned runId against the one
updatePanel returned to tell this run apart from a stale result. updatePanel returned to tell this run apart from a stale result.
@@ -36,10 +36,10 @@ _openapi:
values on success. 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' 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 - 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 connection drops immediately; the panel comes back online ~5-10 seconds
later. 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 - depth: 2
title: Test SMTP connection with stage-by-stage reporting (connect, auth, send). title: Test SMTP connection with stage-by-stage reporting (connect, auth, send).
Returns structured result with stage and message. Returns structured result with stage and message.
@@ -76,10 +76,10 @@ _openapi:
credentials for verification. The session is refreshed with the new credentials for verification. The session is refreshed with the new
values on success. 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 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 connection drops immediately; the panel comes back online ~5-10
seconds later. 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, - content: Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message. 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 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 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 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. the backend at install time; both are first-class.
## SQLite (default) ## 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 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). to the binary).
## PostgreSQL ## PostgreSQL
@@ -19,20 +19,20 @@ to the binary).
Recommended for high client counts or multi-node setups. The installer can 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 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 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" ```bash title="/etc/default/l-ui"
XUI_DB_TYPE=postgres LUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable 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 Tune the connection pool with `LUI_DB_MAX_OPEN_CONNS` and
`XUI_DB_MAX_IDLE_CONNS`. `LUI_DB_MAX_IDLE_CONNS`.
### Docker ### Docker
`docker compose up -d` keeps using SQLite. To run with the bundled PostgreSQL `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: with the profile:
```bash ```bash
@@ -44,13 +44,13 @@ docker compose --profile postgres up -d
Move an existing SQLite install to PostgreSQL with the built-in command: Move an existing SQLite install to PostgreSQL with the built-in command:
```bash ```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 ```bash
systemctl restart x-ui systemctl restart l-ui
``` ```
<Callout type="info"> <Callout type="info">
+30 -30
View File
@@ -1,46 +1,46 @@
--- ---
title: Environment Variables 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 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 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`. 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: Defaults are sensible — set only what you need to change, then restart:
`systemctl restart x-ui`. `systemctl restart l-ui`.
## Database ## Database
| Variable | Default | Description | | Variable | Default | Description |
| ------------------------ | ----------- | -------------------------------------------------------------------- | | ------------------------ | ----------- | -------------------------------------------------------------------- |
| `XUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). | | `LUI_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`). | | `LUI_DB_FOLDER` | `/etc/l-ui` | Folder for the SQLite database file (`l-ui.db`). |
| `XUI_DB_DSN` | — | PostgreSQL connection string (used when `XUI_DB_TYPE=postgres`). | | `LUI_DB_DSN` | — | PostgreSQL connection string (used when `LUI_DB_TYPE=postgres`). |
| `XUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. | | `LUI_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_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. [Database](/docs/reference/database) for the SQLite ↔ PostgreSQL details.
## Panel ## Panel
| Variable | Default | Description | | Variable | Default | Description |
| ------------------------ | ------- | ------------------------------------------------------------------------ | | ------------------------ | ------- | ------------------------------------------------------------------------ |
| `XUI_PORT` | — | Override the panel port (1–65535). Takes precedence over the stored setting. | | `LUI_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`). | | `LUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. | | `LUI_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_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
## Logging & binaries ## Logging & binaries
| Variable | Default | Description | | Variable | Default | Description |
| ---------------- | ---------------- | ----------------------------------------------------------- | | ---------------- | ---------------- | ----------------------------------------------------------- |
| `XUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. | | `LUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `XUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). | | `LUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `XUI_LOG_FOLDER` | `/var/log/x-ui` | Log output directory. | | `LUI_LOG_FOLDER` | `/var/log/l-ui` | Log output directory. |
| `XUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. | | `LUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
## Memory & profiling ## Memory & profiling
@@ -49,11 +49,11 @@ knobs — leave them unset unless you're tuning a constrained host.
| Variable | Default | Description | | Variable | Default | Description |
| ----------------------------- | ------- | ----------------------------------------------------------------- | | ----------------------------- | ------- | ----------------------------------------------------------------- |
| `XUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. | | `LUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `XUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. | | `LUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `XUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. | | `LUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `GOMEMLIMIT` | — | Go-syntax soft limit (e.g. `400MiB`); takes precedence over above.| | `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 ## Xray
@@ -69,16 +69,16 @@ clients, so enable it deliberately.
| Variable | Default | Description | | Variable | Default | Description |
| ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- | | ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| `XUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. | | `LUI_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. | | `LUI_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. | | `LUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `XUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. | | `LUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. | | `LUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `XUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. | | `LUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. | | `LUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
## Unattended install ## Unattended install
| Variable | Description | | 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 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 icon: Network
--- ---
@@ -32,5 +32,5 @@ Your actual inbound ports depend on the inbounds you create.
<Cards> <Cards>
<Card title="Security" href="/docs/operations/security" description="Fail2ban, IP limits, and hardening." /> <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> </Cards>
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: کلاینت‌ها title: کلاینت‌ها
description: مدیریت کلاینت‌های 3x-ui — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین. description: مدیریت کلاینت‌های L-UI — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
icon: Users icon: Users
--- ---
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: ورودی‌ها و پروتکل‌ها title: ورودی‌ها و پروتکل‌ها
description: ساخت ورودی‌ها در 3x-ui — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند. description: ساخت ورودی‌ها در L-UI — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
icon: ArrowDownToLine icon: ArrowDownToLine
--- ---
@@ -74,7 +74,7 @@ TLS یا REALITY) را انتخاب کنید. به [انتقال‌ها](/docs/c
Fallbackها به یک پورت TLS واحد (مثلاً `443`) اجازه می‌دهند بیش از یک پروتکل را Fallbackها به یک پورت TLS واحد (مثلاً `443`) اجازه می‌دهند بیش از یک پروتکل را
سرویس دهد — برای مثال VLESS **و** Trojan — با هدایت دست‌دادن‌های (handshake) سرویس دهد — برای مثال VLESS **و** Trojan — با هدایت دست‌دادن‌های (handshake)
ناهماهنگ به یک ورودی فرزند. در 3x-ui، fallbackها در پنل مدیریت می‌شوند (لیست ناهماهنگ به یک ورودی فرزند. در L-UI، fallbackها در پنل مدیریت می‌شوند (لیست
**Fallbacks** یک ورودی اصلی) به‌جای آنکه به‌صورت دستی در JSON نوشته شوند. **Fallbacks** یک ورودی اصلی) به‌جای آنکه به‌صورت دستی در JSON نوشته شوند.
Fallbackها تنها زمانی در دسترس‌اند که ورودی اصلی این‌گونه باشد: Fallbackها تنها زمانی در دسترس‌اند که ورودی اصلی این‌گونه باشد:
+4 -4
View File
@@ -1,6 +1,6 @@
--- ---
title: تنظیمات پنل title: تنظیمات پنل
description: تمام تنظیمات پنل 3x-ui — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس. description: تمام تنظیمات پنل L-UI — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
icon: SlidersHorizontal icon: SlidersHorizontal
--- ---
@@ -14,7 +14,7 @@ icon: SlidersHorizontal
| Setting | Default | Meaning | | Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- | | ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `XUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. | | `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `LUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webListen` | _(همه‌ی واسط‌ها)_ | پنل را به یک IP مشخص مقید کنید. | | `webListen` | _(همه‌ی واسط‌ها)_ | پنل را به یک IP مشخص مقید کنید. |
| `webBasePath` | `/` | مسیر URLی که پنل زیر آن ارائه می‌شود (همیشه به شکل `/…/` نرمال‌سازی می‌شود). | | `webBasePath` | `/` | مسیر URLی که پنل زیر آن ارائه می‌شود (همیشه به شکل `/…/` نرمال‌سازی می‌شود). |
| `webCertFile` / `webKeyFile` | _(هیچ‌کدام)_ | گواهی + کلید TLS. وقتی هر دو تنظیم شوند، پنل با **HTTPS** ارائه می‌شود. | | `webCertFile` / `webKeyFile` | _(هیچ‌کدام)_ | گواهی + کلید TLS. وقتی هر دو تنظیم شوند، پنل با **HTTPS** ارائه می‌شود. |
@@ -24,12 +24,12 @@ icon: SlidersHorizontal
پس از تغییر پورت یا مسیر پایه، آدرس پنل به‌صورت پس از تغییر پورت یا مسیر پایه، آدرس پنل به‌صورت
`http(s)://<server>:<port><web-base-path>` درمی‌آید. می‌توانید مسیر پایه را در `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 ### TLS
ارائه‌ی پنل روی HTTPS از اطلاعات احراز هویت شما در حین انتقال محافظت می‌کند. یا ارائه‌ی پنل روی HTTPS از اطلاعات احراز هویت شما در حین انتقال محافظت می‌کند. یا
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `x-ui`](/docs/config/ssl-certificates) `webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `l-ui`](/docs/config/ssl-certificates)
می‌تواند یک گواهی Let's Encrypt برای شما تهیه کند — یا TLS را روی یک می‌تواند یک گواهی Let's Encrypt برای شما تهیه کند — یا TLS را روی یک
[پروکسی معکوس](/docs/operations/reverse-proxy) خاتمه دهید. [پروکسی معکوس](/docs/operations/reverse-proxy) خاتمه دهید.
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: REALITY title: REALITY
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در 3x-ui — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج. description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در L-UI — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
icon: ShieldCheck 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: لینک‌های اشتراک‌گذاری title: لینک‌های اشتراک‌گذاری
description: قالب‌های لینک اشتراک‌گذاری 3x-ui (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری. description: قالب‌های لینک اشتراک‌گذاری L-UI (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
icon: Link icon: Link
--- ---
3x-ui برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت L-UI برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
مانند v2rayNG، Hiddify و Mihomo این لینک‌ها را برای پیکربندی خودشان وارد می‌کنند. مانند v2rayNG، Hiddify و Mihomo این لینک‌ها را برای پیکربندی خودشان وارد می‌کنند.
## قالب‌های لینک ## قالب‌های لینک
@@ -1,6 +1,6 @@
--- ---
title: گواهی‌های SSL 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 icon: ShieldCheck
--- ---
@@ -8,7 +8,7 @@ icon: ShieldCheck
API شما رمزگذاری شود) و TLS را روی **ورودی‌ها** خاتمه دهید (VLESS-TLS، Trojan، API شما رمزگذاری شود) و TLS را روی **ورودی‌ها** خاتمه دهید (VLESS-TLS، Trojan،
Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌آوردن گواهی وجود دارد: 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 خام. آسان‌ترین گزینه برای یک دامنه‌ی واحد یا یک IP خام.
- **Cloudflare DNS-01** — این هم از همان منو؛ برای گواهی‌های **wildcard** یا - **Cloudflare DNS-01** — این هم از همان منو؛ برای گواهی‌های **wildcard** یا
زمانی که پورت 80 مسدود است / سرور پشت پراکسی Cloudflare قرار دارد لازم است. زمانی که پورت 80 مسدود است / سرور پشت پراکسی Cloudflare قرار دارد لازم است.
@@ -21,9 +21,9 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
TLS یک سایت واقعی را قرض می‌گیرند. این صفحه برای پنل و برای ورودی‌های کلاسیک TLS است. TLS یک سایت واقعی را قرض می‌گیرند. این صفحه برای پنل و برای ورودی‌های کلاسیک TLS است.
</Callout> </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) را به کار می‌گیرد و موارد زیر را ارائه می‌دهد: [acme.sh](https://github.com/acmesh-official/acme.sh) را به کار می‌گیرد و موارد زیر را ارائه می‌دهد:
| گزینه | کاری که انجام می‌دهد | | گزینه | کاری که انجام می‌دهد |
@@ -57,7 +57,7 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
<Step> <Step>
### صادرکننده را اجرا کنید ### صادرکننده را اجرا کنید
`x-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را `l-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
درخواست می‌کند و آن را زیر `/root/cert/<domain>/` به‌صورت `fullchain.pem` درخواست می‌کند و آن را زیر `/root/cert/<domain>/` به‌صورت `fullchain.pem`
(زنجیره‌ی گواهی) و `privkey.pem` (کلید خصوصی) ذخیره می‌کند. (زنجیره‌ی گواهی) و `privkey.pem` (کلید خصوصی) ذخیره می‌کند.
</Step> </Step>
@@ -104,7 +104,7 @@ DNS دامنه‌ی شما باید توسط Cloudflare مدیریت شود و
<Step> <Step>
### صادرکننده‌ی Cloudflare را اجرا کنید ### صادرکننده‌ی Cloudflare را اجرا کنید
`x-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک `l-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
توکن API (پیش‌فرض) یا **`g`** را برای Global API Key انتخاب کنید، سپس دامنه‌ی خود را توکن API (پیش‌فرض) یا **`g`** را برای Global API Key انتخاب کنید، سپس دامنه‌ی خود را
وارد کنید (و برای Global API Key، ایمیل حساب و کلید خود را). acme.sh رکورد TXT را وارد کنید (و برای Global API Key، ایمیل حساب و کلید خود را). acme.sh رکورد TXT را
می‌سازد، اعتبارسنجی می‌کند و آن را پاک‌سازی می‌کند. می‌سازد، اعتبارسنجی می‌کند و آن را پاک‌سازی می‌کند.
+2 -2
View File
@@ -1,6 +1,6 @@
--- ---
title: Subscription title: Subscription
description: راه‌اندازی سرور اشتراک 3x-ui — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی. description: راه‌اندازی سرور اشتراک L-UI — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
icon: Rss icon: Rss
--- ---
@@ -59,7 +59,7 @@ https://<sub-host>:<sub-port>/sub/<sub-id>
با standard-base64 رمزگذاری شده‌اند (با `subEncrypt` قابل تغییر است). بدنه‌ی **JSON** با standard-base64 رمزگذاری شده‌اند (با `subEncrypt` قابل تغییر است). بدنه‌ی **JSON**
هر کلاینت را در یک پیکربندی کامل کلاینت Xray می‌پیچد — یک اسکلت ثابت (ورودی‌های محلی هر کلاینت را در یک پیکربندی کامل کلاینت Xray می‌پیچد — یک اسکلت ثابت (ورودی‌های محلی
mixed/HTTP، DNS، مسیریابی، policy) به‌علاوه‌ی یک outbound از نوع `proxy` که به ورودی mixed/HTTP، DNS، مسیریابی، policy) به‌علاوه‌ی یک outbound از نوع `proxy` که به ورودی
اشاره می‌کند. 3x-ui **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه** اشاره می‌کند. L-UI **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
تولید می‌کند، از فرم تخت `settings` در outbound استفاده می‌کند تولید می‌کند، از فرم تخت `settings` در outbound استفاده می‌کند
(`address`/`port`/`id`، `level: 8`) و `sockopt` را از `streamSettings` حذف می‌کند. (`address`/`port`/`id`، `level: 8`) و `sockopt` را از `streamSettings` حذف می‌کند.
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
title: انتقال‌ها و امنیت 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 icon: Network
--- ---
+16 -16
View File
@@ -1,6 +1,6 @@
--- ---
title: نخستین ورود title: نخستین ورود
description: مشخصات ورود تولیدشدهٔ 3x-ui را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید. description: مشخصات ورود تولیدشدهٔ L-UI را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
icon: KeyRound icon: KeyRound
--- ---
@@ -24,25 +24,25 @@ http://<your-server-ip>:<port>/<web-base-path>
نصب با اسکریپت پس از پایان، خلاصه‌ای از مشخصات ورود را چاپ می‌کند و آن را در یک نصب با اسکریپت پس از پایان، خلاصه‌ای از مشخصات ورود را چاپ می‌کند و آن را در یک
فایل ویژهٔ root نیز می‌نویسد: فایل ویژهٔ root نیز می‌نویسد:
```bash title="/etc/x-ui/install-result.env (mode 600)" ```bash title="/etc/l-ui/install-result.env (mode 600)"
XUI_USERNAME=... LUI_USERNAME=...
XUI_PASSWORD=... LUI_PASSWORD=...
XUI_PANEL_PORT=... LUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=... LUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=... LUI_ACCESS_URL=...
XUI_API_TOKEN=... LUI_API_TOKEN=...
XUI_DB_TYPE=sqlite LUI_DB_TYPE=sqlite
``` ```
اگر آن‌ها را از دست دادید، از ابزارهای مدیریتی استفاده کنید: اگر آن‌ها را از دست دادید، از ابزارهای مدیریتی استفاده کنید:
```bash ```bash
x-ui # menu → 11 (View Current Settings) l-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form l-ui settings # or the one-shot form
``` ```
برای **Docker**، مشخصات ورود تولیدشده را از لاگ‌های کانتینر بخوانید، یا دستور برای **Docker**، مشخصات ورود تولیدشده را از لاگ‌های کانتینر بخوانید، یا دستور
`docker exec -it <container> x-ui setting -show` را اجرا کنید. `docker exec -it <container> l-ui setting -show` را اجرا کنید.
<Callout type="warn"> <Callout type="warn">
اگر پنل شما هنوز از مقادیر پیش‌فرض `admin` / `admin` استفاده می‌کند (پنل در این اگر پنل شما هنوز از مقادیر پیش‌فرض `admin` / `admin` استفاده می‌کند (پنل در این
@@ -53,7 +53,7 @@ x-ui settings # or the one-shot form
یک پورت غیرپیش‌فرض و یک **مسیر پایهٔ وب** طولانی و تصادفی، یافتن پنل را بسیار یک پورت غیرپیش‌فرض و یک **مسیر پایهٔ وب** طولانی و تصادفی، یافتن پنل را بسیار
دشوارتر می‌کند. آن‌ها را از بخش **Panel Settings** در رابط کاربری، یا از منوی دشوارتر می‌کند. آن‌ها را از بخش **Panel Settings** در رابط کاربری، یا از منوی
`x-ui` تغییر دهید: `l-ui` تغییر دهید:
- **7 — Reset Username & Password** (با امکان غیرفعال‌سازی همزمان 2FA) - **7 — Reset Username & Password** (با امکان غیرفعال‌سازی همزمان 2FA)
- **8 — Reset Web Base Path** (آن را تصادفی می‌کند) - **8 — Reset Web Base Path** (آن را تصادفی می‌کند)
@@ -64,11 +64,11 @@ x-ui settings # or the one-shot form
## احراز هویت دومرحله‌ای (2FA) ## احراز هویت دومرحله‌ای (2FA)
‏3x-ui از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google ‏L-UI از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
Authenticator، Aegis و غیره). آن را در بخش **Panel Settings** فعال کنید — پس از Authenticator، Aegis و غیره). آن را در بخش **Panel Settings** فعال کنید — پس از
فعال‌سازی، صفحهٔ ورود علاوه بر رمز عبور، یک کد ۶ رقمی نیز درخواست می‌کند و فعال‌سازی، صفحهٔ ورود علاوه بر رمز عبور، یک کد ۶ رقمی نیز درخواست می‌کند و
فعال کردن آن همه را وادار به ورود مجدد می‌کند. می‌توانید آن را از مرحلهٔ **Reset فعال کردن آن همه را وادار به ورود مجدد می‌کند. می‌توانید آن را از مرحلهٔ **Reset
Username & Password** در منو یا با دستور `x-ui setting -resetTwoFactor` غیرفعال Username & Password** در منو یا با دستور `l-ui setting -resetTwoFactor` غیرفعال
کنید. کنید.
## محافظت داخلی از ورود ## محافظت داخلی از ورود
@@ -106,7 +106,7 @@ Username & Password** در منو یا با دستور `x-ui setting -resetTwoFa
<Step> <Step>
### پنل را پشت TLS قرار دهید ### پنل را پشت TLS قرار دهید
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `x-ui` یا یک reverse proxy) از یک گواهی معتبر (از طریق مدیریت SSL در منوی `l-ui` یا یک reverse proxy)
استفاده کنید تا پنل تنها از طریق HTTPS در دسترس باشد. استفاده کنید تا پنل تنها از طریق HTTPS در دسترس باشد.
</Step> </Step>
+6 -6
View File
@@ -1,10 +1,10 @@
--- ---
title: آشنایی با 3x-ui title: آشنایی با L-UI
description: یک پنل تحت وب برای Xray-core — ورودی‌ها، پروتکل‌ها، کلاینت‌ها و اشتراک‌ها را به‌جای ویرایش دستی JSON، از مرورگر خود مدیریت کنید. description: یک پنل تحت وب برای Xray-core — ورودی‌ها، پروتکل‌ها، کلاینت‌ها و اشتراک‌ها را به‌جای ویرایش دستی JSON، از مرورگر خود مدیریت کنید.
icon: Info icon: Info
--- ---
**3x-ui** یک پنل کنترل تحت وب است که روی **L-UI** یک پنل کنترل تحت وب است که روی
[Xray-core](https://github.com/XTLS/Xray-core)، همان موتور پروکسی که در واقع [Xray-core](https://github.com/XTLS/Xray-core)، همان موتور پروکسی که در واقع
ترافیک شما را جابه‌جا می‌کند، قرار می‌گیرد. به‌جای نوشتن و بارگذاری مجدد پیکربندی ترافیک شما را جابه‌جا می‌کند، قرار می‌گیرد. به‌جای نوشتن و بارگذاری مجدد پیکربندی
JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها، پروتکل‌ها، کلاینت‌ها، گواهی‌ها، JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها، پروتکل‌ها، کلاینت‌ها، گواهی‌ها،
@@ -15,7 +15,7 @@ JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها،
<Mermaid <Mermaid
chart={` chart={`
flowchart LR 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 -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")] Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -53,19 +53,19 @@ flowchart LR
| پایگاه‌داده | SQLite (پیش‌فرض) یا PostgreSQL | | پایگاه‌داده | SQLite (پیش‌فرض) یا PostgreSQL |
| موتور پروکسی | Xray-core (همراه و مدیریت‌شده توسط پنل) | | موتور پروکسی | Xray-core (همراه و مدیریت‌شده توسط پنل) |
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/x-ui/x-ui.db` قرار دارد و پنل به‌صورت پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/l-ui/l-ui.db` قرار دارد و پنل به‌صورت
پیش‌فرض روی پورت **2053** گوش می‌دهد. هر دو قابل پیکربندی هستند — به پیش‌فرض روی پورت **2053** گوش می‌دهد. هر دو قابل پیکربندی هستند — به
[نخستین ورود](/docs/guide/first-login) و مرجع متغیرهای محیطی مراجعه کنید. [نخستین ورود](/docs/guide/first-login) و مرجع متغیرهای محیطی مراجعه کنید.
## برای چه کسانی است ## برای چه کسانی است
3x-ui برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک L-UI برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
VPS شخصی منفرد تا اپراتورهایی که نودها و کلاینت‌های فراوانی را مدیریت می‌کنند. اگر VPS شخصی منفرد تا اپراتورهایی که نودها و کلاینت‌های فراوانی را مدیریت می‌کنند. اگر
قدرت Xray-core را می‌خواهید بدون اینکه در فایل‌های پیکربندی JSON زندگی کنید، این قدرت Xray-core را می‌خواهید بدون اینکه در فایل‌های پیکربندی JSON زندگی کنید، این
برای شماست. برای شماست.
<Callout type="info"> <Callout type="info">
3x-ui یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از L-UI یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت
چندنودی و بسیاری از قابلیت‌های راحتی‌بخش را اضافه می‌کند. چندنودی و بسیاری از قابلیت‌های راحتی‌بخش را اضافه می‌کند.
</Callout> </Callout>
+24 -57
View File
@@ -1,48 +1,43 @@
--- ---
title: نصب title: نصب
description: نصب 3x-ui با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL. description: نصب L-UI با اسکریپت رسمی (پنل، عامل گره یا نسخهٔ مشخص)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
icon: Download icon: Download
--- ---
‏3x-ui روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian، ‏L-UI روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
Fedora، CentOS، RHEL، AlmaLinux، Rocky Linux، Oracle Linux، Amazon Linux، Fedora، CentOS، RHEL، AlmaLinux، Rocky Linux، Oracle Linux، Amazon Linux،
Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچنین Windows، Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچنین Windows،
روی معماری‌های `amd64`، `386`، `arm64`، `armv7`، `armv6`، `armv5` و `s390x`. روی معماری‌های `amd64` و `arm64`.
<Callout type="warn"> <Callout type="warn">
نصب‌کنندهٔ اسکریپتی را به‌صورت **root** (یا با `sudo`) اجرا کنید. این اسکریپت یک نصب‌کنندهٔ اسکریپتی را به‌صورت **root** (یا با `sudo`) اجرا کنید. اسکریپت‌های یک‌کلیکه فقط از `amd64`/`arm64` پشتیبانی می‌کنند.
سرویس نصب می‌کند، دستور مدیریتی `x-ui` را راه‌اندازی می‌کند و پنل را در زمان
بوت فعال می‌سازد.
</Callout> </Callout>
<Tabs items={['Script', 'Docker', 'Manual']}> <Tabs items={['Script', 'Docker', 'Manual']}>
<Tab value="Script"> <Tab value="Script">
اسکریپت رسمی مسیر توصیه‌شده است. این اسکریپت در طول نصب یک نام کاربری، رمز عبور و اسکریپت رسمی مسیر توصیه‌شده است. نصب یک‌کلیکهٔ پنل:
مسیر دسترسی (مسیر پایهٔ وب) **تصادفی** تولید می‌کند، سرویس را راه‌اندازی می‌کند و
دستور مدیریتی `x-ui` را نصب می‌کند.
```bash title="latest stable" ```bash title="پنل"
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)
``` ```
برای نصب یک **نسخهٔ مشخص**، تگ آن را در انتها اضافه کنید: این اسکریپت باینری پنل، xray و فایل‌های geo را از Releases همین مخزن (Gitea) دانلود و پنل را اجرا می‌کند (درگاه پیش‌فرض 2053). با حساب پیش‌فرض `admin` / `admin` وارد شوید و بلافاصله رمز عبور را تغییر دهید.
```bash title="pinned version" نصب عامل گره: نخست گره را در پنل بسازید — پنل دستور نصب همراه با توکن ثبت را تولید می‌کند؛ آن را به‌صورت root روی گره اجرا کنید، برای نمونه:
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
```bash title="عامل گره"
bash <(curl -fL https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-agent.sh) --master http://MASTER:2053 --token <token> --name <node-name>
``` ```
برای نصب نسخهٔ **dev** غلتان (آخرین پیش‌انتشار به‌ازای هر کامیت از شاخهٔ `main` برای نصب یک نسخهٔ مشخص از پنل، اسکریپت همان تگ را بگیرید (نشانی دانلود پیش‌فرض اسکریپت همان نسخه است)، برای نمونه:
— نه یک نسخهٔ پایدار) عبارت `dev-latest` را پاس دهید:
```bash title="rolling dev build" ```bash title="نسخهٔ مشخص"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/tag/V2.7.5/install-master.sh)
``` ```
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `x-ui` را اجرا کنید تا نصب یک‌کلیکهٔ کانال dev وجود ندارد؛ اسکریپت شاخهٔ main همان آخرین انتشار است.
[منوی مدیریت](/docs/guide/update-uninstall#the-x-ui-management-menu) باز شود، سپس
به [نخستین ورود](/docs/guide/first-login) ادامه دهید.
</Tab> </Tab>
@@ -55,41 +50,24 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
docker compose up -d docker compose up -d
``` ```
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `XUI_DB_*` را در برای اجرا با سرویس **PostgreSQL** همراه، دو خط `LUI_DB_*` را در
`docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل مربوطه اجرا کنید: `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل مربوطه اجرا کنید:
```bash ```bash
docker compose --profile postgres up -d docker compose --profile postgres up -d
``` ```
ترجیح می‌دهید از ایمیج از‌پیش‌ساخته استفاده کنید؟ این ایمیج روی GitHub Container Registry برای این فورک ایمیج از‌پیش‌ساخته‌ای منتشر نمی‌شود — مانند بالا به‌صورت محلی بسازید. ایمیج ساخته‌شدهٔ محلی نیز Fail2ban را به‌همراه دارد (برای [محدودیت‌های IP](/docs/operations/security))؛ مسدودسازی آن از طریق `iptables` انجام می‌شود و به `NET_ADMIN` (و `NET_RAW` برای IPv6) نیاز دارد — فایل Compose هر دو را شامل می‌شود؛ در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند ولی هرگز اعمال نمی‌شوند.
منتشر شده است. این ایمیج Fail2ban را به‌همراه دارد (برای [محدودیت‌های IP](/docs/operations/security))
که با `iptables` مسدودسازی انجام می‌دهد و بنابراین به `NET_ADMIN` (و `NET_RAW` برای IPv6)
نیاز دارد — در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند ولی هرگز اعمال نمی‌شوند:
```bash title="docker run" والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/l-ui/l-ui.db`) را نگه می‌دارد و `cert/`
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
ghcr.io/mhsanaei/3x-ui:latest
```
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/x-ui/x-ui.db`) را نگه می‌دارد و `cert/`
گواهی‌های TLS را، بنابراین داده‌های شما در ارتقاها حفظ می‌شوند. گواهی‌های TLS را، بنابراین داده‌های شما در ارتقاها حفظ می‌شوند.
</Tab> </Tab>
<Tab value="Manual"> <Tab value="Manual">
برای کاربران پیشرفته، یک آرشیو انتشار متناسب با معماری خود را از برای کاربران پیشرفته، یک باینری انتشار متناسب با معماری خود را از
[صفحهٔ releases](https://github.com/MHSanaei/3x-ui/releases) دانلود کنید، آن را [صفحهٔ releases](https://git.881218.xyz/rogue/l-ui/releases) دانلود کنید (`l-ui-linux-amd64` یا `l-ui-linux-arm64`)، آن را در مسیر `/usr/local/l-ui/l-ui` قرار دهید و طبق README ریشهٔ مخزن آن را به‌عنوان یک سرویس systemd اجرا کنید. اسکریپت نصب دقیقاً
استخراج کنید و باینری را به‌عنوان یک سرویس systemd اجرا کنید. اسکریپت نصب دقیقاً
همین مراحل را خودکار می‌کند، بنابراین مگر اینکه دلیل خاصی برای نصب دستی داشته همین مراحل را خودکار می‌کند، بنابراین مگر اینکه دلیل خاصی برای نصب دستی داشته
باشید، روش اسکریپتی ترجیح داده می‌شود. باشید، روش اسکریپتی ترجیح داده می‌شود.
@@ -107,7 +85,7 @@ docker run -d \
شما بک‌اند ذخیره‌سازی را در زمان نصب انتخاب می‌کنید: شما بک‌اند ذخیره‌سازی را در زمان نصب انتخاب می‌کنید:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به هیچ تنظیماتی. - **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **PostgreSQL** — برای تعداد کلاینت بالا یا پیکربندی‌های چندنودی. نصب‌کننده - **PostgreSQL** — برای تعداد کلاینت بالا یا پیکربندی‌های چندنودی. نصب‌کننده
می‌تواند آن را به‌صورت محلی نصب کند یا از یک DSN که شما ارائه می‌دهید استفاده کند. می‌تواند آن را به‌صورت محلی نصب کند یا از یک DSN که شما ارائه می‌دهید استفاده کند.
@@ -116,18 +94,7 @@ docker run -d \
## نصب خودکار / cloud-init ## نصب خودکار / cloud-init
نصب‌کننده برای خودکارسازی به‌صورت **غیرتعاملی** نیز اجرا می‌شود. خود اسکریپت نصب هیچ ورودی تعاملی نمی‌گیرد و می‌توان آن را مستقیماً برای خودکارسازی به کار برد. دایرکتوری [`deploy/cloud-init/`](https://git.881218.xyz/rogue/l-ui/src/branch/main/deploy/cloud-init) در مخزن، یک user-data آمادهٔ **cloud-init** برای نصب‌های خودکار روی هر ابری (Hetzner، AWS، DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
سرتاسری و بدون هیچ پرسشی انجام شود، مشخصات تصادفی تولید کند و آن‌ها را در
`/etc/x-ui/install-result.env` بنویسد:
```bash
XUI_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) در مخزن
یک user-data آمادهٔ **cloud-init** برای نصب‌های خودکار روی هر ابری (Hetzner، AWS،
DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
## گام‌های بعدی ## گام‌های بعدی
@@ -140,7 +107,7 @@ DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
<Card <Card
title="به‌روزرسانی و حذف نصب" title="به‌روزرسانی و حذف نصب"
href="/docs/guide/update-uninstall" href="/docs/guide/update-uninstall"
description="منوی x-ui، به‌روزرسانی‌ها و حذف." description="منوی l-ui، به‌روزرسانی‌ها و حذف."
/> />
<Card <Card
title="REALITY" title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
--- ---
title: به‌روزرسانی و حذف title: به‌روزرسانی و حذف
description: مدیریت 3x-ui با منوی x-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل. description: مدیریت L-UI با منوی l-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
icon: RefreshCw icon: RefreshCw
--- ---
پس از نصب با اسکریپت، دستور `x-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا پس از نصب با اسکریپت، دستور `l-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
کنید تا منوی تعاملی باز شود، یا یک زیردستور به آن بدهید تا یک عملیات تک‌مرحله‌ای انجام شود. کنید تا منوی تعاملی باز شود، یا یک زیردستور به آن بدهید تا یک عملیات تک‌مرحله‌ای انجام شود.
```bash ```bash
x-ui l-ui
``` ```
## منوی مدیریت `x-ui` ## منوی مدیریت `l-ui`
منو (آیتم‌های `0`–`28`) وضعیت پنل/Xray را در بالا نشان می‌دهد و سپس: منو (آیتم‌های `0`–`28`) وضعیت پنل/Xray را در بالا نشان می‌دهد و سپس:
@@ -20,9 +20,9 @@ x-ui
| 1 | Install | (دوباره) نصب از روی اسکریپت راه دور | | 1 | Install | (دوباره) نصب از روی اسکریپت راه دور |
| 2 | Update | به‌روزرسانی به آخرین نسخهٔ **پایدار** | | 2 | Update | به‌روزرسانی به آخرین نسخهٔ **پایدار** |
| 3 | Update to Dev Channel (latest commit) | به‌روزرسانی به بیلد غلتان `dev-latest` | | 3 | Update to Dev Channel (latest commit) | به‌روزرسانی به بیلد غلتان `dev-latest` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `x-ui` | | 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `l-ui` |
| 5 | Legacy Version | نصب یک نسخهٔ قدیمی مشخص (تگ را می‌پرسد) | | 5 | Legacy Version | نصب یک نسخهٔ قدیمی مشخص (تگ را می‌پرسد) |
| 6 | Uninstall | حذف 3x-ui (در ادامه ببینید) | | 6 | Uninstall | حذف L-UI (در ادامه ببینید) |
| 7 | Reset Username & Password | تنظیم مشخصات جدید؛ اختیاراً غیرفعال‌کردن 2FA | | 7 | Reset Username & Password | تنظیم مشخصات جدید؛ اختیاراً غیرفعال‌کردن 2FA |
| 8 | Reset Web Base Path | تصادفی‌کردن مسیر پایهٔ وب | | 8 | Reset Web Base Path | تصادفی‌کردن مسیر پایهٔ وب |
| 9 | Reset Settings | بازنشانی تنظیمات پنل (حساب شما حفظ می‌شود) | | 9 | Reset Settings | بازنشانی تنظیمات پنل (حساب شما حفظ می‌شود) |
@@ -51,29 +51,29 @@ x-ui
## زیردستورهای خط فرمان ## زیردستورهای خط فرمان
برای اسکریپت‌ها و اقدام‌های سریع، `x-ui` یک زیردستور را هم مستقیماً می‌پذیرد: برای اسکریپت‌ها و اقدام‌های سریع، `l-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
| دستور | عملیات | | دستور | عملیات |
| -------------------------- | --------------------------------------------------- | | -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | کنترل سرویس | | `l-ui start` / `stop` / `restart` | کنترل سرویس |
| `x-ui restart-xray` | بارگذاری مجدد فقط Xray-core | | `l-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `x-ui status` | نمایش وضعیت | | `l-ui status` | نمایش وضعیت |
| `x-ui settings` | نمایش تنظیمات فعلی | | `l-ui settings` | نمایش تنظیمات فعلی |
| `x-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت | | `l-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `x-ui log` | دنبال‌کردن لاگ دیباگ | | `l-ui log` | دنبال‌کردن لاگ دیباگ |
| `x-ui banlog` | نمایش لاگ مسدودسازی Fail2ban | | `l-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `x-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار | | `l-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `x-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` | | `l-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `x-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) | | `l-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `x-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر | | `l-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `x-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) | | `l-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `x-ui install` / `uninstall` | نصب / حذف | | `l-ui install` / `uninstall` | نصب / حذف |
## به‌روزرسانی ## به‌روزرسانی
- **پایدار:** گزینهٔ منوی **۲** یا `x-ui update`. اجرای دوبارهٔ اسکریپت نصب هم - **پایدار:** گزینهٔ منوی **۲** یا `l-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
در همان محل به‌روزرسانی می‌کند. در همان محل به‌روزرسانی می‌کند.
- **کانال dev:** گزینهٔ منوی **۳** یا `x-ui update-dev` — بیلد غلتان - **کانال dev:** گزینهٔ منوی **۳** یا `l-ui update-dev` — بیلد غلتان
`dev-latest` به‌ازای هر کامیت (نه یک نسخهٔ پایدار). `dev-latest` به‌ازای هر کامیت (نه یک نسخهٔ پایدار).
- **یک نسخهٔ قدیمی مشخص:** گزینهٔ منوی **۵** (Legacy Version). - **یک نسخهٔ قدیمی مشخص:** گزینهٔ منوی **۵** (Legacy Version).
@@ -82,18 +82,18 @@ x-ui
<Callout type="info"> <Callout type="info">
کاربران Docker به شیوهٔ دیگری به‌روزرسانی می‌کنند — به‌جای استفاده از دستورهای کاربران Docker به شیوهٔ دیگری به‌روزرسانی می‌کنند — به‌جای استفاده از دستورهای
به‌روزرسانی `x-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید به‌روزرسانی `l-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
(`docker compose pull && docker compose up -d`). (`docker compose pull && docker compose up -d`).
</Callout> </Callout>
## حذف ## حذف
گزینهٔ منوی **۶** یا `x-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس گزینهٔ منوی **۶** یا `l-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/x-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL را حذف می‌کند و `/etc/l-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
نصب‌شده به‌صورت محلی استفاده می‌کرده، پیشنهاد می‌دهد آن را هم پاک‌سازی کند (یک تأیید نصب‌شده به‌صورت محلی استفاده می‌کرده، پیشنهاد می‌دهد آن را هم پاک‌سازی کند (یک تأیید
جداگانه و برگشت‌ناپذیر). جداگانه و برگشت‌ناپذیر).
<Callout type="warn"> <Callout type="warn">
حذف، پایگاه‌داده (`/etc/x-ui/x-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است حذف، پایگاه‌داده (`/etc/l-ui/l-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
بعداً به آن نیاز داشته باشید، ابتدا [پشتیبان بگیرید](/docs/operations/backup-restore). بعداً به آن نیاز داشته باشید، ابتدا [پشتیبان بگیرید](/docs/operations/backup-restore).
</Callout> </Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
--- ---
title: مشارکت title: مشارکت
description: چگونه در توسعه 3x-ui مشارکت کنید و این مستندات را ترجمه کنید. description: چگونه در توسعه L-UI مشارکت کنید و این مستندات را ترجمه کنید.
icon: GitPullRequestArrow icon: GitPullRequestArrow
--- ---
3x-ui یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته L-UI یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
می‌شود. می‌شود.
## حمایت از توسعه‌دهنده ## حمایت از توسعه‌دهنده
3x-ui رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان L-UI رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
مفید بوده است، حمایت از ادامه توسعه را در نظر بگیرید: مفید بوده است، حمایت از ادامه توسعه را در نظر بگیرید:
- در [donate.sanaei.dev](https://donate.sanaei.dev/) **کمک مالی** کنید — این صفحه - در [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) **بپیوندید** تا اخبار را - به کانال Telegram یعنی [@XrayUI](https://t.me/XrayUI) **بپیوندید** تا اخبار را
دنبال کنید و به دیگران کمک کنید. دنبال کنید و به دیگران کمک کنید.
## مشارکت در 3x-ui ## مشارکت در L-UI
- فایل `CONTRIBUTING.md` پروژه را در - فایل `CONTRIBUTING.md` پروژه را در
[مخزن](https://github.com/MHSanaei/3x-ui) بخوانید. [مخزن](https://github.com/MHSanaei/L-UI) بخوانید.
- برای باگ‌ها و درخواست‌های امکانات جدید، با گام‌های بازتولید روشن، issue باز کنید. - برای باگ‌ها و درخواست‌های امکانات جدید، با گام‌های بازتولید روشن، issue باز کنید.
- از Conventional Commits استفاده کنید و pull requestها را متمرکز نگه دارید. - از Conventional Commits استفاده کنید و pull requestها را متمرکز نگه دارید.
+9 -9
View File
@@ -1,13 +1,13 @@
--- ---
title: سؤالات متداول title: سؤالات متداول
description: پرسش‌های پرتکرار درباره 3x-ui — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها. description: پرسش‌های پرتکرار درباره L-UI — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
icon: CircleQuestionMark icon: CircleQuestionMark
--- ---
## آیا 3x-ui رایگان و متن‌باز است؟ ## آیا L-UI رایگان و متن‌باز است؟
بله. 3x-ui تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی بله. L-UI تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/3x-ui) در دسترس است. [GitHub](https://github.com/MHSanaei/L-UI) در دسترس است.
## روی چه سیستم‌هایی اجرا می‌شود؟ ## روی چه سیستم‌هایی اجرا می‌شود؟
@@ -18,7 +18,7 @@ Fedora، Arch، Alpine و موارد دیگر) روی معماری‌های `amd
## SQLite یا PostgreSQL؟ ## SQLite یا PostgreSQL؟
SQLite گزینه پیش‌فرض است و برای بیشتر استقرارها مناسب است. PostgreSQL برای SQLite گزینه پیش‌فرض است و برای بیشتر استقرارها مناسب است. PostgreSQL برای
راه‌اندازی‌های بزرگ‌تر از طریق `XUI_DB_TYPE=postgres` و `XUI_DB_DSN` در دسترس است — به راه‌اندازی‌های بزرگ‌تر از طریق `LUI_DB_TYPE=postgres` و `LUI_DB_DSN` در دسترس است — به
[متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید. [متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
## کدام اپلیکیشن‌های کلاینت با آن کار می‌کنند؟ ## کدام اپلیکیشن‌های کلاینت با آن کار می‌کنند؟
@@ -27,9 +27,9 @@ SQLite گزینه پیش‌فرض است و برای بیشتر استقراره
لینک اشتراک‌گذاری یا کد QR یک کلاینت را وارد کنید، یا از لینک اشتراک‌گذاری یا کد QR یک کلاینت را وارد کنید، یا از
[سابسکریپشن](/docs/config/subscription) استفاده کنید. [سابسکریپشن](/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 را دریافت کنید. اسکریپت نصب را دوباره اجرا کنید (به‌صورت درجا به‌روزرسانی می‌شود)، یا ایمیج جدید Docker را دریافت کنید.
به [نصب](/docs/guide/installation) و به [نصب](/docs/guide/installation) و
[صفحه نسخه‌ها](https://github.com/MHSanaei/3x-ui/releases) مراجعه کنید. [صفحه نسخه‌ها](https://github.com/MHSanaei/L-UI/releases) مراجعه کنید.
## از کجا می‌توانم کمک بگیرم؟ ## از کجا می‌توانم کمک بگیرم؟
به کانال رسمی Telegram با نشانی [@XrayUI](https://t.me/XrayUI) برای به کانال رسمی 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) شروع کنید. [عیب‌یابی](/docs/help/troubleshooting) شروع کنید.
+8 -8
View File
@@ -1,6 +1,6 @@
--- ---
title: مهاجرت title: مهاجرت
description: مهاجرت به 3x-ui از x-ui، بین سرورها یا بین نسخه‌های 3x-ui. description: مهاجرت به L-UI از l-ui، بین سرورها یا بین نسخه‌های L-UI.
icon: ArrowRightLeft icon: ArrowRightLeft
--- ---
@@ -13,12 +13,12 @@ icon: ArrowRightLeft
<Step> <Step>
### از سرور قدیمی نسخه پشتیبان بگیرید ### از سرور قدیمی نسخه پشتیبان بگیرید
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/x-ui/x-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید. از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/l-ui/l-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
[پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) را ببینید. [پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) را ببینید.
</Step> </Step>
<Step> <Step>
### 3x-ui را روی سرور جدید نصب کنید ### L-UI را روی سرور جدید نصب کنید
از همان روش نصب و یک نسخهٔ سازگار استفاده کنید. از همان روش نصب و یک نسخهٔ سازگار استفاده کنید.
[نصب](/docs/guide/installation) را ببینید. [نصب](/docs/guide/installation) را ببینید.
@@ -32,17 +32,17 @@ icon: ArrowRightLeft
</Steps> </Steps>
## بین نسخه‌های 3x-ui ## بین نسخه‌های L-UI
در محدودهٔ یک backend یکسان، ارتقا معمولاً تنها به اجرای دوبارهٔ نصب‌کننده یا در محدودهٔ یک backend یکسان، ارتقا معمولاً تنها به اجرای دوبارهٔ نصب‌کننده یا
کشیدن یک image جدید خلاصه می‌شود — پنل خودش پایگاه‌داده‌اش را مهاجرت می‌دهد. هنگام تغییر بین نسخه‌های **اصلی**، کشیدن یک image جدید خلاصه می‌شود — پنل خودش پایگاه‌داده‌اش را مهاجرت می‌دهد. هنگام تغییر بین نسخه‌های **اصلی**،
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/3x-ui/releases) ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/L-UI/releases)
را بخوانید و یک نسخهٔ پشتیبان تهیه کنید. را بخوانید و یک نسخهٔ پشتیبان تهیه کنید.
## از x-ui ## از l-ui
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی x-ui به 3x-ui **پشتیبانی نمی‌شود** — وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی l-ui به L-UI **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. 3x-ui را از نو نصب کنید و inboundها/کلاینت‌ها را چون ساختار schema آن‌ها متفاوت است. L-UI را از نو نصب کنید و inboundها/کلاینت‌ها را
دوباره بسازید و در همین حین لینک‌های اشتراک‌گذاری را از پنل قدیمی خروجی بگیرید. دوباره بسازید و در همین حین لینک‌های اشتراک‌گذاری را از پنل قدیمی خروجی بگیرید.
<Callout type="warn"> <Callout type="warn">
@@ -1,17 +1,17 @@
--- ---
title: عیب‌یابی title: عیب‌یابی
description: رفع مشکلات رایج 3x-ui — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند. description: رفع مشکلات رایج L-UI — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
icon: Wrench 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 / در دسترس نبودن پنل پشت یک پروکسی ## خطای 502 / در دسترس نبودن پنل پشت یک پروکسی
@@ -37,6 +37,6 @@ icon: Wrench
<Callout type="info"> <Callout type="info">
همچنان به مشکل خورده‌اید؟ در میان همچنان به مشکل خورده‌اید؟ در میان
[مسائل GitHub](https://github.com/MHSanaei/3x-ui/issues) جست‌وجو کنید — احتمالاً [مسائل GitHub](https://github.com/MHSanaei/L-UI/issues) جست‌وجو کنید — احتمالاً
علامت مشکل شما قبلاً دیده شده است. علامت مشکل شما قبلاً دیده شده است.
</Callout> </Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
--- ---
title: مستندات 3x-ui title: مستندات L-UI
description: مستندات رسمی 3x-ui — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها. description: مستندات رسمی L-UI — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
icon: House icon: House
--- ---
**3x-ui** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای **L-UI** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
[Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک داشبورد مدرن برای [Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک داشبورد مدرن برای
اینباندها، پروتکل‌ها، کلاینت‌ها، حسابداری ترافیک، سابسکریپشن‌ها و موارد دیگر در اینباندها، پروتکل‌ها، کلاینت‌ها، حسابداری ترافیک، سابسکریپشن‌ها و موارد دیگر در
اختیار شما می‌گذارد — بدون نیاز به ویرایش دستی JSON مربوط به Xray از طریق خط فرمان. اختیار شما می‌گذارد — بدون نیاز به ویرایش دستی JSON مربوط به Xray از طریق خط فرمان.
@@ -17,7 +17,7 @@ icon: House
<Cards> <Cards>
<Card <Card
title="3x-ui چیست؟" title="L-UI چیست؟"
href="/docs/guide" href="/docs/guide"
description="نمای کلی: Xray-core، پنل، و اینکه برای چه کسانی مناسب است." description="نمای کلی: Xray-core، پنل، و اینکه برای چه کسانی مناسب است."
/> />
@@ -49,6 +49,6 @@ icon: House
- **عملیات** — مدیریت چندنودی، ربات Telegram، پشتیبان‌گیری و یک REST API. - **عملیات** — مدیریت چندنودی، ربات Telegram، پشتیبان‌گیری و یک REST API.
<Callout type="info"> <Callout type="info">
با Xray تازه آشنا شده‌اید؟ ابتدا [3x-ui چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و با Xray تازه آشنا شده‌اید؟ ابتدا [L-UI چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
اپلیکیشن‌های کلاینت شما چگونه در کنار هم کار می‌کنند. اپلیکیشن‌های کلاینت شما چگونه در کنار هم کار می‌کنند.
</Callout> </Callout>

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