Xray panel supporting multi-protocol multi-user expire day & traffic & IP limit (Vmess, Vless, Trojan, ShadowSocks, Wireguard, Tunnel, Mixed, HTTP, Tun) https://t.me/XrayUI
Find a file
Yuri Khachaturyan 2b1308ca29
feat(notifications): add a consecutive-failure threshold for outbound.down alerts (#5968)
Problem: a flaky outbound produces hundreds of false-positive "outbound down"
notifications overnight — each fires the moment xray's observatory reports a
single failed probe, and the next successful probe fires an "up".

applyObservatory forwarded every raw alive:true->false transition straight to
EventOutboundDown; xray's observatory has effectively no hysteresis, and nothing
on the panel side debounced it (the email/Telegram subscribers are pure
formatters).

Fix: debounce per outbound. outbound.down now fires only after
outboundDownThreshold consecutive FAILED probes (new setting, default 3);
outbound.up fires immediately on the first successful probe and only when a down
was actually notified. The threshold gates the event itself, so email and
Telegram share one knob (exposed next to the outbound.down toggle).

The streak counts genuinely new probes (last_try_time advancing), not sampler
polls — the sampler runs every 2s but the observatory re-probes per its
probeInterval, so counting samples would trip the threshold instantly.
outboundDownThreshold=1 reproduces the legacy notify-on-first-failure behaviour.

Tuning the observatory's probe interval/timeout is not a workaround: those
probes also drive the load balancer's outbound selection, so loosening them to
quiet notifications would slow real failover away from a genuinely dead
outbound. Notifications don't need observatory-grade latency, so the tolerance
belongs at the notification layer, leaving the observatory (and balancer)
untouched.

Adds TestApplyObservatoryDebounce covering the threshold, probe-vs-sample
counting, single-blip suppression and the legacy path.

Co-authored-by: Yuriy Khachaturian <y.khachaturian@souzmult.ru>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 15:59:07 +02:00
.github fix(ci): publish dev-latest edit-first instead of probing for existence 2026-07-17 01:34:47 +02:00
.vscode chore: add golangci-lint tasks and force LF on Go files 2026-07-08 22:11:28 +02:00
deploy fix(ci): pin the tag smoke test to the release under test 2026-07-03 10:21:46 +02:00
docs chore: standardize the toolchain on Node 24 LTS 2026-07-14 03:39:03 +02:00
frontend feat(notifications): add a consecutive-failure threshold for outbound.down alerts (#5968) 2026-07-21 15:59:07 +02:00
internal feat(notifications): add a consecutive-failure threshold for outbound.down alerts (#5968) 2026-07-21 15:59:07 +02:00
media docs(readme): revamp README and sync all translations 2026-06-02 03:03:14 +02:00
tools/openapigen fix(api): preserve 64-bit integer schema formats (#5908) 2026-07-12 10:58:02 +02:00
windows_files Update OpenSSL installer to version 3.6.0 2026-01-05 18:49:30 +01:00
.dockerignore refactor: focused service files, leaf subpackages, and an internal/ layout (#5167) 2026-06-10 15:19:22 +02:00
.env.example Env vars example file update (#5678) 2026-07-03 00:28:13 +02:00
.gitattributes chore: add golangci-lint tasks and force LF on Go files 2026-07-08 22:11:28 +02:00
.gitignore Add encrypted DNS presets (#5837) 2026-07-09 00:45:35 +02:00
.golangci.yml style: adopt golangci-lint v2 and resolve all findings 2026-06-27 15:42:22 +02:00
.nvmrc chore: standardize the toolchain on Node 24 LTS 2026-07-14 03:39:03 +02:00
CLAUDE.md feat(mtproto): enforce per-client quota & expiry via mtg-multi limits 2026-07-08 15:30:56 +02:00
CONTRIBUTING.md feat(frontend): make Storybook a validated, fully covered component workbench 2026-07-14 03:37:21 +02:00
docker-compose.yml fix(docker): start crond and persist acme.sh state so cert renewal works 2026-07-03 09:32:28 +02:00
DockerEntrypoint.sh fix(docker): start crond and persist acme.sh state so cert renewal works 2026-07-03 09:32:28 +02:00
Dockerfile refactor: focused service files, leaf subpackages, and an internal/ layout (#5167) 2026-06-10 15:19:22 +02:00
DockerInit.sh feat(xray): update xray-core to v26.7.11 and adapt panel 2026-07-12 00:30:47 +02:00
go.mod chore(deps): bump google.golang.org/grpc from 1.82.0 to 1.82.1 (#5994) 2026-07-16 13:16:32 +02:00
go.sum chore(deps): bump google.golang.org/grpc from 1.82.0 to 1.82.1 (#5994) 2026-07-16 13:16:32 +02:00
install.sh fix(script): remove release download time limit (#5952) 2026-07-14 12:44:55 +02:00
LICENSE 3x-ui 2023-02-09 22:48:06 +03:30
main.go style: adopt golangci-lint v2 and resolve all findings 2026-06-27 15:42:22 +02:00
Makefile feat(frontend): make Storybook a validated, fully covered component workbench 2026-07-14 03:37:21 +02:00
README.ar_EG.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.es_ES.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.fa_IR.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.ru_RU.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.tr_TR.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
README.zh_CN.md fix(mtproto): stop dropping connections on client/inbound edits; add live updates + ad-tag (#5838) 2026-07-07 01:13:24 +02:00
update.sh fix(script): Remove old mtg binary (#5955) 2026-07-14 12:44:22 +02:00
x-ui.rc fix(alpine): restart_xray uses rc-service; OpenRC reload reads pidfile contents 2026-05-11 09:05:36 +02:00
x-ui.service.arch Update ExecReload command in x-ui.service.debian (#5219) 2026-06-12 12:09:48 +02:00
x-ui.service.debian Update ExecReload command in x-ui.service.debian (#5219) 2026-06-12 12:09:48 +02:00
x-ui.service.rhel Update ExecReload command in x-ui.service.debian (#5219) 2026-06-12 12:09:48 +02:00
x-ui.sh fix(script): confirm auto-detected public IPv4 before issuing IP certificate 2026-07-11 22:35:31 +02:00

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

3x-ui

Release Build GO Version Downloads License Go Reference

3X-UI is an advanced, open-source web control panel for managing Xray-core servers. It provides a clean, multi-language interface for deploying, configuring, and monitoring a wide range of proxy and VPN protocols — from a single VPS to multi-node deployments.

Built as an enhanced fork of the original X-UI project, 3X-UI adds broader protocol support, improved stability, per-client traffic accounting, and many quality-of-life features.

Important

This project is intended for personal use only. Please do not use it for illegal purposes or in a production environment.

Features

  • Multi-protocol inbounds — VLESS, VMess, Trojan, Shadowsocks, WireGuard, Hysteria2, HTTP, SOCKS (Mixed), Dokodemo-door / Tunnel, and TUN.
  • Modern transports & security — TCP (Raw), mKCP, WebSocket, gRPC, HTTPUpgrade, and XHTTP, secured with TLS, XTLS, and REALITY.
  • Fallbacks — serve multiple protocols on a single port (e.g. VLESS and Trojan on 443) using Xray's fallback support.
  • Per-client management — traffic quotas, expiry dates, IP limits, live online status, and one-click share links, QR codes, and subscriptions.
  • Traffic statistics — per inbound, per client, and per outbound, with reset controls.
  • Multi-node support — manage and scale across multiple servers from a single panel.
  • Outbound & routing — WARP, NordVPN, custom routing rules, load balancers, and outbound proxy chaining.
  • Built-in subscription server with multiple output formats and custom page templates.
  • Telegram bot for remote monitoring and management.
  • RESTful API with in-panel Swagger documentation.
  • Flexible storage — SQLite (default) or PostgreSQL.
  • 13 UI languages with dark and light themes.
  • Fail2ban integration for enforcing per-client IP limits.

Screenshots

Click to expand Overview Inbounds Add client Configs

Quick Start

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

To install a specific version, append its tag (e.g. v3.4.0):

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

To install the rolling dev build (latest per-commit pre-release from main, not a stable release), pass dev-latest:

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

During installation a random username, password, and access path are generated. After installation, run x-ui to open the management menu, where you can start/stop the service, view or reset your login credentials, manage SSL certificates, and more.

For full documentation, please visit the project Wiki.

Unattended install

The installer also runs non-interactively for cloud-init. Set XUI_NONINTERACTIVE=1 (or pipe 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. See deploy/ for:

Supported Platforms

Operating systems: Ubuntu, Debian, Armbian, Fedora, CentOS, RHEL, AlmaLinux, Rocky Linux, Oracle Linux, Amazon Linux, Virtuozzo, Arch, Manjaro, Parch, openSUSE (Tumbleweed / Leap), Alpine, and Windows.

Architectures: amd64 · 386 · arm64 (aarch64) · armv7 · armv6 · armv5 · s390x.

Database Options

3X-UI supports two backends, chosen during the install:

  • SQLite (default) — a single file at /etc/x-ui/x-ui.db. Zero setup, ideal for small and medium deployments.
  • PostgreSQL — 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 (the installer writes these to /etc/default/x-ui for you):

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

Migrating an existing SQLite install to PostgreSQL

x-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:
systemctl restart x-ui

The source SQLite file is left untouched; remove it manually once you have verified the new backend.

Docker

The default docker compose up -d keeps using SQLite. To run with the bundled PostgreSQL service, uncomment the two XUI_DB_* env lines in docker-compose.yml and start with the profile:

docker compose --profile postgres up -d

The image bundles Fail2ban (enabled by default) to enforce per-client IP limits. Fail2ban bans offenders with iptables, which requires the NET_ADMIN capability. docker-compose.yml already grants it via cap_add; if you start the container with docker run instead, add the capabilities yourself, otherwise bans are logged but never applied:

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

Environment Variables

Variable Description Default
XUI_DB_TYPE Database backend: sqlite or postgres sqlite
XUI_DB_DSN PostgreSQL connection string (when XUI_DB_TYPE=postgres)
XUI_DB_FOLDER Directory for the SQLite database file /etc/x-ui
XUI_DB_MAX_OPEN_CONNS Maximum open connections (PostgreSQL pool)
XUI_DB_MAX_IDLE_CONNS Maximum idle connections (PostgreSQL pool)
XUI_INIT_WEB_BASE_PATH The initial URI path for the web panel /
XUI_ENABLE_FAIL2BAN Enable Fail2ban-based IP-limit enforcement true
XUI_LOG_LEVEL Log verbosity (debug, info, warning, error) info
XUI_DEBUG Enable debug mode false
XUI_TUNNEL_HEALTH_MONITOR Enable the tunnel health monitor (probes a URL and restarts xray after repeated failures; a restart drops all clients) false
XUI_TUNNEL_HEALTH_PROXY Proxy the probe is sent through; point it at a local xray inbound so the probe tests the tunnel (e.g. socks5://127.0.0.1:1080). Empty means the probe only checks host connectivity
XUI_TUNNEL_HEALTH_URL URL probed for tunnel health https://www.cloudflare.com/cdn-cgi/trace
XUI_TUNNEL_HEALTH_INTERVAL Interval between probes 30s
XUI_TUNNEL_HEALTH_TIMEOUT Per-probe timeout 10s
XUI_TUNNEL_HEALTH_FAILURES Consecutive failures before a restart is triggered 3
XUI_TUNNEL_HEALTH_COOLDOWN Minimum delay between consecutive restarts 5m

Supported Languages

The panel UI is available in 13 languages:

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

Contributing

Contributions are welcome. Please read the Contributing Guide before opening an issue or pull request.

A Special Thanks to

Acknowledgment

  • Iran v2ray rules (License: GPL-3.0): Enhanced v2ray/xray and v2ray/xray-clients routing rules with built-in Iranian domains and a focus on security and adblocking.
  • Russia v2ray rules (License: GPL-3.0): This repository contains automatically updated V2Ray routing rules based on data on blocked domains and addresses in Russia.

Community Tools

Tools and integrations built by the community around 3x-ui.

  • terraform-provider-3x-ui (License: MIT): Manage inbounds, clients, panel settings, and Xray configuration as code with Terraform / OpenTofu.

Support project

If this project is helpful to you, you may wish to give it a🌟

Buy Me A Coffee
Crypto donation button by NOWPayments

Stargazers over Time

Stargazers over time