Skip to content

feat: 3X-UI(3.0.0) Multi-Node Architecture, Client Management, HWID Tracking, Host Management, Glass Morphism UI & Redis Cache#3635

Draft
konstpic wants to merge 25 commits intoMHSanaei:mainfrom
konstpic:node-mode
Draft

feat: 3X-UI(3.0.0) Multi-Node Architecture, Client Management, HWID Tracking, Host Management, Glass Morphism UI & Redis Cache#3635
konstpic wants to merge 25 commits intoMHSanaei:mainfrom
konstpic:node-mode

Conversation

@konstpic
Copy link
Collaborator

@konstpic konstpic commented Jan 6, 2026

Multi-Node Architecture, Client Management, HWID Tracking, Host Management, Glass Morphism UI & Redis Cache

Description

This pull request introduces a comprehensive architectural overhaul of the 3x-ui panel, adding support for distributed multi-node architecture, independent client management with many-to-many relationships, hardware ID tracking, host management for load balancing, a modern Glass Morphism UI theme, and Redis caching for improved performance.

What Changed?

1. Node Mechanism (Multi-Node Architecture)

Overview

The panel now supports distributed architecture with multiple worker nodes. Instead of running XRAY Core locally, the panel can manage multiple remote nodes running XRAY Core instances.

Node Registration and Interaction

Node Registration Process:

  1. Adding a Node: Users can add nodes through the UI by providing:

  2. Automatic API Key Validation: When adding or updating a node, the system:

    • Validates the API key by making a test request to the node
    • Checks node availability before saving
    • Verifies the node responds correctly to health checks
  3. Node Health Monitoring:

    • Automatic health checks every 5 minutes (CheckNodeHealthJob)
    • Manual health check via UI button
    • Status indicators: online (green), offline (orange), unknown (gray)
    • Response time measurement in milliseconds

Node Interaction

API Endpoints on Panel:

  • GET /panel/node/list - Get list of all nodes
  • GET /panel/node/get/:id - Get information about a specific node
  • POST /panel/node/add - Add a new node (with validation)
  • POST /panel/node/update/:id - Update a node (supports partial updates)
  • POST /panel/node/del/:id - Delete a node
  • POST /panel/node/check/:id - Check health of a specific node
  • POST /panel/node/checkAll - Check health of all nodes
  • POST /panel/node/reload/:id - Reload XRAY on a node
  • POST /panel/node/reloadAll - Reload XRAY on all nodes
  • GET /panel/node/status/:id - Get detailed status of a node

Node Service API (on Worker Nodes):

  • POST /api/v1/apply - Apply XRAY configuration
  • POST /api/v1/reload - Reload XRAY
  • POST /api/v1/force-reload - Force reload XRAY
  • GET /api/v1/status - Get XRAY status
  • GET /api/v1/stats - Get traffic statistics and online clients
  • GET /health - Health check endpoint (no authentication required)

Configuration Synchronization:

  • When an inbound is created/updated, configuration is sent to all assigned nodes
  • Configurations are sent in parallel using goroutines for performance
  • Each node receives only the inbounds assigned to it
  • Automatic retry logic for failed requests

Statistics Collection:

  • Automatic collection every 30 seconds (CollectNodeStatsJob)
  • Traffic statistics aggregated by client email across all nodes
  • Online client information collected from each node
  • Statistics stored directly in ClientEntity table

2. Client Entities (Many-to-Many with Inbounds)

Overview

Clients are now independent entities stored in a separate client_entities table. A single client can be assigned to multiple inbounds, enabling flexible configuration management.

Client Entity Structure

type ClientEntity struct {
    Id         int     // Unique identifier
    UserId     int     // Associated user ID
    Email      string  // Client email (unique per user)
    UUID       string  // UUID for VMESS/VLESS
    Password   string  // Password for Trojan/Shadowsocks
    Security   string  // Encryption method
    Flow       string  // Flow control (XTLS)
    LimitIP    int     // IP limit
    TotalGB    float64 // Traffic limit in GB (supports decimals like 0.01)
    ExpiryTime int64   // Expiration timestamp
    Enable     bool    // Whether client is enabled
    Status     string  // Status: active, expired_traffic, expired_time
    
    // Traffic statistics stored directly in ClientEntity
    Up         int64   // Upload traffic in bytes
    Down       int64   // Download traffic in bytes
    AllTime    int64   // All-time traffic usage
    LastOnline int64   // Last online timestamp
    
    // HWID restrictions
    HWIDEnabled bool   // Whether HWID tracking is enabled
    MaxHWID     int    // Maximum allowed devices (0 = unlimited)
    
    // Relations (loaded via JOIN, not stored in table)
    InboundIds []int   // Inbound IDs this client is assigned to
}

