-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat: Add multi-server support #3269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Thank you for contributing. For this important problem we should use "sync-sofar" solution to make sure that every usages in all slave servers will count. Other concerns:
|
|
3X-UI is growing faster than all other panels! |
|
Currently it doesn't support already created inbounds/clients. When user adds a slave, I think there should be an option to select which inbounds (along with all their clients) the user wants to duplicate on the slave server (with 0 up and down usage stats). |
This commit introduces a multi-server architecture to the Sanai panel, allowing you to manage clients across multiple servers from a central panel. Key changes include: - **Database Schema:** Added a `servers` table to store information about slave servers. - **Server Management:** Implemented a new service and controller (`MultiServerService` and `MultiServerController`) for CRUD operations on servers. - **Web UI:** Created a new web page for managing servers, accessible from the sidebar. - **Client Synchronization:** Modified the `InboundService` to synchronize client additions, updates, and deletions across all active slave servers via a REST API. - **API Security:** Added an API key authentication middleware to secure the communication between the master and slave panels. - **Multi-Server Subscriptions:** Updated the subscription service to generate links that include configurations for all active servers. - **Installation Script:** Modified the `install.sh` script to generate a random API key during installation. **Known Issues:** - The integration test for client synchronization (`TestInboundServiceSync`) is currently failing. It seems that the API request to the mock slave server is not being sent correctly or the API key is not being included in the request header. Further investigation is needed to resolve this issue.
2a6b2ca to
11dc068
Compare
|
such a nice feature, would love to contrib on it! |
|
To make it multi-server, just add traffic equalization and that's it. The problem with the previous scripts was that in addition to equalizing traffic, they also managed time and clients. Please add a script that has no capabilities other than equalizing traffic and that also does this equalization every 2 minutes. I don't think there will be any problems this way. |
|
1208faf to
5420e64
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request adds multi-server support to the Sanai panel, enabling centralized management of clients across multiple slave servers from a master panel.
- Implements complete multi-server architecture with database schema, service layer, and web UI
- Adds automatic client synchronization between master and slave servers via REST API
- Introduces API key-based authentication for secure inter-panel communication
Reviewed Changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
database/model/model.go |
Adds Server model for storing slave server information |
database/db.go |
Registers Server model for auto-migration |
web/service/multi_server_service.go |
Implements CRUD operations for server management |
web/service/setting.go |
Adds API key management functionality |
web/service/inbound.go |
Adds client synchronization to slave servers |
web/controller/multi_server_controller.go |
HTTP endpoints for server management |
web/middleware/auth.go |
API key authentication middleware |
web/controller/xui.go |
Adds servers page route |
web/html/servers.html |
Web interface for managing slave servers |
web/html/component/aSidebar.html |
Adds servers menu item |
sub/subService.go |
Modifies subscription links to include all active servers |
main.go |
Adds API key command-line parameter |
install.sh |
Generates random API key during installation |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| body, _ := json.Marshal(data) | ||
| s.syncWithSlaves("POST", "/panel/inbound/api/addClient", bytes.NewReader(body)) |
Copilot
AI
Sep 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JSON marshaling error is being silently ignored with _. This could lead to silent failures when syncing with slave servers. The error should be handled properly, and if marshaling fails, the sync operation should be skipped or logged.
| body, _ := json.Marshal(data) | |
| s.syncWithSlaves("POST", "/panel/inbound/api/addClient", bytes.NewReader(body)) | |
| body, marshalErr := json.Marshal(data) | |
| if marshalErr != nil { | |
| logger.Error("Failed to marshal data for syncWithSlaves:", marshalErr) | |
| } else { | |
| s.syncWithSlaves("POST", "/panel/inbound/api/addClient", bytes.NewReader(body)) | |
| } |
| body, _ := json.Marshal(data) | ||
| s.syncWithSlaves("POST", fmt.Sprintf("/panel/inbound/api/updateClient/%s", clientId), bytes.NewReader(body)) |
Copilot
AI
Sep 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JSON marshaling error is being silently ignored with _. This could lead to silent failures when syncing with slave servers. The error should be handled properly, and if marshaling fails, the sync operation should be skipped or logged.
| body, _ := json.Marshal(data) | |
| s.syncWithSlaves("POST", fmt.Sprintf("/panel/inbound/api/updateClient/%s", clientId), bytes.NewReader(body)) | |
| body, marshalErr := json.Marshal(data) | |
| if marshalErr != nil { | |
| logger.Warning("Failed to marshal data for syncWithSlaves:", marshalErr) | |
| } else { | |
| s.syncWithSlaves("POST", fmt.Sprintf("/panel/inbound/api/updateClient/%s", clientId), bytes.NewReader(body)) | |
| } |
| req, err := http.NewRequest(method, url, body) | ||
| if err != nil { | ||
| logger.Warningf("Failed to create request for server %s: %v", server.Name, err) | ||
| continue | ||
| } |
Copilot
AI
Sep 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The body parameter is being reused for multiple requests when syncing with multiple servers. After the first request reads from the io.Reader, subsequent requests will receive an empty body. Each server sync should use a fresh copy of the request body.
212238b to
5408a2f
Compare
|
как продвигается создание управления несколькими серверами? а то я щас собираюсь свой простой api backend делать для управления несколькими серверами. Может лучше присоединиться к вам и доделать эту классную важную фичу? how is the creation of multi-server management progressing? otherwise, I'm going to make my simple backend api for managing multiple servers right now. Maybe it's better to join you and finish this cool important feature? |
|
Is it possible for other servers to be managed by low-overhead subprograms and controlled via APIs? |
1a6958c to
3757ae0
Compare
2c2a8c3 to
49430b3
Compare
ffd4c06 to
ee0e309
Compare
|
@javadtgh @alireza0 @dimasmir03 @MHSanaei Hi everyone, I wanted to share my thoughts on the multi-server approach. From my experience, full server management or separate slave panels aren’t strictly necessary for scaling. In my setup, I have two panels running on different servers but using a centralized MySQL database. A simple TCP proxy handles requests in a round-robin manner, and it works reliably while keeping the setup simple. I would suggest migrating the panel to PostgreSQL first. If your servers are configured identically, there’s no need for an extra “server management” layer. A centralized database plus a proxy load balancer is sufficient. This approach is simpler and already resembles a node-based architecture like n8n. Thanks for your work! 😊
|
|
Can you tell me where I can write about the API bug? |
|
@Wasdalt direct telegram channel |
|
@MHSanaei and where did the issue go, you could write about bugs and features there |
|
@javadtgh I ask you to consider the scenario where the multi -server panel will be able to work with Proxy Chain settings, where the inbound of one server serves the outbound another. I use such settings in my installations, but now everything has to be steamed by a separate panels. |
1 panel -> 2 panel -> 3 panel chain? |
Yes, but i use 2 step chains. 1 panel -> 2 panel I need to use inbounds via Wireguard in some infrastructures, but it does not go across the country border. It is also convenient for me to have entry points inside the country and the out nodes are changed as it is conveniently depending on the changing situation. |
|
Have you seen Nodex Script? |
|
Why is sock5 creation not supported? |
In this feature? |
I agree with your idea and fully support you. |


This commit introduces a multi-server architecture to the Sanai panel, allowing you to manage clients across multiple servers from a central panel.
Key changes include:
serverstable to store information about slave servers.MultiServerServiceandMultiServerController) for CRUD operations on servers.InboundServiceto synchronize client additions, updates, and deletions across all active slave servers via a REST API.install.shscript to generate a random API key during installation.Known Issues:
TestInboundServiceSync) is currently failing. It seems that the API request to the mock slave server is not being sent correctly or the API key is not being included in the request header. Further investigation is needed to resolve this issue.What is the pull request?
Which part of the application is affected by the change?
Type of Changes
Screenshots