{"id":50782757,"url":"https://github.com/lolka1333/rx-ui","last_synced_at":"2026-06-12T05:01:45.209Z","repository":{"id":361685484,"uuid":"1255178697","full_name":"lolka1333/rx-ui","owner":"lolka1333","description":"Self-hosted Xray-core panel: VLESS · Reality · XHTTP · Hysteria2 inbounds, clients, traffic quotas, subscription links and built-in anti-DPI — one Rust + React binary.","archived":false,"fork":false,"pushed_at":"2026-06-09T05:57:51.000Z","size":2778,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T07:28:20.025Z","etag":null,"topics":["anti-censorship","dpi-bypass","hysteria2","proxy","react","rust","self-hosted","vless","vless-reality","xhttp","xray","xray-core"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lolka1333.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-31T14:03:06.000Z","updated_at":"2026-06-09T05:57:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/lolka1333/rx-ui","commit_stats":null,"previous_names":["lolka1333/rx-ui"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/lolka1333/rx-ui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lolka1333%2Frx-ui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lolka1333%2Frx-ui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lolka1333%2Frx-ui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lolka1333%2Frx-ui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lolka1333","download_url":"https://codeload.github.com/lolka1333/rx-ui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lolka1333%2Frx-ui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34229624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anti-censorship","dpi-bypass","hysteria2","proxy","react","rust","self-hosted","vless","vless-reality","xhttp","xray","xray-core"],"created_at":"2026-06-12T05:01:44.539Z","updated_at":"2026-06-12T05:01:45.190Z","avatar_url":"https://github.com/lolka1333.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"rx-ui-banner-1280.png\" alt=\"rx-ui — Xray-core admin panel\" width=\"100%\"\u003e\n\u003c/p\u003e\n\n# rx-ui\n\nSelf-hosted admin panel for [Xray-core](https://github.com/XTLS/Xray-core).\nVLESS + Reality/TLS + TCP/WebSocket/XHTTP, fully managed through Xray's\ngRPC `HandlerService` (no config-file restarts).\n\n## What this is\n\n- **Backend** (`backend/`): Rust + axum + sqlx (SQLite) + tonic gRPC.\n  Manages inbounds and clients, pushes changes into the running xray\n  process at runtime, generates Reality keypairs, builds share-links.\n- **Frontend** (`frontend/`): React + Antd v6. Operator-facing UI for\n  inbound/client CRUD, dashboard with CPU/RAM/xray status, settings.\n- **Xray binary**: bootstrapped on first run (downloaded via the\n  \"Xray updates\" modal) or attached to an existing process.\n\nFor the system architecture — process model, request flow,\nschema choices — see [ARCHITECTURE.md](ARCHITECTURE.md).\n\n## Quick start\n\n### Single-binary release (the easy way)\n\nDownload (or build — see below) `rx-ui.exe`, drop it into a\nfresh folder, run it. That's it.\n\n```bash\n./rx-ui.exe        # zero-config: nothing to set up\n```\n\nOn first start the binary auto-creates a `data/` directory next to\nitself and bootstraps everything:\n\n- `data/jwt_secret` — fresh 32-byte secret (so login sessions survive\n  restarts). Delete the file to rotate.\n- `data/panel.db` — SQLite database with all schema migrations applied.\n- `data/xray/xray.exe` — latest stable xray-core, downloaded from GitHub\n  releases. Geofiles included.\n- Default admin user `admin` / `admin` — **change immediately** via the\n  panel's settings.\n\nOpen `http://localhost:8080` in a browser, log in, you're running.\n\n### Docker (compose)\n\nBuild and run everything — frontend, backend, embedded SPA — in a container,\nwith no Rust/Node toolchain on the host:\n\n```bash\ndocker compose up -d --build     # build image + start\ndocker compose logs -f           # follow logs\ndocker compose down              # stop (data volume kept)\n```\n\nSame zero-config bootstrap as the release binary (admin / admin, generated\nJWT secret, xray-core fetched on first run). All state lives in the\n`rx-ui-data` Docker volume.\n\n`docker-compose.yml` uses **host networking** — the right mode for a VPN\npanel, since the xray inbounds you create bind operator-chosen ports and host\nmode makes them all reachable. It's Linux-only; on Docker Desktop\n(macOS/Windows) switch to the commented bridge `ports:` fallback (panel UI\nonly). Optional tuning (port, log level, `JWT_SECRET`, initial admin password)\ngoes in `.env` — copy `.env.example` to `.env`.\n\n### Dev workflow (running from source)\n\n```bash\n# Prerequisites:\n#   - Rust 1.95+ (rustup auto-installs from rust-toolchain.toml)\n#   - Node 22+ and pnpm 10+ (.nvmrc + package.json engines)\n#   - protoc (vendored via protoc-bin-vendored crate; no system install needed)\n\n# Backend (no .env needed — same auto-bootstrap as release):\ncd backend\ncargo run                  # starts on :8080\n\n# Frontend (separate terminal):\ncd frontend\npnpm install\npnpm run dev               # Vite on :5173, proxies /api → :8080\n```\n\nIn dev mode you browse the frontend on **:5173** (with HMR); in\nrelease mode the SPA is embedded in the binary and served from\n**:8080** alongside the API. Same code, two delivery modes.\n\n### Building a release binary\n\n```bash\ncd frontend \u0026\u0026 pnpm install \u0026\u0026 pnpm build     # produces frontend/dist/\ncd ../backend \u0026\u0026 cargo build --release         # embeds dist/ into the binary\n\n# Result: target/release/rx-ui.exe (~10 MB on Windows)\n```\n\nThe backend listens on `0.0.0.0:8080` (override with `PANEL_HOST` /\n`PANEL_PORT` env). On first start it creates `backend/data/panel.db`\nand applies all migrations in `backend/migrations/`.\n\nThe xray binary lives in `backend/data/xray/` after the first\n\"Install xray\" click in the panel; the backend then either spawns it\nas a child or attaches to an existing process with the same exe path.\n\n## Environment\n\nAll env vars are optional — the binary uses sensible defaults and\nauto-generates secrets where needed. Set them only if you want to\noverride behaviour (e.g. systemd service with custom paths).\n\n| Var | Default | Purpose |\n|---|---|---|\n| `JWT_SECRET` | auto-generated, persisted to `data/jwt_secret` | HS256 secret for session tokens. Set explicitly if you manage secrets externally (Vault, env injection from systemd, etc.) |\n| `DATABASE_URL` | `sqlite://data/panel.db` | SQLite connection string |\n| `PANEL_HOST` | `127.0.0.1` | Backend bind host (set to `0.0.0.0` for LAN/public access) |\n| `PANEL_PORT` | `8080` | Backend bind port |\n| `XRAY_BINARY` | `data/xray/xray.exe` (Win) or `data/xray/xray` (Unix) | xray executable path |\n| `XRAY_CONFIG` | `data/xray/config.json` | xray's bootstrap config (auto-generated on first run) |\n| `RUST_LOG` | `rx_ui=info,sqlx=warn` | tracing filter |\n\nOptional `.env` file in the binary's CWD is auto-loaded via `dotenvy`.\n\n## Project layout\n\n```\nrx-ui/\n├── backend/                     # Rust workspace member (the binary)\n│   ├── src/\n│   │   ├── main.rs              # bootstrap + reconcile-on-startup\n│   │   ├── db.rs                # SQLite pool + embedded-migration runner\n│   │   ├── auth.rs              # JWT (HS256) keys + argon2 password hashing\n│   │   ├── error.rs             # AppError + IntoResponse\n│   │   ├── traffic.rs           # per-client traffic accounting\n│   │   ├── host.rs              # host CPU / memory sampler (dashboard)\n│   │   ├── logs.rs              # in-memory log ring buffer (GET /api/logs)\n│   │   ├── static_assets.rs     # serve the embedded React SPA\n│   │   ├── api/                 # axum routes: auth, inbounds, clients, dashboard, settings, subscription, xray, logs\n│   │   ├── models/              # shared data types (Inbound, Client, ...) — ts-rs exported\n│   │   ├── protocols/           # per-protocol config (vless, hysteria)\n│   │   ├── transports/          # per-transport config (tcp, ws, xhttp, quic, hysteria, sockopt, finalmask)\n│   │   ├── security/            # security layer (none / tls / reality)\n│   │   └── xray/                # everything xray-related\n│   │       ├── control.rs       # spawn / attach / stop the xray process\n│   │       ├── grpc.rs          # gRPC HandlerService client wrapper\n│   │       ├── orchestrator.rs  # reconcile panel state → xray (add/remove inbounds)\n│   │       ├── config_gen.rs    # build the xray config.json\n│   │       ├── reload.rs        # live-reload inbound/config changes\n│   │       ├── share_link.rs    # build share-link / vless:// URLs\n│   │       ├── keygen.rs        # Reality x25519 + short_id\n│   │       ├── installer.rs     # download the xray binary from GitHub\n│   │       └── proto.rs         # tonic-generated proto module tree\n│   ├── migrations/              # sqlx migrations (numeric prefix = order)\n│   ├── proto/                   # vendored xray-core .proto files\n│   ├── data/                    # runtime: DB, xray binary + config (gitignored)\n│   └── .sqlx/                   # sqlx offline query cache (committed to source)\n├── frontend/                    # Vite + React + Antd\n│   ├── src/\n│   │   ├── App.tsx, Root.tsx    # app shell + providers\n│   │   ├── pages/               # views: Dashboard, Inbounds, Clients, Settings, Login, SubscriptionLanding\n│   │   ├── components/          # shared UI: Sidebar, LogsModal, XrayUpdatesModal, ServerInfoCard, QrCard, ...\n│   │   ├── api/                 # axios client + auto-generated TS types\n│   │   ├── stores/              # zustand: auth, theme, locale, nav\n│   │   ├── i18n/                # ru.ts (source) + en.ts (mirror)\n│   │   ├── theme/               # Antd theme tokens\n│   │   └── lib/                 # shared helpers\n│   └── package.json\n├── Dockerfile, docker-compose.yml   # container build + run\n├── .github/workflows/ci.yml     # CI: cargo fmt+clippy+test, pnpm typecheck+build\n├── rust-toolchain.toml          # Rust 1.95 pin\n├── .nvmrc                       # Node 22 pin\n└── Cargo.toml                   # workspace root\n```\n\n## Development workflow\n\n```bash\n# Backend changes\ncd backend\ncargo fmt\ncargo clippy --workspace --all-targets -- -D warnings\ncargo test                                  # 74 tests covering pure logic\ncargo sqlx prepare -- --bin rx-ui  # after editing any sqlx::query!()\n\n# Frontend changes\ncd frontend\npnpm run typecheck\npnpm run lint\npnpm run build                              # full Vite production build\n\n# After Rust model changes: regenerate TS types\ncd backend\ncargo test export_bindings                  # ts-rs runs as #[test] fns\n# Generated files land in frontend/src/api/types/ — commit them.\n```\n\n## Migrations\n\nEvery schema change = new file `backend/migrations/NNNN_short_description.sql`,\napplied automatically on backend boot via `sqlx::migrate!()`. **Never edit\nan already-applied migration** — the checksum tracking in `_sqlx_migrations`\nwill refuse to start. Add a corrective migration instead.\n\n## Adding a new inbound field — the cost\n\nA reasonable approximation: ~9-14 file edits per new column on the `inbounds`\ntable. The full chain is documented in [ARCHITECTURE.md § \"Adding a field\"](\nARCHITECTURE.md#adding-an-inbound-field). This is a known maintenance pain\npoint — see the same doc for the planned `config_json` blob refactor.\n\n## License\n\n[GNU Affero General Public License v3.0](LICENSE) (AGPL-3.0). You may use,\nmodify, fork, and self-host this project — including commercially — as long as\nit stays under the AGPL. The network clause is the important part for a panel:\nif you run a modified version as a service for others, you must make its source\navailable to them. See [NOTICE](NOTICE) for copyright and attribution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flolka1333%2Frx-ui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flolka1333%2Frx-ui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flolka1333%2Frx-ui/lists"}