Many-to-Many Relationship

ClientInboundMapping Table:

type ClientInboundMapping struct {
    Id        int // Unique identifier
    ClientId  int // Client ID
    InboundId int // Inbound ID
}

How It Works:

  • One client can be assigned to multiple inbounds
  • One inbound can have multiple clients
  • When a client is created/updated, ClientInboundMapping records are created/updated
  • Inbound.Settings is automatically regenerated from all assigned ClientEntity records

Benefits:

  • Reuse clients across multiple inbounds
  • Centralized client management
  • Traffic statistics aggregated per client (not per inbound-client pair)
  • Easier client updates (change once, applies to all inbounds)

API Endpoints

  • GET /panel/client/list - Get all clients for user
  • GET /panel/client/get/:id - Get client by ID
  • POST /panel/client/add - Add new client (with inbound assignments)
  • POST /panel/client/update/:id - Update client (updates all related inbounds)
  • POST /panel/client/del/:id - Delete client (removes from all inbounds)

3. Inbound Entities (Many-to-Many with Nodes)

Overview

Inbounds can now be assigned to multiple nodes, enabling load distribution and redundancy.

Inbound Structure

type Inbound struct {
    Id       int
    UserId   int
    Port     int
    Protocol Protocol
    
    // Settings is automatically generated from ClientEntity
    Settings string // JSON with clients, generated from ClientEntity
    
    // Node assignments (loaded via JOIN)
    NodeIds  []int  // Node IDs where this inbound runs
    
    // Client statistics (from Xray API, not from DB)
    ClientStats []xray.ClientTraffic
}

Many-to-Many Relationship

InboundNodeMapping Table:

type InboundNodeMapping struct {
    Id        int // Unique identifier
    InboundId int // Inbound ID
    NodeId    int // Node ID
}

How It Works:

  • One inbound can run on multiple nodes simultaneously
  • One node can serve multiple inbounds
  • When creating/updating an inbound, specify NodeIds array
  • Configuration is sent to all assigned nodes in parallel
  • Subscription links are generated with node addresses (not panel address)

Example:

  • Inbound №1 (VMESS, port 443) → Node 1, Node 2, Node 3
  • Inbound 2 (VLESS, port 80) → Node 2
  • Result: Inbound 1 configuration sent to 3 nodes, Inbound 2 to 1 node

Work Modes

Single-Mode (Default):

  • XRAY Core runs locally on panel server
  • Inbounds without assigned nodes work locally
  • Subscriptions generated with panel address

Multi-Mode:

  • XRAY Core does not run locally
  • All inbounds must be assigned to nodes
  • Configurations sent to nodes via REST API
  • Subscriptions generated with node addresses
  • Statistics collected from nodes periodically

4. Host Management (Address Override for Load Balancing)

Overview

Hosts allow overriding the endpoint address in subscription links, useful for load balancing, CDN integration, or custom routing.

Host Structure

type Host struct {
    Id         int    // Unique identifier
    UserId     int    // Associated user ID
    Name       string // Host name/identifier
    Address    string // Host address (IP or domain)
    Port       int    // Host port (0 = use inbound port)
    Protocol   string // Protocol override (optional)
    Remark     string // Description
    Enable     bool   // Whether host is enabled
    InboundIds []int  // Inbound IDs this host applies to
}

Many-to-Many Relationship

HostInboundMapping Table:

type HostInboundMapping struct {
    Id        int // Unique identifier
    HostId    int // Host ID
    InboundId int // Inbound ID
}

How It Works:

  • One host can apply to multiple inbounds
  • One inbound can have multiple hosts
  • When generating subscription, host address is used instead of node/panel address
  • Useful for:
    • Load balancing across multiple nodes
    • CDN integration
    • Custom domain routing
    • Port forwarding scenarios

Example:

  • Node 1 has IP: 192.168.1.100
  • Host "cdn.example.com" applies to Inbound 1
  • Subscription for Inbound 1 contains cdn.example.com instead of 192.168.1.100

