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)
|
||
|---|---|---|
| .. | ||
| src | ||
| .gitignore | ||
| api-docs.html | ||
| eslint.config.js | ||
| inbounds.html | ||
| index.html | ||
| login.html | ||
| nodes.html | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| settings.html | ||
| subpage.html | ||
| vite.config.js | ||
| xray.html | ||
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
- Add
frontend/<page>.htmlreferencing/src/entries/<page>.js. - Add
src/entries/<page>.jsthat imports the page component and mounts it. - Add the page component under
src/pages/<page>/. - Register the entry in
rollupOptions.inputinvite.config.js. - If the page is reachable from the sidebar at
/panel/<route>, add it toMIGRATED_ROUTESso the dev proxy serves the Vite HTML. - Wire the Go controller to
serveDistPage(c, "<page>.html").