Files
3x-ui/README.zh_CN.md
T
Sanaei 6214ff4edc fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838)
* fix(mtproto): split the mtg fingerprint into structural and secrets parts

A reordered clients array in the stored settings used to read as a config
change because the fingerprint concatenated secrets in array order, and one
opaque fingerprint could not tell a restart-worthy change (bind address,
fronting, throttle) from a secret-set change a reload-capable mtg can absorb
in place. Sort the secret pairs so order stops mattering, and split the value
so the upcoming hot-reload path can decide between keeping, reloading, and
restarting the process.

* fix(mtproto): stop restarting mtg on every inbound edit

Saving an mtproto inbound tore down and respawned its mtg sidecar even when
nothing material changed, dropping every live Telegram connection: the update
path pushed DelInbound+AddInbound, and Remove deletes the manager's map entry,
so Ensure's fingerprint no-op gate could never fire. Route mtproto updates
through a single Ensure call so an edit that leaves the generated TOML alone
keeps the process, and only real config changes restart it.

Capturing the pre-edit protocol also fixes a latent leak: changing an
inbound's protocol away from mtproto never stopped the sidecar, because the
snapshot handed to the runtime already carried the new protocol and the
removal took the xray branch, leaving an orphaned mtg holding the port.

An mtproto push failure no longer requests an xray restart - xray cannot fix
the sidecar, and the 10s reconcile job self-heals it.

The regression test fakes mtg by re-executing the test binary, counting
spawns through a pid file: an unchanged save and a remark-only edit must keep
the process, a re-keyed secret must restart it.

* fix(mtproto): exclude depleted clients from the reconcile job to match the sync push

The 10s reconcile job derived mtg secret sets from raw inbound settings while
the interactive push filtered clients through buildRuntimeInboundForAPI, which
drops client_traffics-disabled (depleted or expired) clients. The two paths
therefore disagreed on the fingerprint - each disagreement one needless mtg
restart dropping live connections - and worse, the job kept serving depleted
clients' secrets indefinitely, so running out of traffic never actually cut an
mtproto client's access.

DesiredMtprotoInstances now builds the job's desired state with the same
depletion overlay the push uses (one bulk client_traffics query), drops
inbounds whose every secret is filtered away so their sidecar stops, and
AddInbound pushes the filtered payload too so an imported inbound carrying
disabled stats does not seed a fingerprint the next reconcile disagrees with.

* feat(mtproto): hot-reload mtg secrets in place instead of restarting

A client add, removal, re-key, or enable-toggle changes only the [secrets]
section of the generated config, yet the panel could apply it only by killing
and respawning the mtg sidecar, dropping every Telegram connection on that
inbound. Split the ensure decision three ways: an identical config is a no-op,
a secrets-only change rewrites the TOML on the same api port and asks mtg to
hot-swap it via POST /reload, and a structural change (or a failed reload)
falls back to the full stop-and-start.

The reload endpoint is served by the mhsanaei/mtg-multi fork; against an older
binary the POST 404s and the manager restarts exactly as before, so panel and
binary upgrades stay order-independent.

* feat(mtproto): apply single-client edits to the sidecar immediately

Client CRUD on an mtproto inbound was a runtime no-op, so an add, delete,
re-key, or enable-toggle only reached mtg on the next 10s reconcile. With the
sidecar now able to hot-reload, push the change straight after the edit commits:
applyLocalMtproto rebuilds the inbound's filtered client set and re-applies it,
so a new client works within a moment (and, on a reload-capable binary, without
disturbing the others) and deleting the last client stops the process.

The three interactive single-client paths (add, update, delete) call it; bulk
operations still ride the reconcile job, which converges to the same state.

* chore(mtproto): pin mtg-multi to the mhsanaei fork v1.13.3

The reload endpoint the panel now uses lives in the mhsanaei/mtg-multi fork, so
point the source-build pin (DockerInit.sh + both release.yml matrices) at it and
bump to v1.13.3. The install still produces the same mtg-multi binary name, so
the mtg-<os>-<arch> rename and everything downstream are unchanged. Docs and the
package comment note the hot-reload path and its restart fallback.

* feat(mtproto): apply live secret updates via the management API and add ad-tag