API Endpoints

  • GET /panel/host/list - Get all hosts for user
  • GET /panel/host/get/:id - Get host by ID
  • POST /panel/host/add - Add new host (with inbound assignments)
  • POST /panel/host/update/:id - Update host
  • POST /panel/host/del/:id - Delete host

5. HWID Tracking (Hardware ID Tracking)

Overview

HWID tracking allows limiting the number of devices that can simultaneously use a client account, preventing unauthorized credential sharing and controlling resource usage.

HWID Structure

type ClientHWID struct {
    Id          int    // Unique identifier
    ClientId    int    // Client ID
    HWID        string // Hardware ID (provided by client via x-hwid header)
    DeviceOS    string // Device OS (from x-device-os header)
    DeviceModel string // Device model (from x-device-model header)
    OSVersion   string // OS version (from x-ver-os header)
    IPAddress   string // Last known IP address
    FirstSeenIP string // IP address when first seen
    UserAgent   string // User-Agent string
    FirstSeenAt int64  // First seen timestamp
    LastSeenAt  int64  // Last seen timestamp
    IsActive    bool   // Whether HWID is active
    BlockedAt   *int64 // Block timestamp (if blocked)
    BlockReason string // Block reason
}

How It Works

Registration Process:

  1. Client application sends x-hwid header when requesting subscription
  2. Server registers HWID and links it to client
  3. If HWIDEnabled is true and MaxHWID is set, device limit is checked
  4. If limit exceeded, new device is blocked
  5. History of all devices stored in client_hw_ids table

Modes:

  • off - HWID tracking disabled
  • client_header - Explicit registration via header (recommended)
  • ip_based - Generate HWID from IP (deprecated)

Features:

  • Device limit enforcement per client
  • Device history tracking
  • Block/unblock devices
  • Device metadata (OS, model, version)
  • IP address tracking per device

API Endpoints

  • GET /panel/client/hwid/list/:clientId - Get all HWIDs for client
  • POST /panel/client/hwid/register - Register HWID (via subscription request)
  • POST /panel/client/hwid/del/:id - Delete HWID
  • POST /panel/client/hwid/block/:id - Block HWID
  • POST /panel/client/hwid/unblock/:id - Unblock HWID

Background Jobs

  • CheckClientHWIDJob - Periodic check of HWID limits and status updates

6. Glass Morphism UI Theme

Overview

A modern Glass Morphism design theme has been added to the panel, providing a sleek, translucent glass-like appearance with backdrop blur effects.

Features

Visual Design:

  • Translucent glass-like panels with backdrop blur
  • Smooth gradients and shadows
  • Modern card-based layout
  • Enhanced visual hierarchy
  • Improved readability with proper contrast

Theme Switching:

  • Glass Morphism can be enabled/disabled via theme switcher
  • Mutually exclusive with dark theme (when Glass Morphism is enabled, dark theme is disabled)
  • Default theme: Glass Morphism enabled
  • Settings persisted in localStorage

Implementation:

  • CSS variables for easy customization
  • Responsive design for all screen sizes
  • Smooth transitions and animations
  • Consistent styling across all pages

UI Components Updated:

  • Dashboard cards with glass effect
  • Navigation sidebar
  • Modal windows
  • Tables and forms
  • Buttons and inputs
  • Status indicators
  • Tooltips and popovers

Pages with Glass Morphism:

  • Main dashboard
  • Inbounds page
  • Clients page
  • Nodes page
  • Hosts page
  • Settings page
  • All modal windows

7. Redis Cache Integration

Overview

Redis caching has been integrated to significantly improve panel performance by caching frequently accessed data.

Cache Implementation

Cache Layer:

  • web/cache/cache.go - Cache interface
  • web/cache/redis.go - Redis implementation
  • web/cache/redisstore.go - Redis store for sessions

Cached Data:

  • Client lists (30 seconds TTL)
  • Inbound lists (30 seconds TTL)
  • Node lists (30 seconds TTL)
  • Host lists (30 seconds TTL)
  • System settings

Cache Invalidation:

  • Automatic invalidation on data changes
  • Manual invalidation via API
  • Cache keys prefixed by entity type

Middleware:

  • web/middleware/cache.go - Cache middleware for HTTP requests
  • Automatic cache hit/miss handling
  • Cache warming on startup

