Releases: MHSanaei/3x-ui
Release list
Dev build 8cec47a8
Rolling development build — installs via the panel's Dev update channel.
commit=8cec47a8a5593c586537e9f7005871e9b43a896f
built=2026-08-17T00:45:59Z
Automated per-commit build from main. Not a stable release.
v3.6.0
🚀 Trend-First Overview, xray-core v26.7.28, Subscription Correctness & Panel Hardening
- 🧭 Overview rebuilt as a command deck — the ten small cards are gone: four vitals tiles with 72-sample sparklines, a two-series throughput chart, a TCP/UDP connections chart, a grouped system strip, and a sidebar that became an auto-collapsed icon rail expanding on hover.
- 🛡 xray-core v26.7.28 — the XMC finalmask breaking change is absorbed end to end: incomplete masks are rejected at save time with the missing field named, and only the offending mask is dropped at config-generation time so one bad row can no longer take every inbound offline.
- 🔗 Subscription output correctness — a long run of link and format fixes (forwarded-URL trust, coalesced external refreshes, Clash scalars a YAML parser would misread, VLESS flow gating, external link names, WireGuard Allowed IPs) plus opt-in identity tokens on every link, raw download actions, live online status with a new
?format=infoendpoint, and User-Agent format auto-detection. - 🔐 Panel surface tightened —
openapi.jsonmoved behind session auth (it was serving the whole admin API surface unauthenticated), node API tokens became write-only, production sourcemaps no longer ship inside the binary, and the default freedom rules block private-range egress. - 🧹 Two large verified audit sweeps — 54 fixes from a repo-wide self-correcting audit and 16 more from a bug-label issue sweep, spanning email, node sync, subscriptions, xray config and the database.
- 🗃 Data integrity — SQLite backup snapshots are taken online, legacy string
tgIdvalues in inbound settings are repaired on upgrade, andclient_trafficsrows are no longer deleted for detached-but-alive clients or left stale when an email is reused. - 🎛 Settings UX — settings sitting at their shipped default are tagged as such, clearing a port field keeps the stored port instead of writing zero, date-pickers commit on selection rather than on confirm, and the REALITY client version range is validated at save time.
- 🧰 Frontend platform — the component Storybook became a validated, fully covered workbench and is published on the docs site, every axe accessibility violation in the library is resolved, react-router 8 and Node 24 LTS landed, and 210 dead translation keys were deleted with a test that fails the build on new ones.
ℹ️ Heads-up: The bundled core moved to xray-core v26.7.28, where the XMC finalmask
usernameslist was replaced by a requiredprofilesarray (username + UUID + both Mojang texture fields, no "default to Dream" fallback) — a mask saved by an older panel is now rejected at save time, and stripped from the generated config with a warning rather than failing the whole core, so anyone using that obfuscation must refill their profiles. A database migration repairs legacy stringtgIdvalues in inbound settings that previously broke every client operation on the affected inbound. Two surfaces changed behavior for existing setups:GET /panel/api/openapi.jsonnow requires an authenticated session (it was reachable without one), and node API tokens are write-only — the API no longer returns them, so tooling that read a token back must store it at creation time. The default freedomfinalRulesalso gain ageoip:privateblock rule, applied in place to installs still carrying the stock rules.
🆕 New
- feat(ui): redesign the overview page as a trend-first command deck
- feat(ui): tag settings that sit at their shipped default value (#6128) @PathGao
- feat(ui): validate the REALITY client version range at save time (#6126) @PathGao
- feat(inbounds): allow custom monthly traffic reset days (#6071) @Ki-Seki
- feat(sub): auto-detect subscription format by User-Agent (#5826) @Tomilla
- feat(sub): allow identity tokens on every subscription link (#5935) @H-TTTTT
- feat(sub): expose live online status and add ?format=info endpoint
- feat(sub): add raw subscription download actions (#6017) @w3struk
- feat(sub): add XHTTP session field compatibility in share links and subscriptions (#5929) @beehunt9r
- feat(api): add GET endpoint to look up clients by Telegram ID (#5945) @kimfom01
- feat(notifications): add a consecutive-failure threshold for outbound.down alerts (#5968) @yukh975
- feat(frontend): show client comments on mobile cards (#5942) @sanmaxdev
⚡️ Update & improvement
- feat(xray): update xray-core to v26.7.28 and adapt panel
- perf(clients): make the clients page scale to large panels
- perf(clients): take one email snapshot per client fan-out, not one per inbound (#6091)
- feat(frontend): make Storybook a validated, fully covered component workbench
- feat(docs): publish the component Storybook on the docs site
- refactor(frontend): migrate off deprecated Ant Design 6 props
- refactor(ui): share one onNumber handler for numeric setting inputs (#6127) @PathGao
- chore(lint): forbid the Number-or-clamp idiom in direct-write settings pages (#6129) @PathGao
- chore(build): stop shipping production sourcemaps inside the binary (#6131) @PathGao
- chore(i18n): delete 230 dead translation keys and guard against new ones (#6132) @PathGao
- style(i18n): normalize Chinese-English spacing (#6076) @Yosyoo
- chore(deps): migrate to react-router 8 and refresh frontend dependencies
- chore: standardize the toolchain on Node 24 LTS
- chore: refresh dependencies, fix Linux tool tasks, modernize Go idioms
- fix(docs): force transitive sharp up to patched 0.35.3
- chore(deps): bump google.golang.org/grpc from 1.82.0 to 1.82.1 (#5994)
- chore(deps): bump github.com/go-ldap/ldap/v3 from 3.4.13 to 3.4.14 (#5993)
- chore(deps): bump react-i18next from 17.0.9 to 17.0.10 (#5996)
- chore(deps-dev): bump vite from 8.1.4 to 8.1.5 (#5997)
- chore(deps): bump actions/setup-go from 6 to 7 (#5995)
- chore(deps): bump actions/setup-node from 6 to 7 (#5992)
- refactor(ci): make the bot read-only except for PR conflict resolution
- fix(ci): survive transient GitHub 5xx outages in the release workflow
- fix(ci): resolve the mtg-multi tag from the release-page redirect
- fix(ci): publish dev-latest edit-first instead of probing for existence
🐞 Bug fixed
- Repo-wide self-correcting audit: 54 verified bug fixes (#5970)
- Bug-label issue sweep: 16 fixes (#6083)
- fix(api): authenticate GET /panel/api/openapi.json + pin the route registry to the router (#6133) @PathGao
- fix(nodes): make node API tokens write-only (#5613) @n0ctal
- fix(xray): reject configs xray-core refuses, and check the fixtures against it
- fix(xray): stop the runtime user API from crashing xray-core
- fix(xray): emit an empty client array instead of null in the generated config (#6117)
- fix(xray): validate generated egress targets (#5989) @Alishahrokhiii
- fix(xray): gate embedded unencrypted-outbound rejection on the running core version (#6028) @mvanhorn
- fix(xray): synchronize lifecycle state (#6138) @PathGao
- fix(balancer): pin loopback routing rules ahead of general rules (#6054) @H-TTTTT
- fix(mtproto): synchronize child-process lifecycle (#6141) @PathGao
- fix(sub): honor trustedProxyCIDRs before forwarded URLs (#6135) @PathGao
- [fix(sub): coalesce external subscription refreshes](https://gith...
v3.5.0
🚀 MTProto Multi-Client, SQLite→PostgreSQL Migration, 500k-Scale Performance & Node Sync Hardening
- 📬 MTProto goes multi-client — MTProto inbounds now run on the
mtg-multiengine with one FakeTLS secret per client, per-client ad-tags, and per-client quota & expiry enforced in the sidecar; client edits hot-apply through a management API so live connections survive. - 🐘 SQLite → PostgreSQL, end to end — the PostgreSQL panel restore now accepts SQLite
.dbfiles and migration dumps directly (uploads are sniffed automatically), cross-db migration became lossless, transactional and pre-checked, and a newx-ui pgclientcommand installs or upgrades the PostgreSQL client tools. - 🚄 Built for 500k clients — batched ip-limit lookups, depleted-client disables by id, delta WebSocket stats above a snapshot threshold, and subscriptions resolved from normalized tables — pinned by a scale test suite at 500,000 clients.
- 🧠 Frontend platform overhaul — full React Hook Form migration, axios replaced with the native Fetch API, charts moved to uPlot, and Husky / lint-staged / MSW / Storybook dev tooling.
- 🛰️ Node sync hardening — host overrides adopted into the master, no more premature inbound sweeps or Postgres deadlocks in sync, client edits no longer tear down node inbounds, and node auto-renewals open a fresh quota window.
- 🌍 Outbound insight — egress metadata (IP + country) per outbound, a real-delay connection test measured on a warm connection, and a
targetStrategyfield in the outbound editor. - ⚖️ Routing & balancers — balancer-to-balancer fallback, a default outbound in basic routing, encrypted DNS presets, and private-IP
dns.serversallowed past thegeoip:privateblock rule. - 🔎 Panel QoL — text search on the inbound list and node selects, column sorting, per-client realtime speed, bulk-adding hosts to multiple inbounds, and WireGuard export split into config and links tabs.
ℹ️ Heads-up: MTProto inbounds are now natively multi-client — legacy single-secret inbounds migrate automatically to the clients model, and
tg://deep links no longer carry the remark fragment. The bundled core was bumped to xray-core v26.7.11, and the Final Mask + REALITY combination is now rejected (it crashes Xray-core). A database migration also repairs overflowed traffic counters and drops the legacy UNIQUE constraint on inbound ports.
🆕 New
- feat(mtproto): adopt mtg-multi and make MTProto inbounds multi-client
- feat(mtproto): per-client ad-tags, management-API auth, and secret sync
- feat(mtproto): enforce per-client quota & expiry via mtg-multi limits
- feat(db): import SQLite migration dumps through the PostgreSQL panel restore
- feat(server): sniff SQLite panel restore uploads and keep the fallback on failure
- feat(db): add pgclient command to install or upgrade PostgreSQL client tools
- feat(outbound): add outbound egress metadata (IP + country) (#5886) @isultanov99
- feat(outbound): add real-delay connection test mode
- feat(balancer): add balancer-to-balancer fallback support (#5586) @Ssentiago
- feat(xray): default outbound in basic routing (#5815) @rqzbeh
- feat(dns): add encrypted DNS presets (#5837) @rqzbeh
- feat(hosts): bulk-add multiple hosts to multiple inbounds (#5677) @AmirRnz
- feat(ui): per-client realtime speed (#5687) @NikanZeyaei
- feat(frontend): add text search to the inbound list
- feat(inbounds): add column sorting to the inbounds table (#5661) @isultanov99
- feat(frontend): add text search to node select components
- feat(frontend): treat WireGuard inbounds as multi-user in client actions
- feat(frontend): split WireGuard inbound export into config and links tabs
- feat(wireguard): make client allowedIPs editable with validation
- feat(reality): derive a stable per-client spiderX for shared links
- feat(web): broadcast delta client stats above a snapshot threshold
- feat(sub): show the announcement on the subscription info page
- feat(sub): serve the HTML info page for browser requests on JSON and Clash URLs
- feat(settings): let users clear stored secrets from the UI
- feat(clients): hide disabled inbounds in the client form selector
- feat(frontend): show client group in the client info modal
- feat(frontend): add targetStrategy field to the outbound editor
- feat(clients): clarify which protocols use the password field (#5809) @ecgang
- feat(tgbot): register usage, inbound, restart and clearall in the bot command menu
- feat(tgbot): show inbound remark alongside email in the online clients list
- feat(tgbot): include hostname in backup and ban-log messages
⚡ Update & improvement
- feat(xray): update xray-core to v26.7.11 and adapt panel
- chore(mtproto): bump the mtg-multi binary pin to v1.14.0
- refactor(mtproto): manage ad-tags per client only
- Frontend dev tooling (Husky, lint-staged, MSW, Storybook) + full React Hook Form migration (#5859)
- refactor(frontend): replace axios with the native Fetch API
- refactor(frontend): replace recharts with uPlot for charts
- test(scale): cover traffic poll, ws payloads, ip-limit job, sub and xray config at 500k
- refactor: modernize Go with strings.SplitSeq and maps.Copy
- refactor: use the built-in max/min to simplify the code (#5751) @alaningtrump
- chore: add golangci-lint tasks and force LF on Go files
- docs: vendor the documentation site into the monorepo
- docs: move architecture map into docs/ and refresh it against the live tree
- docs(settings): clarify Sub Port/Sub Domain double as subscription-link fallback (#5721) @volov-de
- docs: update the env vars example file (#5678) @nebulosa2007
- ci(claude-bot): auto-fix trusted PRs and easy issue bugs
- ci(claude-bot): gate write capability to trusted actors
- chore(frontend): bump version and deps
- chore(deps): bump google.golang.org/grpc to 1.82.0 (#5729)
- chore(deps): bump golang.org/x/text to 0.40.0 (#5872)
🐞 Bug fixed
- fix(node): stop client edits from tearing down node inbounds and harden reconcile fingerprints
- fix(node): stop Postgres deadlocks and deleted-client resurrection in node sync
- fix(node): never sweep a node's inbounds before their first adoption
- fix(node): adopt a node inbound's host overrides into the master
- fix(node): stop one rejected inbound from starving a node's traffic sync
- fix(node): fully delete clients on nodes instead of only detaching them
- fix(node): start a fresh quota window when a node auto-renews a client
- fix(node): stop force-restarting a node's Xray when its clients auto-disable
- fix(node): show the activated first-use deadline on the Clients page
- fix(inbound): scope port-conflict check to the stored node on update (#5833) @yukh975
- [fix(panel): use t...
v3.4.2
🚀 WireGuard Multi-Client, Panel Accessibility, Balancer Observatory & Hardened Settings
- 🔐 WireGuard goes multi-client — WireGuard inbounds are now first-class multi-client (native
users), with a reworked client-config UX, a collapsible config card, configurable DNS, and client IPs allocated inside the existing peer subnet. - ♿ Panel accessibility — screen-reader and keyboard accessibility were brought across the whole panel.
- ⚖️ Balancer Observatory — a tabbed Observatory / Burst Observatory form, validation that defers errors until a field is touched or saved, and a burst observer for
random/roundRobinstrategies with afallbackTag. - 🛡️ Hardened settings & restore — sensitive setting changes now require re-confirming 2FA, and the database-restore body-cap exemption was tightened.
- 🛰️ REALITY target scanner — a live REALITY target scanner with IP/CIDR discovery.
- 🧪 Dev channel from stable — opt into the rolling dev channel directly from a stable build.
- 🔗 Subscription & inbound polish — Host VLESS Route baked into subscription UUIDs,
{{EMAIL}}shown on the first sub-body link only, a remark template applied to Export all inbound links, and legacyexternalProxyconverted to hosts on import. - 🧰 Dev toolchain & deps — a canonical
Makefile, golangci-lint v2, plus Ant Design 6.5 and xray-core v26.6.27.
ℹ️ Heads-up: WireGuard inbounds are now natively multi-client — existing single-peer inbounds migrate automatically to the clients model. The minimum eligible Xray version was raised (bundled core bumped to xray-core v26.6.27); update any custom cores accordingly. With 2FA enabled, sensitive setting changes now prompt for a fresh 2FA confirmation before they apply.
🆕 New
- feat(wireguard): multi-client support
- feat(wireguard): client config UX, collapsible config card, configurable DNS
- feat(a11y): screen-reader & keyboard accessibility across the panel (#5486, #5652) @nima1024m
- feat(reality): add live REALITY target scanner with IP/CIDR discovery
- feat(balancers): tabbed Observatory/Burst Observatory form (#5627) @nima1024m
- feat(update): allow opting into the dev channel from a stable build
- feat(groups): reset group traffic without touching client counters
- feat(inbounds): apply remark template to Export all inbound links
- feat(xhttp): default xmux maxConnections to 6
- feat(backup): prefix backup filenames with date and time (#5606) @NikanZeyaei
- feat: ldap skip tls verify (#5637) @NikanZeyaei
- feat(sidebar): add documentation link button
⚡ Update & improvement
- Bump minimum eligible Xray version
- chore(deps): bump xray-core to v26.6.27
- chore(deps): bump antd to 6.5 and migrate deprecated component props
- chore: add Makefile as canonical task runner
- style: adopt golangci-lint v2 and resolve all findings
- chore(ci): bump golangci-lint action to v9
- docs: add CLAUDE.md agent guides for root and frontend
- docs: correct false RTL claim and stale Vite version in CONTRIBUTING.md
- test(sub): align identity-token test with first-link-only EMAIL
- fix(lint): use errors.Is for io.EOF comparison in sys_linux
🐞 Bug fixed
- fix(node): stop the offline-sync toast firing on saves to online nodes
- fix(clients): re-enable depleted clients on API renewal (#5619)
- fix(xray): clean stale routing references when a balancer or outbound is deleted (#5648) @nima1024m
- fix(clients): hide WireGuard config after detaching the WG inbound
- fix(wireguard): allocate client IPs in the existing peer subnet
- fix(sync): mark node dirty inside the mutation transaction (atomic ConfigDirty) (#5611) @n0ctal
- fix(runtime): refresh cached node remotes on identity change (#5614) @n0ctal
- fix(settings): require re-2FA confirmation for sensitive setting changes (#5610) @n0ctal
- fix(web): tighten database restore body-cap exemption (#5609) @n0ctal
- fix(balancers): defer validation errors until touched or save (#5626) @nima1024m
- fix(balancers): create burst observer for random/roundRobin with fallbackTag
- fix(sub): bake Host VLESS Route into subscription UUIDs
- fix(sub): show {{EMAIL}} on first sub-body link only
- fix(inbound): convert legacy externalProxy to hosts on import
- fix(shadowsocks): send per-user Account for SS-2022 runtime AddUser
- fix(routing): write lowercase L4 network to xray config, display uppercase in UI
- fix(settings): normalize API token timestamps (#5599) @Tomilla
- fix(logger): prevent nil-deref panic in migrate/setting CLI paths
Reports
New Contributors
Full Changelog: v3.4.1...v3.4.2
v3.4.1
🚀 Rolling Dev Channel, Logs Viewer Overhaul, Leaner Memory & Client Bulk Ops
- 🧪 Rolling Dev update channel — opt into per-commit builds from the panel, node updates, the
x-ui.shmenu, and the installer (dev-latest); the dev build version is surfaced in the UI, bot, and CLI, and dev nodes reportdev+<commit>so they aren't flagged stale. - 🧾 Logs & Access Logs viewer overhaul — the Xray access-log viewer is now labeled Access Logs across all languages, with an auto-update toggle, a 1000-row option, and verbatim rendering of plain log notices.
- 📉 Leaner memory & tiered metrics history — real process RSS reporting plus a smaller footprint via GOGC + periodic release, and a tiered rollup that keeps 7 days of metrics history at ~1.5 MB.
- 👥 Client bulk operations — bulk enable/disable and bulk-set XTLS flow from the Adjust dialog, with selection actions tidied into a More menu.
- 🧬 VLESS encryption modes & tunnel health — new VLESS encryption modes plus an Xray tunnel health monitor.
- 🔗 Subscription engine upgrades — new
PROTOCOL/TRANSPORT/SECURITYremark variables, Incy client integration + routing tab, template-driven display remarks, and recovery of{{TRAFFIC_USED}}for orphaned traffic rows. - 🛰️ Node traffic history — import per-client traffic history on a node-hosted inbound's first sync so totals don't start from zero.
- 🧹 Uninstall & deploy cleanup — the uninstaller now offers to purge PostgreSQL, and the legacy AWS golden-image build stack was dropped.
ℹ️ Heads-up: The new Dev update channel ships rolling per-commit builds for testers — stable deployments stay on the release channel unless you switch. The uninstaller now also offers to purge PostgreSQL when removing the panel; decline if you share that database with other apps.
🆕 New
- feat(update): add rolling dev update channel for per-commit builds
- feat(nodes): add Dev channel option to node panel updates
- feat(install): add dev-latest install option and sync README translations
- feat(x-ui.sh): add Dev channel update option to the management menu
- feat(panel): surface dev-build version in UI, bot, and CLI
- feat(web): vless encryption new modes (#5517) @FunLay123
- feat(xray): add tunnel health monitor (#5480) @m4tinbeigi-official
- feat(clients): add bulk enable/disable and move selection actions into More menu
- feat(clients): bulk-set XTLS flow from the Adjust dialog (#5524) @rqzbeh
- feat(logs): add auto-update toggle to Access Logs and Logs viewers
- feat(logs): label the Xray access-log viewer 'Access Logs' across all languages
- feat(logs): add 1000 rows option and drop 10 from log row count selectors
- feat(sub): add PROTOCOL, TRANSPORT, SECURITY remark template variables
- feat(sub): add Incy client integration and routing tab
- feat(uninstall): offer to purge PostgreSQL when removing the panel
⚡ Update & improvement
- perf(memory): report real RSS and cut footprint via GOGC + periodic release
- perf(metrics): tiered rollup history (7d at ~1.5MB) and cleaner ranges
- chore: bump deps and modernize test loops
- chore(deploy): drop the AWS golden-image build stack
🐞 Bug fixed
- fix(web): remove deleted multi-inbound client from runtime regardless of shared email (#5543)
- fix(web): show subscription outbounds in dialer proxy dropdown (#5540)
- fix(web): serve panel SPA routes from NoRoute (#5536) @w3struk
- fix(node): import per-client traffic history on first sync of a node-hosted inbound
- fix(nodes): report dev builds as dev+ so updated nodes aren't flagged stale
- fix(flow): restore XTLS Vision when an inbound becomes flow-eligible (#5520) @rqzbeh
- fix(inbounds): accept null rewritePort in tunnel settings (#5516, #5525) @rqzbeh
- fix(sub): recover {{TRAFFIC_USED}} for clients with orphaned traffic rows
- fix(sub): drive display remarks from the template and split multi-host subpage links
- fix(sub): restore client email in panel copy/QR link remark (#5532)
- fix(outbound): preserve custom headers for HTTP outbounds (#5519)
- fix(clients): use new email after rename and de-duplicate save toast
- fix(tgbot): reload bot on settings save so a new token takes effect without a panel restart
- fix(backup): name Telegram backups after webDomain/IP instead of x-ui
- fix(update): read setUpdateChannel body as form field, not JSON
- fix(hosts): show proper page title instead of falling back to 3X-UI
- fix(logs): render plain log notices verbatim instead of mangling them as timestamps
Reports
New Contributors
- @FunLay123 made their first contribution in #5517
Full Changelog: v3.4.0...v3.4.1
v3.4.0
🚀 Multi-Node Hardening, Notification Event Bus, Managed Hosts & Scale to 100k Clients
- 🛰️ Per-node outbound routing & node hardening — route each node through its own outbound, plus mTLS, hashed + zstd reconcile transport, and per-node network metrics.
- 🔔 Notification event bus — a pub/sub architecture with Telegram and SMTP subscribers, a card-based notification settings layout, and memory-threshold alerts.
- 🌐 Managed Hosts — per-host overrides for subscription links so each host can advertise its own address.
- 🧾 Subscription engine upgrades — dynamic remark variables (Jalali date, transport, status tokens), full XHTTP mapping for Clash/Mihomo, per-client external links + remote subscriptions, and an option to hide server settings (happ).
- 📈 Scale & stability to 50k–100k clients — faster traffic/auto-renew/node bulk ops, DB indexes on hot columns, atomic config writes, panic-recovering cron/jobs, and bounded gRPC deadlines & response sizes.
- 🛡️ fail2ban-native IP limiting — IP limit is now gated on fail2ban (auto-installed on install/update) and reads onlines without parsing
access.log. - 🔐 Native TLS/REALITY pinning — remote cert pinning via a native uTLS handshake (no xray subprocess), ported xray TLS/REALITY fields, and cert-hash helpers.
- 🎯 Real client IP behind CDN/relay — capture the visitor IP behind a CDN/relay and attribute IP-limit per node.
- 🧬 Xray-core v26.6.22 — core upgrade with XHTTP
sessionIDtable/length controls, WireGuard field cleanup, andtrustedXForwardedForhonored on gRPC inbounds. - 🛠️ Deployment pipeline & test-quality audit — release-driven golden-image & unattended-install pipeline, plus a test-quality pass adding mutation/fuzz/CI tooling.
ℹ️ Heads-up: IP limiting now relies on fail2ban, which is auto-installed on install/update, and no longer parses
access.log. LegacypanelProxy/tgBotProxysettings are cleared automatically on upgrade. If you previously tuned IP limiting or those proxy settings, review them after upgrading.
🆕 New
- feat(node): per node outbound routing (#5275) @NikanZeyaei
- feat(node): node hardening — mTLS, hashed+zstd reconcile transport, per-node net metrics (#5382)
- feat(notifications): event bus architecture with Telegram and SMTP subscribers (#5326) @Ssentiago
- feat: replace notification checkboxes with card-based layout (#5421) @Ssentiago
- feat(memory): add memory threshold alerts (#5366) @Ssentiago
- feat(hosts): managed Hosts for per-host subscription link overrides (#5409)
- feat(nodes): per-node client IP attribution for IP-limit
- feat(inbounds): add Real client IP presets to capture visitor IP behind CDN/relay
- feat(sub): per-client external links and remote subscriptions
- feat(sub): add dynamic remark variables with Jalali date, transport, and status tokens (#5430) @wahh3b-lgtm
- feat(sub): full XHTTP field mapping for Clash/Mihomo subscriptions (#5417) @w3struk
- feat(sub): add option to hide server settings in subscription (happ) (#5433) @IgorKha
- feat(tls,reality): port xray TLS/REALITY fields, cert-hash helpers, fallback UX
- feat(finalmask): support Salamander packetSize (Gecko) and Realm tlsConfig for Hysteria2 (#5278) @rqzbeh
- feat(xray): add loopback sniffing and per-segment fragment masks
- feat(xray): preview export in a modal and switch rule enable toggle
- feat(xhttp): support sessionID* rename + sessionIDTable/Length (xray v26.6.22) (#5506) @rqzbeh
- Add Enable/Disable Toggle for Xray Routing Rules (#5296) @abdalrahmanx9
- feat(iplimit): gate IP limit on fail2ban and reset stale limits
- feat(iplimit): auto-install fail2ban on install and update
- feat(ui): show per-inbound live speed (#5261) @NikanZeyaei
- feat(metrics): extend history bucket options to include 12h, 24h, and 48h intervals (#5467) @shazzreab
- feat(sidebar): move Routing/Outbounds to top-level items with clean URLs
- feat(clients): orphan cleanup + export/import via CodeMirror modals
- feat(backup): name DB backup files after the server address
- feat(backup): prefer browser request host for backup filename
- feat(web): cap request body size on state-changing routes (#5271) @n0ctal
- feat(docker): support XUI_PORT runtime override (#5240) @surfdps
- feat: release-driven golden-image & unattended-install deployment pipeline (#5323)
⚡ Update & improvement
- Update Xray to v26.6.22
- perf(scale): speed up traffic, auto-renew, and node bulk ops at 50k-100k clients
- perf: prevent cron job overlap, auto-set GOMEMLIMIT, fix tgbot userStates race
- perf(settings): save all settings in one transaction
- perf(db): index group_name and client_traffics hot columns (#5268) @n0ctal
- perf(db): add an index on settings.key (#5359) @n0ctal
- perf(xray): compile log/traffic regexps once at package scope (#5362) @n0ctal
- chore(db): use DELETE journal mode so sqlite stays a single file
- refactor(web): centralize background job cadences (#5269) @n0ctal
- refactor(job): drop access log from IP limiting, wipe it daily instead
- refactor(frontend): stack client credential fields and use label hints on inbound form
- refactor(frontend): move form-item hints from extra to tooltip
- refactor(wireguard): drop removed workers field (xray v26.6.22) (#5509) @rqzbeh
- Use efficient APIs and simplify loops
- Frontend operation button size optimization (#5343) @tonymoses10
- Test-quality audit: fix 2 prod bugs, strengthen weak tests, add mutation/fuzz/CI tooling (#5345)
- chore(deps): bump frontend deps and override js-yaml to patch DoS advisory
- Bump frontend package & deps to new patch versions
- chore(deps): bump telego to v1.10.0
- chore: bump dompurify to 3.4.11 and expand VS Code tasks
- chore(deps): bump aws-actions/configure-aws-credentials from 4 to 6 (#5426)
- chore(deps): bump react-router-dom from 7.17.0 to 7.18.0 in /frontend (#5428)
- chore(deps): bump actions/upload-artifact from 4 to 7 (#5427)
- chore(deps): bump actions/checkout from 6 to 7 (#5454)
- i18n: sync 12 locales with en-US — add missing Hosts/subscription keys
- Update zh-CN.json (#5459) @qin9125
- feat(ci): add PR review job and commit-capable mention bot
- feat(ci): let mention bot push commits to fork PR branches
- fix(ci): check out PR branch for mention bot so commits land on the PR
- fix(ci): use pull_request_target so claude bot gets secrets on fork PRs
- ci(claude-bot): tune models, Copilot-style PR review, issue research mode
- ci(smoke): set least-privilege GITHUB_TOKEN permissions
- ci(smoke): retry transient GitHub download failures
- [ci: use .nvmrc for setup-node version in codeql/release workflows...
v3.3.1
🚀 Live Config Apply, Native Geodata, Smarter Nodes & a Big Internal Refactor
- ⚡ Live config apply — inbound / outbound / routing changes now apply over the Xray gRPC API without a full core restart, so existing connections survive edits.
- 🌍 Native geodata auto-update — the custom geo manager is gone; geo files now auto-update through Xray-core's built-in mechanism.
- 📡 Access-log-free online tracking — onlines and per-client IP limits now read from Xray's online-stats API instead of parsing
access.log. - 🕸️ Smarter multi-node sync — filter inbounds and clients by node, push global client usage to nodes for display + local enforcement, and a per-inbound share-address strategy that carries through to subscriptions.
- 🌉 Outbound-based egress bridge — the panel proxy URL is replaced by a proper outbound egress bridge; a balancer can now serve as the panel traffic outbound.
- 🔐 MTProto upgrades — domain-fronting and essential
mtgoptions, plus Telegram egress routed through your Xray routing rules. - 🧩 WireGuard refresh — latest Xray-core WireGuard features and per-peer comments to identify devices.
- 🛡️ Security fix —
log.access/log.errorpaths are confined to the panel log folder (GHSA-jm48 arbitrary file write). - 🛠️ Internal refactor — focused service files, leaf subpackages and a cleaner
internal/layout (no API surface change).
ℹ️ Heads-up: geo data now auto-updates via Xray-core and the old panel proxy URL is superseded by the outbound egress bridge. If you relied on either, review your settings after upgrading.
🆕 New
- feat: apply inbound/outbound/routing changes live via Xray gRPC API
- feat: replace panel proxy URL with outbound-based egress bridge
- feat(online): use xray online-stats API for onlines and access-log-free IP limit
- feat(node-sync): push global client usage to nodes for display and local enforcement
- feat: filter inbounds and clients by node (#4997)
- feat: add inbound share address strategy (#5162) @yuanzhidao
- feat: allow selecting inbounds synchronized from nodes (#5178) @animesha3
- feat(mtproto): add domain-fronting and essential mtg options
- feat(mtproto): route Telegram egress through Xray routing rules
- feat: support latest Wireguard features from Xray-core (#5131) @rqzbeh
- feat(wireguard): per-peer comments for identifying devices (#5168)
- feat: implement inbound XMUX form fields (#5211) @rqzbeh
- feat(inbound): support abstract unix sockets (@ prefix) in Address field
- feat(sub): per-inbound sort order for subscription links
- feat(sub): add Copy All Configs button to subscription page (#5163) @NikanZeyaei
- feat(outbound): batched connection tester with direct timed HTTP probes
- feat(settings): allow a balancer as the panel traffic outbound
- feat(settings): schedule picker, toggle placement, sub-theme docs link
- feat(groups): show upload/download breakdown in group traffic
- feat(api): include consumed traffic in the client-get response (#4973)
- feat(env): allow setting the initial URI path for the web panel (#5149) @Ponywka
- feat(routing): show tag (remark) in routing rules list (#5151) @aleskxyz
- feat(clients): restore traffic usage progress bars on Clients page (#5150) @nima1024m
- feat(clients): restore reset traffic button in edit client form
- feat(ui): add select all / clear all shortcuts for inbound multi-select (#5175) @NikanZeyaei
- feat(ui): use CodeMirror editor for Import Inbound and Inbound JSON
- feat(ui): improve client form modal UX
- feat(ui): allow custom fragment packets ranges, not just presets (#5075)
⚡ Update & improvement
- refactor: focused service files, leaf subpackages, and an internal/ layout (#5167)
- refactor: replace custom geo manager with Xray-core native geodata auto-update
- refactor(settings): reorganize subscription settings into clearer tabs
- refactor(groups): restyle traffic summary into upload/download + usage cards
- style(inbounds): show total up/down with directional arrows
- style(ui): enlarge row action icons and rebalance clients table widths
- Update ExecReload command in x-ui.service.debian (#5219) @ssrlive
- i18n: point API token hint at the Authentication page in all locales
- docs: add Turkish language link to other README files (#5138) @tarihcituranx
- chore: pin generated files to LF to avoid phantom CRLF diffs on Windows
- chore: bump Go indirect deps; update frontend lock
- chore(deps): bump golang.org/x/net from 0.55.0 to 0.56.0 (#5199)
- ci(bot): update issue-bot repo map and tighten reply style
🐞 Bug fixed
- fix(xray): confine log.access/error to the panel log folder
- fix(client): preserve UUID/password/auth on partial client update (#5111)
- fix(client): apply per-field client edits to every inbound of the email (#5039)
- fix(client): match clients by email for delete/update, not credentials
- fix(clients): invalidate Xray config cache after client mutations
- fix(node-sync): keep node baseline while a sibling inbound still reports the email (#5202)
- fix(node-sync): keep shared client traffic row when email still lives on other inbounds
- fix(nodes): "Invalid input" when saving a node with inbound sync mode "all"
- fix(sub): honor per-inbound share address strategy in subscription output (#5208)
- fix(sub): deduplicate settings.clients entries per inbound in subscription output (#5134)
- fix(sub): tag node-hosted entries with the node name in remarks (#5035)
- fix: derive JSON/Clash subscription URLs from configured subURI (#5203) @w3struk
- fix: enable XTLS vision flow for VLESS+XHTTP+vlessenc in UI and share links (#5157, #5185) @rqzbeh
- fix: expose streamSettings for Tunnel inbounds to support TProxy (#5171) @rqzbeh
- fix(inbound): preserve custom share strategy on edit (#5225) @yuanzhidao
- fix(inbound): offer node share-address strategy only when a node exists
- fix(inbound): avoid UNIQUE email constraint when importing inbounds that share clients
- fix(inbound): remove stale mkcp-legacy finalmask when switching away from mKCP
- fix(inbound): explain how to unlock fallbacks on the inbound form (#5014)
- fix(inbounds): show remark first, else inbound tag, in client labels
- fix(xhttp): stop injecting scMaxEachPostBytes/scMinPostsIntervalMs defaults (#5141)
- fix(hysteria): clamp udpIdleTimeout to xray-core's accepted 2-600s range (#5117)
- fix(warp): prefer IPv4 with v6 fallback and userspace TUN in generated WireGuard outbounds (#5205)
- [fix(outbound): widen probe timeout and surface failure...
v3.3.0
🚀 MTProto, WARP Rotation, Subscription Outbounds & a Typed API
- 🛡️ MTProto (FakeTLS) — new protocol served through a managed
mtgsidecar, no external setup required. - 🌐 WARP IP rotation — rotate WARP egress IPs manually or automatically on a schedule, with API requests routed through the panel proxy.
- 🔄 Subscription-based outbounds — import outbounds straight from a subscription URL, with automatic refresh.
- 🎨 Customizable subscription pages — bring-your-own templates for the subscription landing page.
- 📑 Typed API & OpenAPI — components, schemas, and response examples generated directly from the Go structs;
/panel/settingand/panel/xrayconsolidated under/panel/api. - 🕸️ Multi-hop nodes — correct traffic attribution across chained sub-nodes, synchronized
access.logclient IPs across nodes, and a distinct purple indicator when the panel is online but the Xray core has failed. - 📊 Per-group traffic — used traffic now shown for each group in the groups table.
⚠️ Breaking:/panel/settingand/panel/xraymoved under/panel/api. Update any integrations that call those paths.
🆕 New
- feat(mtproto): add MTProto (FakeTLS) protocol via managed mtg sidecar (#5076)
- feat: add manual and automatic WARP IP rotation (#5099) @rqzbeh
- feat: synchronize access.log client IPs across nodes (#5098) @rqzbeh
- feat: add support for subscription-based outbounds with auto-update (#5037) @rqzbeh
- feat: customizable subscription page templates (#5079) @rqzbeh
- feat(nodes): multi-hop node attribution for chained sub-nodes (#4983, #5005)
- feat(nodes): distinct purple indicator when panel is online but Xray core failed (#5040) @rqzbeh
- feat(groups): show used traffic per group in groups table
- feat(api-docs): generate OpenAPI components/schemas from Go structs
- feat(api-docs): generate response examples from Go structs; fix SS2022 PSK regen (#4996)
- feat(x-ui.sh): add migrateDB command for SQLite .db ⇄ .dump (#4910)
⚡ Update & improvement
- refactor(api)!: move /panel/setting and /panel/xray under /panel/api
- fix(subClashService): improve merging of clash rules in YAML (#5054) @shazzreab
- fix(update.sh): allow skipping ssl setup when updating (#5071)
- chore: bump frontend version and deps
- i18n(tr): improve Turkish translation consistency and terminology (#5066)
- docs(i18n): add Turkish translation for README (#5067)
- docs(i18n): refine Turkish translation and network terminology (#5092)
- i18n: translate sockopt / REALITY-target / Freedom strings for all locales (#4988)
🐞 Bug fixed
- fix: propagate inbound traffic reset to nodes (#5103) @rqzbeh
- fix: route WARP API requests through panel proxy (#5101) @rqzbeh
- fix(db): additional cross-DB and node-traffic edge cases (migration scan + node reset time) (#5045) @rqzbeh
- fix(postgres): make node traffic sync robust after public API inbound updates (#5038) @rqzbeh
- fix(node-sync): merge client enable with boolean AND for PostgreSQL
- fix(xray): sync routing rules when outbound tag is renamed (#5006) @nima1024m
- fix(panel): normalize XHTTP/sockopt/Reality wire output and validate REALITY target (#4988) @nima1024m
- fix(sub): emit VLESS encryption in Clash configs (#5053) @fs438187
- fix(sub): restore standard base64 for Shadowrocket sub link (#5001)
- fix(sub): don't project public inbounds through a fallback master
- fix(inbounds): drop unknown nodeId when importing an inbound
- fix(finalmask): validate fragment mask length so empty/zero-min can't crash xray
- fix(finalmask): treat sudoku customTables as array of tables
- fix(iplimit): skip stale access-log emails after client rename/delete
- fix(tgbot): apply bot settings on panel restart without full service restart
- fix(script): revoke also removes cert files and acme.sh tracking (#5009)
- fix: default hysteria tls to no utls fingerprint
- fix: correct arm architecture xray binary file name (#5060)
- fix(api-docs): target the panel base path in OpenAPI servers
- fix(ui): correct inline style syntax in client counts column on inbounds page (#5097)
- fix(ui): remove pointer cursor from non-interactive elements in cards (#5102)
- fix(inbound-form): wrap long labels and shorten RU pinned-cert label
- fix(mtproto): reap orphaned mtg, fix SysLog viewer, mtg log visibility, export remark
Reports
Full Changelog: v3.2.8...v3.3.0
v3.2.8
🚀 Multi-Node Resilience, ECH & Scale
- 🌐 Multi-node resilience — client/inbound edits survive an offline node, remote updates are scoped to a single inbound, and stale node snapshots no longer re-enable disabled clients or miscount traffic.
- 🔐 End-to-end ECH — now carried in TLS share links, JSON subscriptions, outbound import, and per-entry external proxy.
- 🧩 Modern Xray JSON subscriptions — new format with a unified finalmask editor.
- 🧭 Clash routing — routing rules and an enable-routing option for Clash subscriptions.
- 💾 DB migration — SQLite ⇄
.dumpconversion and Download Migration from the Overview page.
⚡ Performance — scales to ~200k clients
Benchmarked on PostgreSQL 16 (gains are largest on Postgres, where every round-trip pays network latency):
| Operation | Scale | Before | After | Improvement |
|---|---|---|---|---|
Toggle one client (SyncInbound) |
50k-client inbound | 8m 54s | 0.9s | ~600× (~99.8%) |
| Seed clients | 50k clients | 2m 48s | 1.6s | ~100× (~99%) |
| Bulk create | large inbound | 8m 35s | ~1–5s | ~99% |
| Bulk detach | large inbound | 52s | ~4s | ~92% |
| Bulk delete | large inbound | 16s | ~1–4s | ~85% |
| Bulk adjust | large inbound | 20s | ~7–10s | ~55% |
| Delete-all clients | 100k-client inbound | ❌ crashed (param limit) | ~7s | now works |
| Bulk group add/remove | 100k clients | — | ~6s | scaled |
| Full client list | 100k clients | — | ~1s | scaled |
GetClientTrafficByEmail |
flat in N | 439ms | ~1.5ms | ~290× (~99.7%) |
🆕 New
- feat(sub): modern xray JSON format with unified finalmask editor (#4912) @biohazardous-man
- feat(Clash): add routing rules and enable-routing option for Clash subscriptions (#4904) @Misfit-s
- feat(migrate-db): SQLite ⇄ .dump conversion and Download Migration in Overview
⚡ Update & improvement
- perf(clients): make SyncInbound bulk to fix large-inbound timeouts (#4885)
- perf(clients): scale add/delete and bulk client operations
- perf(clients): chunk IN queries and de-quadratic bulk delete/group/list
- perf(clients): scale-audit remaining client/inbound endpoints to 200k
- chore(deps): bump i18next from 26.3.0 to 26.3.1 in /frontend (#4901)
- i18n: add 1-year expiration to language cookie (#4890) @lim-kim930
- docs(contributing): refresh frontend guide and add Postgres launch profile
🐞 Bug fixed
- fix(node): keep client/inbound edits working when a node is offline (#4923, #4931)
- fix(multi-node): scope remote client update/delete to one inbound (#4892)
- fix(node-traffic): prevent stale node snapshot from re-enabling disabled client (#4917) @younesvatan78
- fix: restart remote xray after disabling a client to kill active sessions (#4918) @younesvatan78
- fix(traffic): count local traffic for clients whose shared row is node-owned (#4921)
- fix(sub): include ECH config in TLS share links and JSON subscription
- fix(outbound): import ech and pcs from TLS share links
- fix(external-proxy): relabel "Host" as "Address", add per-entry ECH (#4935)
- fix(ssl): clean ECC state, guard cert reuse, register renew hook (#4875)
- fix(fail2ban): exempt SSH and panel ports from IP-limit ban (#4896)
- fix(migrate-db): drop legacy client_traffics FK before Postgres copy (#4882)
- fix(tgbot): ignore commands for other bots (#4894) @kanghouchao
Reports
Full Changelog: v3.2.7...v3.2.8
v3.2.7
New
- feat(dashboard): richer System History & Xray Metrics charts
- feat(dashboard): more System History metrics, persistence & localized labels
- feat(xray): merge basic routing into the routing rules section
- feat(xray): add connIdle and bufferSize policy controls
- feat(settings): sidebar submenu nav for settings and xray with icon tabs
- feat(settings): move the remark model control to the subscription tab
- feat(inbounds): per-proxy Pinned Peer Cert SHA-256 + labeled External Proxy form
- feat(tls): add ocspStapling to certificate config
- feat(links): richer share-link labels across QR, client info and sub views
- feat(hysteria2): emit UDP port hopping in subscriptions and share links (#4789)
- feat(clients): show filtered count in clients list (#4808)
- feat(clients,routing): label inbounds by remark with tag fallback
Update & improvement
- chore(deps): bump xray-core to v1.260327.1 and add pion/wireguard deps
- chore(frontend): bump deps to 0.2.7 and hide node row selection for single node
- i18n: translate connection-limit strings for all languages
- fix(sidebar): set fixed sider width to 220
- fix(ci): bump Go to 1.26.4 and exempt /panel/groups SPA route from api-docs test
- ci(issue-bot): ground the assistant in repo source with an investigation step
Bug fixed
- fix(api-token): hash tokens at rest and show plaintext only once
- fix(online): scope per-inbound online to inbounds that carried traffic (#4859)
- fix(nodes): Set Cert from Panel uses the node's own web cert for node inbounds (#4854)
- fix(panel): register /groups SPA route so hard refresh returns index.html (#4837)
- fix(clients): keep reverse tag clearable and preserve flow on attach (#4834)
- fix(settings): fall back to defaults for empty/NULL setting values (#4830)
- fix(links): use configured domain for panel copy/QR links on loopback (#4829)
- fix(docker): make x-ui CLI menu work inside containers (#4817)
- fix(hysteria2): emit pinSHA256 as hex in subscriptions, not base64 (#4818)
- fix(online): scope online status per node instead of a global union (#4809)
- fix(iplimit): populate client IP log without an IP limit (#4800)
- fix(sub): advertise routable inbound Listen in subscription links (#4798)
- fix(outbounds): preserve SNI/TLS settings on transport change (#4791)
- fix(clients): derive edit-form flow from per-inbound override (#4792)
- fix(tls): correct pinned cert SHA-256 hint to hex, not base64 (#4793)
- fix(node): fix "invalid input" on save and gate save on connectivity (#4794)
- fix(xray): default freedom finalRules to allow-all so reverse egress works
- fix(migrate): relax legacy freedom finalRules so reverse egress works on existing installs (#4782)
- fix(panel-proxy): route custom geo and http(s) Telegram through panelProxy
- fix(migrate-db): preserve false-valued columns in SQLite to Postgres copy
- fix(clients): use client_inbounds link to resolve inbound, not stale id
- fix(settings): allow pagination size of 0 to disable pagination
- fix(sub): escape Clash subscription profile filename header (#4799) @xiaoxiyao
Reports
Full Changelog: v3.2.6...v3.2.7