Two capabilities the mhsanaei/mtg-multi v1.13.3 fork exposes are now surfaced by
the sidecar manager.

Live updates go through PUT /secrets on the fork's management API instead of
POST /reload: the panel already holds the whole desired set per inbound, so it
sends secrets and the advertising tag as one JSON call that mtg applies
atomically, keeping every unchanged connection and closing only removed or
re-keyed ones. The config file is still written first so a restart or crash
recovery reproduces the state, and any non-200 (an older binary, a refused
connection) still falls back to a full restart.

Per-inbound ad-tag adds an optional 32-hex Telegram advertising tag plus
public-ipv4/public-ipv6 overrides. The ad-tag rides the reloadable secrets
fingerprint, so changing it hot-applies without dropping connections; the public
IPs are proxy-construction parameters and sit in the structural fingerprint, so a
change there restarts the process. Empty public IPs are omitted so mtg
auto-detects the reachable address.

* feat(inbounds): expose the mtproto ad-tag and public IP in the inbound form

Adds an Ad-tag field (validated as 32 hex characters) plus optional Public IPv4
and Public IPv6 overrides to the MTProto inbound form, backed by the same-named
settings the sidecar writes into the mtg config. The public IPs are optional —
left blank, mtg auto-detects the reachable address the ad-tag middle proxy needs.
English strings are added to every locale; the non-English ones carry the
English text until translated and fall back to it meanwhile.

* ci(mtproto): install mtg-multi from prebuilt release binaries

The fork now publishes release archives for every platform we package, so
download and unpack the matching mtg-multi-<ver>-<os>-<arch> binary instead of
compiling it from source with go install. Faster builds and no toolchain step,
and the archive's platform labels line up with our matrix; the produced
mtg-<os>-<arch> filenames are unchanged.

* i18n(mtproto): localize the ad-tag and public IP strings

The six mtgAdTag*/mtgPublicIp* keys shipped with English text in every locale as
a placeholder. Translate them into the twelve non-English locales (Arabic,
Spanish, Persian, Indonesian, Japanese, Portuguese-BR, Russian, Turkish,
Ukrainian, Vietnamese, and Simplified/Traditional Chinese); en-US is unchanged.

* retired goreportcard.com
2026-07-07 01:13:24 +02:00

10 KiB
Raw Blame History

English | فارسی | العربية | 中文 | Español | Русский | Türkçe

3x-ui

Release Build GO Version Downloads License Go Reference

3X-UI 是一个先进的开源 Web 控制面板,用于管理 Xray-core 服务器。它提供简洁、多语言的界面,用于部署、配置和监控各种代理与 VPN 协议——从单台 VPS 到多节点部署。

3X-UI 作为原始 X-UI 项目的增强分支(fork),增加了更广泛的协议支持、更好的稳定性、按客户端的流量统计以及许多提升使用体验的功能。

Important

本项目仅供个人使用。请勿将其用于非法目的,也请勿在生产环境中使用。

功能特性

  • 多协议入站 — VLESS、VMess、Trojan、Shadowsocks、WireGuard、Hysteria2、HTTP、SOCKS (Mixed)、Dokodemo-door / Tunnel 和 TUN。
  • 现代传输与安全 — TCP (Raw)、mKCP、WebSocket、gRPC、HTTPUpgrade 和 XHTTP,并通过 TLS、XTLS 和 REALITY 加密。
  • 回落 (Fallback) — 通过 Xray 的 fallback 功能在单个端口上提供多种协议(例如在 443 端口上同时使用 VLESS 和 Trojan)。
  • 按客户端管理 — 流量配额、到期日期、IP 限制、实时在线状态,以及一键分享链接、二维码和订阅。
  • 流量统计 — 按入站、按客户端、按出站统计,并支持重置控制。
  • 多节点支持 — 从单一面板管理并扩展到多台服务器。
  • 出站与路由 — WARP、NordVPN、自定义路由规则、负载均衡器和出站代理链。
  • 内置订阅服务器,支持多种输出格式和自定义页面模板
  • Telegram 机器人,用于远程监控和管理。
  • RESTful API,带有面板内置的 Swagger 文档。
  • 灵活的存储 — SQLite(默认)或 PostgreSQL。
  • 13 种界面语言,支持深色和浅色主题。
  • Fail2ban 集成,用于强制执行按客户端的 IP 限制。