Performance Benefits

  • Reduced Database Load: Frequently accessed data served from cache
  • Faster Response Times: Cache hits return data in milliseconds
  • Scalability: Redis can be shared across multiple panel instances
  • Session Storage: Redis used for session management

Configuration

Redis connection configured via environment variables or settings:

  • Redis address
  • Redis password (optional)
  • Redis database number
  • Connection pool settings

Database Changes

New Tables

  1. client_entities - Client table

    • All client data and traffic statistics
    • Indexes: user_id, email (unique per user), sub_id
  2. client_inbound_mappings - Client-Inbound mapping

    • Unique index: (client_id, inbound_id)
  3. nodes - Node table

    • Node information and status
  4. inbound_node_mappings - Inbound-Node mapping

    • Unique index: (inbound_id, node_id)
  5. client_hw_ids - HWID table

    • Index: (client_id, hwid)
  6. hosts - Host table

    • Host configurations
  7. host_inbound_mappings - Host-Inbound mapping

    • Unique index: (host_id, inbound_id)

Updated Tables

  • inbounds - Settings now auto-generated from ClientEntity

Backend (Go)

New Services

  • NodeService: Node management, health checks, API validation
  • ClientService: Client CRUD operations, inbound assignments
  • ClientHWIDService: HWID tracking and management
  • ClientTrafficService: Client traffic statistics
  • HostService: Host management and subscription address override

New Controllers

  • NodeController: Node API endpoints
  • ClientController: Client API endpoints
  • ClientHWIDController: HWID API endpoints
  • HostController: Host API endpoints

New Background Jobs

  • CheckNodeHealthJob: Health checks every 5 minutes
  • CollectNodeStatsJob: Statistics collection every 30 seconds
  • CheckClientHWIDJob: HWID limit checks

Updated Services

  • InboundService: Updated for multi-node and client entity support
  • XrayService: Multi-node configuration distribution
  • SubService: Node address and host override support
  • ServerService: Node availability in system status

Frontend (Vue.js/HTML)

New Pages

  • nodes.html: Node management interface
  • clients.html: Client management interface
  • hosts.html: Host management interface

New Modals

  • node_modal.html: Node add/edit modal
  • client_entity_modal.html: Client add/edit modal
  • host_modal.html: Host add/edit modal

Updated Pages

  • inbounds.html: Multi-node selection, client entity integration
  • index.html: Nodes availability speedometer, Glass Morphism
  • settings.html: Multi-Node mode toggle, Glass Morphism settings

Updated Components

  • aThemeSwitch.html: Glass Morphism toggle
  • aSidebar.html: Glass Morphism styling
  • aClientTable.html: Client entity display

Node Service (New Component)

Structure

node/
├── main.go              # Entry point
├── api/
│   └── server.go        # REST API server
├── xray/
│   └── manager.go       # Xray process management
├── logs/
│   └── pusher.go        # Log forwarding
├── config/
│   └── config.go        # Configuration
├── Dockerfile           # Docker image
└── docker-compose.yml   # Docker Compose config

Features

  • Automatic config.json loading on startup
  • API inbound auto-creation if missing
  • Health check endpoint
  • Statistics collection endpoint
  • Configuration application endpoint
  • Xray reload without container restart

Localization

  • Added translations for all new UI elements
  • Russian and English translations
  • Translation keys for:
    • Nodes management
    • Client management
    • Host management
    • HWID tracking
    • Glass Morphism theme
    • Multi-Node mode

Technical Details

Architecture

  • Many-to-Many Relationships: Clients↔Inbounds, Inbounds↔Nodes, Hosts↔Inbounds
  • Pull-based Statistics: Panel polls nodes for statistics
  • Health Checks: Automatic node availability monitoring
  • Backward Compatibility: Support for old nodeId field

Security

  • API key validation for nodes
  • Node availability checks
  • Authentication via API keys for all node requests
  • HWID limit enforcement
  • Input validation and sanitization

Performance

  • Redis caching for frequently accessed data
  • Parallel node request processing (goroutines)
  • Optimized database queries with indexes
  • Cache invalidation on data changes
  • Statistics aggregation optimization

Type of Changes

  • New Feature
  • Database Changes
  • API Changes
  • UI Changes
  • Performance Improvements
  • Localization

Affected Parts of Application

  • Frontend
  • Backend
  • Database
  • Node Service (new component)
  • Caching Layer

