3x-ui/frontend
reza 4f8b0b90c8 feat(inbound): scaffold dedicated SOCKS5 inbound protocol
Adds an initial, intentionally minimal scaffold for a dedicated SOCKS5
inbound (Xray 'socks' protocol, RFC 1928). The existing 'mixed' inbound
already supports SOCKS+HTTP on the same port, but several deployments
need a pure SOCKS5 inbound — for example chained outbounds and clients
that don't tolerate HTTP CONNECT on the same listener.

This PR is purposely a scaffold so other contributors can finish the
full integration (sub link generation, routing UI helpers, Xray runtime
AddUser hooks, translations, docs, tests). It does NOT claim feature
completeness.

What's included
---------------
Backend (Go):
  * database/model/model.go: add Socks model.Protocol constant ('socks')
    next to Mixed, with a doc comment explaining the difference vs Mixed.

Frontend (JS/Vue):
  * frontend/src/models/inbound.js
      - Add Protocols.SOCKS ('socks') to the protocol enum, so the
        existing 'Object.values(Protocols)' selector picks it up
        automatically in the inbound create/edit modal.
      - New Inbound.SocksSettings class (auth, accounts, udp, ip)
        that serialises in the exact shape Xray's socks inbound expects
        (https://xtls.github.io/config/inbounds/socks.html).
      - New Inbound.SocksSettings.SocksAccount for password-mode users.
      - Wire SOCKS into Inbound.Settings.getSettings() and fromJson()
        dispatchers so create/edit/restore round-trips work.

  * frontend/src/pages/inbounds/InboundFormModal.vue
      - Extend the existing 'HTTP / Mixed accounts' form so SOCKS shares
        the same accounts editor + auth/UDP/UDP-IP fields. SOCKS reuses
        the MIXED shape because Xray's socks and mixed inbounds accept
        the same settings keys.
      - New addAccountByProtocol() helper dispatches to the correct
        Account class per protocol (Http / Mixed / Socks) so each
        protocol stores accounts in the right namespace.

What's intentionally NOT done (help wanted)
-------------------------------------------
1. sub/subService.go GetLink: SOCKS currently returns '' (same as
   MIXED/HTTP/Tunnel). If we want a 'socks://' subscription link, that
   needs its own gen* function. The existing comment on GetLink already
   lists socks/http/mixed as link-less, so this is consistent for now.
2. Xray runtime AddUser / UpdateInbound hooks in web/service/inbound.go
   — accounts are persisted in settings JSON and Xray picks them up on
   restart, but live add-user without restart is not wired.
3. Routing UI: routing pages already accept any inbound tag, so SOCKS
   inbounds are routable as-is; a dedicated 'protocol == socks' helper
   in routing rule editors would be a nice follow-up.
4. Translations (web/translation/*.json): the protocol name is rendered
   as the raw string 'socks' in the dropdown today; we don't yet have
   a localised label.
5. Tests: xray/process_test.go has no SOCKS-specific case yet.

Why scaffold instead of full feature?
-------------------------------------
The protocol surface area touches db model, settings serialisation,
form UI, sub link generation, routing rules, and translations for 13
locales. Landing a vetted scaffold first lets multiple contributors
parallelise the remaining work without merge churn on a giant PR.

Refs
----
- Xray socks inbound spec: https://xtls.github.io/config/inbounds/socks.html
- RFC 1928 (SOCKS Protocol Version 5)

Co-developed-by: 3x-ui community (call for contributions)
2026-05-18 08:07:17 +00:00
..
src feat(inbound): scaffold dedicated SOCKS5 inbound protocol 2026-05-18 08:07:17 +00:00
.gitignore Vue3 migration (#4198) 2026-05-09 17:47:35 +02:00
api-docs.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
eslint.config.js fix: reality random target/sni buttons not working (#4337) (#4340) 2026-05-13 14:42:20 +02:00
inbounds.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
index.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
login.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
nodes.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
package-lock.json Remove streamSettings for protocols that don't support it 2026-05-14 23:18:23 +02:00
package.json v3.0.2 2026-05-14 10:27:33 +02:00
README.md Vue3 migration (#4198) 2026-05-09 17:47:35 +02:00
settings.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00
subpage.html Vue3 migration (#4198) 2026-05-09 17:47:35 +02:00
vite.config.js feat(panel): in-panel API documentation page 2026-05-11 13:57:42 +02:00
xray.html feat(ui): use the host as the browser tab title prefix 2026-05-13 14:23:57 +02:00

3x-ui frontend

Vue 3 + Ant Design Vue 4 + Vite. Multi-page app — one HTML entry per panel route — built into ../web/dist/ and embedded into the Go binary via embed.FS.

Dev

npm install
npm run dev

Vite serves on http://localhost:5173/. API calls and /panel/* routes proxy to the Go panel at http://localhost:2053/, so start the Go panel first (go run main.go) and then Vite.

The proxy auto-rewrites /panel, /panel/settings, /panel/inbounds, /panel/xray to the matching Vite-served HTML in dev mode (see MIGRATED_ROUTES in vite.config.js), so the sidebar's production-style links work without round-tripping through Go.

Production build

npm run build

Outputs to ../web/dist/ (HTML at the root, hashed JS/CSS under assets/). The Go binary embeds this directory at compile time and web/controller/dist.go serves the per-page HTML.

Lint

npm run lint

ESLint 10 with eslint.config.js (flat config) — vue3-recommended plus a few rule overrides for the project's formatting style.

Layout

frontend/
├── *.html                 # Vite entry HTML, one per panel route
├── eslint.config.js
├── vite.config.js
└── src/
    ├── entries/           # Per-page bootstrap (createApp + mount)
    ├── pages/             # One folder per route, each with the page
    │   ├── index/         # component + helpers + sub-components
    │   ├── login/
    │   ├── inbounds/
    │   ├── xray/
    │   ├── settings/
    │   └── sub/
    ├── components/        # Cross-page Vue components
    ├── composables/       # Reusable reactive logic (useTheme, …)
    ├── api/               # Axios setup, CSRF interceptor
    ├── i18n/              # vue-i18n init (locales live in web/translation/)
    ├── models/            # Inbound, Outbound, Status, … domain classes
    └── utils/             # HttpUtil, ObjectUtil, LanguageManager, …

Adding a new page

  1. Add frontend/<page>.html referencing /src/entries/<page>.js.
  2. Add src/entries/<page>.js that imports the page component and mounts it.
  3. Add the page component under src/pages/<page>/.
  4. Register the entry in rollupOptions.input in vite.config.js.
  5. If the page is reachable from the sidebar at /panel/<route>, add it to MIGRATED_ROUTES so the dev proxy serves the Vite HTML.
  6. Wire the Go controller to serveDistPage(c, "<page>.html").