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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Agent update tests now derive their targets from the live agent
line instead of a hardcoded A2.0.x the line has passed.
2026-10-23 21:47:10 +00:00
Muse 7244f3c9da install-agent: RELEASE_BASE -> V2.4.0 (sh + ps1)
CI / go-test (push) Waiting to run
CI / postgres-durable-first (push) Waiting to run
CI / codegen (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / race (push) Waiting to run
CI / fuzz-smoke (push) Waiting to run
CI / golangci (push) Waiting to run
CI / frontend (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
Release 3X-UI / Publish rolling dev release (push) Blocked by required conditions
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
2026-10-23 19:40:01 +00:00
Muse f9183e9dbb merge: feat/b6-traditional-removal (B6 phase 2: traditional node removal) 2026-10-23 19:39:51 +00:00
Muse f99c43dd2a tests: restore legacy ApiToken trim in normalize; update probe public contract for stack markers (rider 6); drop legacy panel-probe job test 2026-10-23 19:14:01 +00:00
Muse ef89259a49 B6 frontend: agent-only node form/list, drop mTLS modal and homepage config button (rider 5); regenerate contracts 2026-10-23 19:08:26 +00:00
Muse 4c04cdb1bc rider: anonymous probe view emits ipv4/ipv6 stack markers, never addresses 2026-10-23 19:08:25 +00:00
Muse bdfcce0e11 B6 backend: remove traditional node path, node mTLS and remote merge engine; drop restartXrayOnClientDisable (rider 1) and ApiScopeNodeSync (rider 3) 2026-10-23 19:08:24 +00:00
Muse 7ba1841df2 riders: drop sidebar donate/docs links; rename zh-CN TG bot tab label 2026-10-23 19:08:08 +00:00
562 changed files with 7689 additions and 25182 deletions
+1 -1
View File
@@ -5,6 +5,6 @@ build
db
cert
pgdata
x-ui/
l-ui/
*.db
*.dump
+46 -46
View File
@@ -2,25 +2,25 @@
# 1. Developer Bootstrap: The active (uncommented) variables directly below
# configure a safe, unprivileged local environment for 'go run .'.
# This allows 'cp .env.example .env' to work out-of-the-box without root.
# 2. Production Reference: All available XUI_* configuration options are
# 2. Production Reference: All available LUI_* configuration options are
# documented and commented out in the reference section further below.
#
# 3x-ui reads its runtime configuration from XUI_* environment variables.
# L-UI reads its runtime configuration from LUI_* environment variables.
# On a script install, the installer writes them to the service environment file
# (/etc/default/x-ui, /etc/conf.d/x-ui, or /etc/sysconfig/x-ui depending on the distro).
# (/etc/default/l-ui, /etc/conf.d/l-ui, or /etc/sysconfig/l-ui depending on the distro).
# For Docker, you set them in docker-compose.yml or via 'docker run -e'.
#
# Defaults are sensible — set only what you need to change, then restart:
# systemctl restart x-ui
# systemctl restart l-ui
# ------------------------------------------------------------------------------
# LOCAL DEVELOPMENT OVERRIDES (ACTIVE BY DEFAULT)
# ------------------------------------------------------------------------------
XUI_DEBUG=true
XUI_DB_FOLDER=x-ui
XUI_LOG_FOLDER=x-ui
XUI_BIN_FOLDER=x-ui
XUI_INIT_WEB_BASE_PATH=/
LUI_DEBUG=true
LUI_DB_FOLDER=l-ui
LUI_LOG_FOLDER=l-ui
LUI_BIN_FOLDER=l-ui
LUI_INIT_WEB_BASE_PATH=/
# ==============================================================================
# REFERENCE CONFIGURATION (ALL OPTIONS)
@@ -31,21 +31,21 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Backend database type: sqlite, or postgres (also accepts postgresql / pg)
# Default: sqlite
#XUI_DB_TYPE=sqlite
#LUI_DB_TYPE=sqlite
# Folder for the SQLite database file (x-ui.db)
# Default: /etc/x-ui (Overridden to 'x-ui' in the development block above)
#XUI_DB_FOLDER=/etc/x-ui
# Folder for the SQLite database file (l-ui.db)
# Default: /etc/l-ui (Overridden to 'l-ui' in the development block above)
#LUI_DB_FOLDER=/etc/l-ui
# PostgreSQL connection string (used when XUI_DB_TYPE=postgres)
# PostgreSQL connection string (used when LUI_DB_TYPE=postgres)
# Example: postgres://user:password@localhost:5432/dbname?sslmode=disable
#XUI_DB_DSN=
#LUI_DB_DSN=
# Max open connections in the PostgreSQL pool
#XUI_DB_MAX_OPEN_CONNS=
#LUI_DB_MAX_OPEN_CONNS=
# Max idle connections in the PostgreSQL pool
#XUI_DB_MAX_IDLE_CONNS=
#LUI_DB_MAX_IDLE_CONNS=
# PostgreSQL Docker Container Settings
# Default credentials used if you are running PostgreSQL via docker-compose
@@ -58,19 +58,19 @@ XUI_INIT_WEB_BASE_PATH=/
# Panel
# ------------------------------------------------------------------------------
# Override the panel port (1–65535). Takes precedence over the stored setting.
#XUI_PORT=
#LUI_PORT=
# Initial web base path on FIRST launch (e.g., /panel)
# Default: /
#XUI_INIT_WEB_BASE_PATH=/
#LUI_INIT_WEB_BASE_PATH=/
# Enable Fail2ban-based IP-limit enforcement
# Default: true
#XUI_ENABLE_FAIL2BAN=true
#LUI_ENABLE_FAIL2BAN=true
# Skip the HSTS header — set true when TLS is terminated by a reverse proxy
# Default: false
#XUI_SKIP_HSTS=false
#LUI_SKIP_HSTS=false
# ------------------------------------------------------------------------------
@@ -78,26 +78,26 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Logging level: debug, info, notice, warning, or error
# Default: info
#XUI_LOG_LEVEL=info
#LUI_LOG_LEVEL=info
# Debug mode. Forces log level to debug, enables Gin debug mode,
# and ensures frontend assets are served directly from disk (see CLAUDE.md).
# Default: false (Overridden to 'true' in the development block at the top)
#XUI_DEBUG=false
#LUI_DEBUG=false
# Log output directory
# Default: /var/log/x-ui (Overridden to 'x-ui' in the development block above)
#XUI_LOG_FOLDER=/var/log/x-ui
# Default: /var/log/l-ui (Overridden to 'l-ui' in the development block above)
#LUI_LOG_FOLDER=/var/log/l-ui
# Folder for the Xray-core binary and geosite/geoip files
# Default: bin (Overridden to 'x-ui' in the development block above)
#XUI_BIN_FOLDER=bin
# Default: bin (Overridden to 'l-ui' in the development block above)
#LUI_BIN_FOLDER=bin
# Legacy Path Settings
# Main installation folder (Default: /usr/local/x-ui for Linux, /app for Docker)
#XUI_MAIN_FOLDER=/usr/local/x-ui
# Main installation folder (Default: /usr/local/l-ui for Linux, /app for Docker)
#LUI_MAIN_FOLDER=/usr/local/l-ui
# Path to the systemd service file (Default: /etc/systemd/system)
#XUI_SERVICE=/etc/systemd/system
#LUI_SERVICE=/etc/systemd/system
# ------------------------------------------------------------------------------
@@ -105,27 +105,27 @@ XUI_INIT_WEB_BASE_PATH=/
# ------------------------------------------------------------------------------
# Go GC target percentage; lower = less RAM, slightly more CPU.
# Default: 75
#XUI_GOGC=
#LUI_GOGC=
# Minutes between FreeOSMemory calls; 0 disables.
# Default: 10
#XUI_MEMORY_RELEASE_INTERVAL=
#LUI_MEMORY_RELEASE_INTERVAL=
# Go soft memory limit in MiB
#XUI_MEMORY_LIMIT=
#LUI_MEMORY_LIMIT=
# Go-syntax soft limit (e.g., 400MiB); takes precedence over XUI_MEMORY_LIMIT
# Go-syntax soft limit (e.g., 400MiB); takes precedence over LUI_MEMORY_LIMIT
#GOMEMLIMIT=
# Expose pprof profiling on 127.0.0.1:6060
# Default: false
#XUI_PPROF=false
#LUI_PPROF=false
# Automatically set to 'true' inside the official Docker image.
# Consumed by internal scripts (x-ui.sh) to detect the environment.
# Consumed by internal scripts (l-ui.sh) to detect the environment.
# There is normally no need to set or toggle this variable manually.
# Default: false (automatically 'true' in Docker environments)
#XUI_IN_DOCKER=false
#LUI_IN_DOCKER=false
# ------------------------------------------------------------------------------
@@ -142,36 +142,36 @@ XUI_INIT_WEB_BASE_PATH=/
# Optional watchdog: probes a URL (optionally through a local Xray inbound)
# and restarts Xray after repeated failures. A restart drops all connected clients.
# Default: false
#XUI_TUNNEL_HEALTH_MONITOR=false
#LUI_TUNNEL_HEALTH_MONITOR=false
# Proxy to send the probe through, e.g., socks5://127.0.0.1:1080
# Empty = only checks host connectivity
#XUI_TUNNEL_HEALTH_PROXY=
#LUI_TUNNEL_HEALTH_PROXY=
# URL to probe
# Default: https://www.cloudflare.com/cdn-cgi/trace
#XUI_TUNNEL_HEALTH_URL=https://www.cloudflare.com/cdn-cgi/trace
#LUI_TUNNEL_HEALTH_URL=https://www.cloudflare.com/cdn-cgi/trace
# Interval between probes
# Default: 30s
#XUI_TUNNEL_HEALTH_INTERVAL=30s
#LUI_TUNNEL_HEALTH_INTERVAL=30s
# Per-probe timeout
# Default: 10s
#XUI_TUNNEL_HEALTH_TIMEOUT=10s
#LUI_TUNNEL_HEALTH_TIMEOUT=10s
# Consecutive failures before a restart
# Default: 3
#XUI_TUNNEL_HEALTH_FAILURES=3
#LUI_TUNNEL_HEALTH_FAILURES=3
# Minimum delay between restarts
# Default: 5m
#XUI_TUNNEL_HEALTH_COOLDOWN=5m
#LUI_TUNNEL_HEALTH_COOLDOWN=5m
# ------------------------------------------------------------------------------
# Unattended install
# ------------------------------------------------------------------------------
# Set to 1 (or run with no TTY) to install with zero prompts.
# Generated credentials will be written to /etc/x-ui/install-result.env
#XUI_NONINTERACTIVE=1
# Generated credentials will be written to /etc/l-ui/install-result.env
#LUI_NONINTERACTIVE=1
+4 -4
View File
@@ -54,7 +54,7 @@ body:
attributes:
label: Relevant logs
description: |
Panel logs (`journalctl -u x-ui -n 200`) and/or the browser DevTools
Panel logs (`journalctl -u l-ui -n 200`) and/or the browser DevTools
console output. **Redact** tokens, real domains, IPs, and client UUIDs.
render: shell
validations:
@@ -74,7 +74,7 @@ body:
- type: input
id: xui-version
attributes:
label: 3x-ui version
label: L-UI version
description: Shown at the top of the panel sidebar.
placeholder: 3.1.0
validations:
@@ -92,7 +92,7 @@ body:
- type: dropdown
id: install-method
attributes:
label: How did you install 3x-ui?
label: How did you install L-UI?
options:
- install.sh script
- Docker / Docker Compose
@@ -159,7 +159,7 @@ body:
options:
- label: I searched [existing issues](../issues?q=is%3Aissue) and this bug has not been reported.
required: true
- label: I am running the latest released version of 3x-ui (or have verified the bug still exists on it).
- label: I am running the latest released version of L-UI (or have verified the bug still exists on it).
required: true
- label: This bug report is written in English.
required: true
+3 -3
View File
@@ -1,11 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: 📖 Project home (Gitea)
url: https://git.881218.xyz/rogue/3x-ui-agent
url: https://git.881218.xyz/rogue/l-ui
about: Setup, install, configuration, and "how do I…" guides live here. Please check before opening a question.
- name: 🔍 Search existing issues
url: https://git.881218.xyz/rogue/3x-ui-agent/issues
url: https://git.881218.xyz/rogue/l-ui/issues
about: Your bug, feature, or question may already be tracked. Comment on the existing one rather than opening a duplicate.
- name: 🚀 Latest release
url: https://git.881218.xyz/rogue/3x-ui-agent/releases
url: https://git.881218.xyz/rogue/l-ui/releases
about: Reproduce on the latest version before reporting — many bugs are already fixed in the most recent release.
+1 -1
View File
@@ -1,5 +1,5 @@
name: Feature request
description: Suggest an idea or improvement for 3x-ui
description: Suggest an idea or improvement for L-UI
title: "[Feature]: "
labels: ["enhancement"]
+5 -5
View File
@@ -1,5 +1,5 @@
name: Question
description: Ask how to do something with 3x-ui
description: Ask how to do something with L-UI
title: "[Question]: "
labels: ["question"]
@@ -9,7 +9,7 @@ body:
value: |
Before opening a question, please:
- Read the [project home](https://git.881218.xyz/rogue/3x-ui-agent) —
- Read the [project home](https://git.881218.xyz/rogue/l-ui) —
most setup, install, and "how do I …" answers live there.
- Search [existing issues](../issues?q=is%3Aissue) — the question
may already have been asked.
@@ -43,7 +43,7 @@ body:
- type: input
id: xui-version
attributes:
label: 3x-ui version
label: L-UI version
description: Shown at the top of the panel sidebar.
placeholder: 3.1.0
validations:
@@ -52,7 +52,7 @@ body:
- type: dropdown
id: install-method
attributes:
label: How did you install 3x-ui?
label: How did you install L-UI?
options:
- install.sh script
- Docker / Docker Compose
@@ -85,7 +85,7 @@ body:
attributes:
label: Before submitting
options:
- label: I read the [project home](https://git.881218.xyz/rogue/3x-ui-agent) and searched [existing issues](../issues?q=is%3Aissue).
- label: I read the [project home](https://git.881218.xyz/rogue/l-ui) and searched [existing issues](../issues?q=is%3Aissue).
required: true
- label: This is a usage question, not a bug report.
required: true
+17 -17
View File
@@ -13,7 +13,7 @@ question it already answers.
## Stack
3x-ui is an open-source web control panel for managing Xray-core servers.
L-UI is an open-source web control panel for managing Xray-core servers.
- Backend: Go 1.27, module `github.com/mhsanaei/3x-ui/v3`, Gin and GORM.
- It runs Xray-core as a managed child process (`internal/xray/process.go`) and
@@ -26,8 +26,8 @@ question it already answers.
per inbound. Client, ad-tag and quota/expiry edits are hot-applied through the
fork's management API (`PUT /secrets`) so connections survive, with a process
restart as the fallback on older binaries.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux, the executable
directory on Windows) or PostgreSQL (`XUI_DB_TYPE` / `XUI_DB_DSN`). The SQLite
- Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux, the executable
directory on Windows) or PostgreSQL (`LUI_DB_TYPE` / `LUI_DB_DSN`). The SQLite
driver is CGo, so `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`, built
into `internal/web/dist/` (gitignored) and embedded with `embed.FS`.
@@ -36,7 +36,7 @@ question it already answers.
| area | path |
| --- | --- |
| entry point + `x-ui` CLI | `main.go` |
| entry point + `l-ui` CLI | `main.go` |
| env parsing | `internal/config/` |
| schema, migrations | `internal/database/`, `internal/database/model/` |
| Xray child process + config | `internal/xray/` |
@@ -48,7 +48,7 @@ question it already answers.
| master/sub-node over mTLS | `internal/web/runtime/` |
| i18n | `internal/web/locale/`, `internal/web/translation/` |
| UI source | `frontend/src/` |
| install / upgrade | `install.sh`, `x-ui.sh`, `DockerInit.sh` |
| install / upgrade | `install.sh`, `l-ui.sh`, `DockerInit.sh` |
## Hard rules a change must respect
@@ -93,7 +93,7 @@ question it already answers.
subtests and `t.Helper()` on helpers. An assertion must pin the exact value,
typed error or emitted string — `err != nil` and `len(x) > 0` are findings,
not nits. Prefer real dependencies: a throwaway DB via
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` with `t.Cleanup`, and
`database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` with `t.Cleanup`, and
`httptest` for HTTP. `internal/sub`'s `initSubDB(t)` is the template.
A test must FAIL without its fix; one that passes either way certifies
nothing and then gets cited as proof the fix works.
@@ -143,36 +143,36 @@ variable is set, and CI sets only the PostgreSQL ones above:
| gate | covers |
| --- | --- |
| `XUI_TEST_PG_DSN` | PostgreSQL-specific paths |
| `XUI_DB_TYPE` + `XUI_DB_DSN` | dialect-dependent behaviour |
| `LUI_TEST_PG_DSN` | PostgreSQL-specific paths |
| `LUI_DB_TYPE` + `LUI_DB_DSN` | dialect-dependent behaviour |
| `XRAY_E2E_BINARY` | the Xray gRPC end-to-end tests in `internal/xray/` |
| `XUI_SCALE_TEST` | scale tests in `internal/sub/`, `internal/web/job/`, `internal/web/service/` |
| `LUI_SCALE_TEST` | scale tests in `internal/sub/`, `internal/web/job/`, `internal/web/service/` |
Mutation testing (`mutation.yml`) runs nightly and never on a pull request, so a
test that cannot fail is invisible to CI. `make verify` is the local gate.
## Support facts reporters get wrong
- Linux install: `bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh)`
- Linux install: `bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)`
- Install generates a RANDOM username, password and web base path — never
admin/admin. The `x-ui` menu on the server shows or resets them.
admin/admin. The `l-ui` menu on the server shows or resets them.
- The installer service environment file is DISTRO-DEPENDENT:
`/etc/default/x-ui` (Debian/Ubuntu), `/etc/conf.d/x-ui` (Arch),
`/etc/sysconfig/x-ui` (RHEL/Fedora). Naming the wrong one means the reporter's
`/etc/default/l-ui` (Debian/Ubuntu), `/etc/conf.d/l-ui` (Arch),
`/etc/sysconfig/l-ui` (RHEL/Fedora). Naming the wrong one means the reporter's
edit is silently never read by systemd — a common cause of "I set the variable
and nothing happened".
- Windows is supported. There the database sits next to the executable, not in
`/etc` — never quote the Linux path to a Windows user.
- SQLite to PostgreSQL: `x-ui migrate-db --dsn "postgres://..."`, then set
`XUI_DB_TYPE`/`XUI_DB_DSN` in that file and `systemctl restart x-ui`. The
- SQLite to PostgreSQL: `l-ui migrate-db --dsn "postgres://..."`, then set
`LUI_DB_TYPE`/`LUI_DB_DSN` in that file and `systemctl restart l-ui`. The
source SQLite file is left in place.
- Docker image `ghcr.io/mhsanaei/3x-ui`; PostgreSQL profile
`docker compose --profile postgres up -d`. Fail2ban IP-limit enforcement needs
`NET_ADMIN` + `NET_RAW` (compose grants them; a bare `docker run` must add
`--cap-add=NET_ADMIN --cap-add=NET_RAW`).
- Never state that a `XUI_*` variable does not exist without grepping
- Never state that a `LUI_*` variable does not exist without grepping
`internal/config/` and `internal/tunnelmonitor/` first. The
`XUI_TUNNEL_HEALTH_*` family is the usual answer to "the panel restarts Xray
`LUI_TUNNEL_HEALTH_*` family is the usual answer to "the panel restarts Xray
every few minutes".
- Security per inbound is none / tls / reality. XTLS is a VLESS *flow*
(`xtls-rprx-vision`), not a security setting — never tell anyone to pick XTLS
+2 -2
View File
@@ -58,8 +58,8 @@ jobs:
--health-timeout 5s
--health-retries 5
env:
XUI_DB_TYPE: postgres
XUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
LUI_DB_TYPE: postgres
LUI_DB_DSN: "host=127.0.0.1 port=5432 user=postgres password=postgres dbname=xui_durable sslmode=disable"
steps:
- uses: actions/checkout@v7
- uses: actions/setup-go@v7
+10 -10
View File
@@ -53,7 +53,7 @@ jobs:
--allowedTools "Bash(gh label list:*),Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh issue comment ${{ github.event.issue.number }}:*),Bash(gh issue edit ${{ github.event.issue.number }} --add-label:*),Bash(gh issue edit ${{ github.event.issue.number }} --remove-label:*),Bash(gh issue edit ${{ github.event.issue.number }} --title:*),Bash(gh issue close ${{ github.event.issue.number }}:*),Bash(gh search issues:*),Bash(gh search commits:*),Bash(gh search prs:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh release list:*),Bash(gh release view:*),Bash(git log:*),Bash(git show:*),Bash(git blame:*),Bash(git ls-tree:*),Bash(git tag:*),Read,Glob,Grep,Write(//tmp/**),Edit(//tmp/**)"
--disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: |
You are the SENIOR GITHUB ISSUE ANALYST for the MHSanaei/3x-ui
You are the SENIOR GITHUB ISSUE ANALYST for the MHSanaei/L-UI
repository, an open-source web control panel for managing Xray-core
servers. You are the only automated reply an issue ever gets. Your
question is: IS THE REPORTED PROBLEM REAL, AND IF SO, WHY?
@@ -106,7 +106,7 @@ jobs:
reports, "enhancement" for feature requests, "question" for
questions - so a pre-applied type label is a template default to
verify, not the reporter's considered classification. The bug form
already REQUIRES the 3x-ui version, install method and OS, and also
already REQUIRES the L-UI version, install method and OS, and also
collects logs, the Xray version, affected areas and reverse-proxy
setup; the question form requires the version and install method. It
all arrives under "### <heading>" sections of the body. Read those
@@ -251,7 +251,7 @@ jobs:
question you could have answered by reading more code.
SECURITY EXCEPTION, which overrides everything else: if the report
describes what looks like an exploitable vulnerability in 3x-ui - an
describes what looks like an exploitable vulnerability in L-UI - an
authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation - do NOT investigate or
analyse it publicly. Post one short comment asking the reporter to
@@ -285,7 +285,7 @@ jobs:
- CLOSE AS INVALID when the body, judged exactly as written, is
empty or only whitespace, punctuation or emoji; pure gibberish;
advertising or unrelated links; a throwaway test ("test", "asdf");
or unrelated to 3x-ui and Xray. Then: post the comment, add the
or unrelated to L-UI and Xray. Then: post the comment, add the
`invalid` label, and
`gh issue close ${{ github.event.issue.number }} --reason "not planned"`.
A short, vague, badly formatted, machine-translated or low-quality
@@ -628,11 +628,11 @@ jobs:
--allowedTools "Bash(gh issue view:*),Bash(gh issue list:*),Bash(gh issue comment ${{ github.event.issue.number }}:*),Bash(gh pr view:*),Bash(gh pr diff:*),Bash(gh pr list:*),Bash(gh pr comment ${{ github.event.issue.number }}:*),Bash(gh search issues:*),Bash(gh search commits:*),Bash(gh release list:*),Bash(gh label list:*),Read,Glob,Grep,Write(//tmp/**),Edit(//tmp/**)"
--disallowedTools "Read(//**/.git/**),Edit(//**/.git/**)"
prompt: |
You are replying to an @claude mention from a maintainer of the MHSanaei/3x-ui repository - its owner, or somebody invited to it with write access, an open-source web panel for managing Xray-core servers. This run investigates and explains; it never changes anything. You have no tool that can edit a file in the checkout, no git command that can write, and a token that cannot push, so no file is edited, no branch is created, no commit is made and no pull request is opened or merged - on an issue and on a pull request alike. The one exception in this repository lives in a separate workflow job that only the repository owner can start, so do not mention it or offer it. The full repo source is checked out in the working directory; use Read, Glob and Grep to open and verify the relevant files before stating any default, path, flag, option name, or behavior. Your file-writing tool is limited to /tmp: a long reply goes to /tmp/comment.md and is posted with gh issue comment <number> --body-file /tmp/comment.md (or gh pr comment for a pull request). If that write is refused for any reason, pass the body inline with --body instead - never leave the thread unanswered.
You are replying to an @claude mention from a maintainer of the MHSanaei/L-UI repository - its owner, or somebody invited to it with write access, an open-source web panel for managing Xray-core servers. This run investigates and explains; it never changes anything. You have no tool that can edit a file in the checkout, no git command that can write, and a token that cannot push, so no file is edited, no branch is created, no commit is made and no pull request is opened or merged - on an issue and on a pull request alike. The one exception in this repository lives in a separate workflow job that only the repository owner can start, so do not mention it or offer it. The full repo source is checked out in the working directory; use Read, Glob and Grep to open and verify the relevant files before stating any default, path, flag, option name, or behavior. Your file-writing tool is limited to /tmp: a long reply goes to /tmp/comment.md and is posted with gh issue comment <number> --body-file /tmp/comment.md (or gh pr comment for a pull request). If that write is refused for any reason, pass the body inline with --body instead - never leave the thread unanswered.
Key layout:
- main.go holds the entry point and the x-ui management CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert).
- internal/config/ parses env vars (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER, XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_FOLDER, XUI_DB_TYPE, XUI_DB_DSN).
- main.go holds the entry point and the l-ui management CLI (run, migrate, migrate-db, encrypt-tokens, setting, cert).
- internal/config/ parses env vars (LUI_DEBUG, LUI_LOG_LEVEL, LUI_LOG_FOLDER, LUI_BIN_FOLDER, LUI_SKIP_HSTS, LUI_PORT, LUI_DB_FOLDER, LUI_DB_TYPE, LUI_DB_DSN).
- internal/database/ and internal/database/model/ hold the GORM schema (Inbound, Client, Setting, User) and the inbound protocol enum (vmess, vless, tunnel, http, trojan, shadowsocks, mixed, wireguard, hysteria, mtproto).
- internal/mtproto/ runs MTProto (Telegram) proxy inbounds via the bundled mtg binary.
- internal/web/controller/ has panel and REST API handlers with the OpenAPI spec served at /panel/api/openapi.json.
@@ -643,13 +643,13 @@ jobs:
- internal/sub/ is the subscription server.
- internal/eventbus/ is an in-process pub/sub event bus (outbound and node health, xray.crash, cpu.high, memory.high, login.attempt).
- internal/xray/ runs Xray-core as a managed child process and generates its config; internal/xray/geodata/ streams the geosite/geoip .dat files.
- internal/crypto/ (node-token encryption), internal/logger/, internal/util/ (link, ldap, sys, wireguard - leaf-only helpers) and internal/tunnelmonitor/ (the XUI_TUNNEL_HEALTH_* tunnel watchdog) are shared infrastructure.
- internal/crypto/ (node-token encryption), internal/logger/, internal/util/ (link, ldap, sys, wireguard - leaf-only helpers) and internal/tunnelmonitor/ (the LUI_TUNNEL_HEALTH_* tunnel watchdog) are shared infrastructure.
- frontend/ is the React 19 plus Ant Design 6 plus Vite 8 plus TypeScript source built into the embedded internal/web/dist/.
- tools/openapigen emits the frontend API types and Zod/JSON schemas; the OpenAPI document itself is assembled by frontend/scripts/build-openapi.mjs.
- docs/ is a separate Next.js docs site; docs/lib/xray/ holds a third independent implementation of link/subscription generation.
CLAUDE.md and docs/architecture.md in the checkout are the maintained maps; when they and this layout disagree, they win.
Stack and runtime facts: Backend is Go (module github.com/mhsanaei/3x-ui/v3) with Gin and GORM; storage is SQLite by default at /etc/x-ui/x-ui.db or PostgreSQL via XUI_DB_TYPE and XUI_DB_DSN; further env vars include XUI_DB_MAX_OPEN_CONNS, XUI_DB_MAX_IDLE_CONNS, XUI_INIT_WEB_BASE_PATH, XUI_ENABLE_FAIL2BAN, and the XUI_TUNNEL_HEALTH_* family in internal/tunnelmonitor/ - never say a XUI_* variable does not exist without grepping internal/config/ and internal/tunnelmonitor/ first; the installer's service env file is distro-dependent - /etc/default/x-ui (Debian/Ubuntu/Armbian), /etc/conf.d/x-ui (Arch/Alpine), /etc/sysconfig/x-ui (RHEL/Fedora and others); SQLite to PostgreSQL migration is x-ui migrate-db --dsn followed by a service restart; install uses install.sh and the x-ui menu, generating random initial credentials; Docker image is ghcr.io/mhsanaei/3x-ui and Fail2ban IP-limit enforcement needs NET_ADMIN and NET_RAW; Windows is a supported platform (the DB sits next to the executable there, not in /etc). Do not hardcode a version: for version or is-this-fixed questions, check the latest release and recent commits or closed PRs with gh. The same discipline applies to every fact in this prompt - the repo moves, so re-verify names, paths, flags, and enum values in the source before quoting them.
Stack and runtime facts: Backend is Go (module github.com/mhsanaei/3x-ui/v3) with Gin and GORM; storage is SQLite by default at /etc/l-ui/l-ui.db or PostgreSQL via LUI_DB_TYPE and LUI_DB_DSN; further env vars include LUI_DB_MAX_OPEN_CONNS, LUI_DB_MAX_IDLE_CONNS, LUI_INIT_WEB_BASE_PATH, LUI_ENABLE_FAIL2BAN, and the LUI_TUNNEL_HEALTH_* family in internal/tunnelmonitor/ - never say a LUI_* variable does not exist without grepping internal/config/ and internal/tunnelmonitor/ first; the installer's service env file is distro-dependent - /etc/default/l-ui (Debian/Ubuntu/Armbian), /etc/conf.d/l-ui (Arch/Alpine), /etc/sysconfig/l-ui (RHEL/Fedora and others); SQLite to PostgreSQL migration is l-ui migrate-db --dsn followed by a service restart; install uses install.sh and the l-ui menu, generating random initial credentials; Docker image is ghcr.io/mhsanaei/3x-ui and Fail2ban IP-limit enforcement needs NET_ADMIN and NET_RAW; Windows is a supported platform (the DB sits next to the executable there, not in /etc). Do not hardcode a version: for version or is-this-fixed questions, check the latest release and recent commits or closed PRs with gh. The same discipline applies to every fact in this prompt - the repo moves, so re-verify names, paths, flags, and enum values in the source before quoting them.
Style: lead with the answer in the first sentence; use fenced code blocks for commands and backtick formatting for paths and setting names; distinguish what you confirmed in the source (name the file) from what you infer; never promise fixes, timelines, or releases. Ground every claim in the code or the README and wiki; do not invent features, paths, flags, or commands, and do not stop at the first plausible match. Token cost is not a concern, so investigate as deeply as the question needs.
@@ -836,7 +836,7 @@ jobs:
--disallowedTools "Bash,WebFetch,WebSearch,Task,Edit(//**/.git/**),Read(//**/.git/**)"
prompt: |
The repository owner asked for the merge conflicts on pull request
#${{ github.event.issue.number }} of MHSanaei/3x-ui, an open-source
#${{ github.event.issue.number }} of MHSanaei/L-UI, an open-source
web panel for managing Xray-core servers, to be resolved. The merge
of `${{ steps.merge.outputs.base }}` into the pull request's branch
`${{ steps.merge.outputs.head }}` is already in progress in the
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
uses: docker/metadata-action@v6
with:
images: |
hsanaeii/3x-ui
hsanaeii/L-UI
ghcr.io/mhsanaei/3x-ui
tags: |
type=ref,event=branch
+29 -29
View File
@@ -13,9 +13,9 @@ on:
- "go.sum"
- "**.sh"
- "frontend/**"
- "x-ui.service.debian"
- "x-ui.service.arch"
- "x-ui.service.rhel"
- "l-ui.service.debian"
- "l-ui.service.arch"
- "l-ui.service.rhel"
- ".github/workflows/release.yml"
pull_request:
paths:
@@ -24,9 +24,9 @@ on:
- "go.sum"
- "**.sh"
- "frontend/**"
- "x-ui.service.debian"
- "x-ui.service.arch"
- "x-ui.service.rhel"
- "l-ui.service.debian"
- "l-ui.service.arch"
- "l-ui.service.rhel"
- ".github/workflows/release.yml"
jobs:
@@ -113,15 +113,15 @@ jobs:
file xui-release
ldd xui-release || echo "Static binary confirmed"
mkdir x-ui
cp xui-release x-ui/
cp x-ui.service.debian x-ui/
cp x-ui.service.arch x-ui/
cp x-ui.service.rhel x-ui/
cp x-ui.sh x-ui/
mv x-ui/xui-release x-ui/x-ui
mkdir x-ui/bin
cd x-ui/bin
mkdir l-ui
cp xui-release l-ui/
cp l-ui.service.debian l-ui/
cp l-ui.service.arch l-ui/
cp l-ui.service.rhel l-ui/
cp l-ui.sh l-ui/
mv l-ui/xui-release l-ui/l-ui
mkdir l-ui/bin
cd l-ui/bin
# Download dependencies
Xray_URL="https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -183,13 +183,13 @@ jobs:
cd ../..
- name: Package
run: tar -zcvf x-ui-linux-${{ matrix.platform }}.tar.gz x-ui
run: tar -zcvf l-ui-linux-${{ matrix.platform }}.tar.gz l-ui
- name: Upload files to Artifacts
uses: actions/upload-artifact@v7
with:
name: x-ui-linux-${{ matrix.platform }}
path: ./x-ui-linux-${{ matrix.platform }}.tar.gz
name: l-ui-linux-${{ matrix.platform }}
path: ./l-ui-linux-${{ matrix.platform }}.tar.gz
- name: Upload files to GH release
uses: svenstaro/upload-release-action@v2
@@ -197,8 +197,8 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: x-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: x-ui-linux-${{ matrix.platform }}.tar.gz
file: l-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: l-ui-linux-${{ matrix.platform }}.tar.gz
overwrite: true
prerelease: true
@@ -277,10 +277,10 @@ jobs:
shell: pwsh
run: |
$retry = @{ MaximumRetryCount = 5; RetryIntervalSec = 10 }
mkdir x-ui
Copy-Item xui-release.exe x-ui\x-ui.exe
mkdir x-ui\bin
cd x-ui\bin
mkdir l-ui
Copy-Item xui-release.exe l-ui\l-ui.exe
mkdir l-ui\bin
cd l-ui\bin
# Download Xray for Windows
$Xray_URL = "https://github.com/XTLS/Xray-core/releases/download/v26.7.28/"
@@ -315,13 +315,13 @@ jobs:
- name: Package to Zip
shell: pwsh
run: |
Compress-Archive -Path .\x-ui -DestinationPath "x-ui-windows-amd64.zip"
Compress-Archive -Path .\l-ui -DestinationPath "l-ui-windows-amd64.zip"
- name: Upload files to Artifacts
uses: actions/upload-artifact@v7
with:
name: x-ui-windows-amd64
path: ./x-ui-windows-amd64.zip
name: l-ui-windows-amd64
path: ./l-ui-windows-amd64.zip
- name: Upload files to GH release
uses: svenstaro/upload-release-action@v2
@@ -329,8 +329,8 @@ jobs:
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref_name }}
file: x-ui-windows-amd64.zip
asset_name: x-ui-windows-amd64.zip
file: l-ui-windows-amd64.zip
asset_name: l-ui-windows-amd64.zip
overwrite: true
prerelease: true
+2 -2
View File
@@ -65,5 +65,5 @@ jobs:
- uses: actions/checkout@v7
- name: Pinned release install smoke test
env:
XUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }}
run: bash deploy/test/smoke-noninteractive.sh "$XUI_SMOKE_VERSION"
LUI_SMOKE_VERSION: ${{ github.event.workflow_run.head_branch }}
run: bash deploy/test/smoke-noninteractive.sh "$LUI_SMOKE_VERSION"
+4 -4
View File
@@ -17,7 +17,7 @@ tmp/
# Ignore build and distribution directories
backup/
bin/
x-ui/
l-ui/
dist/
# Exception: the vendored embedded fallback theme ships its dist/ as
# source (go:embed) — it is not a build output.
@@ -34,9 +34,9 @@ Thumbs.db
# Ignore Go build files
*.exe
x-ui.db
x-ui.db-shm
x-ui.db-wal
l-ui.db
l-ui.db-shm
l-ui.db-wal
system_metrics.gob
*.dump
+16 -16
View File
@@ -3,41 +3,41 @@
"version": "0.2.0",
"configurations": [
{
"name": "Run 3x-ui (Debug)",
"name": "Run L-UI (Debug)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui"
"LUI_DEBUG": "true",
"LUI_DB_FOLDER": "l-ui",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui"
},
"console": "integratedTerminal"
},
{
"name": "Run 3x-ui (Postgres)",
"name": "Run L-UI (Postgres)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable"
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable"
},
"windows": {
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
}
},
+3 -3
View File
@@ -8,14 +8,14 @@
"args": [
"build",
"-o",
"bin/3x-ui",
"bin/L-UI",
"./main.go"
],
"windows": {
"args": [
"build",
"-o",
"bin/3x-ui.exe",
"bin/L-UI.exe",
"./main.go"
]
},
@@ -41,7 +41,7 @@
"options": {
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true"
"LUI_DEBUG": "true"
}
},
"problemMatcher": [
+9 -9
View File
@@ -24,16 +24,16 @@ file locations when it can answer in one hop.
falls back to a process restart on older binaries. A client's panel-side
traffic reset also calls `POST /secrets/{name}/reset-quota` so a renewed client
is not re-blocked by the sidecar's quota counter.
- Storage: SQLite by default (`/etc/x-ui/x-ui.db` on Linux; the executable dir on
Windows), PostgreSQL optional (`XUI_DB_TYPE` / `XUI_DB_DSN`). The CGo SQLite
- Storage: SQLite by default (`/etc/l-ui/l-ui.db` on Linux; the executable dir on
Windows), PostgreSQL optional (`LUI_DB_TYPE` / `LUI_DB_DSN`). The CGo SQLite
driver (`mattn/go-sqlite3`) needs a C compiler — `CGO_ENABLED=0` builds fail.
- Frontend: React 19 + Ant Design 6 + Vite 8 + TypeScript in `frontend/`,
built into `internal/web/dist/` (gitignored) and embedded via `embed.FS`.
## Repo map
- `main.go` — entry point + `x-ui` CLI (run, migrate, migrate-db, setting, cert).
- `internal/config/` — env parsing (XUI_DEBUG, XUI_LOG_LEVEL, XUI_LOG_FOLDER,
XUI_BIN_FOLDER, XUI_SKIP_HSTS, XUI_PORT, XUI_DB_*).
- `main.go` — entry point + `l-ui` CLI (run, migrate, migrate-db, setting, cert).
- `internal/config/` — env parsing (LUI_DEBUG, LUI_LOG_LEVEL, LUI_LOG_FOLDER,
LUI_BIN_FOLDER, LUI_SKIP_HSTS, LUI_PORT, LUI_DB_*).
- `internal/database/` + `internal/database/model/` — GORM schema (~24 models;
Inbound, Client, Setting, User are the core), inbound Protocol enum,
AutoMigrate + hand-written migrations in `db.go`.
@@ -116,7 +116,7 @@ file locations when it can answer in one hop.
- Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests,
`t.Helper()` on helpers. Assert the exact value / typed error / emitted
string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` +
`database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` +
`t.Cleanup(func() { _ = database.CloseDB() })`; `httptest` for HTTP.
`internal/sub`'s `initSubDB(t)` is the template.
- A test must fail without its fix. Write it, revert the fix, watch it go red,
@@ -126,8 +126,8 @@ file locations when it can answer in one hop.
pure map lookup, or inputs the function can never receive. One real test that
drives the bug through the actual code path beats five that restate the code.
- Code must pass `golangci-lint run` (gofumpt + goimports formatting): `make lint`.
- Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `XUI_TEST_PG_DSN`,
`XUI_DB_TYPE`+`XUI_DB_DSN`, `XRAY_E2E_BINARY` or `XUI_SCALE_TEST` is set — a
- Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `LUI_TEST_PG_DSN`,
`LUI_DB_TYPE`+`LUI_DB_DSN`, `XRAY_E2E_BINARY` or `LUI_SCALE_TEST` is set — a
green `go test ./...` does not mean those paths ran.
## Frontend conventions (summary; full version in frontend/CLAUDE.md)
@@ -140,7 +140,7 @@ file locations when it can answer in one hop.
a headless-Chromium Storybook project, so run
`npx playwright install --with-deps chromium` once or `make verify` fails.
- Editing `frontend/src` does NOT change what users see until the Vite build is
regenerated into `internal/web/dist/`. In `XUI_DEBUG=true`, HTML is served from
regenerated into `internal/web/dist/`. In `LUI_DEBUG=true`, HTML is served from
the frozen embedded FS but JS/CSS off disk — after `npm run build` you MUST
restart `go run .` or you get a blank page with 404s.
- After touching share-link logic (`src/lib/xray/`), run `npm run test` (golden
+40 -40
View File
@@ -1,6 +1,6 @@
# Contributing
Thanks for taking the time to contribute to 3x-ui. This guide gets a development panel running locally and explains the conventions the project follows so changes land cleanly.
Thanks for taking the time to contribute to L-UI. This guide gets a development panel running locally and explains the conventions the project follows so changes land cleanly.
## Prerequisites
@@ -50,12 +50,12 @@ Cross-building the Linux SQLite target from Windows (or vice versa) requires a s
## First-time setup
```bash
git clone https://git.881218.xyz/rogue/3x-ui-agent.git
cd 3x-ui-agent
git clone https://git.881218.xyz/rogue/l-ui.git
cd L-UI
cp .env.example .env
mkdir x-ui
mkdir l-ui
go mod download
@@ -65,18 +65,18 @@ npm run build
cd ..
```
`.env.example` ships with defaults that keep the database, logs, and xray binary inside the local `x-ui/` folder so nothing escapes the project directory:
`.env.example` ships with defaults that keep the database, logs, and xray binary inside the local `l-ui/` folder so nothing escapes the project directory:
```
XUI_DEBUG=true
XUI_DB_FOLDER=x-ui
XUI_LOG_FOLDER=x-ui
XUI_BIN_FOLDER=x-ui
XUI_INIT_WEB_BASE_PATH=/
# XUI_PORT=8080
LUI_DEBUG=true
LUI_DB_FOLDER=l-ui
LUI_LOG_FOLDER=l-ui
LUI_BIN_FOLDER=l-ui
LUI_INIT_WEB_BASE_PATH=/
# LUI_PORT=8080
```
Drop the xray binary (`xray-windows-amd64.exe` on Windows, `xray-linux-amd64` on Linux, etc.) plus the matching `geoip.dat` and `geosite.dat` files into `x-ui/`. The easiest source is a [released Xray-core build](https://github.com/XTLS/Xray-core/releases). On Windows, `wintun.dll` is also required for testing TUN inbounds.
Drop the xray binary (`xray-windows-amd64.exe` on Windows, `xray-linux-amd64` on Linux, etc.) plus the matching `geoip.dat` and `geosite.dat` files into `l-ui/`. The easiest source is a [released Xray-core build](https://github.com/XTLS/Xray-core/releases). On Windows, `wintun.dll` is also required for testing TUN inbounds.
## Running
@@ -88,7 +88,7 @@ Open [http://localhost:2053](http://localhost:2053) and log in with `admin` / `a
### Inside VS Code
The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run 3x-ui (Debug)** for the default SQLite setup, and **Run 3x-ui (Postgres)** which points `XUI_DB_TYPE`/`XUI_DB_DSN` at a local PostgreSQL. The Postgres profile also prepends the PostgreSQL `bin` to `PATH` so the panel can find `pg_dump`/`pg_restore` (the `postgresql-client` tools used for DB backup/restore) — adjust the DSN and that path to your machine:
The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run L-UI (Debug)** for the default SQLite setup, and **Run L-UI (Postgres)** which points `LUI_DB_TYPE`/`LUI_DB_DSN` at a local PostgreSQL. The Postgres profile also prepends the PostgreSQL `bin` to `PATH` so the panel can find `pg_dump`/`pg_restore` (the `postgresql-client` tools used for DB backup/restore) — adjust the DSN and that path to your machine:
```jsonc
{
@@ -96,33 +96,33 @@ The repo checks in two VS Code launch profiles in `.vscode/launch.json`: **Run 3
"version": "0.2.0",
"configurations": [
{
"name": "Run 3x-ui (Debug)",
"name": "Run L-UI (Debug)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_DB_FOLDER": "x-ui",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui"
"LUI_DEBUG": "true",
"LUI_DB_FOLDER": "l-ui",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui"
},
"console": "integratedTerminal"
},
{
"name": "Run 3x-ui (Postgres)",
"name": "Run L-UI (Postgres)",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"env": {
"XUI_DEBUG": "true",
"XUI_LOG_FOLDER": "x-ui",
"XUI_BIN_FOLDER": "x-ui",
"XUI_DB_TYPE": "postgres",
"XUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"LUI_DEBUG": "true",
"LUI_LOG_FOLDER": "l-ui",
"LUI_BIN_FOLDER": "l-ui",
"LUI_DB_TYPE": "postgres",
"LUI_DB_DSN": "postgres://xui:xuipass@127.0.0.1:5432/xui?sslmode=disable",
"PATH": "C:\\Program Files\\PostgreSQL\\18\\bin;${env:PATH}"
},
"console": "integratedTerminal"
@@ -167,7 +167,7 @@ Locale strings live in `internal/web/translation/<locale>.json`, **not** under `
The Vite dev proxy serves the admin SPA for any `/panel/*` URL — `bypassMigratedRoute` in `vite.config.js` rewrites those requests to `index.html` and lets React Router take over — while forwarding `/panel/api/*`, `/panel/api/setting/*`, `/panel/api/xray/*`, and the WebSocket to the Go panel. Because routing is now client-side, new panel routes need no proxy or allowlist changes.
> **`XUI_DEBUG=true` gotcha** — in debug mode the panel serves HTML from the embedded FS (frozen at the last `go build` / `go run`) but JS/CSS off disk. Re-running `npm run build` without restarting Go leaves the embedded HTML pointing at the *old* hashed asset names, producing a blank page with 404s in the console. Always restart `go run .` after a frontend rebuild.
> **`LUI_DEBUG=true` gotcha** — in debug mode the panel serves HTML from the embedded FS (frozen at the last `go build` / `go run`) but JS/CSS off disk. Re-running `npm run build` without restarting Go leaves the embedded HTML pointing at the *old* hashed asset names, producing a blank page with 404s in the console. Always restart `go run .` after a frontend rebuild.
### Adding a new page
@@ -237,7 +237,7 @@ For deeper notes on the frontend toolchain see [`frontend/README.md`](frontend/R
| `internal/xray/` | Xray-core process lifecycle and gRPC API client |
| `internal/sub/` | Subscription endpoints (raw, JSON, Clash) |
| `internal/config/` | Environment-variable helpers, paths, defaults |
| `x-ui/` | **Runtime data** — db, logs, xray binary, geo files (gitignored) |
| `l-ui/` | **Runtime data** — db, logs, xray binary, geo files (gitignored) |
## Testing
@@ -247,7 +247,7 @@ Tests live next to the code (`foo.go` ↔ `foo_test.go`); frontend specs and gol
- **Stdlib `testing` only** — no testify. Table-driven with `t.Run` subtests and `t.Helper()` on helpers.
- **Assert the contract, not internals.** Pin the exact value / typed error / emitted string — not `err != nil` or `len > 0`. A test that still passes when the behavior is broken is worse than no test.
- **Real dependencies over mocks.** Get a throwaway DB with `database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` + `t.Cleanup(func() { _ = database.CloseDB() })` (Windows-safe), and use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
- **Real dependencies over mocks.** Get a throwaway DB with `database.InitDB(filepath.Join(t.TempDir(), "l-ui.db"))` + `t.Cleanup(func() { _ = database.CloseDB() })` (Windows-safe), and use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
### Running
@@ -297,24 +297,24 @@ CI runs this for you nightly (and on demand) via `.github/workflows/mutation.yml
| Variable | Default | Purpose |
|----------|---------|---------|
| `XUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk |
| `XUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` |
| `XUI_DB_FOLDER` | platform default | Where `x-ui.db` lives |
| `XUI_LOG_FOLDER` | platform default | Where `3xui.log` lives |
| `XUI_BIN_FOLDER` | `bin` | Where the xray binary, geo files, and xray `config.json` live |
| `XUI_INIT_WEB_BASE_PATH` | `/` | The initial URI path for the web panel |
| `XUI_PORT` | persisted `webPort` | Runtime-only web panel listener port override (`1` through `65535`) |
| `XUI_DB_TYPE` | `sqlite` | Set to `postgres` to use PostgreSQL via `XUI_DB_DSN` |
| `XUI_DB_DSN` | — | PostgreSQL DSN when `XUI_DB_TYPE=postgres` |
| `LUI_DEBUG` | `false` | Verbose logs + Gin debug mode + serve `/assets` from disk |
| `LUI_LOG_LEVEL` | `info` | `debug` / `info` / `notice` / `warning` / `error` |
| `LUI_DB_FOLDER` | platform default | Where `l-ui.db` lives |
| `LUI_LOG_FOLDER` | platform default | Where `3xui.log` lives |
| `LUI_BIN_FOLDER` | `bin` | Where the xray binary, geo files, and xray `config.json` live |
| `LUI_INIT_WEB_BASE_PATH` | `/` | The initial URI path for the web panel |
| `LUI_PORT` | persisted `webPort` | Runtime-only web panel listener port override (`1` through `65535`) |
| `LUI_DB_TYPE` | `sqlite` | Set to `postgres` to use PostgreSQL via `LUI_DB_DSN` |
| `LUI_DB_DSN` | — | PostgreSQL DSN when `LUI_DB_TYPE=postgres` |
A valid `XUI_PORT` takes precedence over the database-backed `webPort` for the
A valid `LUI_PORT` takes precedence over the database-backed `webPort` for the
current process without changing the stored setting. Unset, empty, whitespace-only,
malformed, or out-of-range values fall back to `webPort`; invalid configured values
also produce a warning. With Docker bridge networking, the published container port
must match the override, for example `XUI_PORT: "8080"` with `ports: ["8080:8080"]`.
must match the override, for example `LUI_PORT: "8080"` with `ports: ["8080:8080"]`.
## Issues
- Bug reports and feature requests: [Issues](https://git.881218.xyz/rogue/3x-ui-agent/issues)
- Bug reports and feature requests: [Issues](https://git.881218.xyz/rogue/l-ui/issues)
Before filing a bug, include the OS, Go version, panel version (`/panel/api/server/status` or the dashboard footer), and the relevant excerpt from `x-ui/3xui.log`.
Before filing a bug, include the OS, Go version, panel version (`/panel/api/server/status` or the dashboard footer), and the relevant excerpt from `l-ui/3xui.log`.
+5 -5
View File
@@ -1,8 +1,8 @@
#!/bin/sh
# Start fail2ban with the 3x-ipl jail
if [ "$XUI_ENABLE_FAIL2BAN" = "true" ]; then
LOG_FOLDER="${XUI_LOG_FOLDER:-/var/log/x-ui}"
if [ "$LUI_ENABLE_FAIL2BAN" = "true" ]; then
LOG_FOLDER="${LUI_LOG_FOLDER:-/var/log/l-ui}"
mkdir -p "$LOG_FOLDER"
touch "$LOG_FOLDER/3xipl.log" "$LOG_FOLDER/3xipl-banned.log"
@@ -33,7 +33,7 @@ EOF
# added later without regenerating these files.
SSH_PORTS=$(grep -oE '^[[:space:]]*Port[[:space:]]+[0-9]+' /etc/ssh/sshd_config 2>/dev/null | grep -oE '[0-9]+' | paste -sd, -)
[ -z "$SSH_PORTS" ] && SSH_PORTS="22"
PANEL_PORT=$(/app/x-ui setting -show true 2>/dev/null | grep -Eo 'port: .+' | awk '{print $2}')
PANEL_PORT=$(/app/l-ui setting -show true 2>/dev/null | grep -Eo 'port: .+' | awk '{print $2}')
EXEMPT_PORTS="$SSH_PORTS"
[ -n "$PANEL_PORT" ] && EXEMPT_PORTS="$EXEMPT_PORTS,$PANEL_PORT"
@@ -78,5 +78,5 @@ if [ -f /root/.acme.sh/acme.sh ]; then
crond
fi
# Run x-ui
exec /app/x-ui
# Run l-ui
exec /app/l-ui
+12 -12
View File
@@ -27,11 +27,11 @@ COPY --from=frontend /src/internal/web/dist ./internal/web/dist
ENV CGO_ENABLED=1
ENV CGO_CFLAGS="-D_LARGEFILE64_SOURCE"
RUN go build -ldflags "-w -s" -o build/x-ui main.go
RUN go build -ldflags "-w -s" -o build/l-ui main.go
RUN ./DockerInit.sh "$TARGETARCH"
# ========================================================
# Stage: Final Image of 3x-ui
# Stage: Final Image of L-UI
# ========================================================
FROM alpine
ENV TZ=Asia/Tehran
@@ -47,7 +47,7 @@ RUN apk add --no-cache --update \
COPY --from=builder /app/build/ /app/
COPY --from=builder /app/DockerEntrypoint.sh /app/
COPY --from=builder /app/x-ui.sh /usr/bin/x-ui
COPY --from=builder /app/l-ui.sh /usr/bin/l-ui
COPY --from=builder /app/internal/web/translation /app/internal/web/translation
@@ -60,15 +60,15 @@ RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \
RUN chmod +x \
/app/DockerEntrypoint.sh \
/app/x-ui \
/usr/bin/x-ui
/app/l-ui \
/usr/bin/l-ui
ENV XUI_IN_DOCKER="true"
ENV XUI_MAIN_FOLDER="/app"
ENV XUI_ENABLE_FAIL2BAN="true"
ENV XUI_DB_TYPE=""
ENV XUI_DB_DSN=""
ENV LUI_IN_DOCKER="true"
ENV LUI_MAIN_FOLDER="/app"
ENV LUI_ENABLE_FAIL2BAN="true"
ENV LUI_DB_TYPE=""
ENV LUI_DB_DSN=""
EXPOSE 2053
VOLUME [ "/etc/x-ui" ]
CMD [ "./x-ui" ]
VOLUME [ "/etc/l-ui" ]
CMD [ "./l-ui" ]
ENTRYPOINT [ "/app/DockerEntrypoint.sh" ]
+2 -2
View File
@@ -1,7 +1,7 @@
# 3x-ui 路由器主控精简版 — 定版清单
# L-UI 路由器主控精简版 — 定版清单
> 2026-10-20 与用户逐项讨论中。本文档定版前不开工。
> 背景:AX6600 路由器 = **主控**(3x-ui 3.7.0,纯控制面,本机 xray 已 chmod -x 禁用,RSS ~130MB);
> 背景:AX6600 路由器 = **主控**(L-UI 3.7.0,纯控制面,本机 xray 已 chmod -x 禁用,RSS ~130MB);
> Alpine 主控 = 备用,趋于退役。精简目标:二开构建压内存,验收线 RSS ≤ 90MB。
## 保留(已定)
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -64,7 +64,7 @@
## البدء السريع
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
لتثبيت إصدار محدد، أضِف وسمه (مثل `v3.4.0`):
@@ -79,16 +79,16 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
أثناء التثبيت، يتم إنشاء اسم مستخدم وكلمة مرور ومسار وصول عشوائية. بعد التثبيت، شغّل `x-ui` لفتح قائمة الإدارة، حيث يمكنك بدء/إيقاف الخدمة، وعرض أو إعادة تعيين بيانات تسجيل الدخول، وإدارة شهادات SSL، والمزيد.
أثناء التثبيت، يتم إنشاء اسم مستخدم وكلمة مرور ومسار وصول عشوائية. بعد التثبيت، شغّل `l-ui` لفتح قائمة الإدارة، حيث يمكنك بدء/إيقاف الخدمة، وعرض أو إعادة تعيين بيانات تسجيل الدخول، وإدارة شهادات SSL، والمزيد.
للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://git.881218.xyz/rogue/3x-ui-agent).
للحصول على الوثائق الكاملة، يرجى زيارة [ويكي المشروع](https://git.881218.xyz/rogue/l-ui).
### التثبيت غير التفاعلي
يعمل المثبِّت أيضًا **بشكل غير تفاعلي** لـ cloud-init.
عيّن `XUI_NONINTERACTIVE=1` (أو مرّره عبر أنبوب دون TTY) وسيتولى التثبيت من البداية إلى النهاية
عيّن `LUI_NONINTERACTIVE=1` (أو مرّره عبر أنبوب دون TTY) وسيتولى التثبيت من البداية إلى النهاية
دون أي مطالبات، مُنشئًا بيانات اعتماد عشوائية وكاتبًا إياها في
`/etc/x-ui/install-result.env`. راجع [`deploy/`](deploy/) لـ:
`/etc/l-ui/install-result.env`. راجع [`deploy/`](deploy/) لـ:
- [بيانات مستخدم cloud-init](deploy/cloud-init/) — تثبيت غير تفاعلي على أي سحابة (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [ملاحظات Hetzner Cloud](deploy/marketplace/hetzner/) — نشر يعتمد على cloud-init على Hetzner
@@ -103,29 +103,29 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
يدعم 3X-UI خلفيتين (backends) يتم اختيارهما أثناء التثبيت:
- **SQLite** (افتراضي) — ملف واحد في `/etc/x-ui/x-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة.
- **SQLite** (افتراضي) — ملف واحد في `/etc/l-ui/l-ui.db`. بدون إعداد، مثالي لعمليات النشر الصغيرة والمتوسطة.
- **PostgreSQL** — موصى به لأعداد العملاء الكبيرة أو الإعدادات متعددة العقد. يمكن للمثبِّت تثبيت PostgreSQL محليًا لك، أو قبول DSN لخادم موجود.
في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/x-ui`):
في وقت التشغيل، يتم اختيار الخلفية عبر متغيرات البيئة (يكتبها المثبِّت لك في `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### ترحيل تثبيت SQLite موجود إلى PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ثم عيّن XUI_DB_TYPE و XUI_DB_DSN في /etc/default/x-ui وأعد التشغيل:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ثم عيّن LUI_DB_TYPE و LUI_DB_DSN في /etc/default/l-ui وأعد التشغيل:
systemctl restart l-ui
```
يبقى ملف SQLite الأصلي دون تغيير؛ احذفه يدويًا بعد التحقق من الخلفية الجديدة.
### Docker
يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `XUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل:
يستمر الأمر الافتراضي `docker compose up -d` في استخدام SQLite. للتشغيل مع خدمة PostgreSQL المرفقة، أزِل التعليق عن سطري متغيرات البيئة `LUI_DB_*` في `docker-compose.yml` وشغّل باستخدام البروفايل:
```bash
docker compose --profile postgres up -d
@@ -134,29 +134,29 @@ docker compose --profile postgres up -d
تتضمن الصورة Fail2ban (مُفعَّل افتراضيًا) لفرض **حدود IP** لكل عميل. يحظر Fail2ban المخالفين باستخدام `iptables`، الذي يتطلب صلاحية `NET_ADMIN`. يمنح `docker-compose.yml` هذه الصلاحية مسبقًا عبر `cap_add`؛ إذا شغّلت الحاوية باستخدام `docker run` بدلاً من ذلك، فأضِف الصلاحيات بنفسك، وإلا فسيتم تسجيل عمليات الحظر دون تطبيقها أبدًا:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## متغيرات البيئة
| المتغير | الوصف | الافتراضي |
| --- | --- | --- |
| `XUI_DB_TYPE` | خلفية قاعدة البيانات: `sqlite` أو `postgres` | `sqlite` |
| `XUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` |
| `XUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` |
| `XUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | تفعيل وضع التصحيح | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — |
| `XUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | الحد الأدنى للتأخير بين عمليات إعادة التشغيل المتتالية | `5m` |
| `LUI_DB_TYPE` | خلفية قاعدة البيانات: `sqlite` أو `postgres` | `sqlite` |
| `LUI_DB_DSN` | سلسلة اتصال PostgreSQL (عندما `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | مجلد ملف قاعدة بيانات SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | الحد الأقصى للاتصالات المفتوحة (تجمّع PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | الحد الأقصى للاتصالات الخاملة (تجمّع PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | مسار URI الأولي للوحة الويب | `/` |
| `LUI_ENABLE_FAIL2BAN` | تفعيل فرض حدود IP المعتمد على Fail2ban | `true` |
| `LUI_LOG_LEVEL` | مستوى السجل (`debug`، `info`، `warning`، `error`) | `info` |
| `LUI_DEBUG` | تفعيل وضع التصحيح | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | تفعيل مراقب صحة النفق (يفحص عنوان URL ويعيد تشغيل xray بعد فشل متكرر؛ إعادة التشغيل تقطع جميع العملاء) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | الوكيل الذي يُرسَل عبره الفحص؛ وجّهه إلى اتصال xray وارد محلي ليختبر الفحص النفق (مثل `socks5://127.0.0.1:1080`). القيمة الفارغة تعني أن الفحص يتحقق فقط من اتصال المضيف | — |
| `LUI_TUNNEL_HEALTH_URL` | عنوان URL الذي يُفحَص لمعرفة صحة النفق | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | الفترة بين عمليات الفحص | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلة كل عملية فحص | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | عدد حالات الفشل المتتالية قبل تشغيل إعادة التشغيل | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | الحد الأدنى للتأخير بين عمليات إعادة التشغيل المتتالية | `5m` |
## اللغات المدعومة
@@ -179,9 +179,9 @@ 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._
## دعم المشروع
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -64,7 +64,7 @@ Construido como un fork mejorado del proyecto X-UI original, 3X-UI añade un sop
## Inicio Rápido
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.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`):
@@ -79,16 +79,16 @@ Para instalar la versión **dev** continua (la última prelanzamiento por commit
# 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://git.881218.xyz/rogue/3x-ui-agent).
Para la documentación completa, visita la [Wiki del proyecto](https://git.881218.xyz/rogue/l-ui).
### Instalación desatendida
El instalador también se ejecuta de forma **no interactiva** para cloud-init.
Define `XUI_NONINTERACTIVE=1` (o canalízalo sin TTY) y realizará la instalación de principio a fin sin
Define `LUI_NONINTERACTIVE=1` (o canalízalo sin TTY) y realizará la instalación de principio a fin sin
ninguna pregunta, generando credenciales aleatorias y escribiéndolas en
`/etc/x-ui/install-result.env`. Consulta [`deploy/`](deploy/) para:
`/etc/l-ui/install-result.env`. Consulta [`deploy/`](deploy/) para:
- [User-data de cloud-init](deploy/cloud-init/) — instalación desatendida en cualquier nube (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Notas de Hetzner Cloud](deploy/marketplace/hetzner/) — despliegue basado en cloud-init en Hetzner
@@ -103,29 +103,29 @@ ninguna pregunta, generando credenciales aleatorias y escribiéndolas en
3X-UI admite dos backends, que se eligen durante la instalación:
- **SQLite** (predeterminado) — un único archivo en `/etc/x-ui/x-ui.db`. Sin configuración, ideal para despliegues pequeños y medianos.
- **SQLite** (predeterminado) — un único archivo en `/etc/l-ui/l-ui.db`. Sin configuración, ideal para despliegues pequeños y medianos.
- **PostgreSQL** — recomendado para un gran número de clientes o configuraciones multinodo. El instalador puede instalar PostgreSQL localmente por ti, o aceptar un DSN a un servidor existente.
En tiempo de ejecución, el backend se selecciona mediante variables de entorno (el instalador las escribe por ti en `/etc/default/x-ui`):
En tiempo de ejecución, el backend se selecciona mediante variables de entorno (el instalador las escribe por ti en `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Migrar una instalación de SQLite existente a PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# luego define XUI_DB_TYPE y XUI_DB_DSN en /etc/default/x-ui y reinicia:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# luego define LUI_DB_TYPE y LUI_DB_DSN en /etc/default/l-ui y reinicia:
systemctl restart l-ui
```
El archivo SQLite de origen permanece intacto; elimínalo manualmente una vez que hayas verificado el nuevo backend.
### Docker
El comando predeterminado `docker compose up -d` sigue usando SQLite. Para ejecutarlo con el servicio PostgreSQL incluido, descomenta las dos líneas de variables de entorno `XUI_DB_*` en `docker-compose.yml` e inícialo con el perfil:
El comando predeterminado `docker compose up -d` sigue usando SQLite. Para ejecutarlo con el servicio PostgreSQL incluido, descomenta las dos líneas de variables de entorno `LUI_DB_*` en `docker-compose.yml` e inícialo con el perfil:
```bash
docker compose --profile postgres up -d
@@ -134,29 +134,29 @@ docker compose --profile postgres up -d
La imagen incluye Fail2ban (habilitado de forma predeterminada) para aplicar **límites de IP** por cliente. Fail2ban banea a los infractores con `iptables`, lo que requiere la capacidad `NET_ADMIN`. `docker-compose.yml` ya la concede mediante `cap_add`; si en su lugar inicias el contenedor con `docker run`, añade tú mismo las capacidades, de lo contrario los baneos se registran pero nunca se aplican:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Variables de Entorno
| Variable | Descripción | Predeterminado |
| --- | --- | --- |
| `XUI_DB_TYPE` | Backend de base de datos: `sqlite` o `postgres` | `sqlite` |
| `XUI_DB_DSN` | Cadena de conexión de PostgreSQL (cuando `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Máximo de conexiones abiertas (pool de PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Máximo de conexiones inactivas (pool de PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | La ruta URI inicial para el panel web | `/` |
| `XUI_ENABLE_FAIL2BAN` | Habilitar la aplicación de límites de IP basada en Fail2ban | `true` |
| `XUI_LOG_LEVEL` | Nivel de registro (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Habilitar el modo de depuración | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Habilitar el monitor de salud del túnel (sondea una URL y reinicia xray tras fallos repetidos; un reinicio desconecta a todos los clientes) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Proxy a través del cual se envía el sondeo; apúntalo a una entrada local de xray para que el sondeo pruebe el túnel (p. ej. `socks5://127.0.0.1:1080`). Vacío significa que el sondeo solo comprueba la conectividad del host | — |
| `XUI_TUNNEL_HEALTH_URL` | URL sondeada para verificar la salud del túnel | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Intervalo entre sondeos | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Fallos consecutivos antes de que se active un reinicio | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Retardo mínimo entre reinicios consecutivos | `5m` |
| `LUI_DB_TYPE` | Backend de base de datos: `sqlite` o `postgres` | `sqlite` |
| `LUI_DB_DSN` | Cadena de conexión de PostgreSQL (cuando `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | Directorio del archivo de base de datos SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Máximo de conexiones abiertas (pool de PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Máximo de conexiones inactivas (pool de PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | La ruta URI inicial para el panel web | `/` |
| `LUI_ENABLE_FAIL2BAN` | Habilitar la aplicación de límites de IP basada en Fail2ban | `true` |
| `LUI_LOG_LEVEL` | Nivel de registro (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Habilitar el modo de depuración | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Habilitar el monitor de salud del túnel (sondea una URL y reinicia xray tras fallos repetidos; un reinicio desconecta a todos los clientes) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Proxy a través del cual se envía el sondeo; apúntalo a una entrada local de xray para que el sondeo pruebe el túnel (p. ej. `socks5://127.0.0.1:1080`). Vacío significa que el sondeo solo comprueba la conectividad del host | — |
| `LUI_TUNNEL_HEALTH_URL` | URL sondeada para verificar la salud del túnel | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Intervalo entre sondeos | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Tiempo de espera por sondeo | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Fallos consecutivos antes de que se active un reinicio | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Retardo mínimo entre reinicios consecutivos | `5m` |
## Idiomas Compatibles
@@ -179,9 +179,9 @@ Las contribuciones son bienvenidas. Por favor, lee la [Guía de contribución](/
## Herramientas de la Comunidad
Herramientas e integraciones construidas por la comunidad alrededor de 3x-ui.
Herramientas e integraciones construidas por la comunidad alrededor de L-UI.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Licencia: **MIT**): _Gestiona inbounds, clientes, configuración del panel y configuración de Xray como código con Terraform / OpenTofu._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (Licencia: **MIT**): _Gestiona inbounds, clientes, configuración del panel y configuración de Xray como código con Terraform / OpenTofu._
## Apoyar el Proyecto
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -64,7 +64,7 @@
## شروع سریع
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
برای نصب یک نسخه‌ی مشخص، تگ آن را در انتها اضافه کنید (مثلاً `v3.4.0`):
@@ -79,16 +79,16 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
در حین نصب، یک نام کاربری، رمز عبور و مسیر دسترسی تصادفی تولید می‌شود. پس از نصب، دستور `x-ui` را اجرا کنید تا منوی مدیریت باز شود؛ در آنجا می‌توانید سرویس را شروع/متوقف کنید، اطلاعات ورود خود را ببینید یا بازنشانی کنید، گواهی‌های SSL را مدیریت کنید و کارهای دیگری انجام دهید.
در حین نصب، یک نام کاربری، رمز عبور و مسیر دسترسی تصادفی تولید می‌شود. پس از نصب، دستور `l-ui` را اجرا کنید تا منوی مدیریت باز شود؛ در آنجا می‌توانید سرویس را شروع/متوقف کنید، اطلاعات ورود خود را ببینید یا بازنشانی کنید، گواهی‌های SSL را مدیریت کنید و کارهای دیگری انجام دهید.
برای مستندات کامل، لطفاً به [ویکی پروژه](https://git.881218.xyz/rogue/3x-ui-agent) مراجعه کنید.
برای مستندات کامل، لطفاً به [ویکی پروژه](https://git.881218.xyz/rogue/l-ui) مراجعه کنید.
### نصب بدون نظارت
نصب‌کننده به‌صورت **غیرتعاملی** نیز برای cloud-init اجرا می‌شود.
‏`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY از طریق pipe اجرا کنید) تا نصب به‌صورت سرتاسری و بدون
‏`LUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY از طریق pipe اجرا کنید) تا نصب به‌صورت سرتاسری و بدون
هیچ پرسشی انجام شود، اطلاعات ورود تصادفی تولید کرده و آن‌ها را در
`/etc/x-ui/install-result.env` می‌نویسد. برای موارد زیر به [`deploy/`](deploy/) مراجعه کنید:
`/etc/l-ui/install-result.env` می‌نویسد. برای موارد زیر به [`deploy/`](deploy/) مراجعه کنید:
- [user-data مربوط به Cloud-init](deploy/cloud-init/) — نصب بدون نظارت روی هر ابری (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [یادداشت‌های Hetzner Cloud](deploy/marketplace/hetzner/) — استقرار مبتنی بر cloud-init روی Hetzner
@@ -103,29 +103,29 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
‏3X-UI از دو بک‌اند پشتیبانی می‌کند که در حین نصب انتخاب می‌شوند:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط.
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به تنظیمات، ایده‌آل برای استقرارهای کوچک و متوسط.
- **PostgreSQL** — برای تعداد کلاینت بالا یا راه‌اندازی‌های چندنودی توصیه می‌شود. نصب‌کننده می‌تواند PostgreSQL را به‌صورت محلی برایتان نصب کند، یا یک DSN به یک سرور موجود را بپذیرد.
در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/x-ui` می‌نویسد):
در زمان اجرا، بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود (نصب‌کننده این موارد را برای شما در `/etc/default/l-ui` می‌نویسد):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### انتقال یک نصب موجود SQLite به PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# سپس XUI_DB_TYPE و XUI_DB_DSN را در /etc/default/x-ui تنظیم کرده و ری‌استارت کنید:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# سپس LUI_DB_TYPE و LUI_DB_DSN را در /etc/default/l-ui تنظیم کرده و ری‌استارت کنید:
systemctl restart l-ui
```
فایل اصلی SQLite دست‌نخورده باقی می‌ماند؛ پس از اطمینان از صحت بک‌اند جدید، آن را به‌صورت دستی حذف کنید.
### Docker
دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `XUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید:
دستور پیش‌فرض `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس PostgreSQL همراه، دو خط متغیر محیطی `LUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل زیر اجرا کنید:
```bash
docker compose --profile postgres up -d
@@ -134,29 +134,29 @@ docker compose --profile postgres up -d
این ایمیج، Fail2ban را (که به‌صورت پیش‌فرض فعال است) برای اعمال **محدودیت‌های IP** به‌ازای هر کلاینت همراه دارد. ‏Fail2ban متخلفان را با `iptables` مسدود می‌کند که به مجوز `NET_ADMIN` نیاز دارد. فایل `docker-compose.yml` این مجوز را از قبل از طریق `cap_add` می‌دهد؛ اگر به‌جای آن کانتینر را با `docker run` اجرا می‌کنید، خودتان مجوزها را اضافه کنید، در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند اما هرگز اعمال نمی‌شوند:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## متغیرهای محیطی
| متغیر | توضیحات | پیش‌فرض |
| --- | --- | --- |
| `XUI_DB_TYPE` | بک‌اند پایگاه‌داده: `sqlite` یا `postgres` | `sqlite` |
| `XUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` |
| `XUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` |
| `XUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` |
| `XUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — |
| `XUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | حداقل تأخیر بین ری‌استارت‌های متوالی | `5m` |
| `LUI_DB_TYPE` | بک‌اند پایگاه‌داده: `sqlite` یا `postgres` | `sqlite` |
| `LUI_DB_DSN` | رشته‌ی اتصال PostgreSQL (وقتی `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | حداکثر اتصالات باز (استخر PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | حداکثر اتصالات بی‌کار (استخر PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | مسیر URI اولیه برای پنل وب | `/` |
| `LUI_ENABLE_FAIL2BAN` | فعال‌سازی اعمال محدودیت IP مبتنی بر Fail2ban | `true` |
| `LUI_LOG_LEVEL` | سطح گزارش‌گیری (`debug`، `info`، `warning`، `error`) | `info` |
| `LUI_DEBUG` | فعال‌سازی حالت دیباگ | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | فعال‌سازی پایشگر سلامت تونل (یک URL را پروب می‌کند و پس از خطاهای مکرر، xray را ری‌استارت می‌کند؛ یک ری‌استارت همه‌ی کلاینت‌ها را قطع می‌کند) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | پراکسی‌ای که پروب از طریق آن ارسال می‌شود؛ آن را به یک اینباند محلی xray اشاره دهید تا پروب خودِ تونل را آزمایش کند (مثلاً `socks5://127.0.0.1:1080`). خالی بودن یعنی پروب فقط اتصال به هاست را بررسی می‌کند | — |
| `LUI_TUNNEL_HEALTH_URL` | URL ای که برای سلامت تونل پروب می‌شود | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | فاصله‌ی زمانی بین پروب‌ها | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | مهلت زمانی هر پروب | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | تعداد خطاهای متوالی پیش از آن‌که یک ری‌استارت فعال شود | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | حداقل تأخیر بین ری‌استارت‌های متوالی | `5m` |
## زبان‌های پشتیبانی‌شده
@@ -179,9 +179,9 @@ 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._
## پشتیبانی از پروژه
+29 -29
View File
@@ -1,71 +1,71 @@
# 3x-ui-agent
# L-UI
基于上游 3x-ui v3.7.0 的二次开发 fork:节点 agent 化。节点鸡不再跑完整面板,只跑一个轻量 agent(约 60MB 内存),由主控统一管理、下发 xray 配置。
本仓库托管在自建 Gitea:<https://git.881218.xyz/rogue/3x-ui-agent>,二进制从本仓库的 Releases 下载。**不要**使用上游的一键安装脚本/命令(`install.sh`、`update.sh` 等仍指向原版,会装成上游原版,与本 fork 不兼容)。
本仓库托管在自建 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 两类入站(本 fork 的取向)。
同一个二进制、两种角色:不带参数运行是主控面板,`x-ui agent --config /etc/x-ui/agent.json` 运行是 agent。
同一个二进制、两种角色:不带参数运行是主控面板,`l-ui agent --config /etc/l-ui/agent.json` 运行是 agent。
## 安装
二进制下载:本仓库 [Releases](https://git.881218.xyz/rogue/3x-ui-agent/releases),按架构选 `x-ui-linux-amd64` 或 `x-ui-linux-arm64`。
二进制下载:本仓库 [Releases](https://git.881218.xyz/rogue/l-ui/releases),按架构选 `l-ui-linux-amd64` 或 `l-ui-linux-arm64`。
> 仓库根目录的 `install-master.sh` / `install-agent.sh` 是一键脚本,下载源已迁至本仓 Gitea Releases(tag `v3.7.0-agent.1`),可直接使用;也可按下面步骤手动部署。
### 主控
```bash
mkdir -p /usr/local/x-ui/bin /etc/x-ui
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放主控二进制(Releases 下载的 x-ui-linux-<架构>)
cp x-ui-linux-amd64 /usr/local/x-ui/x-ui && chmod +x /usr/local/x-ui/x-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/x-ui/bin/
cp geoip.dat geosite.dat /usr/local/x-ui/bin/
cp xray-linux-amd64 /usr/local/l-ui/bin/
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
```
启动(二选一):
- Debian/Ubuntu(systemd):把仓库的 `x-ui.service.debian` 复制为 `/etc/systemd/system/x-ui.service`,然后 `systemctl daemon-reload && systemctl enable --now x-ui`。
- OpenWrt(procd):用 init 脚本以 `/usr/local/x-ui/x-ui` 为命令启动,工作目录 `/usr/local/x-ui`。
- 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/x-ui/x-ui.db`。面板端口按设置,默认 2053,首次登录默认账号 `admin` / `admin`,请登录后立即修改。
数据库在 `/etc/l-ui/l-ui.db`。面板端口按设置,默认 2053,首次登录默认账号 `admin` / `admin`,请登录后立即修改。
### Agent(节点鸡)
先在主控侧为该节点生成注册 token(建节点 → 用面板 API Token 签发绑定该节点的 agent token,完整步骤见 [docs/AGENT.md](docs/AGENT.md)),然后在节点鸡上:
```bash
mkdir -p /usr/local/x-ui/bin /etc/x-ui
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放同一个二进制(与主控同版本),在节点上改名为 xui-agent(与主控进程区分、避免同机覆盖)
cp x-ui-linux-amd64 /usr/local/x-ui/xui-agent && chmod +x /usr/local/x-ui/xui-agent
# 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/x-ui/bin/xray && chmod +x /usr/local/x-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/x-ui/bin/
cp xray-linux-amd64 /usr/local/l-ui/bin/xray && chmod +x /usr/local/l-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
# 3. 写 agent 配置
cat > /etc/x-ui/agent.json <<'EOF'
cat > /etc/l-ui/agent.json <<'EOF'
{
"master_url": "http://主控地址:2053",
"token": "<主控签发的注册 token>",
"node_name": "节点名"
}
EOF
chmod 600 /etc/x-ui/agent.json
chmod 600 /etc/l-ui/agent.json
```
- `master_url` 走内网用 `http://`;走 `https://` 需可信证书(自签连不上)。
- agent 另有独立的运行时配置 `config-agent.json`(生成于 `bin/`);`agent.json` 可选 `api_port` 指定 xray stats API 端口(部署口径 62790,metrics 端口为其下一位 62791)。
- 启动:Debian 把仓库的 `systemd/x-ui-agent.service` 复制到 `/etc/systemd/system/` 后 `systemctl enable --now x-ui-agent`;OpenRC 用仓库的 `openrc/x-ui-agent` 放到 `/etc/init.d/x-ui-agent`。
- 启动: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)。
@@ -74,20 +74,20 @@ agent 约 30 秒后拉到配置并启动 xray,节点在面板显示在线。
### 主控
```bash
# 先停服务:systemctl disable --now x-ui(或 /etc/init.d/x-ui stop)
rm -f /etc/systemd/system/x-ui.service # 或删掉对应的 procd init 脚本
rm -rf /usr/local/x-ui /etc/x-ui
# 先停服务: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 x-ui-agent(或 rc-service x-ui-agent stop)
rm -f /etc/systemd/system/x-ui-agent.service # 或 /etc/init.d/x-ui-agent
rm -rf /usr/local/x-ui /etc/x-ui
# 先停服务: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/x-ui` 里含数据库与 token 配置,确认不再需要再删。)
(`/etc/l-ui` 里含数据库与 token 配置,确认不再需要再删。)
## 使用流程
@@ -101,7 +101,7 @@ rm -rf /usr/local/x-ui /etc/x-ui
| | 内存 |
|---|---|
| agent + xray | 约 63MB |
| 完整 3x-ui 面板 | 130–160MB |
| 完整 L-UI 面板 | 130–160MB |
另有路由器主控精简版构建(剥离 xray-core 库,见仓库内 PANEL-LITE-SPEC.md),面向纯控制面部署,内存显著更低。
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -64,7 +64,7 @@
## Быстрый старт
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
Чтобы установить конкретную версию, добавьте её тег (например, `v3.4.0`):
@@ -79,16 +79,16 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
Во время установки генерируются случайные имя пользователя, пароль и путь доступа. После установки выполните `x-ui`, чтобы открыть меню управления, где можно запускать/останавливать сервис, просматривать или сбрасывать учётные данные для входа, управлять SSL-сертификатами и многое другое.
Во время установки генерируются случайные имя пользователя, пароль и путь доступа. После установки выполните `l-ui`, чтобы открыть меню управления, где можно запускать/останавливать сервис, просматривать или сбрасывать учётные данные для входа, управлять SSL-сертификатами и многое другое.
Полную документацию смотрите в [вики проекта](https://git.881218.xyz/rogue/3x-ui-agent).
Полную документацию смотрите в [вики проекта](https://git.881218.xyz/rogue/l-ui).
### Автоматическая установка
Установщик также работает в **неинтерактивном** режиме для cloud-init.
Задайте `XUI_NONINTERACTIVE=1` (или передайте по конвейеру без TTY), и установка пройдёт от начала до конца
Задайте `LUI_NONINTERACTIVE=1` (или передайте по конвейеру без TTY), и установка пройдёт от начала до конца
без единого запроса: будут сгенерированы случайные учётные данные и записаны в
`/etc/x-ui/install-result.env`. Смотрите [`deploy/`](deploy/) для:
`/etc/l-ui/install-result.env`. Смотрите [`deploy/`](deploy/) для:
- [Cloud-init user-data](deploy/cloud-init/) — автоматическая установка в любом облаке (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Заметки по Hetzner Cloud](deploy/marketplace/hetzner/) — развёртывание на Hetzner на базе cloud-init
@@ -103,29 +103,29 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
3X-UI поддерживает два бэкенда, выбираемых при установке:
- **SQLite** (по умолчанию) — единый файл по пути `/etc/x-ui/x-ui.db`. Без настройки, идеально для небольших и средних развёртываний.
- **SQLite** (по умолчанию) — единый файл по пути `/etc/l-ui/l-ui.db`. Без настройки, идеально для небольших и средних развёртываний.
- **PostgreSQL** — рекомендуется при большом числе клиентов или конфигурациях с несколькими узлами. Установщик может установить PostgreSQL локально за вас или принять DSN к существующему серверу.
Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/x-ui`):
Во время выполнения бэкенд выбирается через переменные окружения (установщик записывает их за вас в `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Перенос существующей установки SQLite в PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# затем задайте XUI_DB_TYPE и XUI_DB_DSN в /etc/default/x-ui и перезапустите:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# затем задайте LUI_DB_TYPE и LUI_DB_DSN в /etc/default/l-ui и перезапустите:
systemctl restart l-ui
```
Исходный файл SQLite остаётся нетронутым; удалите его вручную после проверки нового бэкенда.
### Docker
Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `XUI_DB_*` в `docker-compose.yml` и запустите с профилем:
Команда по умолчанию `docker compose up -d` продолжает использовать SQLite. Чтобы запустить со встроенным сервисом PostgreSQL, раскомментируйте две строки переменных окружения `LUI_DB_*` в `docker-compose.yml` и запустите с профилем:
```bash
docker compose --profile postgres up -d
@@ -134,29 +134,29 @@ docker compose --profile postgres up -d
Образ включает Fail2ban (включён по умолчанию) для применения **лимитов IP** по каждому клиенту. Fail2ban блокирует нарушителей с помощью `iptables`, что требует возможности `NET_ADMIN`. `docker-compose.yml` уже предоставляет её через `cap_add`; если вы вместо этого запускаете контейнер через `docker run`, добавьте возможности самостоятельно, иначе блокировки будут регистрироваться, но никогда не применяться:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Переменные окружения
| Переменная | Описание | По умолчанию |
| --- | --- | --- |
| `XUI_DB_TYPE` | Бэкенд базы данных: `sqlite` или `postgres` | `sqlite` |
| `XUI_DB_DSN` | Строка подключения PostgreSQL (когда `XUI_DB_TYPE=postgres`) | — |
| `XUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — |
| `XUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` |
| `XUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` |
| `XUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Включить режим отладки | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — |
| `XUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Минимальная задержка между последовательными перезапусками | `5m` |
| `LUI_DB_TYPE` | Бэкенд базы данных: `sqlite` или `postgres` | `sqlite` |
| `LUI_DB_DSN` | Строка подключения PostgreSQL (когда `LUI_DB_TYPE=postgres`) | — |
| `LUI_DB_FOLDER` | Каталог для файла базы данных SQLite | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Максимум открытых соединений (пул PostgreSQL) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Максимум простаивающих соединений (пул PostgreSQL) | — |
| `LUI_INIT_WEB_BASE_PATH` | Начальный URI-путь для веб-панели | `/` |
| `LUI_ENABLE_FAIL2BAN` | Включить применение лимитов IP на основе Fail2ban | `true` |
| `LUI_LOG_LEVEL` | Уровень логирования (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Включить режим отладки | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Включить монитор состояния туннеля (опрашивает URL и перезапускает xray после многократных сбоев; перезапуск отключает всех клиентов) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Прокси, через который отправляется проба; укажите локальный входящий xray, чтобы проба проверяла туннель (например, `socks5://127.0.0.1:1080`). Пустое значение означает, что проба проверяет только связь с хостом | — |
| `LUI_TUNNEL_HEALTH_URL` | URL, опрашиваемый для проверки состояния туннеля | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Интервал между пробами | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Таймаут на одну пробу | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Число последовательных сбоев до запуска перезапуска | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Минимальная задержка между последовательными перезапусками | `5m` |
## Поддерживаемые языки
@@ -179,9 +179,9 @@ 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._
## Поддержка проекта
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -64,7 +64,7 @@ Orijinal X-UI projesinin geliştirilmiş bir çatallaması (fork) olarak inşa e
## Hızlı Başlangıç
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.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:
@@ -79,16 +79,16 @@ Sürekli güncellenen **dev** sürümünü (kararlı bir sürüm değil; `main`
# 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://git.881218.xyz/rogue/3x-ui-agent) ziyaret edin.
Tam dokümantasyon için lütfen [proje Wiki sayfasını](https://git.881218.xyz/rogue/l-ui) ziyaret edin.
### Etkileşimsiz kurulum
Yükleyici, cloud-init için **etkileşimsiz** olarak da çalışır.
`XUI_NONINTERACTIVE=1` ayarlayın (veya TTY olmadan boru hattına aktarın); kurulum baştan
`LUI_NONINTERACTIVE=1` ayarlayın (veya TTY olmadan boru hattına aktarın); kurulum baştan
sona hiçbir soru sormadan tamamlanır, rastgele kimlik bilgileri oluşturup bunları
`/etc/x-ui/install-result.env` dosyasına yazar. Şunlar için [`deploy/`](deploy/) klasörüne bakın:
`/etc/l-ui/install-result.env` dosyasına yazar. Şunlar için [`deploy/`](deploy/) klasörüne bakın:
- [Cloud-init user-data](deploy/cloud-init/) — herhangi bir bulutta etkileşimsiz kurulum (Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Hetzner Cloud notları](deploy/marketplace/hetzner/) — Hetzner üzerinde cloud-init tabanlı dağıtım
@@ -103,29 +103,29 @@ sona hiçbir soru sormadan tamamlanır, rastgele kimlik bilgileri oluşturup bun
3X-UI kurulum sırasında seçilebilecek iki arka uç (backend) destekler:
- **SQLite** (varsayılan) — `/etc/x-ui/x-ui.db` konumunda tek bir dosya. Kurulum gerektirmez, küçük ve orta ölçekli dağıtımlar için idealdir.
- **SQLite** (varsayılan) — `/etc/l-ui/l-ui.db` konumunda tek bir dosya. Kurulum gerektirmez, küçük ve orta ölçekli dağıtımlar için idealdir.
- **PostgreSQL** — Yüksek kullanıcı sayıları veya çoklu düğüm (multi-node) kurulumları için önerilir. Yükleyici sizin için yerel olarak PostgreSQL kurabilir veya mevcut bir sunucuya DSN bağlantısı kabul edebilir.
Çalışma anında veritabanı türü ortam değişkenleri (environment variables) ile seçilir (yükleyici bunları sizin için `/etc/default/x-ui` dosyasına yazar):
Çalışma anında veritabanı türü ortam değişkenleri (environment variables) ile seçilir (yükleyici bunları sizin için `/etc/default/l-ui` dosyasına yazar):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### Mevcut bir SQLite Kurulumunu PostgreSQL'e Taşıma
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ardından /etc/default/x-ui içindeki XUI_DB_TYPE ve XUI_DB_DSN değerlerini ayarlayıp yeniden başlatın:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# ardından /etc/default/l-ui içindeki LUI_DB_TYPE ve LUI_DB_DSN değerlerini ayarlayıp yeniden başlatın:
systemctl restart l-ui
```
Kaynak SQLite dosyasına dokunulmaz; yeni veritabanının düzgün çalıştığını doğruladıktan sonra eski SQLite dosyasını manuel olarak silebilirsiniz.
### Docker
Varsayılan `docker compose up -d` komutu SQLite kullanmaya devam eder. Birlikte paketlenmiş PostgreSQL servisi ile çalıştırmak için, `docker-compose.yml` dosyasındaki iki `XUI_DB_*` değişken satırının yorumunu kaldırın ve profille başlatın:
Varsayılan `docker compose up -d` komutu SQLite kullanmaya devam eder. Birlikte paketlenmiş PostgreSQL servisi ile çalıştırmak için, `docker-compose.yml` dosyasındaki iki `LUI_DB_*` değişken satırının yorumunu kaldırın ve profille başlatın:
```bash
docker compose --profile postgres up -d
@@ -134,29 +134,29 @@ docker compose --profile postgres up -d
Docker imajı, kullanıcı başına **IP limitlerini** zorunlu kılmak için Fail2ban ile (varsayılan olarak etkindir) paketlenmiştir. Fail2ban, ihlalcileri `iptables` ile engeller ve bunun için `NET_ADMIN` yetkisine ihtiyaç duyar. `docker-compose.yml` bunu zaten `cap_add` üzerinden vermektedir; ancak konteyneri bunun yerine `docker run` ile başlatırsanız bu yetkileri kendiniz eklemelisiniz, aksi takdirde yasaklamalar günlüğe kaydedilir ancak uygulanmaz:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## Ortam Değişkenleri (Environment Variables)
| Değişken | Açıklama | Varsayılan |
| --- | --- | --- |
| `XUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `XUI_DB_TYPE=postgres` ise) | — |
| `XUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | Maksimum açık bağlantı sayısı (PostgreSQL havuzu) | — |
| `XUI_DB_MAX_IDLE_CONNS` | Maksimum boşta bekleme bağlantısı (PostgreSQL havuzu) | — |
| `XUI_INIT_WEB_BASE_PATH` | Web paneli için başlangıç URI yolu | `/` |
| `XUI_ENABLE_FAIL2BAN` | Fail2ban tabanlı IP limit uygulamasını etkinleştir | `true` |
| `XUI_LOG_LEVEL` | Günlük (Log) ayrıntı seviyesi (`debug`, `info`, `warning`, `error`) | `info` |
| `XUI_DEBUG` | Hata ayıklama (debug) modunu etkinleştir | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | Tünel sağlık izleyicisini etkinleştir (bir URL'yi yoklar ve tekrarlanan başarısızlıklardan sonra xray'i yeniden başlatır; yeniden başlatma tüm istemcilerin bağlantısını düşürür) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | Yoklamanın gönderildiği proxy; yoklamanın tüneli test etmesi için bunu yerel bir xray gelen bağlantısına yönlendirin (ör. `socks5://127.0.0.1:1080`). Boş bırakılırsa yoklama yalnızca ana makine bağlantısını kontrol eder | — |
| `XUI_TUNNEL_HEALTH_URL` | Tünel sağlığı için yoklanan URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | Yoklamalar arasındaki aralık | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | Yoklama başına zaman aşımı | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | Yeniden başlatma tetiklenmeden önceki ardışık başarısızlık sayısı | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | Ardışık yeniden başlatmalar arasındaki minimum gecikme | `5m` |
| `LUI_DB_TYPE` | Veritabanı türü: `sqlite` veya `postgres` | `sqlite` |
| `LUI_DB_DSN` | PostgreSQL bağlantı dizesi (eğer `LUI_DB_TYPE=postgres` ise) | — |
| `LUI_DB_FOLDER` | SQLite veritabanı dizini | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | Maksimum açık bağlantı sayısı (PostgreSQL havuzu) | — |
| `LUI_DB_MAX_IDLE_CONNS` | Maksimum boşta bekleme bağlantısı (PostgreSQL havuzu) | — |
| `LUI_INIT_WEB_BASE_PATH` | Web paneli için başlangıç URI yolu | `/` |
| `LUI_ENABLE_FAIL2BAN` | Fail2ban tabanlı IP limit uygulamasını etkinleştir | `true` |
| `LUI_LOG_LEVEL` | Günlük (Log) ayrıntı seviyesi (`debug`, `info`, `warning`, `error`) | `info` |
| `LUI_DEBUG` | Hata ayıklama (debug) modunu etkinleştir | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | Tünel sağlık izleyicisini etkinleştir (bir URL'yi yoklar ve tekrarlanan başarısızlıklardan sonra xray'i yeniden başlatır; yeniden başlatma tüm istemcilerin bağlantısını düşürür) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | Yoklamanın gönderildiği proxy; yoklamanın tüneli test etmesi için bunu yerel bir xray gelen bağlantısına yönlendirin (ör. `socks5://127.0.0.1:1080`). Boş bırakılırsa yoklama yalnızca ana makine bağlantısını kontrol eder | — |
| `LUI_TUNNEL_HEALTH_URL` | Tünel sağlığı için yoklanan URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | Yoklamalar arasındaki aralık | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | Yoklama başına zaman aşımı | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | Yeniden başlatma tetiklenmeden önceki ardışık başarısızlık sayısı | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | Ardışık yeniden başlatmalar arasındaki minimum gecikme | `5m` |
## Desteklenen Diller
@@ -179,9 +179,9 @@ Katkılarınızı her zaman bekliyoruz. Bir sorun (issue) açmadan veya pull req
## Topluluk Araçları
3x-ui çevresindeki topluluk tarafından oluşturulmuş araçlar ve entegrasyonlar.
L-UI çevresindeki topluluk tarafından oluşturulmuş araçlar ve entegrasyonlar.
- [terraform-provider-3x-ui](https://github.com/batonogov/terraform-provider-threexui) (Lisans: **MIT**): _Gelen bağlantılarnı, kullanıcıları, panel ayarlarını ve Xray yapılandırmasını Terraform / OpenTofu ile kod olarak (as code) yönetin._
- [terraform-provider-L-UI](https://github.com/batonogov/terraform-provider-threexui) (Lisans: **MIT**): _Gelen bağlantılarnı, kullanıcıları, panel ayarlarını ve Xray yapılandırmasını Terraform / OpenTofu ile kod olarak (as code) yönetin._
## Projeyi Destekleyin
+34 -34
View File
@@ -2,8 +2,8 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./media/3x-ui-dark.png">
<img alt="3x-ui" src="./media/3x-ui-light.png">
<source media="(prefers-color-scheme: dark)" srcset="./media/L-UI-dark.png">
<img alt="L-UI" src="./media/L-UI-light.png">
</picture>
</p>
@@ -65,7 +65,7 @@
## 快速开始
```bash
bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh)
bash <(curl -Ls https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh)
```
若要安装特定版本,请在命令后附加对应的标签(例如 `v3.4.0`):
@@ -80,16 +80,16 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
# This fork provides no dev-channel one-click install; see the main README (README.md).
```
安装过程中会生成随机的用户名、密码和访问路径。安装完成后,运行 `x-ui` 打开管理菜单,您可以在其中启动/停止服务、查看或重置登录凭据、管理 SSL 证书等。
安装过程中会生成随机的用户名、密码和访问路径。安装完成后,运行 `l-ui` 打开管理菜单,您可以在其中启动/停止服务、查看或重置登录凭据、管理 SSL 证书等。
完整文档请参阅 [项目Wiki](https://git.881218.xyz/rogue/3x-ui-agent)。
完整文档请参阅 [项目Wiki](https://git.881218.xyz/rogue/l-ui)。
### 无人值守安装
安装程序也可以**非交互式**运行,适用于 cloud-init。
设置 `XUI_NONINTERACTIVE=1`(或在无 TTY 的情况下通过管道传入),它就会全程
设置 `LUI_NONINTERACTIVE=1`(或在无 TTY 的情况下通过管道传入),它就会全程
零提示地完成端到端安装,生成随机凭据并写入
`/etc/x-ui/install-result.env`。请参阅 [`deploy/`](deploy/):
`/etc/l-ui/install-result.env`。请参阅 [`deploy/`](deploy/):
- [Cloud-init user-data](deploy/cloud-init/) — 在任意云平台上无人值守安装(Hetzner/AWS/DO/Vultr/GCP/Azure/Oracle)
- [Hetzner Cloud 说明](deploy/marketplace/hetzner/) — 在 Hetzner 上基于 cloud-init 的部署
@@ -104,29 +104,29 @@ bash <(curl -Ls https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install
3X-UI 支持两种后端,可在安装时选择:
- **SQLite**(默认)— 位于 `/etc/x-ui/x-ui.db` 的单个文件。无需配置,适合中小型部署。
- **SQLite**(默认)— 位于 `/etc/l-ui/l-ui.db` 的单个文件。无需配置,适合中小型部署。
- **PostgreSQL** — 推荐用于大量客户端或多节点设置。安装程序可以为您在本地安装 PostgreSQL,或接受指向现有服务器的 DSN。
运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/x-ui`):
运行时通过环境变量选择后端(安装程序会为您写入 `/etc/default/l-ui`):
```
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
### 将现有的 SQLite 安装迁移到 PostgreSQL
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# 然后在 /etc/default/x-ui 中设置 XUI_DB_TYPE 和 XUI_DB_DSN 并重启:
systemctl restart x-ui
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
# 然后在 /etc/default/l-ui 中设置 LUI_DB_TYPE 和 LUI_DB_DSN 并重启:
systemctl restart l-ui
```
源 SQLite 文件保持不变;在确认新后端正常工作后,请手动删除它。
### Docker
默认的 `docker compose up -d` 仍使用 SQLite。若要使用捆绑的 PostgreSQL 服务运行,请取消注释 `docker-compose.yml` 中的两行 `XUI_DB_*` 环境变量,并使用该 profile 启动:
默认的 `docker compose up -d` 仍使用 SQLite。若要使用捆绑的 PostgreSQL 服务运行,请取消注释 `docker-compose.yml` 中的两行 `LUI_DB_*` 环境变量,并使用该 profile 启动:
```bash
docker compose --profile postgres up -d
@@ -135,29 +135,29 @@ docker compose --profile postgres up -d
该镜像捆绑了 Fail2ban(默认启用),用于强制执行按客户端的 **IP 限制**。Fail2ban 使用 `iptables` 封禁违规者,这需要 `NET_ADMIN` 权限。`docker-compose.yml` 已通过 `cap_add` 授予该权限;如果您改用 `docker run` 启动容器,请自行添加这些权限,否则封禁只会被记录而永远不会生效:
```bash
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... 3x-ui-agent:local
docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... L-UI:local
```
## 环境变量
| 变量 | 说明 | 默认值 |
| --- | --- | --- |
| `XUI_DB_TYPE` | 数据库后端:`sqlite` 或 `postgres` | `sqlite` |
| `XUI_DB_DSN` | PostgreSQL 连接字符串(当 `XUI_DB_TYPE=postgres` 时) | — |
| `XUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/x-ui` |
| `XUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — |
| `XUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — |
| `XUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` |
| `XUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` |
| `XUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` |
| `XUI_DEBUG` | 启用调试模式 | `false` |
| `XUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` |
| `XUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — |
| `XUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `XUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` |
| `XUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | 两次连续重启之间的最小间隔 | `5m` |
| `LUI_DB_TYPE` | 数据库后端:`sqlite` 或 `postgres` | `sqlite` |
| `LUI_DB_DSN` | PostgreSQL 连接字符串(当 `LUI_DB_TYPE=postgres` 时) | — |
| `LUI_DB_FOLDER` | SQLite 数据库文件所在目录 | `/etc/l-ui` |
| `LUI_DB_MAX_OPEN_CONNS` | 最大打开连接数(PostgreSQL 连接池) | — |
| `LUI_DB_MAX_IDLE_CONNS` | 最大空闲连接数(PostgreSQL 连接池) | — |
| `LUI_INIT_WEB_BASE_PATH` | Web 面板的初始 URI 路径 | `/` |
| `LUI_ENABLE_FAIL2BAN` | 启用基于 Fail2ban 的 IP 限制 | `true` |
| `LUI_LOG_LEVEL` | 日志级别(`debug`、`info`、`warning`、`error`) | `info` |
| `LUI_DEBUG` | 启用调试模式 | `false` |
| `LUI_TUNNEL_HEALTH_MONITOR` | 启用隧道健康监控(探测某个 URL,在连续多次失败后重启 xray;重启会断开所有客户端) | `false` |
| `LUI_TUNNEL_HEALTH_PROXY` | 探测请求所经过的代理;将其指向本地 xray 入站,使探测能够测试隧道(例如 `socks5://127.0.0.1:1080`)。留空表示探测仅检查主机连通性 | — |
| `LUI_TUNNEL_HEALTH_URL` | 用于检测隧道健康状况的探测 URL | `https://www.cloudflare.com/cdn-cgi/trace` |
| `LUI_TUNNEL_HEALTH_INTERVAL` | 两次探测之间的间隔 | `30s` |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | 单次探测的超时时间 | `10s` |
| `LUI_TUNNEL_HEALTH_FAILURES` | 触发重启前的连续失败次数 | `3` |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | 两次连续重启之间的最小间隔 | `5m` |
## 支持的语言
@@ -180,9 +180,9 @@ 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 配置。_
## 支持项目
+195
View File
@@ -0,0 +1,195 @@
# Renaming: 3x-ui / x-ui → L-UI / l-ui / lui-agent
Base: `8158ced` (panel V2.6.0 / agent A2.5.0). This batch is a pure
rename: **no version bump, no feature change, no production change,
no Gitea change, no release**. Versions stay V2.6.0 / A2.5.0; the
version bump is left to the release step (see Pending below).
## Mapping (exact — do not invent other aliases)
| old | new | where it shows up |
| --- | --- | --- |
| display brand `3x-ui` / `x-ui` | `L-UI` | panel UI, i18n, README, docs |
| panel binary / process | `l-ui` | release asset, `ps`, `/usr/bin/l-ui` (Docker), `l-ui setting …` |
| agent binary / process | `lui-agent` | release asset, `ps`, `lui-agent agent …` |
| install dir | `/usr/local/l-ui` | panel + agent binaries |
| config / state dir | `/etc/l-ui` | `agent.json`, `node_token_key.json`, env files |
| panel DB | `/etc/l-ui/l-ui.db` | driven by `internal/config/name` (`l-ui`) via `GetName()` + `GetDBFolderPath()` — no separate DB-name constant |
| probe DB | `/etc/l-ui/probe.db` | name unchanged, directory moved (`probe/store.go` joins `GetDBFolderPath()`) |
| cert dir | `/etc/l-ui/cert` | panel + subscription share it |
| binary dir | `/usr/local/l-ui/bin` | `DefaultBinFolder`; sing-box live config `config-singbox.json` lives here |
| log dir | `/var/log/l-ui` | panel log, agent log, sing-box log |
| panel service | `l-ui.service` | systemd units `l-ui.service.{debian,arch,rhel}`, OpenRC `l-ui.rc` |
| agent service | `lui-agent.service` | `systemd/lui-agent.service`, OpenRC `openrc/lui-agent` |
| management CLI | `l-ui.sh` | was `x-ui.sh`; Docker copies it to `/usr/bin/l-ui` |
| panel release assets | `l-ui-linux-amd64`, `l-ui-linux-arm64` (+ `.sha256`) | `scripts/release-build.sh`, `selfupdate.AssetName` |
| agent release assets | `lui-agent-linux-amd64`, `lui-agent-linux-arm64` (+ `.sha256`) | `scripts/release-build.sh`, `selfupdate.AgentAssetName` |
| agent version marker | `agent-version.txt` | name unchanged |
| env prefix | `LUI_` | every `XUI_` variable, code + scripts + docs + tests (inventory below) |
| source dir (Linux agent) | `cmd/lui-agent` | was `cmd/xui-agent`; `release-build.sh` builds `./cmd/lui-agent` |
| Gitea repo (PLACEHOLDER) | `rogue/l-ui` | see Pending — **not yet real** |
## Environment variables renamed
Code reads **only** the new `LUI_` prefix. There is no dual-read
fallback in code: an old unit file that still exports `XUI_*` will
silently lose those settings, which is why the migration doc
(`docs/migration-l-ui.md`) has an explicit unit-env translation
table. Old units must be replaced, not edited in place.
Full inventory (from a whole-tree scan; `LUI_DB_*` below is a docs
glob, not a variable):
`LUI_ACCESS_URL`, `LUI_ACME_EMAIL`, `LUI_ACME_HTTP_PORT`,
`LUI_API_TOKEN`, `LUI_B1_OLD_BACKUP`, `LUI_B2_OLD_DB`,
`LUI_BIN_FOLDER`, `LUI_DB_CACHE_MB`, `LUI_DB_DSN`,
`LUI_DB_FOLDER`, `LUI_DB_JOURNAL_MODE`, `LUI_DB_MAX_IDLE_CONNS`,
`LUI_DB_MAX_OPEN_CONNS`, `LUI_DB_MMAP_MB`, `LUI_DB_SYNCHRONOUS`,
`LUI_DB_TYPE`, `LUI_DEBUG`, `LUI_DOMAIN`, `LUI_ENABLE_FAIL2BAN`,
`LUI_GOGC`, `LUI_HOME` (install-agent.sh only), `LUI_INIT_SYSTEM`
(install-agent.sh only), `LUI_INIT_WEB_BASE_PATH`, `LUI_IN_DOCKER`,
`LUI_LOG_FOLDER`, `LUI_LOG_LEVEL`, `LUI_MAIN_FOLDER`,
`LUI_MEMORY_LIMIT`, `LUI_MEMORY_RELEASE_INTERVAL`,
`LUI_NODE_TOKEN_KEY`, `LUI_NODE_TOKEN_KEY_FILE`,
`LUI_NODE_TOKEN_KEY_TEST`, `LUI_NONINTERACTIVE`,
`LUI_ORPHAN_DUMMY`, `LUI_PANEL_PORT`, `LUI_PASSWORD`, `LUI_PORT`,
`LUI_PPROF`, `LUI_RELEASE_BASE_URL`, `LUI_RELEASE_LATEST_URL`,
`LUI_ROOT` (install-agent.sh only), `LUI_SCALE_DB_PATH`,
`LUI_SCALE_SIZES`, `LUI_SCALE_TEST`, `LUI_SELFUPDATE_SYSTEMD`,
`LUI_SERVER_IP`, `LUI_SERVICE`, `LUI_SERVICE_NAME`,
`LUI_SINGBOX_BIN`, `LUI_SKIP_HSTS`, `LUI_SMOKE_VERSION`,
`LUI_SOURCEMAP`, `LUI_SSL_IPV6`, `LUI_SSL_MODE`,
`LUI_TEST_PG_DSN`, `LUI_TUNNEL_HEALTH_COOLDOWN`,
`LUI_TUNNEL_HEALTH_FAILURES`, `LUI_TUNNEL_HEALTH_INTERVAL`,
`LUI_TUNNEL_HEALTH_MONITOR`, `LUI_TUNNEL_HEALTH_PROXY`,
`LUI_TUNNEL_HEALTH_TIMEOUT`, `LUI_TUNNEL_HEALTH_URL`,
`LUI_UPDATE_RUN_ID`, `LUI_UPDATE_STATUS_FILE`, `LUI_UPDATE_TAG`,
`LUI_URL` (install scripts only), `LUI_USERNAME`,
`LUI_WEB_BASE_PATH`.
## sing-box orphan-core check (special re-verification)
The orphan scan (`internal/agent/singbox.go`,
`singboxCmdlineMatchesConfig`) matches a core process by the exact
argv triple `run -c <live config path>`. Both sides use the same
source: the live path is `filepath.Join(config.GetBinFolderPath(),
"config-singbox.json")`, and the agent sets `LUI_BIN_FOLDER` to
`DefaultBinFolder` (`/usr/local/l-ui/bin`) when unset. So the rename
propagates to both the writer and the matcher automatically; there
is no hardcoded old path in `singbox.go`. After migration the only
cores the new agent will reap are cores started with
`/usr/local/l-ui/bin/config-singbox.json` — a core still running
the old `/usr/local/x-ui/bin/config-singbox.json` is **not** matched
and must be killed by the migration step (see migration doc), or it
will hold the inbound ports and the new core will fail to bind.
This is the one place where "rename both sides" is not enough: the
old core has to be stopped, not re-adopted.
## Tianyi update badge (same batch, panel side only)
- Backend: `NodeView.agentOs` (from `AgentNode.ProbeOS`), overlaid
in `annotateAgentTelemetry` ahead of the telemetry early-exit,
like `ProbeOnly`.
- Frontend: both badge sites in `NodeList.tsx` (list column +
detail) now gate on `!isWindowsAgentOS(agentOs)`, where the
helper (in `panel-version.ts`) is a case-insensitive `windows`
prefix test. Empty OS fails open (badge as before).
- Backend: `requestAgentUpdate` refuses Windows rows up front
("not available on Windows … re-running install-agent.ps1")
instead of recording an intent that would only age out. The
one-click action button itself is unchanged; clicking it on a
Windows row now errors clearly.
- Why ProbeOS is reliable: the frozen A2.2.1 Windows agent reports
`probeFacts.os` = `winOSName()` — registry ProductName
("Windows 10", "Windows 11", …) with DisplayVersion appended,
falling back to bare "Windows" — on register and on heartbeat,
and the panel persists it to `probe_os` (pinned by
`TestAgentLegacyWindows221Contract`). No fake version, no
per-node freeze switch, no Windows agent change, no new win asset.
- Tianyi's machine itself is untouched; its agent stays A2.2.1.
## Intentionally kept (not omissions)
- **Go module path `github.com/mhsanaei/3x-ui/v3`** — the upstream
import path. Renaming it would break every import and the
`-ldflags -X` injection paths; it is not user-visible.
- **Upstream mentions** — sentences that name the upstream original
("upstream 3x-ui", "stock 3x-ui", "based on upstream 3x-ui",
`ghcr.io/mhsanaei/3x-ui`, `raw.githubusercontent.com/mhsanaei/3x-ui`)
stay, because that is the upstream project's actual name.
- **Windows agent, frozen** — `cmd/xui-agent-windows/` untouched:
service name `x-ui-agent`, `C:\x-ui\agent.json`, display name
"3x-ui Agent", `x-ui-agent-windows.exe`. The shipped A2.2.1
binary cannot change without a new win release, which this batch
explicitly does not ship. Renaming its source would only make
the source lie about the shipped binary.
- **`install-agent.ps1` untouched** — see Pending.
- **Log filenames `3xui.log`, `3xipl.log`, `3xipl-banned.log` and
the fail2ban jail name `3x-ipl`** — only their directory moves
(`/var/log/l-ui/`). Renaming the files would break external
fail2ban configs beyond the directory move the migration
already requires.
- **Docker Postgres user/DB `xui`** — renaming them would orphan
existing `pgdata` volumes (a fresh empty DB would appear and
the panel would start empty). Service/container names were
renamed (`l-ui`, `l-ui_app`, `l-ui_postgres`); credentials kept.
- **Windows-only DB copy in `internal/config/config.go` `init()`** —
its source is now explicitly `/etc/x-ui/x-ui.db` (the only
pre-rename path left in Go code, as a copy source only). Normal
operation never reads it; operator migration moves the DB by mv.
- **`install-agent.sh` legacy-process kill** — it now kills both
`/usr/local/l-ui/l-ui agent` and `/usr/local/x-ui/x-ui agent`.
The old form is a one-time migration cleanup, not a runtime
dual-path fallback; it can be deleted once old forms are gone.
- **`frontend/src/generated/schemas.ts`** — generated by
`tools/openapigen`, marked DO NOT EDIT. Its three "3x-ui panel"
descriptions come from Go model comments and will refresh on
the next regeneration; hand-editing a generated file would be
overwritten anyway.
- **Tracked test binaries `x-ui-agent-test-amd64`,
`x-ui-master-new-amd64`, `x-ui-with-ui-amd64`** — stale ELF
artifacts committed earlier, not referenced by any script or by
`release-build.sh`, not release assets. Left untouched (not
rebuilt, not renamed); deleting committed binaries is a separate
cleanup decision, not part of this rename.
- **`docs/release.md` version-table examples (V2.4.0 / A2.3.0)** —
pre-existing stale examples, not version constants; left as-is
so this diff stays a rename. The agent-change glob there now
reads `cmd/lui-agent*`, which correctly excludes the frozen
Windows dir (Windows-only changes must not move the agent line).
## Pending / must be decided before any release
1. **Gitea repo spelling (BLOCKER).** `rogue/l-ui` is a placeholder.
The Gitea repo has NOT been renamed in this batch and must not
be assumed renamed. Before any release: user confirms the exact
spelling, then update `internal/selfupdate/selfupdate.go`
(annotated in code), `internal/web/service/panel/panel.go`,
`scripts/release-build.sh`, `install-agent.sh`,
`install-master.sh`, `update.sh`, `install.sh`, `docs/release.md`
and every `rogue/l-ui` URL in the tree to the confirmed spelling.
Until then, the renamed update check points at a repo that does
not exist yet — this branch must not be released as-is.
2. **Version bump.** Panel stays V2.6.0, agent stays A2.5.0 in this
diff. The release step must bump the panel line (and the agent
line only if agent code changed in the release commit) and
`install-agent.sh`'s `RELEASE_BASE`.
3. **`install-agent.ps1` (Windows, frozen, TYYUN only).** Untouched
on purpose: it is pinned to the V2.4.0 release base and
downloads `x-ui-agent-windows-amd64.exe` into `C:\x-ui`.
After the Gitea repo is renamed, that download URL
(`rogue/3x-ui-agent/releases/download/V2.4.0/…`) will 404
unless one of these is chosen: (a) leave ps1 alone and accept
that a future Windows reinstall needs a manual exe (the frozen
line needs no reinstall by design); (b) update only its repo
segment to the confirmed spelling, keeping the V2.4.0 pin and
the old asset name (the V2.4.0 release's assets keep their old
names only if the repo is renamed without re-uploading them —
verify before choosing); (c) unfreeze Windows and ship a new
win asset (out of scope for this batch). Do NOT quietly bump
its pin to a release that has no win asset.
4. **Generated schemas regeneration** — run `tools/openapigen`
at release time so `frontend/src/generated/schemas.ts`
descriptions pick up the L-UI wording.
5. **Tracked test binaries** — decide separately whether to delete
the three stale ELF files from the repo.
+2 -2
View File
@@ -1,6 +1,6 @@
# Review instructions
3x-ui is a Go (Gin + GORM) web panel that generates configuration, share links
L-UI is a Go (Gin + GORM) web panel that generates configuration, share links
and subscriptions for other programs — Xray-core, mihomo, sing-box, mtg-multi —
and is deployed by operators who upgrade in place. Judge findings by what
breaks for those consumers and operators, not by style.
@@ -111,7 +111,7 @@ near-certain about and that actually breaks something:
- "CI passed" is a claim too, and needs the same evidence: say it only of a
run you actually read. A green one proves less here than it looks — only
`postgres-durable-first` runs against PostgreSQL, `go-test` and `race` are
SQLite, and `XRAY_E2E_BINARY` and `XUI_SCALE_TEST` are set by no job, so
SQLite, and `XRAY_E2E_BINARY` and `LUI_SCALE_TEST` are set by no job, so
those tests have never run in CI at all. Where a change touches dialect,
migration or Xray gRPC code that no job exercised, say it is unverified
rather than repeating a green tick as proof.
+2 -2
View File
@@ -5,11 +5,11 @@
Do not open a public issue for anything you believe is exploitable — an
authentication bypass, remote code execution, injection, secret or
credential exposure, privilege escalation. A public report gives attackers
a head start against every 3x-ui deployment.
a head start against every L-UI deployment.
Instead, use GitHub's private vulnerability reporting: open this
repository's **Security** tab and click **Report a vulnerability**. Include
the affected 3x-ui version, reproduction steps, and the impact you see.
the affected L-UI version, reproduction steps, and the impact you see.
You will receive replies in the advisory thread.
There is no bug-bounty program. Fixes ship in the next release, and the
+4 -2
View File
@@ -125,7 +125,9 @@ func TestBotContextSkipGatesExist(t *testing.T) {
table := section(t, doc, "**What CI does NOT prove.**", "Mutation testing")
// [A-Z0-9_] and not [A-Z_]: XRAY_E2E_BINARY carries a digit, and excluding it
// silently dropped that gate from the check instead of failing.
gates := regexp.MustCompile("`((?:XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(table, -1)
// LUI_ joins XUI_ here because the rename changed the env prefix; the
// old prefix stays so a stray XUI_ gate still gets checked, not ignored.
gates := regexp.MustCompile("`((?:LUI|XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(table, -1)
if len(gates) < 5 {
t.Fatalf("expected at least 5 skip-gate variables in %s, found %d", botContextPath, len(gates))
}
@@ -171,7 +173,7 @@ func TestReviewNamesRealCIJobsAndGates(t *testing.T) {
}
})
}
for _, g := range regexp.MustCompile("`((?:XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(doc, -1) {
for _, g := range regexp.MustCompile("`((?:LUI|XUI|XRAY)_[A-Z0-9_]+)`").FindAllStringSubmatch(doc, -1) {
t.Run(g[1], func(t *testing.T) {
if strings.Contains(ci, g[1]) {
t.Errorf("%s claims %s is never set in CI, but %s sets it", reviewPath, g[1], ciWorkflowPath)
@@ -1,14 +1,14 @@
// Command xui-agent is the standalone Linux build of the 3x-ui node
// 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 two util leaves), so the node
// 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
// "xui-agent agent [-config /etc/x-ui/agent.json]" (the bare
// "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;
@@ -25,6 +25,8 @@ import (
"flag"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"path/filepath"
@@ -33,6 +35,7 @@ import (
"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"
)
@@ -58,7 +61,7 @@ func main() {
if len(args) > 0 && args[0] == "agent" {
args = args[1:]
} else if len(args) > 0 && args[0][0] != '-' {
fmt.Fprintf(os.Stderr, "xui-agent: unknown subcommand %q (this binary only runs the node agent)\n", args[0])
fmt.Fprintf(os.Stderr, "lui-agent: unknown subcommand %q (this binary only runs the node agent)\n", args[0])
os.Exit(2)
}
@@ -70,14 +73,14 @@ func main() {
func runAgent(args []string) {
agentCmd := flag.NewFlagSet("agent", flag.ExitOnError)
var configPath string
agentCmd.StringVar(&configPath, "config", "/etc/x-ui/agent.json", "Path to agent config file")
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("XUI_BIN_FOLDER") == "" {
_ = os.Setenv("XUI_BIN_FOLDER", agent.DefaultBinFolder)
if os.Getenv("LUI_BIN_FOLDER") == "" {
_ = os.Setenv("LUI_BIN_FOLDER", agent.DefaultBinFolder)
}
cfg, err := agent.LoadConfig(configPath)
@@ -86,7 +89,7 @@ func runAgent(args []string) {
}
// The acknowledged traffic baseline persists next to the agent
// config (its state home, e.g. /etc/x-ui), unless the config
// 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")
@@ -94,7 +97,24 @@ func runAgent(args []string) {
// Initialize logger
logger.InitLogger(logging.INFO)
log.Printf("Starting 3x-ui agent (node: %s)", cfg.NodeName)
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)
+9 -9
View File
@@ -1,6 +1,6 @@
# Cloud deployment (unattended install)
Tooling to ship the 3x-ui panel via unattended install, with **per-instance
Tooling to ship the L-UI panel via unattended install, with **per-instance
credentials generated on first boot** (never `admin/admin`, never a shared
session secret). Works on amd64 and arm64.
@@ -12,7 +12,7 @@ session secret). Works on amd64 and arm64.
## How it works
`install.sh` runs unattended when `XUI_NONINTERACTIVE=1` or stdin is not a TTY.
`install.sh` runs unattended when `LUI_NONINTERACTIVE=1` or stdin is not a TTY.
Each instance installs and configures itself with random credentials. See
[`cloud-init/README.md`](cloud-init/README.md).
@@ -21,11 +21,11 @@ Each instance installs and configures itself with random credentials. See
`install.sh` reads these env vars in non-interactive mode (all optional; unset ⇒
secure random / default):
`XUI_USERNAME`, `XUI_PASSWORD`, `XUI_PANEL_PORT`, `XUI_WEB_BASE_PATH`,
`XUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `XUI_DOMAIN`,
`XUI_ACME_EMAIL`, `XUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`),
`XUI_SSL_IPV6` (optional IPv6 address to add to an `ip`-mode cert),
`XUI_SERVER_IP` (fallback IP for the displayed access URL when auto-detection fails),
`XUI_DB_TYPE` (`sqlite`|`postgres`), `XUI_DB_DSN`.
`LUI_USERNAME`, `LUI_PASSWORD`, `LUI_PANEL_PORT`, `LUI_WEB_BASE_PATH`,
`LUI_SSL_MODE` (`none`|`ip`|`domain`, default `none`), `LUI_DOMAIN`,
`LUI_ACME_EMAIL`, `LUI_ACME_HTTP_PORT` (ACME HTTP-01 listener port, default `80`),
`LUI_SSL_IPV6` (optional IPv6 address to add to an `ip`-mode cert),
`LUI_SERVER_IP` (fallback IP for the displayed access URL when auto-detection fails),
`LUI_DB_TYPE` (`sqlite`|`postgres`), `LUI_DB_DSN`.
The resulting credentials are written to `/etc/x-ui/install-result.env` (mode 600).
The resulting credentials are written to `/etc/l-ui/install-result.env` (mode 600).
+14 -14
View File
@@ -1,6 +1,6 @@
# 3x-ui via cloud-init
# L-UI via cloud-init
A single [`cloud-init.yaml`](cloud-init.yaml) user-data file that installs 3x-ui
A single [`cloud-init.yaml`](cloud-init.yaml) user-data file that installs L-UI
non-interactively on a fresh Ubuntu/Debian VM and generates **unique random
credentials per instance**. It works on any cloud-init platform.
@@ -8,35 +8,35 @@ credentials per instance**. It works on any cloud-init platform.
1. The VM boots a stock Ubuntu/Debian cloud image.
2. cloud-init writes and runs `/opt/xui-bootstrap.sh`, which exports
`XUI_NONINTERACTIVE=1` and pipes the project's `install.sh` into `bash`.
`LUI_NONINTERACTIVE=1` and pipes the project's `install.sh` into `bash`.
3. `install.sh` runs end-to-end with **zero prompts**, picking secure random
values for any credential you didn't pin.
4. The generated credentials are written to `/etc/x-ui/install-result.env`
4. The generated credentials are written to `/etc/l-ui/install-result.env`
(mode 600), echoed to the **serial console**, and appended to `/etc/motd`.
Retrieve them after boot with either:
```bash
sudo cat /etc/x-ui/install-result.env # over SSH
sudo cat /etc/l-ui/install-result.env # over SSH
```
…or read the provider's **serial console** output (handy before you have SSH).
## Customising
Edit the `export XUI_*` lines inside the `write_files` block of
Edit the `export LUI_*` lines inside the `write_files` block of
[`cloud-init.yaml`](cloud-init.yaml). All knobs are optional; unset ⇒ random/secure default.
| Env var | Default | Meaning |
| --- | --- | --- |
| `XUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` |
| `XUI_USERNAME` | random | Admin username |
| `XUI_PASSWORD` | random | Admin password |
| `XUI_PANEL_PORT` | random high port | Panel listen port |
| `XUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) |
| `XUI_DOMAIN` | — | Required when `XUI_SSL_MODE=domain` |
| `XUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) |
| `XUI_DB_TYPE` / `XUI_DB_DSN` | `sqlite` | Set `postgres` + DSN to use PostgreSQL |
| `LUI_SSL_MODE` | `none` | `none` (plain HTTP), `ip` (Let's Encrypt IP cert), `domain` |
| `LUI_USERNAME` | random | Admin username |
| `LUI_PASSWORD` | random | Admin password |
| `LUI_PANEL_PORT` | random high port | Panel listen port |
| `LUI_WEB_BASE_PATH` | random | Panel base path (obscures the URL) |
| `LUI_DOMAIN` | — | Required when `LUI_SSL_MODE=domain` |
| `LUI_ACME_EMAIL` | — | Let's Encrypt account email (domain mode) |
| `LUI_DB_TYPE` / `LUI_DB_DSN` | `sqlite` | Set `postgres` + DSN to use PostgreSQL |
> **TLS note:** `none` serves the panel over plain HTTP on a random high port —
> fine behind a reverse proxy or an SSH tunnel, but put TLS in front of it before
+26 -26
View File
@@ -1,19 +1,19 @@
#cloud-config
# ---------------------------------------------------------------------------
# Generic 3x-ui unattended install via cloud-init user-data.
# Generic L-UI unattended install via cloud-init user-data.
#
# Works on any cloud-init platform: Hetzner, AWS, DigitalOcean, Vultr, GCP,
# Azure, Oracle. Paste the whole file as the instance "user data".
#
# It installs the latest 3x-ui release NON-INTERACTIVELY, generating unique
# It installs the latest L-UI release NON-INTERACTIVELY, generating unique
# random credentials per instance. Full credentials are surfaced ONLY on the
# serial console (owner-only); /etc/motd (world-readable) shows just the access
# URL + username. Nothing is baked in advance — every instance is unique.
#
# Fork note (3x-ui-agent): the bootstrap below installs this fork's
# Fork note (L-UI): the bootstrap below installs this fork's
# install-master.sh from its own Gitea repository. The fork installer does
# NOT consume the XUI_* non-interactive knobs and does NOT write
# /etc/x-ui/install-result.env, so the XUI_* exports and the credential-
# 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.
# ---------------------------------------------------------------------------
@@ -30,46 +30,46 @@ write_files:
export DEBIAN_FRONTEND=noninteractive
# --- Non-interactive install knobs --------------------------------------
export XUI_NONINTERACTIVE=1
export LUI_NONINTERACTIVE=1
# SSL mode: none (plain HTTP, default) | ip | domain
export XUI_SSL_MODE="${XUI_SSL_MODE:-none}"
export LUI_SSL_MODE="${LUI_SSL_MODE:-none}"
# Pin credentials instead of random (leave unset for secure random values):
# export XUI_USERNAME="admin2"
# export XUI_PASSWORD="change-me-please"
# export XUI_PANEL_PORT="2053"
# export XUI_WEB_BASE_PATH="panel"
# export LUI_USERNAME="admin2"
# export LUI_PASSWORD="change-me-please"
# export LUI_PANEL_PORT="2053"
# export LUI_WEB_BASE_PATH="panel"
# Let's Encrypt domain certificate instead of plain HTTP:
# export XUI_SSL_MODE="domain"
# export XUI_DOMAIN="panel.example.com"
# export XUI_ACME_EMAIL="you@example.com"
# export LUI_SSL_MODE="domain"
# export LUI_DOMAIN="panel.example.com"
# export LUI_ACME_EMAIL="you@example.com"
# PostgreSQL instead of SQLite:
# export XUI_DB_TYPE="postgres"
# export XUI_DB_DSN="postgres://user:pass@host:5432/db?sslmode=disable"
# export LUI_DB_TYPE="postgres"
# export LUI_DB_DSN="postgres://user:pass@host:5432/db?sslmode=disable"
# ------------------------------------------------------------------------
curl -fsSL https://git.881218.xyz/rogue/3x-ui-agent/raw/branch/main/install-master.sh | bash
curl -fsSL https://git.881218.xyz/rogue/l-ui/raw/branch/main/install-master.sh | bash
# Surface the generated credentials. Full creds (incl. password + API token)
# go ONLY to the serial console (/dev/console, owner-only). /etc/motd is
# world-readable, so it gets just the access URL + username and a pointer
# to the root-only env file.
if [ -r /etc/x-ui/install-result.env ]; then
if [ -r /etc/l-ui/install-result.env ]; then
{
echo
echo "=== 3x-ui panel credentials (generated on first boot) ==="
cat /etc/x-ui/install-result.env
echo "=== L-UI panel credentials (generated on first boot) ==="
cat /etc/l-ui/install-result.env
echo "========================================================"
echo "Change the password after first login."
} > /dev/console 2>/dev/null || true
# shellcheck disable=SC1091
. /etc/x-ui/install-result.env
. /etc/l-ui/install-result.env
{
echo
echo "=== 3x-ui panel (generated on first boot) ==="
echo "URL: ${XUI_ACCESS_URL:-unknown}"
echo "Username: ${XUI_USERNAME:-unknown}"
echo "Password + API token: sudo cat /etc/x-ui/install-result.env"
echo "=== L-UI panel (generated on first boot) ==="
echo "URL: ${LUI_ACCESS_URL:-unknown}"
echo "Username: ${LUI_USERNAME:-unknown}"
echo "Password + API token: sudo cat /etc/l-ui/install-result.env"
echo "============================================="
echo "Change the password after first login."
} >> /etc/motd 2>/dev/null || true
@@ -78,4 +78,4 @@ write_files:
runcmd:
- [bash, /opt/xui-bootstrap.sh]
final_message: "3x-ui installed — full credentials in /etc/x-ui/install-result.env (sudo); /etc/motd shows the URL + username only."
final_message: "L-UI installed — full credentials in /etc/l-ui/install-result.env (sudo); /etc/motd shows the URL + username only."
+5 -5
View File
@@ -1,13 +1,13 @@
# 3x-ui on Hetzner Cloud
# L-UI on Hetzner Cloud
Hetzner Cloud does **not** have a third-party image marketplace the way AWS does.
Ship 3x-ui via **cloud-init**: each instance installs non-interactively and
Ship L-UI via **cloud-init**: each instance installs non-interactively and
generates unique per-instance credentials (no `admin/admin`, no shared secret).
## cloud-init (no image build)
Use the generic user-data from [`../../cloud-init/`](../../cloud-init/). It installs
3x-ui non-interactively and generates unique per-instance credentials.
L-UI non-interactively and generates unique per-instance credentials.
Web console: **Create Server → Cloud config** → paste
[`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml).
@@ -25,13 +25,13 @@ hcloud server create \
After boot, fetch the generated credentials:
```bash
ssh root@<server-ip> 'cat /etc/x-ui/install-result.env'
ssh root@<server-ip> 'cat /etc/l-ui/install-result.env'
```
## "App"-style listing
Hetzner's curated apps live in the community repo
[`github.com/hetznercloud/apps`](https://github.com/hetznercloud/apps): each app
is essentially a documented cloud-init config plus metadata. To propose 3x-ui as
is essentially a documented cloud-init config plus metadata. To propose L-UI as
a Hetzner app, follow that repo's contribution pattern and base the app's
cloud-config on [`deploy/cloud-init/cloud-init.yaml`](../../cloud-init/cloud-init.yaml).
+31 -31
View File
@@ -3,8 +3,8 @@
# smoke-noninteractive.sh — verify the non-interactive install path.
#
# Runs install.sh inside an Ubuntu container with NO TTY (piped) and
# XUI_NONINTERACTIVE=1, then asserts:
# * /etc/x-ui/install-result.env exists (mode 600) with random, non-default creds
# LUI_NONINTERACTIVE=1, then asserts:
# * /etc/l-ui/install-result.env exists (mode 600) with random, non-default creds
# * the panel reports hasDefaultCredential: false (no admin/admin remains)
# * the panel HTTP server actually serves on the generated port/base path
# * with a [version] argument: the installed binary reports exactly that version
@@ -18,41 +18,41 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
IMAGE="${SMOKE_IMAGE:-ubuntu:24.04}"
XUI_SMOKE_VERSION="${1:-}"
LUI_SMOKE_VERSION="${1:-}"
if ! command -v docker > /dev/null 2>&1; then
echo "ERROR: docker is required for this smoke test." >&2
exit 1
fi
echo "== non-interactive install smoke test (image: $IMAGE, version: ${XUI_SMOKE_VERSION:-latest}) =="
echo "== non-interactive install smoke test (image: $IMAGE, version: ${LUI_SMOKE_VERSION:-latest}) =="
docker run --rm \
-v "${REPO_ROOT}/install.sh:/root/install.sh:ro" \
-e XUI_NONINTERACTIVE=1 \
-e XUI_SSL_MODE=none \
-e XUI_SMOKE_VERSION="$XUI_SMOKE_VERSION" \
-e LUI_NONINTERACTIVE=1 \
-e LUI_SSL_MODE=none \
-e LUI_SMOKE_VERSION="$LUI_SMOKE_VERSION" \
-e DEBIAN_FRONTEND=noninteractive \
"$IMAGE" bash -euo pipefail -c '
apt-get update -qq
apt-get install -y -qq curl tar openssl ca-certificates > /dev/null
echo "--- running install.sh piped (no TTY), version: ${XUI_SMOKE_VERSION:-latest} ---"
echo "--- running install.sh piped (no TTY), version: ${LUI_SMOKE_VERSION:-latest} ---"
# Piping guarantees stdin is not a TTY, exercising the auto non-interactive path.
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else
cat /root/install.sh | bash
fi
echo "--- assertions ---"
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
installed=$(/usr/local/x-ui/x-ui -v)
[ "$installed" = "${XUI_SMOKE_VERSION#v}" ] \
|| { echo "FAIL: installed version $installed, want ${XUI_SMOKE_VERSION#v}"; exit 1; }
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
installed=$(/usr/local/l-ui/l-ui -v)
[ "$installed" = "${LUI_SMOKE_VERSION#v}" ] \
|| { echo "FAIL: installed version $installed, want ${LUI_SMOKE_VERSION#v}"; exit 1; }
fi
RESULT=/etc/x-ui/install-result.env
RESULT=/etc/l-ui/install-result.env
test -f "$RESULT" || { echo "FAIL: $RESULT missing"; exit 1; }
perms=$(stat -c %a "$RESULT")
@@ -60,23 +60,23 @@ docker run --rm \
# shellcheck disable=SC1090
. "$RESULT"
[ -n "${XUI_USERNAME:-}" ] && [ "$XUI_USERNAME" != "admin" ] \
[ -n "${LUI_USERNAME:-}" ] && [ "$LUI_USERNAME" != "admin" ] \
|| { echo "FAIL: username missing or still admin"; exit 1; }
[ -n "${XUI_PASSWORD:-}" ] && [ "$XUI_PASSWORD" != "admin" ] \
[ -n "${LUI_PASSWORD:-}" ] && [ "$LUI_PASSWORD" != "admin" ] \
|| { echo "FAIL: password missing or still admin"; exit 1; }
[ -n "${XUI_PANEL_PORT:-}" ] || { echo "FAIL: port missing"; exit 1; }
[ -n "${LUI_PANEL_PORT:-}" ] || { echo "FAIL: port missing"; exit 1; }
# No default admin in the DB.
/usr/local/x-ui/x-ui setting -show | grep -q "hasDefaultCredential: false" \
/usr/local/l-ui/l-ui setting -show | grep -q "hasDefaultCredential: false" \
|| { echo "FAIL: hasDefaultCredential is not false"; exit 1; }
echo "--- verifying the panel serves HTTP ---"
cd /usr/local/x-ui
./x-ui > /tmp/xui.log 2>&1 &
cd /usr/local/l-ui
./l-ui > /tmp/lui.log 2>&1 &
xpid=$!
for _ in $(seq 1 15); do
code=$(curl -s -o /dev/null -w "%{http_code}" \
"http://127.0.0.1:${XUI_PANEL_PORT}/${XUI_WEB_BASE_PATH}/" 2>/dev/null || true)
"http://127.0.0.1:${LUI_PANEL_PORT}/${LUI_WEB_BASE_PATH}/" 2>/dev/null || true)
case "$code" in 200|301|302|307|308) break ;; esac
sleep 1
done
@@ -84,28 +84,28 @@ docker run --rm \
echo "panel HTTP status: ${code:-none}"
case "${code:-}" in
200|301|302|307|308) : ;;
*) echo "FAIL: panel did not serve (status ${code:-none})"; tail -n 30 /tmp/xui.log; exit 1 ;;
*) echo "FAIL: panel did not serve (status ${code:-none})"; tail -n 30 /tmp/lui.log; exit 1 ;;
esac
echo "--- verifying a second install preserves custom bin/ files ---"
echo "custom-sentinel" > /usr/local/x-ui/bin/geoip_custom.dat
geoip_sum_before=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
echo "custom-sentinel" > /usr/local/l-ui/bin/geoip_custom.dat
geoip_sum_before=$(sha256sum /usr/local/l-ui/bin/geoip.dat | cut -d" " -f1)
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
if [ -n "${LUI_SMOKE_VERSION:-}" ]; then
cat /root/install.sh | bash -s -- "$LUI_SMOKE_VERSION"
else
cat /root/install.sh | bash
fi
test -f /usr/local/x-ui/bin/geoip_custom.dat \
test -f /usr/local/l-ui/bin/geoip_custom.dat \
|| { echo "FAIL: custom bin/ file did not survive a second install"; exit 1; }
[ "$(cat /usr/local/x-ui/bin/geoip_custom.dat)" = "custom-sentinel" ] \
[ "$(cat /usr/local/l-ui/bin/geoip_custom.dat)" = "custom-sentinel" ] \
|| { echo "FAIL: custom bin/ file content changed across a second install"; exit 1; }
geoip_sum_after=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
geoip_sum_after=$(sha256sum /usr/local/l-ui/bin/geoip.dat | cut -d" " -f1)
[ "$geoip_sum_after" = "$geoip_sum_before" ] \
|| { echo "FAIL: bundled geoip.dat changed across a same-version reinstall"; exit 1; }
echo "SMOKE_PASS: user=$XUI_USERNAME port=$XUI_PANEL_PORT path=$XUI_WEB_BASE_PATH"
echo "SMOKE_PASS: user=$LUI_USERNAME port=$LUI_PANEL_PORT path=$LUI_WEB_BASE_PATH"
'
echo "== non-interactive smoke test PASSED =="
+15 -15
View File
@@ -1,14 +1,14 @@
services:
3xui:
l-ui:
build:
context: .
dockerfile: ./Dockerfile
container_name: 3xui_app
container_name: l-ui_app
# hostname: yourhostname <- optional
# Optional hard memory cap. When set, the panel derives its Go soft limit
# (GOMEMLIMIT, ~90% of this cap) so it GCs before the OOM killer fires.
# mem_limit: 512m
# The bundled Fail2ban (XUI_ENABLE_FAIL2BAN below) enforces the IP limit
# The bundled Fail2ban (LUI_ENABLE_FAIL2BAN below) enforces the IP limit
# with iptables, which needs NET_ADMIN. Without these caps a ban is logged
# and shown in fail2ban status but never actually applied. NET_RAW covers
# ip6tables. If you disable Fail2ban, you can drop cap_add.
@@ -20,39 +20,39 @@ services:
- NET_ADMIN
- NET_RAW
volumes:
- $PWD/db/:/etc/x-ui/
- $PWD/db/:/etc/l-ui/
- $PWD/cert/:/root/cert/
# Persists acme.sh state so certificate auto-renewal survives container
# recreation (the entrypoint re-registers the renewal cron job from it).
- $PWD/acme/:/root/.acme.sh/
environment:
XRAY_VMESS_AEAD_FORCED: "false"
XUI_ENABLE_FAIL2BAN: "true"
LUI_ENABLE_FAIL2BAN: "true"
# Memory tuning. The panel keeps RAM low via GOGC + periodic release; it no
# longer sets a soft limit from total host RAM (no benefit, risks GC thrash).
# XUI_GOGC: "75" # lower = less RAM, slightly more CPU; GOGC env overrides
# XUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables
# LUI_GOGC: "75" # lower = less RAM, slightly more CPU; GOGC env overrides
# LUI_MEMORY_RELEASE_INTERVAL: "10" # minutes between FreeOSMemory; 0 disables
# Go memory soft limit, only applied from an explicit budget below (or a
# real cgroup/mem_limit cap). Pin it with one of:
# XUI_MEMORY_LIMIT: "400" # in MiB
# LUI_MEMORY_LIMIT: "400" # in MiB
# GOMEMLIMIT: "400MiB" # Go syntax, takes precedence
# XUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling
# XUI_INIT_WEB_BASE_PATH: "/"
# XUI_PORT: "8080"
# LUI_PPROF: "true" # expose pprof on 127.0.0.1:6060 for profiling
# LUI_INIT_WEB_BASE_PATH: "/"
# LUI_PORT: "8080"
# To use PostgreSQL instead of the default SQLite, run:
# docker compose --profile postgres up -d
# and uncomment the two lines below.
# XUI_DB_TYPE: "postgres"
# XUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable"
# LUI_DB_TYPE: "postgres"
# LUI_DB_DSN: "postgres://xui:xui@postgres:5432/xui?sslmode=disable" # postgres user/db kept: renaming them would orphan existing pgdata
tty: true
ports:
# When XUI_PORT is set, publish the same container port (for example "8080:8080").
# When LUI_PORT is set, publish the same container port (for example "8080:8080").
- "2053:2053"
restart: unless-stopped
postgres:
image: postgres:16-alpine
container_name: 3xui_postgres
container_name: l-ui_postgres
profiles: ["postgres"]
environment:
POSTGRES_USER: xui
+21 -21
View File
@@ -1,13 +1,13 @@
# 3x-ui Agent 模式安装说明
# L-UI Agent 模式安装说明
节点鸡不再跑完整 3x-ui 面板,只跑一个轻量 agent:用 token 向主控注册,
节点鸡不再跑完整 L-UI 面板,只跑一个轻量 agent:用 token 向主控注册,
主控下发完整 xray 配置(含入站、出站、路由规则),agent 写配置并管理 xray 进程,
每 60 秒向主控上报流量/在线数。
## 架构
- 主控:完整 3x-ui(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。
- 节点:`x-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。
- 主控:完整 L-UI(v3.7.0+agent 补丁),负责生成配置、下发、管理出站与路由规则。
- 节点:`l-ui agent` 二进制 + xray 二进制 + geo 文件,无面板、无数据库。
- 出站/路由规则只能在主控上建和改(面板是唯一可信源),agent 只管应用下发
的完整配置,不上报本地配置。
@@ -35,24 +35,24 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
## 二、节点安装
```bash
mkdir -p /usr/local/x-ui/bin /etc/x-ui
mkdir -p /usr/local/l-ui/bin /etc/l-ui
# 1. 放 x-ui 二进制(agent 补丁版,与主控同版本),在节点上改名为 xui-agent(与主控进程区分)
cp x-ui /usr/local/x-ui/xui-agent && chmod +x /usr/local/x-ui/xui-agent
# 1. 放 l-ui 二进制(agent 补丁版,与主控同版本),在节点上改名为 lui-agent(与主控进程区分)
cp l-ui /usr/local/l-ui/lui-agent && chmod +x /usr/local/l-ui/lui-agent
# 2. 放 xray 二进制与 geo 文件(agent 不负责下载,手动放置)
cp xray-linux-amd64 /usr/local/x-ui/bin/xray && chmod +x /usr/local/x-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/x-ui/bin/
cp xray-linux-amd64 /usr/local/l-ui/bin/xray && chmod +x /usr/local/l-ui/bin/xray
cp geoip.dat geosite.dat /usr/local/l-ui/bin/
# 3. 写 agent 配置
cat > /etc/x-ui/agent.json <<'EOF'
cat > /etc/l-ui/agent.json <<'EOF'
{
"master_url": "http://主控内网地址:2053",
"token": "<上一步生成的 token>",
"node_name": "hk-node-1"
}
EOF
chmod 600 /etc/x-ui/agent.json
chmod 600 /etc/l-ui/agent.json
```
说明:
@@ -60,27 +60,27 @@ chmod 600 /etc/x-ui/agent.json
- `master_url` 用 `http://`(内网)或 `https://`(需可信证书;自签证书连不上,
agent 默认校验 TLS)。
- `poll_interval` 可省略,默认 30 秒轮询一次配置。
- 不要在节点上再启动完整面板(`x-ui` 不带 `agent` 参数的模式)。
- 不要在节点上再启动完整面板(`l-ui` 不带 `agent` 参数的模式)。
## 三、启动 agent
systemd(Debian/Ubuntu):
```bash
cp systemd/x-ui-agent.service /etc/systemd/system/
cp systemd/lui-agent.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now x-ui-agent
journalctl -u x-ui-agent -f
systemctl enable --now lui-agent
journalctl -u lui-agent -f
```
OpenWrt(procd):
```bash
cp openrc/x-ui-agent /etc/init.d/x-ui-agent
chmod +x /etc/init.d/x-ui-agent
/etc/init.d/x-ui-agent enable
/etc/init.d/x-ui-agent start
logread -f | grep x-ui-agent
cp openrc/lui-agent /etc/init.d/lui-agent
chmod +x /etc/init.d/lui-agent
/etc/init.d/lui-agent enable
/etc/init.d/lui-agent start
logread -f | grep lui-agent
```
## 四、主控管理该节点的出站与路由规则
@@ -120,6 +120,6 @@ curl -sk -H "Authorization: Bearer <PANEL_API_TOKEN>" \
|---|---|
| `register failed ... 401` | token 贴错,或 token 没在主控生成 |
| `config fetch failed ... 409` | token 未绑定节点(生成时没传 `node_id`) |
| xray 起不来 | `/usr/local/x-ui/bin/xray` 是否存在可执行;`xray -test -c /usr/local/x-ui/bin/config.json` 看配置报错 |
| xray 起不来 | `/usr/local/l-ui/bin/xray` 是否存在可执行;`xray -test -c /usr/local/l-ui/bin/config.json` 看配置报错 |
| 流量不上报 | xray 的 api 入站端口是否被占用;agent 日志看 `Traffic report failed` |
| 主控连不上 | `master_url` 拼错;https 自签证书改走 `http://` 内网地址 |
+2 -2
View File
@@ -1,6 +1,6 @@
# Contributing to 3x-ui-docs
# Contributing to L-UI-docs
Thanks for helping improve the 3x-ui documentation and product site!
Thanks for helping improve the L-UI documentation and product site!
## Prerequisites
+6 -6
View File
@@ -2,22 +2,22 @@
<a href="https://docs.sanaei.dev">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="public/logo-dark.png" />
<img src="public/logo-light.png" alt="3x-ui" width="180" />
<img src="public/logo-light.png" alt="L-UI" width="180" />
</picture>
</a>
</p>
<h1 align="center">3x-ui Documentation</h1>
<h1 align="center">L-UI Documentation</h1>
<p align="center">
The official documentation and product site for
<a href="https://github.com/MHSanaei/3x-ui"><b>3x-ui</b></a> —
<a href="https://github.com/MHSanaei/L-UI"><b>L-UI</b></a> —
an advanced web panel for managing Xray-core servers.
</p>
<p align="center">
<a href="https://docs.sanaei.dev"><img src="https://img.shields.io/badge/docs-docs.sanaei.dev-22d3ee?style=flat-square" alt="Live site" /></a>
<a href="https://github.com/MHSanaei/3x-ui/actions/workflows/docs-ci.yml"><img src="https://github.com/MHSanaei/3x-ui/actions/workflows/docs-ci.yml/badge.svg" alt="CI" /></a>
<a href="https://github.com/MHSanaei/L-UI/actions/workflows/docs-ci.yml"><img src="https://github.com/MHSanaei/L-UI/actions/workflows/docs-ci.yml/badge.svg" alt="CI" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-GPL--3.0-blue?style=flat-square" alt="License: GPL-3.0" /></a>
<img src="https://img.shields.io/badge/Next.js-16-black?style=flat-square&logo=next.js" alt="Next.js 16" />
<img src="https://img.shields.io/badge/Fumadocs-16-0ea5e9?style=flat-square" alt="Fumadocs 16" />
@@ -31,7 +31,7 @@
## Overview
This directory (`docs/` in the [3x-ui](https://github.com/MHSanaei/3x-ui) monorepo) contains
This directory (`docs/` in the [L-UI](https://github.com/MHSanaei/L-UI) monorepo) contains
the source for [docs.sanaei.dev](https://docs.sanaei.dev) — a static-first documentation and
marketing site built with [Fumadocs](https://fumadocs.dev) on Next.js. It has **no backend,
no database, and no auth**: every page is prerendered and every tool runs entirely in the
@@ -39,7 +39,7 @@ browser.
## What's inside
The documentation walks you through 3x-ui from first install to day-to-day operation:
The documentation walks you through L-UI from first install to day-to-day operation:
- **Getting Started** — installation, first login, and updating or uninstalling the panel.
- **Configuration** — the panel, inbounds, REALITY, transports, clients, subscriptions, and share links.
+1 -1
View File
@@ -2,7 +2,7 @@
@import 'fumadocs-ui/css/neutral.css';
@import 'fumadocs-ui/css/preset.css';
/* 3x-ui brand: cyan / turquoise accent (matches the panel logo). */
/* L-UI brand: cyan / turquoise accent (matches the panel logo). */
:root {
--color-fd-primary: hsl(190, 95%, 39%);
--color-fd-primary-foreground: hsl(0, 0%, 100%);
+19 -22
View File
@@ -1,4 +1,4 @@
# 3x-ui — Architecture & Code Map
# L-UI — Architecture & Code Map
> Navigation map for contributors and AI coding agents (referenced from `CLAUDE.md`).
> Goal: jump to the right file in one hop instead of grepping the whole tree.
@@ -13,7 +13,7 @@
## 1. Mental model (the 30-second version)
3x-ui is a **web control panel for [Xray-core](https://github.com/XTLS/Xray-core)**. The Go
L-UI is a **web control panel for [Xray-core](https://github.com/XTLS/Xray-core)**. The Go
backend is the source of truth: it stores inbounds/clients/settings in a DB, renders an
Xray JSON config from that state, supervises the Xray child process, and exposes a REST +
WebSocket API. A React SPA (built by Vite, embedded into the Go binary) is the UI. A second,
@@ -41,7 +41,7 @@ Two key ideas that explain most of the complexity:
1. **The DB → Xray config pipeline.** Inbounds/clients live in the DB. On every change the
backend regenerates the Xray config and applies it — preferring a _hot diff_ (live gRPC
API mutation) over a full process restart. See §5.1.
2. **The Runtime abstraction (multi-node).** A panel can manage remote "nodes" (other 3x-ui
2. **The Runtime abstraction (multi-node).** A panel can manage remote "nodes" (other L-UI
instances). Every state-changing inbound/client operation is dispatched through a
`runtime.Runtime` interface that is either **`Local`** (this box's Xray gRPC API) or
**`Remote`** (HTTPS call to a child node, with `verify`/`skip`/`pin`/`mtls` TLS modes).
@@ -54,7 +54,7 @@ Two key ideas that explain most of the complexity:
**Backend (Go 1.27):**
- Web framework: **Gin** (`gin-gonic/gin`) + sessions (cookie store), gzip.
- ORM: **GORM** with **SQLite** (default) or **PostgreSQL** (`XUI_DB_TYPE=postgres`).
- ORM: **GORM** with **SQLite** (default) or **PostgreSQL** (`LUI_DB_TYPE=postgres`).
- Scheduler: **robfig/cron/v3** (seconds-precision) for all background jobs.
- Xray: **xtls/xray-core** vendored as a library; the panel talks to the running core over
its **gRPC API** and also shells out to manage the process.
@@ -85,7 +85,7 @@ Browser (React, fetch)
→ POST {basePath}/panel/api/...
→ Gin engine (internal/web/web.go: initRouter)
→ middleware chain: SecurityHeaders → MaxBodyBytes (10 MiB; importDB exempt)
→ [DomainValidator, if webDomain set] → gzip → sessions("3x-ui")
→ [DomainValidator, if webDomain set] → gzip → sessions("L-UI")
→ base-path/cache-control context → Localizer
→ API routes add: ConfigEnvelope (zstd + SHA-256) → CSRF
→ Controller (internal/web/controller/*.go) // HTTP concerns only: bind, validate, respond
@@ -120,14 +120,14 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
## 4. Directory map (what lives where)
```
3x-ui/
L-UI/
├── main.go # Entry point: CLI (run / migrate / migrate-db / setting / cert),
│ # bootstrap, signal handling, restart loop
├── go.mod / go.sum # Go deps (module path ends in /v3)
│
├── internal/ # ALL backend Go code (private packages)
│ ├── config/ # Env-var config: paths, DB kind/DSN, log level, version
│ │ # Every XUI_* env var is read here (config.go)
│ │ # Every LUI_* env var is read here (config.go)
│ ├── database/
│ │ ├── db.go # InitDB: connect, AutoMigrate, seeders (~1.4k lines). DB hotspot.
│ │ ├── migrate_data.go # Data migrations (seeders/normalizers beyond AutoMigrate)
@@ -139,7 +139,7 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ ├── pia/ # PIA WireGuard protocol client (auth, signed server list, /addKey)
│ ├── eventbus/ # In-process pub/sub (buffered channel): outbound.down|up,
│ │ # xray.crash, node.down|up, cpu.high, memory.high, login.attempt
│ ├── tunnelmonitor/ # Optional tunnel health probe (XUI_TUNNEL_HEALTH_* env vars):
│ ├── tunnelmonitor/ # Optional tunnel health probe (LUI_TUNNEL_HEALTH_* env vars):
│ │ # HTTP probe (default Cloudflare trace); repeated failures
│ │ # trigger an Xray restart hook. Independent of panel settings.
│ ├── xray/ # Xray-core integration (the proxy engine wrapper)
@@ -163,9 +163,9 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ │ │ ├── node.go # /panel/api/nodes (multi-node management)
│ │ │ ├── host.go # /panel/api/hosts (per-inbound subscription host overrides)
│ │ │ ├── server.go # /panel/api/server (status, xray version, certs, logs, DB import/export)
│ │ │ ├── setting.go # /panel/api/setting (settings + API tokens)
│ │ │ ├── setting.go # /panel/api/setting (settings)
│ │ │ ├── xray_setting.go # /panel/api/xray (raw Xray config editor, WARP/Nord/PIA, geodata)
│ │ │ ├── api.go # /panel/api gateway (token auth, envelope + CSRF wiring)
│ │ │ ├── api.go # /panel/api gateway (envelope + CSRF wiring)
│ │ │ ├── index.go # login/logout/csrf/2FA
│ │ │ ├── spa.go # SPA fallback for /panel UI routes
│ │ │ └── websocket.go # WS upgrade endpoint
@@ -203,12 +203,11 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
│ │ │ ├── port_conflict.go # Detect inbound port collisions
│ │ │ ├── fallback.go # Xray fallback (SNI/ALPN routing on shared port)
│ │ │ ├── email/ # Email notification service (SMTP)
│ │ │ ├── integration/ # External providers: warp.go, nord.go, pia.go
│ │ │ ├── integration/ # External providers: warp.go
│ │ │ ├── outbound/ # Outbound config service
│ │ │ ├── panel/ # Cross-cutting panel services:
│ │ │ │ ├── panel.go # panel-level helpers
│ │ │ │ ├── user.go # admin user auth (bcrypt)
│ │ │ │ ├── api_token.go # API token CRUD (SHA-256 hashed)
│ │ │ │ └── websocket.go # WS hub / push service
│ │ │ └── tgbot/ # Telegram bot command handlers
│ │ ├── runtime/ # ⭐⭐ The Local/Remote node abstraction (see §5.2)
@@ -281,8 +280,8 @@ node heartbeat every 5s, periodic traffic resets (hourly/daily/weekly/monthly).
├── media/ # README images
│
├── Dockerfile / docker-compose.yml / DockerEntrypoint.sh / DockerInit.sh # Container build/run
├── install.sh / update.sh / x-ui.sh # VPS install + management CLI
├── x-ui.service.* / x-ui.rc # systemd units (debian/rhel/arch) + rc script
├── install.sh / update.sh / l-ui.sh # VPS install + management CLI
├── l-ui.service.* / l-ui.rc # systemd units (debian/rhel/arch) + rc script
├── windows_files/ # Windows service support
└── .github/workflows/ # CI: ci.yml, codeql.yml, docker.yml, release.yml, smoke.yml,
# mutation.yml, cleanup_caches.yml, claude-bot.yml
@@ -314,7 +313,7 @@ Restart is debounced via an atomic "need restart" flag (`SetToNeedRestart` /
### 5.2 Runtime abstraction — Local vs Remote (multi-node) ⭐ most important
A "node" (`model.Node`) is another 3x-ui instance this panel controls. Every state-changing
A "node" (`model.Node`) is another L-UI instance this panel controls. Every state-changing
inbound/client operation goes through the `runtime.Runtime` interface so the _same service
code_ works whether the target is the local Xray or a remote node.
@@ -327,7 +326,7 @@ code_ works whether the target is the local Xray or a remote node.
- **TLS modes** (`tls_client.go`, per-node `TlsVerifyMode`):
`verify` (system CAs, default) / `skip` (no validation) / `pin` (leaf cert SHA-256 must
match `PinnedCertSha256`) / `mtls` (master presents a client certificate; node cert checked
against system roots; API token optional). Master-side cert management:
against system roots). Master-side cert management:
`service/node_mtls.go` + `service/setting_mtls.go`.
- **Dispatch:** `manager.go` → `Manager.RuntimeFor(nodeID *int)`; `nil` nodeID → `Local`,
otherwise a cached/lazy-loaded `Remote`. `InvalidateNode(id)` drops a cached remote client.
@@ -431,7 +430,7 @@ notifications instead of importing notification services into producers.
### 5.8 Tunnel health monitor
`internal/tunnelmonitor/` is an optional watchdog configured **only via env vars**
(`XUI_TUNNEL_HEALTH_*`, read in `internal/config/`), deliberately independent of panel
(`LUI_TUNNEL_HEALTH_*`, read in `internal/config/`), deliberately independent of panel
settings so it can be enabled from a systemd `EnvironmentFile` even when the panel is
unreachable. It periodically probes an HTTP URL (default: Cloudflare trace endpoint) through
the tunnel; after N successive failures (default 3) it fires a recovery callback wired to an
@@ -462,7 +461,6 @@ for AutoMigrate in `internal/database/db.go`.
| `OutboundTraffics` | Outbound counters | per outbound tag |
| `OutboundSubscription` | External provider subs | Warp/Nord style |
| `Setting` | Key/value panel settings | everything configurable |
| `ApiToken` | REST API tokens | SHA-256 hash (plaintext shown once) |
| `InboundFallback` | Fallback routing on a shared port | SNI/ALPN/path → dest |
| `HistoryOfSeeders` | Seeder bookkeeping | prevents re-running one-off migrations |
@@ -490,7 +488,6 @@ for AutoMigrate in `internal/database/db.go`.
| **External subscription** import/aggregation | `sub/external_subscription.go`, `sub/external_config.go` | `sub/clash_external.go` |
| **Settings** not saving / defaults | `service/setting.go`, `controller/setting.go` | model `Setting` |
| **Login / 2FA / sessions / CSRF** | `controller/index.go`, `service/panel/user.go`, `middleware/` | `session/` |
| **API tokens** | `service/panel/api_token.go`, `controller/setting.go` | model `ApiToken` |
| **Port conflict** on inbound add | `service/port_conflict.go` | `controller/inbound.go` |
| **Fallbacks** (shared 443, SNI routing) | `service/fallback.go`, `controller/inbound.go` | model `InboundFallback` |
| **Geo category browser** empty / won't open | `xray/geodata/` (`Store`, `reader.go`), `service/geodata.go` | `controller/xray_setting.go` (`/panel/api/xray/geodata/*`), asset dir = `config.GetBinFolderPath()` |
@@ -498,7 +495,7 @@ for AutoMigrate in `internal/database/db.go`.
| **Telegram bot** commands | `service/tgbot/` | `job/stats_notify_job.go` |
| **Email notifications** | `service/email/` | `internal/eventbus/` (consumers) |
| **CPU / memory alerts** not firing | `job/check_cpu_usage.go`, `job/check_memory_usage.go` | `internal/eventbus/`, notifier settings in `service/setting.go` |
| Xray auto-restart on **dead tunnel** | `internal/tunnelmonitor/` | `XUI_TUNNEL_HEALTH_*` in `internal/config/` |
| Xray auto-restart on **dead tunnel** | `internal/tunnelmonitor/` | `LUI_TUNNEL_HEALTH_*` in `internal/config/` |
| **WARP / Nord / PIA** outbound integration | `service/integration/warp.go` / `nord.go` / `pia.go` | `internal/pia/`, `frontend/src/pages/xray/overrides/` |
| **MTProto** proxy issues | `internal/mtproto/manager.go`, `mtproto/process*.go` | `job/mtproto_job.go` |
| **DB migration** / new column | `internal/database/db.go` (AutoMigrate list), `migrate_data.go` | `model/model.go` |
@@ -580,8 +577,8 @@ root → `go build ./...` / `go run main.go`.
## 10. Gotchas & conventions
- **Module path is `.../v3`.** Internal imports use `github.com/mhsanaei/3x-ui/v3/internal/...`.
- **SQLite vs Postgres.** Default is SQLite at `{XUI_DB_FOLDER}/x-ui.db`. Postgres via
`XUI_DB_TYPE=postgres` + `XUI_DB_DSN`. Some SQL paths are dialect-aware (`database/dialect.go`);
- **SQLite vs Postgres.** Default is SQLite at `{LUI_DB_FOLDER}/l-ui.db`. Postgres via
`LUI_DB_TYPE=postgres` + `LUI_DB_DSN`. Some SQL paths are dialect-aware (`database/dialect.go`);
test both when touching raw queries (there are `*_scale_postgres_test.go` suites).
- **`Inbound.Settings` / `StreamSettings` / `Sniffing` are raw JSON strings**, not structured
columns. Parsing/validation happens in services and the `xray` package, not in GORM.
+3 -3
View File
@@ -1,15 +1,15 @@
import { cn } from '@/lib/cn';
// Official 3x-ui logo (media/3x-ui-{light,dark}.png from the upstream repo).
// Official L-UI logo (media/L-UI-{light,dark}.png from the upstream repo).
// Theme-aware via Tailwind's `dark:` variant. Pass a height class (e.g. `h-6`);
// width scales automatically (the artwork is 2:1).
export function Logo({ className }: { className?: string }) {
return (
<>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/logo-light.png" alt="3x-ui" className={cn('w-auto dark:hidden', className)} />
<img src="/logo-light.png" alt="L-UI" className={cn('w-auto dark:hidden', className)} />
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="/logo-dark.png" alt="3x-ui" className={cn('hidden w-auto dark:block', className)} />
<img src="/logo-dark.png" alt="L-UI" className={cn('hidden w-auto dark:block', className)} />
</>
);
}
@@ -35,7 +35,7 @@ export function ApiRequestBuilder() {
return (
<ToolFrame
title="API request builder"
description="Build an authenticated cURL command or fetch() snippet for any 3x-ui panel API endpoint under /panel/api/*."
description="Build an authenticated cURL command or fetch() snippet for any L-UI panel API endpoint under /panel/api/*."
onReset={reset}
>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: AmneziaWG
description: Set up an AmneziaWG inbound in 3x-ui — obfuscation parameters, native IPv6, per-client port-forwarding, and routing client traffic through Xray.
description: Set up an AmneziaWG inbound in L-UI — obfuscation parameters, native IPv6, per-client port-forwarding, and routing client traffic through Xray.
icon: Lock
---
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Clients
description: Manage 3x-ui clients — credentials, traffic and expiry limits, IP limits, groups, bulk actions, external links, and online status.
description: Manage L-UI clients — credentials, traffic and expiry limits, IP limits, groups, bulk actions, external links, and online status.
icon: Users
---
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Inbounds & Protocols
description: Create inbounds in 3x-ui — protocols, transports, traffic reset and expiry, and fallbacks that serve multiple protocols on one port.
description: Create inbounds in L-UI — protocols, transports, traffic reset and expiry, and fallbacks that serve multiple protocols on one port.
icon: ArrowDownToLine
---
@@ -75,7 +75,7 @@ The inbound editor accepts these protocols:
Fallbacks let a single TLS port (e.g. `443`) serve more than one protocol — for
example VLESS **and** Trojan — by routing unmatched handshakes to a child
inbound. In 3x-ui, fallbacks are managed in the panel (a master inbound's
inbound. In L-UI, fallbacks are managed in the panel (a master inbound's
**Fallbacks** list) rather than hand-written into JSON.
Fallbacks are available only when the master inbound is:
+4 -4
View File
@@ -1,6 +1,6 @@
---
title: Panel Settings
description: Every 3x-ui panel setting — web server, TLS, display, security, and notifications — with defaults from the source.
description: Every L-UI panel setting — web server, TLS, display, security, and notifications — with defaults from the source.
icon: SlidersHorizontal
---
@@ -14,7 +14,7 @@ browser in full.
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | Panel port (1–65535). The `XUI_PORT` env var overrides it at runtime. |
| `webPort` | `2053` | Panel port (1–65535). The `LUI_PORT` env var overrides it at runtime. |
| `webListen` | _(all interfaces)_ | Bind the panel to a specific IP. |
| `webBasePath` | `/` | URL path the panel is served under (always normalized to `/…/`). |
| `webCertFile` / `webKeyFile` | _(none)_ | TLS certificate + key. When both are set, the panel serves **HTTPS**. |
@@ -24,12 +24,12 @@ browser in full.
After changing the port or base path, the panel URL becomes
`http(s)://<server>:<port><web-base-path>`. You can preset the base path on first
launch with [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
launch with [`LUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
### TLS
Serving the panel over HTTPS protects your credentials in transit. Either set
`webCertFile` + `webKeyFile` — the [`x-ui` SSL menu](/docs/config/ssl-certificates)
`webCertFile` + `webKeyFile` — the [`l-ui` SSL menu](/docs/config/ssl-certificates)
can obtain a Let's Encrypt certificate for you — or terminate TLS at a
[reverse proxy](/docs/operations/reverse-proxy).
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: REALITY
description: Set up a VLESS + REALITY inbound with XTLS-Vision in 3x-ui — keys, short IDs, SNI, fingerprints, and common pitfalls.
description: Set up a VLESS + REALITY inbound with XTLS-Vision in L-UI — keys, short IDs, SNI, fingerprints, and common pitfalls.
icon: ShieldCheck
---
@@ -15,7 +15,7 @@ REALITY is used with **VLESS** (and Trojan). The recommended flow is
## Key settings
When you choose **REALITY** as the security mode on a VLESS inbound, 3x-ui
When you choose **REALITY** as the security mode on a VLESS inbound, L-UI
exposes these fields:
| Field | What it is |
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: Share Links
description: 3x-ui share-link formats (vless, vmess, trojan, ss, hysteria2, mtproto), the remark template variables, and an in-browser link inspector.
description: L-UI share-link formats (vless, vmess, trojan, ss, hysteria2, mtproto), the remark template variables, and an in-browser link inspector.
icon: Link
---
3x-ui generates a **share link** (and QR code) for each client. Client apps such
L-UI generates a **share link** (and QR code) for each client. Client apps such
as v2rayNG, Hiddify, and Mihomo import these links to configure themselves.
## Link formats
@@ -1,6 +1,6 @@
---
title: SSL Certificates
description: Get and renew TLS certificates for the 3x-ui panel and inbounds — with the x-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot.
description: Get and renew TLS certificates for the L-UI panel and inbounds — with the l-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot.
icon: ShieldCheck
---
@@ -8,7 +8,7 @@ A TLS certificate lets you serve the **panel** over HTTPS (so your login and API
traffic are encrypted) and terminate TLS on **inbounds** (VLESS-TLS, Trojan,
Shadowsocks-TLS, and friends). There are three ways to obtain one:
- **The `x-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
- **The `l-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
client. Easiest for a single domain or a bare IP.
- **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or
when port 80 is blocked / the server sits behind Cloudflare's proxy.
@@ -22,9 +22,9 @@ Shadowsocks-TLS, and friends). There are three ways to obtain one:
inbounds.
</Callout>
## The `x-ui` SSL menu (Let's Encrypt)
## The `l-ui` SSL menu (Let's Encrypt)
Run `x-ui` and choose **`20` — SSL Certificate Management**. It drives
Run `l-ui` and choose **`20` — SSL Certificate Management**. It drives
[acme.sh](https://github.com/acmesh-official/acme.sh) and offers:
| Option | What it does |
@@ -58,7 +58,7 @@ use. Stop anything bound to it for the duration, and allow it through the
<Step>
### Run the issuer
`x-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests
`l-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests
the certificate and saves it under `/root/cert/<domain>/` as `fullchain.pem`
(the certificate chain) and `privkey.pem` (the private key).
</Step>
@@ -105,7 +105,7 @@ it. Copy the token — it's shown only once.
<Step>
### Run the Cloudflare issuer
`x-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an
`l-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an
API token (the default) or **`g`** for the Global API Key, then enter your
domain (and, for the Global API Key, your account email and key). acme.sh creates
the TXT record, validates, and cleans it up.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Subscription
description: Run the 3x-ui subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
description: Run the L-UI subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
icon: Rss
---
@@ -58,7 +58,7 @@ page instead of the raw body.
The **Base64** body is just the newline-joined share links, standard-base64
encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a
complete Xray client config — a fixed skeleton (local mixed/HTTP inbounds, DNS,
routing, policy) plus a `proxy` outbound pointing at the inbound. 3x-ui emits a
routing, policy) plus a `proxy` outbound pointing at the inbound. L-UI emits a
**single config object for one client and an array for several**, uses the flat
outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips
`sockopt` from `streamSettings`.
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: Transports & Security
description: Every transport 3x-ui exposes — TCP, mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, Hysteria — with their settings, plus FinalMask obfuscation, sockopt, TLS/REALITY, XTLS-Vision, and VLESS encryption.
description: Every transport L-UI exposes — TCP, mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, Hysteria — with their settings, plus FinalMask obfuscation, sockopt, TLS/REALITY, XTLS-Vision, and VLESS encryption.
icon: Network
---
+16 -16
View File
@@ -1,6 +1,6 @@
---
title: First Login
description: Find your generated 3x-ui credentials, reach the panel, enable two-factor auth, and harden it before exposing anything.
description: Find your generated L-UI credentials, reach the panel, enable two-factor auth, and harden it before exposing anything.
icon: KeyRound
---
@@ -24,25 +24,25 @@ path, so check your actual values.
A script install prints a credential summary when it finishes and also writes it
to a root-only file:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```bash title="/etc/l-ui/install-result.env (mode 600)"
LUI_USERNAME=...
LUI_PASSWORD=...
LUI_PANEL_PORT=...
LUI_WEB_BASE_PATH=...
LUI_ACCESS_URL=...
LUI_API_TOKEN=...
LUI_DB_TYPE=sqlite
```
If you missed them, use the management tools:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
l-ui # menu → 11 (View Current Settings)
l-ui settings # or the one-shot form
```
For **Docker**, read the generated credentials from the container logs, or run
`docker exec -it <container> x-ui setting -show`.
`docker exec -it <container> l-ui setting -show`.
<Callout type="warn">
If your panel still uses the default `admin` / `admin` (the panel warns when it
@@ -53,7 +53,7 @@ For **Docker**, read the generated credentials from the container logs, or run
A non-default port and a long, random **web base path** make the panel much
harder to find. Change them from **Panel Settings** in the UI, or from the
`x-ui` menu:
`l-ui` menu:
- **7 — Reset Username & Password** (optionally disabling 2FA at the same time)
- **8 — Reset Web Base Path** (randomizes it)
@@ -64,11 +64,11 @@ two-factor auth was on, disables it.
## Two-factor authentication (2FA)
3x-ui supports TOTP two-factor auth (compatible with Google Authenticator, Aegis,
L-UI supports TOTP two-factor auth (compatible with Google Authenticator, Aegis,
etc.). Enable it in **Panel Settings** — once enabled, the login page asks for a
6-digit code in addition to your password, and turning it on forces everyone to
log in again. You can disable it from the menu's **Reset Username & Password**
step or with `x-ui setting -resetTwoFactor`.
step or with `l-ui setting -resetTwoFactor`.
## Built-in login protection
@@ -105,7 +105,7 @@ Turn on 2FA so a leaked password alone can't grant access.
<Step>
### Put the panel behind TLS
Use a valid certificate (via the `x-ui` menu's SSL management, or a reverse
Use a valid certificate (via the `l-ui` menu's SSL management, or a reverse
proxy) so the panel is only reachable over HTTPS.
</Step>
+6 -6
View File
@@ -1,10 +1,10 @@
---
title: Meet 3x-ui
title: Meet L-UI
description: A web panel for Xray-core — manage inbounds, protocols, clients, and subscriptions from your browser instead of editing JSON by hand.
icon: Info
---
**3x-ui** is a web control panel that sits on top of
**L-UI** is a web control panel that sits on top of
[Xray-core](https://github.com/XTLS/Xray-core), the proxy engine that actually
moves your traffic. Instead of writing and reloading Xray's JSON configuration
by hand, you manage everything — inbounds, protocols, clients, certificates,
@@ -15,7 +15,7 @@ subscriptions — from a browser dashboard.
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Admin["Admin browser"] -->|HTTPS panel| Panel["L-UI panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -52,18 +52,18 @@ flowchart LR
| Database | SQLite (default) or PostgreSQL |
| Proxy engine | Xray-core (bundled and managed by the panel) |
The default SQLite database lives at `/etc/x-ui/x-ui.db`, and the panel listens
The default SQLite database lives at `/etc/l-ui/l-ui.db`, and the panel listens
on port **2053** by default. Both are configurable — see
[First login](/docs/guide/first-login) and the environment variable reference.
## Who it's for
3x-ui is aimed at anyone running their own Xray server: from a single personal
L-UI is aimed at anyone running their own Xray server: from a single personal
VPS to operators managing many nodes and clients. If you want the power of
Xray-core without living in JSON config files, this is for you.
<Callout type="info">
3x-ui is an enhanced fork of the original X-UI project, adding broader protocol
L-UI is an enhanced fork of the original X-UI project, adding broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, and many quality-of-life features.
</Callout>
+18 -18
View File
@@ -1,17 +1,17 @@
---
title: Installation
description: Install 3x-ui via the official script (stable, pinned, or dev-latest), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
description: Install L-UI via the official script (stable, pinned, or dev-latest), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
icon: Download
---
3x-ui runs on a wide range of Linux distributions — Ubuntu, Debian, Armbian,
L-UI runs on a wide range of Linux distributions — Ubuntu, Debian, Armbian,
Fedora, CentOS, RHEL, AlmaLinux, Rocky Linux, Oracle Linux, Amazon Linux,
Virtuozzo, Arch, Manjaro, openSUSE (Tumbleweed/Leap), Alpine — and Windows,
across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`.
<Callout type="warn">
Run the script installer as **root** (or with `sudo`). It installs a service,
sets up the `x-ui` management command, and enables the panel on boot.
sets up the `l-ui` management command, and enables the panel on boot.
</Callout>
<Tabs items={['Script', 'Docker', 'Manual']}>
@@ -20,7 +20,7 @@ across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`.
The official script is the recommended path. During installation it generates a
**random** username, password, and access (web base) path, sets up the service,
and installs the `x-ui` management command.
and installs the `l-ui` management command.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
@@ -39,8 +39,8 @@ Install the rolling **dev** build (the latest per-commit pre-release from `main`
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
When it finishes, note the printed login details and run `x-ui` to open the
[management menu](/docs/guide/update-uninstall#the-x-ui-management-menu), then
When it finishes, note the printed login details and run `l-ui` to open the
[management menu](/docs/guide/update-uninstall#the-l-ui-management-menu), then
continue to [First login](/docs/guide/first-login).
</Tab>
@@ -54,7 +54,7 @@ The default Compose setup uses SQLite. Clone the repo (or copy its
docker compose up -d
```
To run with the bundled **PostgreSQL** service, uncomment the two `XUI_DB_*`
To run with the bundled **PostgreSQL** service, uncomment the two `LUI_DB_*`
lines in `docker-compose.yml` and start with the profile:
```bash
@@ -70,16 +70,16 @@ otherwise bans are logged but never applied:
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-e LUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/l-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
--name L-UI \
ghcr.io/mhsanaei/3x-ui:latest
```
The `db/` volume holds the SQLite database (`/etc/x-ui/x-ui.db`) and `cert/`
The `db/` volume holds the SQLite database (`/etc/l-ui/l-ui.db`) and `cert/`
holds TLS certificates, so your data survives upgrades.
</Tab>
@@ -87,7 +87,7 @@ holds TLS certificates, so your data survives upgrades.
<Tab value="Manual">
For advanced users, download a release archive for your architecture from the
[releases page](https://github.com/MHSanaei/3x-ui/releases), extract it, and run
[releases page](https://github.com/MHSanaei/L-UI/releases), extract it, and run
the binary as a systemd service. The install script automates exactly these
steps, so it's preferred unless you have a specific reason to install by hand.
@@ -105,7 +105,7 @@ Tailor the command to your setup:
You pick the storage backend at install time:
- **SQLite** (default) — a single file at `/etc/x-ui/x-ui.db`. Zero setup.
- **SQLite** (default) — a single file at `/etc/l-ui/l-ui.db`. Zero setup.
- **PostgreSQL** — for high client counts or multi-node setups. The installer
can install it locally or use a DSN you provide.
@@ -115,15 +115,15 @@ migration.
## Unattended / cloud-init
The installer also runs **non-interactively** for automation. Set
`XUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero
`LUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero
prompts, generating random credentials and writing them to
`/etc/x-ui/install-result.env`:
`/etc/l-ui/install-result.env`:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
LUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
The repo's [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy)
The repo's [`deploy/`](https://github.com/MHSanaei/L-UI/tree/main/deploy)
directory has ready-made **cloud-init** user-data for unattended installs on any
cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
@@ -138,7 +138,7 @@ cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
<Card
title="Update & uninstall"
href="/docs/guide/update-uninstall"
description="The x-ui menu, updates, and removal."
description="The l-ui menu, updates, and removal."
/>
<Card
title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
---
title: Update & Uninstall
description: Manage 3x-ui with the x-ui menu and CLI — update (stable, dev, or legacy), change settings, and uninstall cleanly.
description: Manage L-UI with the l-ui menu and CLI — update (stable, dev, or legacy), change settings, and uninstall cleanly.
icon: RefreshCw
---
After a script install, the `x-ui` command is your control center. Run it with
After a script install, the `l-ui` command is your control center. Run it with
no arguments for the interactive menu, or pass a subcommand for a one-shot action.
```bash
x-ui
l-ui
```
## The `x-ui` management menu
## The `l-ui` management menu
The menu (items `0`–`28`) shows the panel/Xray status at the top, then:
@@ -20,9 +20,9 @@ The menu (items `0`–`28`) shows the panel/Xray status at the top, then:
| 1 | Install | (Re)install from the remote script |
| 2 | Update | Update to the latest **stable** release |
| 3 | Update to Dev Channel (latest commit) | Update to the rolling `dev-latest` build |
| 4 | Update Menu | Update just the `x-ui` menu script |
| 4 | Update Menu | Update just the `l-ui` menu script |
| 5 | Legacy Version | Install a specific older version (prompts for a tag) |
| 6 | Uninstall | Remove 3x-ui (see below) |
| 6 | Uninstall | Remove L-UI (see below) |
| 7 | Reset Username & Password | Set new credentials; optionally disable 2FA |
| 8 | Reset Web Base Path | Randomize the web base path |
| 9 | Reset Settings | Reset panel settings (your account is preserved) |
@@ -51,29 +51,29 @@ Some of these have their own pages: [SSL certificates](/docs/config/ssl-certific
## CLI subcommands
For scripts and quick actions, `x-ui` also takes a subcommand directly:
For scripts and quick actions, `l-ui` also takes a subcommand directly:
| Command | Action |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | Control the service |
| `x-ui restart-xray` | Reload only Xray-core |
| `x-ui status` | Show status |
| `x-ui settings` | Show current settings |
| `x-ui enable` / `disable` | Toggle autostart on boot |
| `x-ui log` | Tail the debug log |
| `x-ui banlog` | Show Fail2ban ban log |
| `x-ui update` | Update to the latest stable release |
| `x-ui update-dev` | Update to the rolling `dev-latest` build |
| `x-ui legacy` | Install a specific older version (prompts) |
| `x-ui update-all-geofiles` | Update all geo files, restart if changed |
| `x-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `x-ui install` / `uninstall` | Install / uninstall |
| `l-ui start` / `stop` / `restart` | Control the service |
| `l-ui restart-xray` | Reload only Xray-core |
| `l-ui status` | Show status |
| `l-ui settings` | Show current settings |
| `l-ui enable` / `disable` | Toggle autostart on boot |
| `l-ui log` | Tail the debug log |
| `l-ui banlog` | Show Fail2ban ban log |
| `l-ui update` | Update to the latest stable release |
| `l-ui update-dev` | Update to the rolling `dev-latest` build |
| `l-ui legacy` | Install a specific older version (prompts) |
| `l-ui update-all-geofiles` | Update all geo files, restart if changed |
| `l-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `l-ui install` / `uninstall` | Install / uninstall |
## Updating
- **Stable:** menu option **2** or `x-ui update`. Re-running the install script
- **Stable:** menu option **2** or `l-ui update`. Re-running the install script
also updates in place.
- **Dev channel:** menu option **3** or `x-ui update-dev` — the rolling
- **Dev channel:** menu option **3** or `l-ui update-dev` — the rolling
`dev-latest` per-commit build (not a stable release).
- **A specific older version:** menu option **5** (Legacy Version).
@@ -83,17 +83,17 @@ Updating preserves your database and settings. Take a
<Callout type="info">
Docker users update differently — pull the new image and recreate the
container (`docker compose pull && docker compose up -d`) rather than using the
`x-ui` update commands.
`l-ui` update commands.
</Callout>
## Uninstalling
Menu option **6** or `x-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/x-ui/` and the install folder. If the panel
Menu option **6** or `l-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/l-ui/` and the install folder. If the panel
used a locally-installed PostgreSQL, it offers to purge that too (a separate,
irreversible confirmation).
<Callout type="warn">
Uninstalling removes the database (`/etc/x-ui/x-ui.db`) and your configuration.
Uninstalling removes the database (`/etc/l-ui/l-ui.db`) and your configuration.
[Back up](/docs/operations/backup-restore) first if you might need it.
</Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
---
title: Contributing
description: How to contribute to 3x-ui and to translate this documentation.
description: How to contribute to L-UI and to translate this documentation.
icon: GitPullRequestArrow
---
3x-ui is community-driven. Contributions to the panel and to these docs are
L-UI is community-driven. Contributions to the panel and to these docs are
welcome.
## Support the developer
3x-ui is free and open source, built and maintained in the open. If it's useful
L-UI is free and open source, built and maintained in the open. If it's useful
to you, consider supporting continued development:
- **Donate** at [donate.sanaei.dev](https://donate.sanaei.dev/) — the page shows
current funding **goals and targets** you can help reach.
- **Star** the [repository](https://github.com/MHSanaei/3x-ui) and share the
- **Star** the [repository](https://github.com/MHSanaei/L-UI) and share the
project.
- **Join** the Telegram channel [@XrayUI](https://t.me/XrayUI) to follow news and
help others.
## Contribute to 3x-ui
## Contribute to L-UI
- Read the project's `CONTRIBUTING.md` in the
[repository](https://github.com/MHSanaei/3x-ui).
[repository](https://github.com/MHSanaei/L-UI).
- Open issues for bugs and feature requests with clear reproduction steps.
- Use Conventional Commits and keep pull requests focused.
+9 -9
View File
@@ -1,13 +1,13 @@
---
title: FAQ
description: Frequently asked questions about 3x-ui — licensing, supported systems, databases, and clients.
description: Frequently asked questions about L-UI — licensing, supported systems, databases, and clients.
icon: CircleQuestionMark
---
## Is 3x-ui free and open source?
## Is L-UI free and open source?
Yes. 3x-ui is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/3x-ui).
Yes. L-UI is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/L-UI).
## What systems does it run on?
@@ -18,7 +18,7 @@ It also runs as a Docker container. See [Installation](/docs/guide/installation)
## SQLite or PostgreSQL?
SQLite is the default and is fine for most deployments. PostgreSQL is available
for larger setups via `XUI_DB_TYPE=postgres` and `XUI_DB_DSN` — see the
for larger setups via `LUI_DB_TYPE=postgres` and `LUI_DB_DSN` — see the
[environment variables](/docs/reference/env-vars).
## Which client apps work with it?
@@ -27,9 +27,9 @@ Any Xray-compatible client — for example v2rayNG, Hiddify, and Clash/Mihomo.
Import a client's share link or QR code, or use a
[subscription](/docs/config/subscription).
## How is 3x-ui different from x-ui?
## How is L-UI different from l-ui?
3x-ui is an enhanced fork of the original X-UI project. It adds broader protocol
L-UI is an enhanced fork of the original X-UI project. It adds broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, a 13-language UI, and many quality-of-life features.
@@ -37,11 +37,11 @@ management, a 13-language UI, and many quality-of-life features.
Re-run the install script (it updates in place), or pull the new Docker image.
See [Installation](/docs/guide/installation) and the
[releases page](https://github.com/MHSanaei/3x-ui/releases).
[releases page](https://github.com/MHSanaei/L-UI/releases).
## Where can I get help?
Join the official Telegram channel [@XrayUI](https://t.me/XrayUI) for
announcements and community support, or open an issue on
[GitHub](https://github.com/MHSanaei/3x-ui/issues). For common problems, start
[GitHub](https://github.com/MHSanaei/L-UI/issues). For common problems, start
with [Troubleshooting](/docs/help/troubleshooting).
+8 -8
View File
@@ -1,6 +1,6 @@
---
title: Migration
description: Migrate to 3x-ui from x-ui, between servers, or between 3x-ui versions.
description: Migrate to L-UI from l-ui, between servers, or between L-UI versions.
icon: ArrowRightLeft
---
@@ -13,12 +13,12 @@ Moving to a new server is a database move:
<Step>
### Back up the old server
Copy the database (default `/etc/x-ui/x-ui.db`) and your certificates. See
Copy the database (default `/etc/l-ui/l-ui.db`) and your certificates. See
[Backup & restore](/docs/operations/backup-restore).
</Step>
<Step>
### Install 3x-ui on the new server
### Install L-UI on the new server
Use the same install method and a compatible version. See
[Installation](/docs/guide/installation).
@@ -33,17 +33,17 @@ panel. Update any IP/domain-specific settings.
</Steps>
## Between 3x-ui versions
## Between L-UI versions
Within the same backend, upgrading is usually just re-running the installer or
pulling a new image — the panel migrates its own database. Across **major**
versions, read the [release notes](https://github.com/MHSanaei/3x-ui/releases)
versions, read the [release notes](https://github.com/MHSanaei/L-UI/releases)
first and take a backup.
## From x-ui
## From l-ui
Importing an older x-ui panel's database directly into 3x-ui is **not
supported** — the schemas differ. Install 3x-ui fresh and recreate
Importing an older l-ui panel's database directly into L-UI is **not
supported** — the schemas differ. Install L-UI fresh and recreate
inbounds/clients, exporting share links from the old panel as you go.
<Callout type="warn">
@@ -1,17 +1,17 @@
---
title: Troubleshooting
description: Fix common 3x-ui problems — the panel won't start, 502 errors, certificate issues, and clients that can't connect.
description: Fix common L-UI problems — the panel won't start, 502 errors, certificate issues, and clients that can't connect.
icon: Wrench
---
A checklist for the most common issues. When in doubt, raise the log level
(`XUI_LOG_LEVEL=debug`) and check the panel and Xray logs.
(`LUI_LOG_LEVEL=debug`) and check the panel and Xray logs.
## The panel won't start
- Check the service status and logs (`x-ui` menu → status/logs).
- Check the service status and logs (`l-ui` menu → status/logs).
- Make sure the **panel port isn't already in use** by another service.
- Verify the database path is writable (default `/etc/x-ui/x-ui.db`).
- Verify the database path is writable (default `/etc/l-ui/l-ui.db`).
## 502 / panel unreachable behind a proxy
@@ -37,6 +37,6 @@ A checklist for the most common issues. When in doubt, raise the log level
<Callout type="info">
Still stuck? Search the
[GitHub issues](https://github.com/MHSanaei/3x-ui/issues) — your symptom has
[GitHub issues](https://github.com/MHSanaei/L-UI/issues) — your symptom has
probably been seen before.
</Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
---
title: 3x-ui Documentation
description: Official documentation for 3x-ui — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
title: L-UI Documentation
description: Official documentation for L-UI — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
icon: House
---
**3x-ui** is an open-source web panel for deploying and managing
**L-UI** is an open-source web panel for deploying and managing
[Xray-core](https://github.com/XTLS/Xray-core) servers. It gives you a modern
dashboard for inbounds, protocols, clients, traffic accounting, subscriptions,
and more — without hand-editing Xray JSON on the command line.
@@ -17,7 +17,7 @@ leaves the page.
<Cards>
<Card
title="What is 3x-ui?"
title="What is L-UI?"
href="/docs/guide"
description="The big picture: Xray-core, the panel, and who it's for."
/>
@@ -49,6 +49,6 @@ leaves the page.
- **Operations** — multi-node management, Telegram bot, backups, and a REST API.
<Callout type="info">
New to Xray? Read [What is 3x-ui?](/docs/guide) first — it explains how the panel, Xray-core, and
New to Xray? Read [What is L-UI?](/docs/guide) first — it explains how the panel, Xray-core, and
your client apps fit together.
</Callout>
@@ -1,6 +1,6 @@
---
title: Backup & Restore
description: Back up and restore your 3x-ui database and certificates, manually or via the Telegram bot.
description: Back up and restore your L-UI database and certificates, manually or via the Telegram bot.
icon: DatabaseBackup
---
@@ -9,7 +9,7 @@ database. Back it up regularly so you can recover or migrate.
## What to back up
- **The database** — SQLite at `/etc/x-ui/x-ui.db` by default (or your
- **The database** — SQLite at `/etc/l-ui/l-ui.db` by default (or your
PostgreSQL database if you use that backend).
- **Certificates** — anything under `/root/cert/` (or wherever you store TLS
certs).
@@ -20,7 +20,7 @@ You can download a backup from the panel's overview, or copy the database file
directly from the server:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
cp /etc/l-ui/l-ui.db /root/l-ui-backup-$(date +%F).db
```
To restore, stop the panel, put the database back in place, and start it again.
@@ -41,12 +41,12 @@ can also request a backup on demand from the bot's menu.
## SQLite dump / restore
The `x-ui migrate-db` command converts the SQLite database to and from a plain
The `l-ui migrate-db` command converts the SQLite database to and from a plain
SQL text dump (handy for inspection or transferring between machines):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
l-ui migrate-db --dump /root/l-ui.sql # SQLite -> SQL text
l-ui migrate-db --restore /root/l-ui.sql # SQL text -> SQLite
```
To move to PostgreSQL instead, see [Database](/docs/reference/database).
@@ -1,15 +1,15 @@
---
title: Multi-node & Managed Hosts
description: Manage multiple 3x-ui panels from one master, with API-token or mTLS trust, heartbeats, and per-inbound host overrides for subscriptions.
description: Manage multiple L-UI panels from one master, with API-token or mTLS trust, heartbeats, and per-inbound host overrides for subscriptions.
icon: Boxes
---
3x-ui can manage **multiple servers** from a single master panel, and override
L-UI can manage **multiple servers** from a single master panel, and override
how each inbound is advertised in subscriptions with **managed hosts**.
## Nodes
A **node** is another 3x-ui panel that your master panel manages over the node's
A **node** is another L-UI panel that your master panel manages over the node's
API. The master polls each node and shows its status, versions, CPU/memory,
uptime, and traffic in one place.
@@ -1,11 +1,11 @@
---
title: Outbounds & Routing
description: Shape egress in 3x-ui — WARP, NordVPN, PIA WireGuard, outbound subscriptions, routing rules, and load balancers.
description: Shape egress in L-UI — WARP, NordVPN, PIA WireGuard, outbound subscriptions, routing rules, and load balancers.
icon: Route
---
Inbounds accept clients; **outbounds** decide where their traffic goes next.
3x-ui can route traffic through Cloudflare WARP, NordVPN, Private Internet Access
L-UI can route traffic through Cloudflare WARP, NordVPN, Private Internet Access
(WireGuard), or arbitrary outbound pools imported from a subscription,
and select between them with routing rules and balancers.
@@ -39,7 +39,7 @@ inbound's transport and security. Two outbounds are almost always present:
A **proxy** outbound (VLESS, VMess, Trojan, Shadowsocks) forwards to another
server — handy for chaining or sending select traffic abroad. Mind the wire
shapes 3x-ui uses: **VLESS is the flat form** (`address`/`port`/`id`/`flow`/
shapes L-UI uses: **VLESS is the flat form** (`address`/`port`/`id`/`flow`/
`encryption`), **VMess uses `settings.vnext[]`**, and **Trojan/Shadowsocks use
`settings.servers[]`**. The `streamSettings` must mirror the destination's
[transport and security](/docs/config/transports).
@@ -50,7 +50,7 @@ Assemble any outbound below and paste the JSON into **Xray Settings → Outbound
## Cloudflare WARP
WARP lets your server egress through Cloudflare's network. 3x-ui can register a
WARP lets your server egress through Cloudflare's network. L-UI can register a
WARP account for you and wire it into a WireGuard outbound tagged **`warp`**:
<Steps>
@@ -64,7 +64,7 @@ Create a WireGuard outbound with the tag `warp` in your Xray config.
<Step>
### Register WARP
From the panel's WARP controls, register an account. 3x-ui fills the outbound's
From the panel's WARP controls, register an account. L-UI fills the outbound's
keys, addresses, reserved bytes, and peer endpoint automatically.
</Step>
@@ -82,13 +82,13 @@ with a routing rule.
## NordVPN
3x-ui can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
L-UI can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
accept a private key directly) and list countries/servers, so you can build a
NordVPN outbound.
## PIA WireGuard
3x-ui can sign in with a PIA username and password, list countries/regions/servers
L-UI can sign in with a PIA username and password, list countries/regions/servers
from the signed PIA server list, and build a WireGuard outbound. Open
**Xray → Outbounds → More → PIA**, sign in, pick a server, and add the outbound.
You can add several servers (one outbound per hostname). The tag is
@@ -100,7 +100,7 @@ revoke the WireGuard peer on the PIA account.
The password is not stored. The PIA API token is stored with the same
`NODE_TOKEN_ENCRYPTION` setting as node API tokens. If you retire an old
`XUI_NODE_TOKEN_KEY` without signing into PIA again, Add/Reset fail until you
`LUI_NODE_TOKEN_KEY` without signing into PIA again, Add/Reset fail until you
re-login. Peer `allowedIPs` is IPv4-only (`0.0.0.0/0`).
## Outbound subscriptions (server pools)
@@ -1,13 +1,13 @@
---
title: Reverse Proxy
description: Put the 3x-ui panel and subscription behind Nginx or Caddy with Let's Encrypt TLS.
description: Put the L-UI panel and subscription behind Nginx or Caddy with Let's Encrypt TLS.
icon: Waypoints
---
A reverse proxy lets you serve the panel and subscription on a clean domain with
automatic HTTPS, and hide the real ports behind ports 80/443. Prefer to let the
panel terminate TLS directly? Get a certificate with the
[`x-ui` SSL menu](/docs/config/ssl-certificates) instead.
[`l-ui` SSL menu](/docs/config/ssl-certificates) instead.
## Generate a config
@@ -45,7 +45,7 @@ panel.example.com {
## Tips
- Keep the panel's **web base path** even behind a proxy; defense in depth.
- If you terminate TLS at the proxy, you may want `XUI_SKIP_HSTS=true` on the
- If you terminate TLS at the proxy, you may want `LUI_SKIP_HSTS=true` on the
panel — see the [environment variables reference](/docs/reference/env-vars).
- Proxy the [subscription](/docs/config/subscription) server too, so its contents
are served over HTTPS.
+10 -10
View File
@@ -1,6 +1,6 @@
---
title: Security
description: Harden 3x-ui — panel auth and 2FA, Fail2ban IP limits, firewall rules, BBR, and staying current.
description: Harden L-UI — panel auth and 2FA, Fail2ban IP limits, firewall rules, BBR, and staying current.
icon: ShieldCheck
---
@@ -21,15 +21,15 @@ See [First login](/docs/guide/first-login) for the full checklist.
Set an **IP limit** per client (see [Clients](/docs/config/clients)) to cap the
number of simultaneous source IPs. Enforcement is handled by **Fail2ban**, which
3x-ui installs and configures for you (enabled by default on script installs, and
on Docker via `XUI_ENABLE_FAIL2BAN=true`).
L-UI installs and configures for you (enabled by default on script installs, and
on Docker via `LUI_ENABLE_FAIL2BAN=true`).
Manage it from the `x-ui` menu (**22 — IP Limit Management**): install/configure,
Manage it from the `l-ui` menu (**22 — IP Limit Management**): install/configure,
change the ban duration (default **30 minutes**), ban/unban an IP, view ban logs,
and check status. Under the hood:
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/x-ui/3xipl.log` and
`/var/log/x-ui/3xipl-banned.log` (also via `x-ui banlog`).
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/l-ui/3xipl.log` and
`/var/log/l-ui/3xipl-banned.log` (also via `l-ui banlog`).
- Bans cover all TCP/UDP **except** your SSH and panel ports, so a ban can't lock
you out of the server or panel.
@@ -43,7 +43,7 @@ and check status. Under the hood:
## Firewall
Open only the ports you actually use: SSH, the panel port, the subscription
port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) wraps
port, and your inbound ports. The `l-ui` menu (**23 — Firewall Management**) wraps
`ufw`, or generate rules here:
<FirewallRulesGenerator />
@@ -55,12 +55,12 @@ port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) w
## Network tuning (BBR)
The `x-ui` menu (**26 — Enable BBR**) toggles Google's BBR congestion control
The `l-ui` menu (**26 — Enable BBR**) toggles Google's BBR congestion control
(`net.ipv4.tcp_congestion_control = bbr`, `net.core.default_qdisc = fq`), which
often improves throughput on congested links.
## Keep current
Update 3x-ui and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/3x-ui/releases) and see
Update L-UI and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/L-UI/releases) and see
[Update & uninstall](/docs/guide/update-uninstall).
@@ -1,10 +1,10 @@
---
title: Telegram Bot
description: Connect a Telegram bot to 3x-ui for commands, periodic reports, event alerts (login, CPU, node up/down), backups, and client self-service.
description: Connect a Telegram bot to L-UI for commands, periodic reports, event alerts (login, CPU, node up/down), backups, and client self-service.
icon: Send
---
3x-ui can drive a Telegram bot for monitoring, alerts, backups, and remote
L-UI can drive a Telegram bot for monitoring, alerts, backups, and remote
management. Admins get full control; regular users (linked by Telegram ID) can
check their own usage and links.
@@ -1,56 +0,0 @@
---
title: API Tokens
description: Manage scoped Bearer tokens for programmatic auth. Tokens grant
admin, monitor, or node-sync access, may expire, and are stored as SHA-256
hashes. The plaintext is returned only once at creation.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: List every API token, enabled or not. The token value is never returned —
only metadata.
url: '#list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata'
- depth: 2
title: Mint a scoped API token. The server-generated plaintext is returned only
once and stored as a hash.
url: '#mint-a-scoped-api-token-the-server-generated-plaintext-is-returned-only-once-and-stored-as-a-hash'
- depth: 2
title: Permanently delete a token. Any caller using it stops authenticating
immediately.
url: '#permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately'
- depth: 2
title: Toggle a token enabled/disabled without deleting it. Disabled tokens are
rejected by checkAPIAuth on the next request.
url: '#toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request'
structuredData:
headings:
- content: List every API token, enabled or not. The token value is never returned
— only metadata.
id: list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- content: Mint a scoped API token. The server-generated plaintext is returned
only once and stored as a hash.
id: mint-a-scoped-api-token-the-server-generated-plaintext-is-returned-only-once-and-stored-as-a-hash
- content: Permanently delete a token. Any caller using it stops authenticating
immediately.
id: permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- content: Toggle a token enabled/disabled without deleting it. Disabled tokens
are rejected by checkAPIAuth on the next request.
id: toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/apiTokens","method":"get"},{"path":"/panel/api/setting/apiTokens/create","method":"post"},{"path":"/panel/api/setting/apiTokens/delete/{id}","method":"post"},{"path":"/panel/api/setting/apiTokens/setEnabled/{id}","method":"post"}]} showTitle />
</>
);
}
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: API Reference
description: The 3x-ui panel REST API — authentication, inbounds, clients, server stats, and more, generated from the OpenAPI spec.
description: The L-UI panel REST API — authentication, inbounds, clients, server stats, and more, generated from the OpenAPI spec.
icon: Webhook
---
The 3x-ui panel exposes a REST API for automation. These pages are generated from
The L-UI panel exposes a REST API for automation. These pages are generated from
the panel's OpenAPI specification, so they always match the documented schema.
## Authentication
@@ -4,7 +4,6 @@
"pages": [
"index",
"authentication",
"api-tokens",
"inbounds",
"clients",
"server",
+11 -17
View File
@@ -1,6 +1,6 @@
---
title: Nodes
description: Manage remote 3x-ui panels acting as nodes for a central panel. All
description: Manage remote L-UI panels acting as nodes for a central panel. All
endpoints under /panel/api/nodes.
full: true
_openapi:
@@ -37,15 +37,12 @@ _openapi:
panel.
url: '#fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel'
- depth: 2
title: Register a new remote node. Provide its URL, write-only apiToken, and
optional remark / allowPrivateAddress flag. Responses expose hasApiToken
only.
url: '#register-a-new-remote-node-provide-its-url-write-only-apitoken-and-optional-remark--allowprivateaddress-flag-responses-expose-hasapitoken-only'
title: Register a new remote node. Provide its URL and optional remark /
allowPrivateAddress flag.
url: '#register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag'
- depth: 2
title: 'Replace a node’s connection details. apiToken is write-only: omit it or
send an empty string to keep the stored token; set clearApiToken=true to
clear it.'
url: '#replace-a-nodes-connection-details-apitoken-is-write-only-omit-it-or-send-an-empty-string-to-keep-the-stored-token-set-clearapitokentrue-to-clear-it'
title: Replace a node’s connection details.
url: '#replace-a-nodes-connection-details'
- depth: 2
title: Delete a node. Inbounds bound to it are not auto-migrated.
url: '#delete-a-node-inbounds-bound-to-it-are-not-auto-migrated'
@@ -105,14 +102,11 @@ _openapi:
node-assigned inbound gets paths that exist on the node, not the
central panel.
id: fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- content: Register a new remote node. Provide its URL, write-only apiToken, and
optional remark / allowPrivateAddress flag. Responses expose
hasApiToken only.
id: register-a-new-remote-node-provide-its-url-write-only-apitoken-and-optional-remark--allowprivateaddress-flag-responses-expose-hasapitoken-only
- content: 'Replace a node’s connection details. apiToken is write-only: omit it
or send an empty string to keep the stored token; set
clearApiToken=true to clear it.'
id: replace-a-nodes-connection-details-apitoken-is-write-only-omit-it-or-send-an-empty-string-to-keep-the-stored-token-set-clearapitokentrue-to-clear-it
- content: Register a new remote node. Provide its URL and optional remark /
allowPrivateAddress flag.
id: register-a-new-remote-node-provide-its-url-and-optional-remark--allowprivateaddress-flag
- content: Replace a node’s connection details.
id: replace-a-nodes-connection-details
- content: Delete a node. Inbounds bound to it are not auto-migrated.
id: delete-a-node-inbounds-bound-to-it-are-not-auto-migrated
- content: Pause or resume traffic sync with this node.
@@ -53,8 +53,8 @@ _openapi:
title: List Xray binary versions available for install on this host.
url: '#list-xray-binary-versions-available-for-install-on-this-host'
- depth: 2
title: Check whether a newer 3x-ui release is available on GitHub.
url: '#check-whether-a-newer-3x-ui-release-is-available-on-github'
title: Check whether a newer L-UI release is available on GitHub.
url: '#check-whether-a-newer-L-UI-release-is-available-on-github'
- depth: 2
title: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one
@@ -218,8 +218,8 @@ _openapi:
id: time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- content: List Xray binary versions available for install on this host.
id: list-xray-binary-versions-available-for-install-on-this-host
- content: Check whether a newer 3x-ui release is available on GitHub.
id: check-whether-a-newer-3x-ui-release-is-available-on-github
- content: Check whether a newer L-UI release is available on GitHub.
id: check-whether-a-newer-L-UI-release-is-available-on-github
- content: Report the outcome of the most recently launched panel self-update (see
POST updatePanel). Compare the returned runId against the one
updatePanel returned to tell this run apart from a stale result.
@@ -36,10 +36,10 @@ _openapi:
values on success.
url: '#change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success'
- depth: 2
title: Restart the entire 3x-ui process after a 3-second grace period. The
title: Restart the entire L-UI process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10 seconds
later.
url: '#restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later'
url: '#restart-the-entire-L-UI-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later'
- depth: 2
title: Test SMTP connection with stage-by-stage reporting (connect, auth, send).
Returns structured result with stage and message.
@@ -76,10 +76,10 @@ _openapi:
credentials for verification. The session is refreshed with the new
values on success.
id: change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- content: Restart the entire 3x-ui process after a 3-second grace period. The
- content: Restart the entire L-UI process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10
seconds later.
id: restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
id: restart-the-entire-L-UI-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- content: Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
id: test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
+14 -14
View File
@@ -1,17 +1,17 @@
---
title: Database
description: 3x-ui storage backends — SQLite (default) and PostgreSQL — the database path, connection pool, and SQLite-to-PostgreSQL migration.
description: L-UI storage backends — SQLite (default) and PostgreSQL — the database path, connection pool, and SQLite-to-PostgreSQL migration.
icon: Database
---
3x-ui stores everything — inbounds, clients, settings — in a database. You choose
L-UI stores everything — inbounds, clients, settings — in a database. You choose
the backend at install time; both are first-class.
## SQLite (default)
A single file at `/etc/x-ui/x-ui.db`. Zero setup, ideal for small and medium
A single file at `/etc/l-ui/l-ui.db`. Zero setup, ideal for small and medium
deployments. The folder is configurable with
[`XUI_DB_FOLDER`](/docs/reference/env-vars#database) (on Windows it defaults next
[`LUI_DB_FOLDER`](/docs/reference/env-vars#database) (on Windows it defaults next
to the binary).
## PostgreSQL
@@ -19,20 +19,20 @@ to the binary).
Recommended for high client counts or multi-node setups. The installer can
install PostgreSQL locally for you, or accept a DSN to an existing server. At
runtime the backend is selected via environment variables, which the installer
writes to `/etc/default/x-ui`:
writes to `/etc/default/l-ui`:
```bash title="/etc/default/x-ui"
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```bash title="/etc/default/l-ui"
LUI_DB_TYPE=postgres
LUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
Tune the connection pool with `XUI_DB_MAX_OPEN_CONNS` and
`XUI_DB_MAX_IDLE_CONNS`.
Tune the connection pool with `LUI_DB_MAX_OPEN_CONNS` and
`LUI_DB_MAX_IDLE_CONNS`.
### Docker
`docker compose up -d` keeps using SQLite. To run with the bundled PostgreSQL
service, uncomment the two `XUI_DB_*` lines in `docker-compose.yml` and start
service, uncomment the two `LUI_DB_*` lines in `docker-compose.yml` and start
with the profile:
```bash
@@ -44,13 +44,13 @@ docker compose --profile postgres up -d
Move an existing SQLite install to PostgreSQL with the built-in command:
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
l-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
```
Then set `XUI_DB_TYPE` and `XUI_DB_DSN` in `/etc/default/x-ui` and restart:
Then set `LUI_DB_TYPE` and `LUI_DB_DSN` in `/etc/default/l-ui` and restart:
```bash
systemctl restart x-ui
systemctl restart l-ui
```
<Callout type="info">
+30 -30
View File
@@ -1,46 +1,46 @@
---
title: Environment Variables
description: Complete reference for 3x-ui's XUI_* environment variables — database, panel, logging, memory, and the tunnel health monitor.
description: Complete reference for L-UI's LUI_* environment variables — database, panel, logging, memory, and the tunnel health monitor.
icon: Variable
---
3x-ui reads its runtime configuration from `XUI_*` environment variables. On a
L-UI reads its runtime configuration from `LUI_*` environment variables. On a
script install the installer writes them to the service environment file
(`/etc/default/x-ui`, or `/etc/conf.d/x-ui` / `/etc/sysconfig/x-ui` depending on
(`/etc/default/l-ui`, or `/etc/conf.d/l-ui` / `/etc/sysconfig/l-ui` depending on
the distro); for Docker you set them in `docker-compose.yml` or `docker run -e`.
Defaults are sensible — set only what you need to change, then restart:
`systemctl restart x-ui`.
`systemctl restart l-ui`.
## Database
| Variable | Default | Description |
| ------------------------ | ----------- | -------------------------------------------------------------------- |
| `XUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). |
| `XUI_DB_FOLDER` | `/etc/x-ui` | Folder for the SQLite database file (`x-ui.db`). |
| `XUI_DB_DSN` | — | PostgreSQL connection string (used when `XUI_DB_TYPE=postgres`). |
| `XUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. |
| `XUI_DB_MAX_IDLE_CONNS` | — | Max idle connections in the PostgreSQL pool. |
| `LUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). |
| `LUI_DB_FOLDER` | `/etc/l-ui` | Folder for the SQLite database file (`l-ui.db`). |
| `LUI_DB_DSN` | — | PostgreSQL connection string (used when `LUI_DB_TYPE=postgres`). |
| `LUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. |
| `LUI_DB_MAX_IDLE_CONNS` | — | Max idle connections in the PostgreSQL pool. |
The default SQLite database path is `/etc/x-ui/x-ui.db`. See
The default SQLite database path is `/etc/l-ui/l-ui.db`. See
[Database](/docs/reference/database) for the SQLite ↔ PostgreSQL details.
## Panel
| Variable | Default | Description |
| ------------------------ | ------- | ------------------------------------------------------------------------ |
| `XUI_PORT` | — | Override the panel port (1–65535). Takes precedence over the stored setting. |
| `XUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. |
| `XUI_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
| `LUI_PORT` | — | Override the panel port (1–65535). Takes precedence over the stored setting. |
| `LUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `LUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. |
| `LUI_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
## Logging & binaries
| Variable | Default | Description |
| ---------------- | ---------------- | ----------------------------------------------------------- |
| `XUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `XUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `XUI_LOG_FOLDER` | `/var/log/x-ui` | Log output directory. |
| `XUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
| `LUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `LUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `LUI_LOG_FOLDER` | `/var/log/l-ui` | Log output directory. |
| `LUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
## Memory & profiling
@@ -49,11 +49,11 @@ knobs — leave them unset unless you're tuning a constrained host.
| Variable | Default | Description |
| ----------------------------- | ------- | ----------------------------------------------------------------- |
| `XUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `XUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `XUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `LUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `LUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `LUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `GOMEMLIMIT` | — | Go-syntax soft limit (e.g. `400MiB`); takes precedence over above.|
| `XUI_PPROF` | `false` | Expose pprof profiling on `127.0.0.1:6060`. |
| `LUI_PPROF` | `false` | Expose pprof profiling on `127.0.0.1:6060`. |
## Xray
@@ -69,16 +69,16 @@ clients, so enable it deliberately.
| Variable | Default | Description |
| ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| `XUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. |
| `XUI_TUNNEL_HEALTH_PROXY` | — | Proxy to send the probe through, e.g. `socks5://127.0.0.1:1080`. Empty = only checks host connectivity. |
| `XUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `XUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `XUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
| `LUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. |
| `LUI_TUNNEL_HEALTH_PROXY` | — | Proxy to send the probe through, e.g. `socks5://127.0.0.1:1080`. Empty = only checks host connectivity. |
| `LUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `LUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `LUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `LUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `LUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
## Unattended install
| Variable | Description |
| -------------------- | -------------------------------------------------------------------------------------------- |
| `XUI_NONINTERACTIVE` | Set to `1` (or run with no TTY) to install with zero prompts; generated credentials are written to `/etc/x-ui/install-result.env`. See [Installation](/docs/guide/installation#unattended--cloud-init). |
| `LUI_NONINTERACTIVE` | Set to `1` (or run with no TTY) to install with zero prompts; generated credentials are written to `/etc/l-ui/install-result.env`. See [Installation](/docs/guide/installation#unattended--cloud-init). |
@@ -1,6 +1,6 @@
---
title: Ports & Firewall
description: The ports 3x-ui uses by default and ready-made ufw / nftables rules to open them.
description: The ports L-UI uses by default and ready-made ufw / nftables rules to open them.
icon: Network
---
@@ -32,5 +32,5 @@ Your actual inbound ports depend on the inbounds you create.
<Cards>
<Card title="Security" href="/docs/operations/security" description="Fail2ban, IP limits, and hardening." />
<Card title="Environment variables" href="/docs/reference/env-vars" description="XUI_PORT and friends." />
<Card title="Environment variables" href="/docs/reference/env-vars" description="LUI_PORT and friends." />
</Cards>
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: کلاینت‌ها
description: مدیریت کلاینت‌های 3x-ui — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
description: مدیریت کلاینت‌های L-UI — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
icon: Users
---
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: ورودی‌ها و پروتکل‌ها
description: ساخت ورودی‌ها در 3x-ui — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
description: ساخت ورودی‌ها در L-UI — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
icon: ArrowDownToLine
---
@@ -74,7 +74,7 @@ TLS یا REALITY) را انتخاب کنید. به [انتقال‌ها](/docs/c
Fallbackها به یک پورت TLS واحد (مثلاً `443`) اجازه می‌دهند بیش از یک پروتکل را
سرویس دهد — برای مثال VLESS **و** Trojan — با هدایت دست‌دادن‌های (handshake)
ناهماهنگ به یک ورودی فرزند. در 3x-ui، fallbackها در پنل مدیریت می‌شوند (لیست
ناهماهنگ به یک ورودی فرزند. در L-UI، fallbackها در پنل مدیریت می‌شوند (لیست
**Fallbacks** یک ورودی اصلی) به‌جای آنکه به‌صورت دستی در JSON نوشته شوند.
Fallbackها تنها زمانی در دسترس‌اند که ورودی اصلی این‌گونه باشد:
+4 -4
View File
@@ -1,6 +1,6 @@
---
title: تنظیمات پنل
description: تمام تنظیمات پنل 3x-ui — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
description: تمام تنظیمات پنل L-UI — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
icon: SlidersHorizontal
---
@@ -14,7 +14,7 @@ icon: SlidersHorizontal
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `XUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `LUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webListen` | _(همه‌ی واسط‌ها)_ | پنل را به یک IP مشخص مقید کنید. |
| `webBasePath` | `/` | مسیر URLی که پنل زیر آن ارائه می‌شود (همیشه به شکل `/…/` نرمال‌سازی می‌شود). |
| `webCertFile` / `webKeyFile` | _(هیچ‌کدام)_ | گواهی + کلید TLS. وقتی هر دو تنظیم شوند، پنل با **HTTPS** ارائه می‌شود. |
@@ -24,12 +24,12 @@ icon: SlidersHorizontal
پس از تغییر پورت یا مسیر پایه، آدرس پنل به‌صورت
`http(s)://<server>:<port><web-base-path>` درمی‌آید. می‌توانید مسیر پایه را در
نخستین اجرا با [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars) از پیش تعیین کنید.
نخستین اجرا با [`LUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars) از پیش تعیین کنید.
### TLS
ارائه‌ی پنل روی HTTPS از اطلاعات احراز هویت شما در حین انتقال محافظت می‌کند. یا
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `x-ui`](/docs/config/ssl-certificates)
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `l-ui`](/docs/config/ssl-certificates)
می‌تواند یک گواهی Let's Encrypt برای شما تهیه کند — یا TLS را روی یک
[پروکسی معکوس](/docs/operations/reverse-proxy) خاتمه دهید.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: REALITY
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در 3x-ui — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در L-UI — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
icon: ShieldCheck
---
@@ -15,7 +15,7 @@ REALITY همراه با **VLESS** (و Trojan) به‌کار می‌رود. جر
## تنظیمات کلیدی
وقتی **REALITY** را به‌عنوان حالت امنیتی روی یک ورودی VLESS انتخاب می‌کنید، 3x-ui
وقتی **REALITY** را به‌عنوان حالت امنیتی روی یک ورودی VLESS انتخاب می‌کنید، L-UI
این فیلدها را نمایش می‌دهد:
| فیلد | چیست |
+2 -2
View File
@@ -1,10 +1,10 @@
---
title: لینک‌های اشتراک‌گذاری
description: قالب‌های لینک اشتراک‌گذاری 3x-ui (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
description: قالب‌های لینک اشتراک‌گذاری L-UI (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
icon: Link
---
3x-ui برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
L-UI برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
مانند v2rayNG، Hiddify و Mihomo این لینک‌ها را برای پیکربندی خودشان وارد می‌کنند.
## قالب‌های لینک
@@ -1,6 +1,6 @@
---
title: گواهی‌های SSL
description: دریافت و تمدید گواهی‌های TLS برای پنل و ورودی‌های 3x-ui — با منوی ACME در x-ui (دامنه یا IP خام)، گواهی wildcard از طریق Cloudflare DNS-01، یا Certbot دستی.
description: دریافت و تمدید گواهی‌های TLS برای پنل و ورودی‌های L-UI — با منوی ACME در l-ui (دامنه یا IP خام)، گواهی wildcard از طریق Cloudflare DNS-01، یا Certbot دستی.
icon: ShieldCheck
---
@@ -8,7 +8,7 @@ icon: ShieldCheck
API شما رمزگذاری شود) و TLS را روی **ورودی‌ها** خاتمه دهید (VLESS-TLS، Trojan،
Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌آوردن گواهی وجود دارد:
- **منوی `x-ui`** — کلاینت داخلی [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment).
- **منوی `l-ui`** — کلاینت داخلی [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment).
آسان‌ترین گزینه برای یک دامنه‌ی واحد یا یک IP خام.
- **Cloudflare DNS-01** — این هم از همان منو؛ برای گواهی‌های **wildcard** یا
زمانی که پورت 80 مسدود است / سرور پشت پراکسی Cloudflare قرار دارد لازم است.
@@ -21,9 +21,9 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
TLS یک سایت واقعی را قرض می‌گیرند. این صفحه برای پنل و برای ورودی‌های کلاسیک TLS است.
</Callout>
## منوی SSL در `x-ui` (Let's Encrypt)
## منوی SSL در `l-ui` (Let's Encrypt)
`x-ui` را اجرا کنید و **`20` — SSL Certificate Management** را انتخاب کنید. این گزینه
`l-ui` را اجرا کنید و **`20` — SSL Certificate Management** را انتخاب کنید. این گزینه
[acme.sh](https://github.com/acmesh-official/acme.sh) را به کار می‌گیرد و موارد زیر را ارائه می‌دهد:
| گزینه | کاری که انجام می‌دهد |
@@ -57,7 +57,7 @@ Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌
<Step>
### صادرکننده را اجرا کنید
`x-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
`l-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
درخواست می‌کند و آن را زیر `/root/cert/<domain>/` به‌صورت `fullchain.pem`
(زنجیره‌ی گواهی) و `privkey.pem` (کلید خصوصی) ذخیره می‌کند.
</Step>
@@ -104,7 +104,7 @@ DNS دامنه‌ی شما باید توسط Cloudflare مدیریت شود و
<Step>
### صادرکننده‌ی Cloudflare را اجرا کنید
`x-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
`l-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
توکن API (پیش‌فرض) یا **`g`** را برای Global API Key انتخاب کنید، سپس دامنه‌ی خود را
وارد کنید (و برای Global API Key، ایمیل حساب و کلید خود را). acme.sh رکورد TXT را
می‌سازد، اعتبارسنجی می‌کند و آن را پاک‌سازی می‌کند.
+2 -2
View File
@@ -1,6 +1,6 @@
---
title: Subscription
description: راه‌اندازی سرور اشتراک 3x-ui — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
description: راه‌اندازی سرور اشتراک L-UI — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
icon: Rss
---
@@ -59,7 +59,7 @@ https://<sub-host>:<sub-port>/sub/<sub-id>
با standard-base64 رمزگذاری شده‌اند (با `subEncrypt` قابل تغییر است). بدنه‌ی **JSON**
هر کلاینت را در یک پیکربندی کامل کلاینت Xray می‌پیچد — یک اسکلت ثابت (ورودی‌های محلی
mixed/HTTP، DNS، مسیریابی، policy) به‌علاوه‌ی یک outbound از نوع `proxy` که به ورودی
اشاره می‌کند. 3x-ui **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
اشاره می‌کند. L-UI **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
تولید می‌کند، از فرم تخت `settings` در outbound استفاده می‌کند
(`address`/`port`/`id`، `level: 8`) و `sockopt` را از `streamSettings` حذف می‌کند.
+1 -1
View File
@@ -1,6 +1,6 @@
---
title: انتقال‌ها و امنیت
description: هر انتقالی که 3x-ui ارائه می‌دهد — TCP، mKCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، Hysteria — به‌همراه تنظیماتشان، و نیز مبهم‌سازی FinalMask، sockopt، TLS/REALITY، XTLS-Vision و رمزنگاری VLESS.
description: هر انتقالی که L-UI ارائه می‌دهد — TCP، mKCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، Hysteria — به‌همراه تنظیماتشان، و نیز مبهم‌سازی FinalMask، sockopt، TLS/REALITY، XTLS-Vision و رمزنگاری VLESS.
icon: Network
---
+16 -16
View File
@@ -1,6 +1,6 @@
---
title: نخستین ورود
description: مشخصات ورود تولیدشدهٔ 3x-ui را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
description: مشخصات ورود تولیدشدهٔ L-UI را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
icon: KeyRound
---
@@ -24,25 +24,25 @@ http://<your-server-ip>:<port>/<web-base-path>
نصب با اسکریپت پس از پایان، خلاصه‌ای از مشخصات ورود را چاپ می‌کند و آن را در یک
فایل ویژهٔ root نیز می‌نویسد:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```bash title="/etc/l-ui/install-result.env (mode 600)"
LUI_USERNAME=...
LUI_PASSWORD=...
LUI_PANEL_PORT=...
LUI_WEB_BASE_PATH=...
LUI_ACCESS_URL=...
LUI_API_TOKEN=...
LUI_DB_TYPE=sqlite
```
اگر آن‌ها را از دست دادید، از ابزارهای مدیریتی استفاده کنید:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
l-ui # menu → 11 (View Current Settings)
l-ui settings # or the one-shot form
```
برای **Docker**، مشخصات ورود تولیدشده را از لاگ‌های کانتینر بخوانید، یا دستور
`docker exec -it <container> x-ui setting -show` را اجرا کنید.
`docker exec -it <container> l-ui setting -show` را اجرا کنید.
<Callout type="warn">
اگر پنل شما هنوز از مقادیر پیش‌فرض `admin` / `admin` استفاده می‌کند (پنل در این
@@ -53,7 +53,7 @@ x-ui settings # or the one-shot form
یک پورت غیرپیش‌فرض و یک **مسیر پایهٔ وب** طولانی و تصادفی، یافتن پنل را بسیار
دشوارتر می‌کند. آن‌ها را از بخش **Panel Settings** در رابط کاربری، یا از منوی
`x-ui` تغییر دهید:
`l-ui` تغییر دهید:
- **7 — Reset Username & Password** (با امکان غیرفعال‌سازی همزمان 2FA)
- **8 — Reset Web Base Path** (آن را تصادفی می‌کند)
@@ -64,11 +64,11 @@ x-ui settings # or the one-shot form
## احراز هویت دومرحله‌ای (2FA)
‏3x-ui از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
‏L-UI از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
Authenticator، Aegis و غیره). آن را در بخش **Panel Settings** فعال کنید — پس از
فعال‌سازی، صفحهٔ ورود علاوه بر رمز عبور، یک کد ۶ رقمی نیز درخواست می‌کند و
فعال کردن آن همه را وادار به ورود مجدد می‌کند. می‌توانید آن را از مرحلهٔ **Reset
Username & Password** در منو یا با دستور `x-ui setting -resetTwoFactor` غیرفعال
Username & Password** در منو یا با دستور `l-ui setting -resetTwoFactor` غیرفعال
کنید.
## محافظت داخلی از ورود
@@ -106,7 +106,7 @@ Username & Password** در منو یا با دستور `x-ui setting -resetTwoFa
<Step>
### پنل را پشت TLS قرار دهید
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `x-ui` یا یک reverse proxy)
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `l-ui` یا یک reverse proxy)
استفاده کنید تا پنل تنها از طریق HTTPS در دسترس باشد.
</Step>
+6 -6
View File
@@ -1,10 +1,10 @@
---
title: آشنایی با 3x-ui
title: آشنایی با L-UI
description: یک پنل تحت وب برای Xray-core — ورودی‌ها، پروتکل‌ها، کلاینت‌ها و اشتراک‌ها را به‌جای ویرایش دستی JSON، از مرورگر خود مدیریت کنید.
icon: Info
---
**3x-ui** یک پنل کنترل تحت وب است که روی
**L-UI** یک پنل کنترل تحت وب است که روی
[Xray-core](https://github.com/XTLS/Xray-core)، همان موتور پروکسی که در واقع
ترافیک شما را جابه‌جا می‌کند، قرار می‌گیرد. به‌جای نوشتن و بارگذاری مجدد پیکربندی
JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها، پروتکل‌ها، کلاینت‌ها، گواهی‌ها،
@@ -15,7 +15,7 @@ JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها،
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Admin["Admin browser"] -->|HTTPS panel| Panel["L-UI panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
@@ -53,19 +53,19 @@ flowchart LR
| پایگاه‌داده | SQLite (پیش‌فرض) یا PostgreSQL |
| موتور پروکسی | Xray-core (همراه و مدیریت‌شده توسط پنل) |
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/x-ui/x-ui.db` قرار دارد و پنل به‌صورت
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/l-ui/l-ui.db` قرار دارد و پنل به‌صورت
پیش‌فرض روی پورت **2053** گوش می‌دهد. هر دو قابل پیکربندی هستند — به
[نخستین ورود](/docs/guide/first-login) و مرجع متغیرهای محیطی مراجعه کنید.
## برای چه کسانی است
3x-ui برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
L-UI برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
VPS شخصی منفرد تا اپراتورهایی که نودها و کلاینت‌های فراوانی را مدیریت می‌کنند. اگر
قدرت Xray-core را می‌خواهید بدون اینکه در فایل‌های پیکربندی JSON زندگی کنید، این
برای شماست.
<Callout type="info">
3x-ui یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
L-UI یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت
چندنودی و بسیاری از قابلیت‌های راحتی‌بخش را اضافه می‌کند.
</Callout>
+18 -18
View File
@@ -1,17 +1,17 @@
---
title: نصب
description: نصب 3x-ui با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
description: نصب L-UI با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
icon: Download
---
‏3x-ui روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
‏L-UI روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
Fedora، CentOS، RHEL، AlmaLinux، Rocky Linux، Oracle Linux، Amazon Linux،
Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچنین Windows،
روی معماری‌های `amd64`، `386`، `arm64`، `armv7`، `armv6`، `armv5` و `s390x`.
<Callout type="warn">
نصب‌کنندهٔ اسکریپتی را به‌صورت **root** (یا با `sudo`) اجرا کنید. این اسکریپت یک
سرویس نصب می‌کند، دستور مدیریتی `x-ui` را راه‌اندازی می‌کند و پنل را در زمان
سرویس نصب می‌کند، دستور مدیریتی `l-ui` را راه‌اندازی می‌کند و پنل را در زمان
بوت فعال می‌سازد.
</Callout>
@@ -21,7 +21,7 @@ Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچن
اسکریپت رسمی مسیر توصیه‌شده است. این اسکریپت در طول نصب یک نام کاربری، رمز عبور و
مسیر دسترسی (مسیر پایهٔ وب) **تصادفی** تولید می‌کند، سرویس را راه‌اندازی می‌کند و
دستور مدیریتی `x-ui` را نصب می‌کند.
دستور مدیریتی `l-ui` را نصب می‌کند.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
@@ -40,8 +40,8 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `x-ui` را اجرا کنید تا
[منوی مدیریت](/docs/guide/update-uninstall#the-x-ui-management-menu) باز شود، سپس
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `l-ui` را اجرا کنید تا
[منوی مدیریت](/docs/guide/update-uninstall#the-l-ui-management-menu) باز شود، سپس
به [نخستین ورود](/docs/guide/first-login) ادامه دهید.
</Tab>
@@ -55,7 +55,7 @@ bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.
docker compose up -d
```
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `XUI_DB_*` را در
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `LUI_DB_*` را در
`docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل مربوطه اجرا کنید:
```bash
@@ -71,16 +71,16 @@ docker compose --profile postgres up -d
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-e LUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/l-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
--name L-UI \
ghcr.io/mhsanaei/3x-ui:latest
```
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/x-ui/x-ui.db`) را نگه می‌دارد و `cert/`
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/l-ui/l-ui.db`) را نگه می‌دارد و `cert/`
گواهی‌های TLS را، بنابراین داده‌های شما در ارتقاها حفظ می‌شوند.
</Tab>
@@ -88,7 +88,7 @@ docker run -d \
<Tab value="Manual">
برای کاربران پیشرفته، یک آرشیو انتشار متناسب با معماری خود را از
[صفحهٔ releases](https://github.com/MHSanaei/3x-ui/releases) دانلود کنید، آن را
[صفحهٔ releases](https://github.com/MHSanaei/L-UI/releases) دانلود کنید، آن را
استخراج کنید و باینری را به‌عنوان یک سرویس systemd اجرا کنید. اسکریپت نصب دقیقاً
همین مراحل را خودکار می‌کند، بنابراین مگر اینکه دلیل خاصی برای نصب دستی داشته
باشید، روش اسکریپتی ترجیح داده می‌شود.
@@ -107,7 +107,7 @@ docker run -d \
شما بک‌اند ذخیره‌سازی را در زمان نصب انتخاب می‌کنید:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/l-ui/l-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **PostgreSQL** — برای تعداد کلاینت بالا یا پیکربندی‌های چندنودی. نصب‌کننده
می‌تواند آن را به‌صورت محلی نصب کند یا از یک DSN که شما ارائه می‌دهید استفاده کند.
@@ -117,15 +117,15 @@ docker run -d \
## نصب خودکار / cloud-init
نصب‌کننده برای خودکارسازی به‌صورت **غیرتعاملی** نیز اجرا می‌شود.
`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
`LUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
سرتاسری و بدون هیچ پرسشی انجام شود، مشخصات تصادفی تولید کند و آن‌ها را در
`/etc/x-ui/install-result.env` بنویسد:
`/etc/l-ui/install-result.env` بنویسد:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
LUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
دایرکتوری [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy) در مخزن
دایرکتوری [`deploy/`](https://github.com/MHSanaei/L-UI/tree/main/deploy) در مخزن
یک user-data آمادهٔ **cloud-init** برای نصب‌های خودکار روی هر ابری (Hetzner، AWS،
DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
@@ -140,7 +140,7 @@ DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
<Card
title="به‌روزرسانی و حذف نصب"
href="/docs/guide/update-uninstall"
description="منوی x-ui، به‌روزرسانی‌ها و حذف."
description="منوی l-ui، به‌روزرسانی‌ها و حذف."
/>
<Card
title="REALITY"
+26 -26
View File
@@ -1,17 +1,17 @@
---
title: به‌روزرسانی و حذف
description: مدیریت 3x-ui با منوی x-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
description: مدیریت L-UI با منوی l-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
icon: RefreshCw
---
پس از نصب با اسکریپت، دستور `x-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
پس از نصب با اسکریپت، دستور `l-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
کنید تا منوی تعاملی باز شود، یا یک زیردستور به آن بدهید تا یک عملیات تک‌مرحله‌ای انجام شود.
```bash
x-ui
l-ui
```
## منوی مدیریت `x-ui`
## منوی مدیریت `l-ui`
منو (آیتم‌های `0`–`28`) وضعیت پنل/Xray را در بالا نشان می‌دهد و سپس:
@@ -20,9 +20,9 @@ x-ui
| 1 | Install | (دوباره) نصب از روی اسکریپت راه دور |
| 2 | Update | به‌روزرسانی به آخرین نسخهٔ **پایدار** |
| 3 | Update to Dev Channel (latest commit) | به‌روزرسانی به بیلد غلتان `dev-latest` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `x-ui` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `l-ui` |
| 5 | Legacy Version | نصب یک نسخهٔ قدیمی مشخص (تگ را می‌پرسد) |
| 6 | Uninstall | حذف 3x-ui (در ادامه ببینید) |
| 6 | Uninstall | حذف L-UI (در ادامه ببینید) |
| 7 | Reset Username & Password | تنظیم مشخصات جدید؛ اختیاراً غیرفعال‌کردن 2FA |
| 8 | Reset Web Base Path | تصادفی‌کردن مسیر پایهٔ وب |
| 9 | Reset Settings | بازنشانی تنظیمات پنل (حساب شما حفظ می‌شود) |
@@ -51,29 +51,29 @@ x-ui
## زیردستورهای خط فرمان
برای اسکریپت‌ها و اقدام‌های سریع، `x-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
برای اسکریپت‌ها و اقدام‌های سریع، `l-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
| دستور | عملیات |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | کنترل سرویس |
| `x-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `x-ui status` | نمایش وضعیت |
| `x-ui settings` | نمایش تنظیمات فعلی |
| `x-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `x-ui log` | دنبال‌کردن لاگ دیباگ |
| `x-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `x-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `x-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `x-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `x-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `x-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `x-ui install` / `uninstall` | نصب / حذف |
| `l-ui start` / `stop` / `restart` | کنترل سرویس |
| `l-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `l-ui status` | نمایش وضعیت |
| `l-ui settings` | نمایش تنظیمات فعلی |
| `l-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `l-ui log` | دنبال‌کردن لاگ دیباگ |
| `l-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `l-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `l-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `l-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `l-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `l-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `l-ui install` / `uninstall` | نصب / حذف |
## به‌روزرسانی
- **پایدار:** گزینهٔ منوی **۲** یا `x-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
- **پایدار:** گزینهٔ منوی **۲** یا `l-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
در همان محل به‌روزرسانی می‌کند.
- **کانال dev:** گزینهٔ منوی **۳** یا `x-ui update-dev` — بیلد غلتان
- **کانال dev:** گزینهٔ منوی **۳** یا `l-ui update-dev` — بیلد غلتان
`dev-latest` به‌ازای هر کامیت (نه یک نسخهٔ پایدار).
- **یک نسخهٔ قدیمی مشخص:** گزینهٔ منوی **۵** (Legacy Version).
@@ -82,18 +82,18 @@ x-ui
<Callout type="info">
کاربران Docker به شیوهٔ دیگری به‌روزرسانی می‌کنند — به‌جای استفاده از دستورهای
به‌روزرسانی `x-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
به‌روزرسانی `l-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
(`docker compose pull && docker compose up -d`).
</Callout>
## حذف
گزینهٔ منوی **۶** یا `x-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/x-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
گزینهٔ منوی **۶** یا `l-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/l-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
نصب‌شده به‌صورت محلی استفاده می‌کرده، پیشنهاد می‌دهد آن را هم پاک‌سازی کند (یک تأیید
جداگانه و برگشت‌ناپذیر).
<Callout type="warn">
حذف، پایگاه‌داده (`/etc/x-ui/x-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
حذف، پایگاه‌داده (`/etc/l-ui/l-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
بعداً به آن نیاز داشته باشید، ابتدا [پشتیبان بگیرید](/docs/operations/backup-restore).
</Callout>
+6 -6
View File
@@ -1,28 +1,28 @@
---
title: مشارکت
description: چگونه در توسعه 3x-ui مشارکت کنید و این مستندات را ترجمه کنید.
description: چگونه در توسعه L-UI مشارکت کنید و این مستندات را ترجمه کنید.
icon: GitPullRequestArrow
---
3x-ui یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
L-UI یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
می‌شود.
## حمایت از توسعه‌دهنده
3x-ui رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
L-UI رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
مفید بوده است، حمایت از ادامه توسعه را در نظر بگیرید:
- در [donate.sanaei.dev](https://donate.sanaei.dev/) **کمک مالی** کنید — این صفحه
**اهداف و سقف‌های** جاری تأمین مالی را که می‌توانید در رسیدن به آن‌ها کمک کنید نشان می‌دهد.
- به [مخزن](https://github.com/MHSanaei/3x-ui) **ستاره** بدهید و پروژه را به اشتراک
- به [مخزن](https://github.com/MHSanaei/L-UI) **ستاره** بدهید و پروژه را به اشتراک
بگذارید.
- به کانال Telegram یعنی [@XrayUI](https://t.me/XrayUI) **بپیوندید** تا اخبار را
دنبال کنید و به دیگران کمک کنید.
## مشارکت در 3x-ui
## مشارکت در L-UI
- فایل `CONTRIBUTING.md` پروژه را در
[مخزن](https://github.com/MHSanaei/3x-ui) بخوانید.
[مخزن](https://github.com/MHSanaei/L-UI) بخوانید.
- برای باگ‌ها و درخواست‌های امکانات جدید، با گام‌های بازتولید روشن، issue باز کنید.
- از Conventional Commits استفاده کنید و pull requestها را متمرکز نگه دارید.
+9 -9
View File
@@ -1,13 +1,13 @@
---
title: سؤالات متداول
description: پرسش‌های پرتکرار درباره 3x-ui — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
description: پرسش‌های پرتکرار درباره L-UI — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
icon: CircleQuestionMark
---
## آیا 3x-ui رایگان و متن‌باز است؟
## آیا L-UI رایگان و متن‌باز است؟
بله. 3x-ui تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/3x-ui) در دسترس است.
بله. L-UI تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/L-UI) در دسترس است.
## روی چه سیستم‌هایی اجرا می‌شود؟
@@ -18,7 +18,7 @@ Fedora، Arch، Alpine و موارد دیگر) روی معماری‌های `amd
## SQLite یا PostgreSQL؟
SQLite گزینه پیش‌فرض است و برای بیشتر استقرارها مناسب است. PostgreSQL برای
راه‌اندازی‌های بزرگ‌تر از طریق `XUI_DB_TYPE=postgres` و `XUI_DB_DSN` در دسترس است — به
راه‌اندازی‌های بزرگ‌تر از طریق `LUI_DB_TYPE=postgres` و `LUI_DB_DSN` در دسترس است — به
[متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
## کدام اپلیکیشن‌های کلاینت با آن کار می‌کنند؟
@@ -27,9 +27,9 @@ SQLite گزینه پیش‌فرض است و برای بیشتر استقراره
لینک اشتراک‌گذاری یا کد QR یک کلاینت را وارد کنید، یا از
[سابسکریپشن](/docs/config/subscription) استفاده کنید.
## 3x-ui چه تفاوتی با x-ui دارد؟
## L-UI چه تفاوتی با l-ui دارد؟
3x-ui یک فورک ارتقایافته از پروژه اصلی X-UI است. این پروژه پشتیبانی گسترده‌تری از
L-UI یک فورک ارتقایافته از پروژه اصلی X-UI است. این پروژه پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت چندنودی،
یک رابط کاربری ۱۳ زبانه و بسیاری از امکانات رفاهی را اضافه می‌کند.
@@ -37,11 +37,11 @@ SQLite گزینه پیش‌فرض است و برای بیشتر استقراره
اسکریپت نصب را دوباره اجرا کنید (به‌صورت درجا به‌روزرسانی می‌شود)، یا ایمیج جدید Docker را دریافت کنید.
به [نصب](/docs/guide/installation) و
[صفحه نسخه‌ها](https://github.com/MHSanaei/3x-ui/releases) مراجعه کنید.
[صفحه نسخه‌ها](https://github.com/MHSanaei/L-UI/releases) مراجعه کنید.
## از کجا می‌توانم کمک بگیرم؟
به کانال رسمی Telegram با نشانی [@XrayUI](https://t.me/XrayUI) برای
اطلاعیه‌ها و پشتیبانی انجمن بپیوندید، یا یک ایشو روی
[GitHub](https://github.com/MHSanaei/3x-ui/issues) باز کنید. برای مشکلات رایج، با
[GitHub](https://github.com/MHSanaei/L-UI/issues) باز کنید. برای مشکلات رایج، با
[عیب‌یابی](/docs/help/troubleshooting) شروع کنید.
+8 -8
View File
@@ -1,6 +1,6 @@
---
title: مهاجرت
description: مهاجرت به 3x-ui از x-ui، بین سرورها یا بین نسخه‌های 3x-ui.
description: مهاجرت به L-UI از l-ui، بین سرورها یا بین نسخه‌های L-UI.
icon: ArrowRightLeft
---
@@ -13,12 +13,12 @@ icon: ArrowRightLeft
<Step>
### از سرور قدیمی نسخه پشتیبان بگیرید
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/x-ui/x-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/l-ui/l-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
[پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) را ببینید.
</Step>
<Step>
### 3x-ui را روی سرور جدید نصب کنید
### L-UI را روی سرور جدید نصب کنید
از همان روش نصب و یک نسخهٔ سازگار استفاده کنید.
[نصب](/docs/guide/installation) را ببینید.
@@ -32,17 +32,17 @@ icon: ArrowRightLeft
</Steps>
## بین نسخه‌های 3x-ui
## بین نسخه‌های L-UI
در محدودهٔ یک backend یکسان، ارتقا معمولاً تنها به اجرای دوبارهٔ نصب‌کننده یا
کشیدن یک image جدید خلاصه می‌شود — پنل خودش پایگاه‌داده‌اش را مهاجرت می‌دهد. هنگام تغییر بین نسخه‌های **اصلی**،
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/3x-ui/releases)
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/L-UI/releases)
را بخوانید و یک نسخهٔ پشتیبان تهیه کنید.
## از x-ui
## از l-ui
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی x-ui به 3x-ui **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. 3x-ui را از نو نصب کنید و inboundها/کلاینت‌ها را
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی l-ui به L-UI **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. L-UI را از نو نصب کنید و inboundها/کلاینت‌ها را
دوباره بسازید و در همین حین لینک‌های اشتراک‌گذاری را از پنل قدیمی خروجی بگیرید.
<Callout type="warn">
@@ -1,17 +1,17 @@
---
title: عیب‌یابی
description: رفع مشکلات رایج 3x-ui — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
description: رفع مشکلات رایج L-UI — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
icon: Wrench
---
فهرستی برای رسیدگی به رایج‌ترین مشکلات. هرگاه مطمئن نبودید، سطح لاگ را بالا ببرید
(`XUI_LOG_LEVEL=debug`) و لاگ‌های پنل و Xray را بررسی کنید.
(`LUI_LOG_LEVEL=debug`) و لاگ‌های پنل و Xray را بررسی کنید.
## پنل اجرا نمی‌شود
- وضعیت سرویس و لاگ‌ها را بررسی کنید (منوی `x-ui` ← وضعیت/لاگ‌ها).
- وضعیت سرویس و لاگ‌ها را بررسی کنید (منوی `l-ui` ← وضعیت/لاگ‌ها).
- مطمئن شوید که **پورت پنل از قبل توسط سرویس دیگری اشغال نشده** باشد.
- بررسی کنید که مسیر دیتابیس قابل نوشتن باشد (پیش‌فرض `/etc/x-ui/x-ui.db`).
- بررسی کنید که مسیر دیتابیس قابل نوشتن باشد (پیش‌فرض `/etc/l-ui/l-ui.db`).
## خطای 502 / در دسترس نبودن پنل پشت یک پروکسی
@@ -37,6 +37,6 @@ icon: Wrench
<Callout type="info">
همچنان به مشکل خورده‌اید؟ در میان
[مسائل GitHub](https://github.com/MHSanaei/3x-ui/issues) جست‌وجو کنید — احتمالاً
[مسائل GitHub](https://github.com/MHSanaei/L-UI/issues) جست‌وجو کنید — احتمالاً
علامت مشکل شما قبلاً دیده شده است.
</Callout>
+5 -5
View File
@@ -1,10 +1,10 @@
---
title: مستندات 3x-ui
description: مستندات رسمی 3x-ui — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
title: مستندات L-UI
description: مستندات رسمی L-UI — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
icon: House
---
**3x-ui** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
**L-UI** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
[Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک داشبورد مدرن برای
اینباندها، پروتکل‌ها، کلاینت‌ها، حسابداری ترافیک، سابسکریپشن‌ها و موارد دیگر در
اختیار شما می‌گذارد — بدون نیاز به ویرایش دستی JSON مربوط به Xray از طریق خط فرمان.
@@ -17,7 +17,7 @@ icon: House
<Cards>
<Card
title="3x-ui چیست؟"
title="L-UI چیست؟"
href="/docs/guide"
description="نمای کلی: Xray-core، پنل، و اینکه برای چه کسانی مناسب است."
/>
@@ -49,6 +49,6 @@ icon: House
- **عملیات** — مدیریت چندنودی، ربات Telegram، پشتیبان‌گیری و یک REST API.
<Callout type="info">
با Xray تازه آشنا شده‌اید؟ ابتدا [3x-ui چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
با Xray تازه آشنا شده‌اید؟ ابتدا [L-UI چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
اپلیکیشن‌های کلاینت شما چگونه در کنار هم کار می‌کنند.
</Callout>
@@ -1,6 +1,6 @@
---
title: پشتیبان‌گیری و بازیابی
description: از پایگاه‌داده و گواهی‌های 3x-ui خود به‌صورت دستی یا از طریق ربات Telegram پشتیبان بگیرید و آن‌ها را بازیابی کنید.
description: از پایگاه‌داده و گواهی‌های L-UI خود به‌صورت دستی یا از طریق ربات Telegram پشتیبان بگیرید و آن‌ها را بازیابی کنید.
icon: DatabaseBackup
---
@@ -9,7 +9,7 @@ icon: DatabaseBackup
## از چه چیزی پشتیبان بگیریم
- **پایگاه‌داده** — به‌صورت پیش‌فرض یک SQLite در `/etc/x-ui/x-ui.db` (یا پایگاه‌داده‌ی
- **پایگاه‌داده** — به‌صورت پیش‌فرض یک SQLite در `/etc/l-ui/l-ui.db` (یا پایگاه‌داده‌ی
PostgreSQL شما اگر از آن backend استفاده می‌کنید).
- **گواهی‌ها** — هر چیزی که زیر `/root/cert/` (یا هر جایی که گواهی‌های TLS را نگه می‌دارید)
قرار دارد.
@@ -20,7 +20,7 @@ icon: DatabaseBackup
مستقیماً از سرور کپی نمایید:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
cp /etc/l-ui/l-ui.db /root/l-ui-backup-$(date +%F).db
```
برای بازیابی، پنل را متوقف کنید، پایگاه‌داده را سر جای خود برگردانید و دوباره آن را اجرا کنید.
@@ -41,12 +41,12 @@ cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
## دامپ / بازیابی SQLite
دستور `x-ui migrate-db` پایگاه‌داده‌ی SQLite را به یک دامپ متنی SQL ساده و بالعکس تبدیل
دستور `l-ui migrate-db` پایگاه‌داده‌ی SQLite را به یک دامپ متنی SQL ساده و بالعکس تبدیل
می‌کند (برای بررسی یا انتقال میان دستگاه‌ها کاربردی است):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
l-ui migrate-db --dump /root/l-ui.sql # SQLite -> SQL text
l-ui migrate-db --restore /root/l-ui.sql # SQL text -> SQLite
```
برای مهاجرت به PostgreSQL، به [پایگاه‌داده](/docs/reference/database) مراجعه کنید.
@@ -1,14 +1,14 @@
---
title: چندنودی و میزبان‌های مدیریت‌شده
description: مدیریت چند پنل 3x-ui از یک مستر، با اعتماد مبتنی بر توکن API یا mTLS، ضربان قلب، و بازنویسی میزبان برای هر inbound جهت اشتراک‌ها.
description: مدیریت چند پنل L-UI از یک مستر، با اعتماد مبتنی بر توکن API یا mTLS، ضربان قلب، و بازنویسی میزبان برای هر inbound جهت اشتراک‌ها.
icon: Boxes
---
3x-ui می‌تواند **چندین سرور** را از یک پنل مستر واحد مدیریت کند و با **میزبان‌های مدیریت‌شده** نحوهٔ معرفی هر inbound در اشتراک‌ها را بازنویسی کند.
L-UI می‌تواند **چندین سرور** را از یک پنل مستر واحد مدیریت کند و با **میزبان‌های مدیریت‌شده** نحوهٔ معرفی هر inbound در اشتراک‌ها را بازنویسی کند.
## نودها
یک **نود** پنل 3x-ui دیگری است که پنل مستر شما آن را از طریق API نود مدیریت می‌کند. مستر هر نود را فراخوانی (poll) می‌کند و وضعیت، نسخه‌ها، CPU/حافظه، آپ‌تایم و ترافیک آن را در یک مکان نمایش می‌دهد.
یک **نود** پنل L-UI دیگری است که پنل مستر شما آن را از طریق API نود مدیریت می‌کند. مستر هر نود را فراخوانی (poll) می‌کند و وضعیت، نسخه‌ها، CPU/حافظه، آپ‌تایم و ترافیک آن را در یک مکان نمایش می‌دهد.
### افزودن یک نود
@@ -1,11 +1,11 @@
---
title: خروجی‌ها و مسیریابی
description: مدیریت ترافیک خروجی در 3x-ui — خروجی‌های WARP، NordVPN، WireGuard PIA، اشتراک‌های خروجی (مجموعه سرورها)، قواعد مسیریابی و متعادل‌کننده‌های بار.
description: مدیریت ترافیک خروجی در L-UI — خروجی‌های WARP، NordVPN، WireGuard PIA، اشتراک‌های خروجی (مجموعه سرورها)، قواعد مسیریابی و متعادل‌کننده‌های بار.
icon: Route
---
ورودی‌ها کلاینت‌ها را می‌پذیرند؛ **خروجی‌ها** تعیین می‌کنند ترافیک آن‌ها در ادامه به کجا برود.
3x-ui می‌تواند ترافیک را از طریق Cloudflare WARP، NordVPN، Private Internet Access
L-UI می‌تواند ترافیک را از طریق Cloudflare WARP، NordVPN، Private Internet Access
(خروجی WireGuard) یا مجموعه‌های خروجی دلخواه
وارد‌شده از یک اشتراک مسیریابی کند و با قواعد مسیریابی و متعادل‌کننده‌ها میان آن‌ها
انتخاب نماید.
@@ -39,7 +39,7 @@ icon: Route
```
یک خروجی **proxy** (VLESS، VMess، Trojan، Shadowsocks) به سرور دیگری ارسال می‌کند —
که برای زنجیره‌کردن یا فرستادن ترافیک منتخب به خارج مفید است. به شکل‌های سیمی که 3x-ui
که برای زنجیره‌کردن یا فرستادن ترافیک منتخب به خارج مفید است. به شکل‌های سیمی که L-UI
استفاده می‌کند توجه کنید: **VLESS شکل تخت است** (`address`/`port`/`id`/`flow`/
`encryption`)، **VMess از `settings.vnext[]` استفاده می‌کند**، و **Trojan/Shadowsocks از
`settings.servers[]` استفاده می‌کنند**. مقدار `streamSettings` باید با
@@ -51,7 +51,7 @@ icon: Route
## Cloudflare WARP
WARP به سرور شما امکان می‌دهد ترافیک خود را از طریق شبکه Cloudflare خارج کند. 3x-ui می‌تواند
WARP به سرور شما امکان می‌دهد ترافیک خود را از طریق شبکه Cloudflare خارج کند. L-UI می‌تواند
یک حساب WARP برای شما ثبت کند و آن را به یک خروجی WireGuard با برچسب **`warp`** متصل نماید:
<Steps>
@@ -65,7 +65,7 @@ WARP به سرور شما امکان می‌دهد ترافیک خود را از
<Step>
### ثبت WARP
از کنترل‌های WARP در پنل، یک حساب ثبت کنید. 3x-ui کلیدها، نشانی‌ها، بایت‌های رزروشده و نقطه
از کنترل‌های WARP در پنل، یک حساب ثبت کنید. L-UI کلیدها، نشانی‌ها، بایت‌های رزروشده و نقطه
انتهایی peer مربوط به خروجی را به‌صورت خودکار پر می‌کند.
</Step>
@@ -83,13 +83,13 @@ WARP به سرور شما امکان می‌دهد ترافیک خود را از
## NordVPN
3x-ui می‌تواند اعتبارنامه‌های NordVPN (NordLynx/WireGuard) را از یک توکن دسترسی دریافت کند (یا
L-UI می‌تواند اعتبارنامه‌های NordVPN (NordLynx/WireGuard) را از یک توکن دسترسی دریافت کند (یا
یک کلید خصوصی را مستقیماً بپذیرد) و کشورها/سرورها را فهرست کند تا بتوانید یک خروجی NordVPN
بسازید.
## خروجی WireGuard PIA
3x-ui می‌تواند با نام کاربری و رمز عبور PIA وارد شود، کشورها/منطقه‌ها/سرورها را
L-UI می‌تواند با نام کاربری و رمز عبور PIA وارد شود، کشورها/منطقه‌ها/سرورها را
از فهرست امضاشده نشان دهد و یک خروجی WireGuard بسازد. از
**Xray → خروجی‌ها → بیشتر → PIA** وارد شوید، سرور را انتخاب کنید و خروجی را
اضافه کنید. می‌توان چند سرور افزود (هر hostname یک خروجی). برچسب
@@ -100,7 +100,7 @@ Reset یا حذف، peer مربوط به WireGuard را در حساب PIA باط
گذرواژه ذخیره نمی‌شود. توکن API مربوط به PIA با همان تنظیم
`NODE_TOKEN_ENCRYPTION` گره‌ها ذخیره می‌شود. اگر کلید قدیمی
`XUI_NODE_TOKEN_KEY` را بدون ورود دوباره به PIA کنار بگذارید، Add/Reset
`LUI_NODE_TOKEN_KEY` را بدون ورود دوباره به PIA کنار بگذارید، Add/Reset
تا ورود مجدد شکست می‌خورد. `allowedIPs` فقط
`0.0.0.0/0` است.
@@ -1,13 +1,13 @@
---
title: پراکسی معکوس
description: قرار دادن پنل و اشتراک 3x-ui پشت Nginx یا Caddy همراه با TLS از Let's Encrypt.
description: قرار دادن پنل و اشتراک L-UI پشت Nginx یا Caddy همراه با TLS از Let's Encrypt.
icon: Waypoints
---
پراکسی معکوس به شما امکان می‌دهد پنل و اشتراک را روی یک دامنه تمیز با HTTPS خودکار
ارائه دهید و پورت‌های واقعی را پشت پورت‌های 80/443 پنهان کنید. ترجیح می‌دهید خودِ
پنل مستقیماً TLS را مدیریت کند؟ به‌جای آن، گواهی را از طریق
[منوی SSL در `x-ui`](/docs/config/ssl-certificates) دریافت کنید.
[منوی SSL در `l-ui`](/docs/config/ssl-certificates) دریافت کنید.
## ساخت یک پیکربندی
@@ -45,7 +45,7 @@ panel.example.com {
## نکته‌ها
- حتی پشت یک پراکسی هم **مسیر پایه وب** پنل را حفظ کنید؛ دفاع لایه‌به‌لایه.
- اگر TLS را در پراکسی مدیریت می‌کنید، ممکن است بخواهید `XUI_SKIP_HSTS=true` را روی
- اگر TLS را در پراکسی مدیریت می‌کنید، ممکن است بخواهید `LUI_SKIP_HSTS=true` را روی
پنل تنظیم کنید — به [مرجع متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
- سرور [اشتراک](/docs/config/subscription) را هم پراکسی کنید تا محتوای آن نیز روی
HTTPS ارائه شود.
+7 -7
View File
@@ -1,6 +1,6 @@
---
title: امنیت
description: سخت‌سازی 3x-ui — احراز هویت پنل و 2FA، محدودیت IP با Fail2ban، قوانین فایروال، BBR و به‌روز ماندن.
description: سخت‌سازی L-UI — احراز هویت پنل و 2FA، محدودیت IP با Fail2ban، قوانین فایروال، BBR و به‌روز ماندن.
icon: ShieldCheck
---
@@ -17,11 +17,11 @@ icon: ShieldCheck
## Fail2ban و محدودیت‌های IP
برای هر کلاینت یک **محدودیت IP** تنظیم کنید (به [کلاینت‌ها](/docs/config/clients) مراجعه کنید) تا تعداد IPهای مبدأ همزمان محدود شود. اعمال این محدودیت توسط **Fail2ban** انجام می‌شود که 3x-ui آن را برای شما نصب و پیکربندی می‌کند (در نصب‌های اسکریپتی به‌طور پیش‌فرض فعال است و در Docker از طریق `XUI_ENABLE_FAIL2BAN=true`).
برای هر کلاینت یک **محدودیت IP** تنظیم کنید (به [کلاینت‌ها](/docs/config/clients) مراجعه کنید) تا تعداد IPهای مبدأ همزمان محدود شود. اعمال این محدودیت توسط **Fail2ban** انجام می‌شود که L-UI آن را برای شما نصب و پیکربندی می‌کند (در نصب‌های اسکریپتی به‌طور پیش‌فرض فعال است و در Docker از طریق `LUI_ENABLE_FAIL2BAN=true`).
آن را از منوی `x-ui` مدیریت کنید (**۲۲ — IP Limit Management**): نصب/پیکربندی، تغییر مدت مسدودسازی (پیش‌فرض **۳۰ دقیقه**)، مسدودسازی/رفع مسدودی یک IP، مشاهده لاگ‌های مسدودسازی و بررسی وضعیت. در پشت صحنه:
آن را از منوی `l-ui` مدیریت کنید (**۲۲ — IP Limit Management**): نصب/پیکربندی، تغییر مدت مسدودسازی (پیش‌فرض **۳۰ دقیقه**)، مسدودسازی/رفع مسدودی یک IP، مشاهده لاگ‌های مسدودسازی و بررسی وضعیت. در پشت صحنه:
- این jail با نام **`3x-ipl`** شناخته می‌شود؛ لاگ‌های مسدودسازی در `/var/log/x-ui/3xipl.log` و `/var/log/x-ui/3xipl-banned.log` قرار دارند (همچنین از طریق `x-ui banlog`).
- این jail با نام **`3x-ipl`** شناخته می‌شود؛ لاگ‌های مسدودسازی در `/var/log/l-ui/3xipl.log` و `/var/log/l-ui/3xipl-banned.log` قرار دارند (همچنین از طریق `l-ui banlog`).
- مسدودسازی‌ها همه TCP/UDP را پوشش می‌دهند **به‌جز** پورت‌های SSH و پنل شما، بنابراین یک مسدودسازی نمی‌تواند شما را از سرور یا پنل بیرون بیندازد.
<Callout type="warn">
@@ -33,7 +33,7 @@ icon: ShieldCheck
## فایروال
تنها پورت‌هایی را باز کنید که واقعاً استفاده می‌کنید: SSH، پورت پنل، پورت اشتراک و پورت‌های inbound خود. منوی `x-ui` (**۲۳ — Firewall Management**) ابزار `ufw` را در بر می‌گیرد، یا اینجا قوانین را تولید کنید:
تنها پورت‌هایی را باز کنید که واقعاً استفاده می‌کنید: SSH، پورت پنل، پورت اشتراک و پورت‌های inbound خود. منوی `l-ui` (**۲۳ — Firewall Management**) ابزار `ufw` را در بر می‌گیرد، یا اینجا قوانین را تولید کنید:
<FirewallRulesGenerator />
@@ -45,9 +45,9 @@ icon: ShieldCheck
## تنظیم شبکه (BBR)
منوی `x-ui` (**۲۶ — Enable BBR**) کنترل ازدحام BBR گوگل را فعال/غیرفعال می‌کند
منوی `l-ui` (**۲۶ — Enable BBR**) کنترل ازدحام BBR گوگل را فعال/غیرفعال می‌کند
(`net.ipv4.tcp_congestion_control = bbr`، `net.core.default_qdisc = fq`) که اغلب توان عملیاتی را روی لینک‌های شلوغ بهبود می‌بخشد.
## به‌روز ماندن
3x-ui و Xray-core را به‌طور منظم به‌روزرسانی کنید — اصلاحات امنیتی در نسخه‌های جدید منتشر می‌شوند. [صفحه انتشارها](https://github.com/MHSanaei/3x-ui/releases) را دنبال کنید و به [به‌روزرسانی و حذف نصب](/docs/guide/update-uninstall) مراجعه کنید.
L-UI و Xray-core را به‌طور منظم به‌روزرسانی کنید — اصلاحات امنیتی در نسخه‌های جدید منتشر می‌شوند. [صفحه انتشارها](https://github.com/MHSanaei/L-UI/releases) را دنبال کنید و به [به‌روزرسانی و حذف نصب](/docs/guide/update-uninstall) مراجعه کنید.

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