Testing

  • Node registration and management
  • Client creation and assignment to multiple inbounds
  • Inbound assignment to multiple nodes
  • Host configuration and address override
  • HWID registration and limit enforcement
  • Glass Morphism theme switching
  • Redis cache functionality
  • Statistics collection from nodes
  • Health checks
  • Configuration synchronization

Migration

When updating an existing installation:

  1. Database automatically creates new tables
  2. Old inbounds without assigned nodes continue working in local mode
  3. Old clients in Settings are automatically converted to ClientEntity
  4. To migrate to Multi-Node mode:
    • Add nodes through the interface
    • Enable Multi-Node Mode in settings
    • Assign inbounds to nodes
  5. Redis cache is optional but recommended for performance

Notes

  • Multi-Node mode is completely optional - panel works in local mode by default
  • When Multi-Node is enabled, local XRAY Core stops
  • All configurations are automatically synchronized with assigned nodes
  • Glass Morphism is enabled by default but can be disabled
  • Redis cache significantly improves performance, especially with many clients/inbounds
  • HWID tracking helps prevent credential sharing
  • Host management enables advanced load balancing scenarios

@konstpic
Copy link
Collaborator Author

konstpic commented Jan 6, 2026

@MHSanaei
Hi! 👋
This is a large feature PR introducing Multi-Node architecture.
Could you please mark it as beta so we can start community testing?

I’d really appreciate help from the community to test different setups, edge cases, and give feedback before moving toward stable.
Thanks a lot for reviewing this 🙌

@konstpic konstpic changed the title Add Multi-Node Architecture Support (Beta) feat: Add Multi-Node Architecture Support (Beta) Jan 6, 2026
@allkeltysss
Copy link

wow

@MHSanaei MHSanaei requested a review from alireza0 January 9, 2026 23:49
@konstpic
Copy link
Collaborator Author

konstpic commented Jan 9, 2026

@alireza0 please see)

I need approval to remove local package sub-substitions

Copy link
Collaborator

@alireza0 alireza0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are mandatory primary needs for this change which requested to have a solution for.

Some other optional points which could be done after this MR as well:

  • Define outbound specific for each node (optional-good to have)
  • Define separate DNS+rules for each node
  • Stop working node when Manager is not available.
  • Auto build pipeline for node and use script/docker for installation
  • Node script to control and check the status as asme as x-ui.sh
  • Change port possibility

Comment on lines +95 to +110
RUN echo "Contents of /app/bin after COPY:" && \
ls -la ./bin/ && \
echo "Looking for xray binary..." && \
if [ -f ./bin/xray-linux-amd64 ]; then \
chmod +x ./bin/xray-linux-amd64 && \
echo "✓ Found and made executable: xray-linux-amd64"; \
elif [ -f ./bin/xray ]; then \
chmod +x ./bin/xray && \
mv ./bin/xray ./bin/xray-linux-amd64 && \
echo "✓ Found xray, renamed to xray-linux-amd64"; \
else \
echo "✗ ERROR: No xray binary found!" && \
echo "All files in bin directory:" && \
find ./bin -type f -o -type l && \
exit 1; \
fi
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes docekr file too big but not needed to be

# Copy XRAY binary and data files
# Use wildcard to copy all files from bin directory
COPY --from=builder /build/bin/ ./bin/

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to download xray-core in build time.
Move it here

Comment on lines +23 to +78
RUN mkdir -p bin && \
cd bin && \
case ${TARGETARCH} in \
amd64) \
ARCH="64" \
FNAME="amd64" \
;; \
arm64) \
ARCH="arm64-v8a" \
FNAME="arm64" \
;; \
arm) \
ARCH="arm32-v7a" \
FNAME="arm32" \
;; \
armv6) \
ARCH="arm32-v6" \
FNAME="armv6" \
;; \
386) \
ARCH="32" \
FNAME="i386" \
;; \
*) \
ARCH="64" \
FNAME="amd64" \
;; \
esac && \
echo "Downloading Xray for ${TARGETARCH} (ARCH=${ARCH}, FNAME=${FNAME})" && \
curl -sfLRO "https://github.com/XTLS/Xray-core/releases/download/v25.12.8/Xray-linux-${ARCH}.zip" && \
echo "Unzipping..." && \
unzip -q "Xray-linux-${ARCH}.zip" && \
echo "Files after unzip:" && \
ls -la && \
echo "Removing zip and old data files..." && \
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat && \
echo "Renaming xray to xray-linux-${FNAME}..." && \
mv xray "xray-linux-${FNAME}" && \
chmod +x "xray-linux-${FNAME}" && \
echo "Verifying xray binary:" && \
ls -lh "xray-linux-${FNAME}" && \
test -f "xray-linux-${FNAME}" && echo "✓ xray-linux-${FNAME} exists" && \
echo "Downloading geo files..." && \
curl -sfLRO https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat && \
curl -sfLRO https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat && \
curl -sfLRo geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat && \
curl -sfLRo geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat && \
curl -sfLRo geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat && \
curl -sfLRo geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat && \
echo "Final files in bin:" && \
ls -lah && \
echo "File sizes:" && \
du -h * && \
cd .. && \
echo "Verifying files in /build/bin:" && \
ls -lah /build/bin/
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Big line make no sense!
Please convert it to a script and use it. in runtime stage instead of build stage