截图

点击展开 Overview Inbounds Add client Configs

快速开始

bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)

若要安装特定版本,请在命令后附加对应的标签(例如 v3.4.0):

bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0

若要安装滚动更新的 dev 版本(来自 main 的最新逐次提交预发布版本,而非稳定版本),请传入 dev-latest

bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest

安装过程中会生成随机的用户名、密码和访问路径。安装完成后,运行 x-ui 打开管理菜单,您可以在其中启动/停止服务、查看或重置登录凭据、管理 SSL 证书等。

完整文档请参阅 项目Wiki

无人值守安装

安装程序也可以非交互式运行,适用于 cloud-init。 设置 XUI_NONINTERACTIVE=1(或在无 TTY 的情况下通过管道传入),它就会全程 零提示地完成端到端安装,生成随机凭据并写入 /etc/x-ui/install-result.env。请参阅 deploy/

支持的平台

操作系统: Ubuntu、Debian、Armbian、Fedora、CentOS、RHEL、AlmaLinux、Rocky Linux、Oracle Linux、Amazon Linux、Virtuozzo、Arch、Manjaro、Parch、openSUSE (Tumbleweed / Leap)、Alpine 和 Windows。

架构: amd64 · 386 · arm64 (aarch64) · armv7 · armv6 · armv5 · s390x

数据库选项

3X-UI 支持两种后端,可在安装时选择:

  • SQLite(默认)— 位于 /etc/x-ui/x-ui.db 的单个文件。无需配置,适合中小型部署。
  • PostgreSQL — 推荐用于大量客户端或多节点设置。安装程序可以为您在本地安装 PostgreSQL,或接受指向现有服务器的 DSN。

运行时通过环境变量选择后端(安装程序会为您写入 /etc/default/x-ui):

XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable

将现有的 SQLite 安装迁移到 PostgreSQL

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

源 SQLite 文件保持不变;在确认新后端正常工作后,请手动删除它。

Docker

默认的 docker compose up -d 仍使用 SQLite。若要使用捆绑的 PostgreSQL 服务运行,请取消注释 docker-compose.yml 中的两行 XUI_DB_* 环境变量,并使用该 profile 启动:

docker compose --profile postgres up -d

该镜像捆绑了 Fail2ban(默认启用),用于强制执行按客户端的 IP 限制。Fail2ban 使用 iptables 封禁违规者,这需要 NET_ADMIN 权限。docker-compose.yml 已通过 cap_add 授予该权限;如果您改用 docker run 启动容器,请自行添加这些权限,否则封禁只会被记录而永远不会生效:

docker run -d --cap-add=NET_ADMIN --cap-add=NET_RAW ... ghcr.io/mhsanaei/3x-ui

环境变量

变量 说明 默认值
XUI_DB_TYPE 数据库后端:sqlitepostgres 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 日志级别(debuginfowarningerror 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

支持的语言

面板界面提供 13 种语言:

English · فارسی · العربية · 中文(简体) · 中文(繁體) · Español · Русский · Українська · Türkçe · Tiếng Việt · 日本語 · Bahasa Indonesia · Português (Brasil)

贡献

欢迎贡献。在提交 issue 或 pull request 之前,请阅读贡献指南

特别感谢

致谢

  • Iran v2ray rules (许可证: GPL-3.0): 增强的 v2ray/xray 和 v2ray/xray-clients 路由规则,内置伊朗域名,专注于安全性和广告拦截。
  • Russia v2ray rules (许可证: GPL-3.0): 此仓库包含基于俄罗斯被阻止域名和地址数据自动更新的 V2Ray 路由规则。

社区工具

社区围绕 3x-ui 构建的工具和集成。

  • terraform-provider-3x-ui (许可证: MIT): 使用 Terraform / OpenTofu 通过代码管理入站、客户端、面板设置和 Xray 配置。

支持项目

如果这个项目对您有帮助,您可以给它一个🌟

Buy Me A Coffee
Crypto donation button by NOWPayments

随时间变化的星标数

Stargazers over time