Comment on lines +53 to +58
s.httpServer = &http.Server{
Addr: fmt.Sprintf(":%d", s.port),
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not enough!
Security for this kind of usage is mandatory.
Plain HTTP test is dangerous

api.POST("/force-reload", s.forceReload)
api.GET("/status", s.status)
api.GET("/stats", s.stats)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is better to have /logs endpoint to get core's log available in manager

This comment was marked as outdated.

@konstpic konstpic changed the title feat: Add Multi-Node Architecture Support (Beta) feat: 3X-UI(3.0.0) Multi-Node Architecture, Client Management, HWID Tracking, Host Management, Glass Morphism UI & Redis Cache Jan 12, 2026
@konstpic
Copy link
Collaborator Author

Hi @MHSanaei @alireza0 👋

This is a very large update with a major panel refactor.
I’ve just finished it and I’d really appreciate help with testing and catching potential bugs.

I think involving the dev community would be the best way to validate this change before moving forward.

Here is the demo version of the panel:
http://3xnew.usa.konstpic.ru:2053/

Credentials: admin | admin

Thanks a lot for your time and support 🙌

@konstpic
Copy link
Collaborator Author

I understand that this is a very large update, and that’s exactly why I’m asking for your help.
I truly hope that together we can make this important change stable and solid for everyone.

@konstpic konstpic mentioned this pull request Jan 12, 2026
6 tasks
@somebodywashere somebodywashere self-requested a review January 12, 2026 22:26
@somebodywashere
Copy link
Collaborator

Does this architecture really fits 3x-ui? It's great to have multi node capability, but seems it's too much of a refactor. Why does it impossible to use current subID as a somewhat pseudo-unique ID (no duplicates on generation).

@MHSanaei MHSanaei marked this pull request as draft January 18, 2026 17:22
@konstpic
Copy link
Collaborator Author

@somebodywashere

Does this architecture really fits 3x-ui? It's great to have multi node capability, but seems it's too much of a refactor. Why does it impossible to use current subID as a somewhat pseudo-unique ID (no duplicates on generation).

We discussed this architecture in detail together with the original author and came to the conclusion that yes — these changes are indeed critical and go far beyond a small refactor of the current 3x-ui design.
That’s exactly why I decided to move this work into a separate fork instead of forcing it into the main project.

At the same time, I’m not abandoning the original panel — I’ll continue supporting it with bug fixes and small improvements that fit its existing architecture.

Regarding using the current subID as a pseudo-unique identifier: this approach works fine in a single-core / single-node setup, but it doesn’t scale to the scenario we’re targeting.
Once we want to manage multiple remote Xray cores from a single panel, subID alone is no longer sufficient — we need explicit, first-class entities for nodes and their relationships. Otherwise we end up with implicit coupling, collisions, and edge cases that are very hard to maintain long-term.

So the fork is not about “making things more complex for no reason”, but about enabling a clean and predictable multi-node model that the current design was not built for.

@e-n-pugachev
Copy link

e-n-pugachev commented Jan 24, 2026

@konstpic do you know when the code will be opened for beta testing? Is there a build guide for the project? I could post about it on my end.

http://3xnew.usa.konstpic.ru:2053
Credentials: admin | admin

unavailable

@konstpic
Copy link
Collaborator Author

@e-n-pugachev

Hello!
Open beta testing started ago 2 weeks

Please see my repo https://github.com/konstpic/3x-ui-new

I periodic update images

Now final stage beta testing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants