diff --git a/README.md b/README.md index 9a85c3e1..92b47b37 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# 3x-ui +# 3x-ui + > **Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment** [![](https://img.shields.io/github/v/release/mhsanaei/3x-ui.svg)](https://github.com/MHSanaei/3x-ui/releases) @@ -12,7 +13,8 @@ **If you think this project is helpful to you, you may wish to give a** :star2: **Buy Me a Coffee :** - - Tron USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC` + +- Tron USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC` # Install & Upgrade @@ -47,12 +49,12 @@ or you can use x-ui menu then number '16' (Apply for an SSL Certificate) Before you set ssl on settings -- http://ip:2053/xui -- http://domain:2053/xui +- http://ip:2053/panel +- http://domain:2053/panel After you set ssl on settings -- https://yourdomain:2053/xui +- https://yourdomain:2053/panel # Environment Variables @@ -69,6 +71,31 @@ Example: XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go ``` +# Install with Docker + +1. Install Docker: + ```sh + bash <(curl -sSL https://get.docker.com) + ``` +2. Run 3x-ui: + + ```sh + docker compose up -d + ``` + + OR + + ```sh + docker run -itd \ + -e XRAY_VMESS_AEAD_FORCED=false \ + -v $PWD/db/:/etc/x-ui/ \ + -v $PWD/cert/:/root/cert/ \ + --network=host \ + --restart=unless-stopped \ + --name 3x-ui \ + ghcr.io/mhsanaei/3x-ui:latest + ``` + # Xray Configurations: **copy and paste to xray Configuration :** (you don't need to do this if you have a fresh install) @@ -173,19 +200,19 @@ Reference syntax: | `POST` | `"/clientIps/:email"` | Client Ip address | | `POST` | `"/clearClientIps/:email"` | Clear Client Ip address | | `POST` | `"/addClient"` | Add Client to inbound | -| `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId* | -| `POST` | `"/updateClient/:clientId"` | Update Client by clientId* | +| `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId\* | +| `POST` | `"/updateClient/:clientId"` | Update Client by clientId\* | | `POST` | `"/:id/resetClientTraffic/:email"` | Reset Client's Traffic | | `POST` | `"/resetAllTraffics"` | Reset traffics of all inbounds | | `POST` | `"/resetAllClientTraffics/:id"` | Reset traffics of all clients in an inbound | | `POST` | `"/delDepletedClients/:id"` | Delete inbound depleted clients (-1: all) | -*- The field `clientId` should be filled by: +\*- The field `clientId` should be filled by: + - `client.id` for VMESS and VLESS - `client.password` for TROJAN - `client.email` for Shadowsocks - - [Postman Collection](https://gist.github.com/mehdikhody/9a862801a2e41f6b5fb6bbc7e1326044) # A Special Thanks To diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..f0231309 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,15 @@ +--- +version: "3.9" + +services: + 3x-ui: + image: ghcr.io/mhsanaei/3x-ui:latest + container_name: 3x-ui + volumes: + - $PWD/db/:/etc/x-ui/ + - $PWD/cert/:/root/cert/ + environment: + XRAY_VMESS_AEAD_FORCED: "false" + tty: true + network_mode: host + restart: unless-stopped diff --git a/web/controller/index.go b/web/controller/index.go index 802f3f7d..b0ee83f8 100644 --- a/web/controller/index.go +++ b/web/controller/index.go @@ -39,7 +39,7 @@ func (a *IndexController) initRouter(g *gin.RouterGroup) { func (a *IndexController) index(c *gin.Context) { if session.IsLogin(c) { - c.Redirect(http.StatusTemporaryRedirect, "xui/") + c.Redirect(http.StatusTemporaryRedirect, "panel/") return } html(c, "login.html", "pages.login.title", nil) @@ -101,5 +101,4 @@ func (a *IndexController) getSecretStatus(c *gin.Context) { if err == nil { jsonObj(c, status, nil) } - } diff --git a/web/controller/setting.go b/web/controller/setting.go index bd9c2a5f..248f3ee5 100644 --- a/web/controller/setting.go +++ b/web/controller/setting.go @@ -3,6 +3,7 @@ package controller import ( "errors" "time" + "x-ui/util/common" "x-ui/web/entity" "x-ui/web/service" "x-ui/web/session" @@ -44,6 +45,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) { g.GET("/getDefaultJsonConfig", a.getDefaultJsonConfig) g.POST("/updateUserSecret", a.updateSecret) g.POST("/getUserSecret", a.getUserSecret) + g.GET("/searchDatafiles", a.searchDatafiles) } func (a *SettingController) getAllSetting(c *gin.Context) { @@ -149,6 +151,7 @@ func (a *SettingController) updateSecret(c *gin.Context) { } jsonMsg(c, I18n(c, "pages.settings.toasts.modifyUser"), err) } + func (a *SettingController) getUserSecret(c *gin.Context) { loginUser := session.GetLoginUser(c) user := a.userService.GetUserSecret(loginUser.Id) @@ -156,3 +159,18 @@ func (a *SettingController) getUserSecret(c *gin.Context) { jsonObj(c, user, nil) } } + +func (a *SettingController) searchDatafiles(c *gin.Context) { + searchString := c.Query("query") + if searchString == "" { + err := common.NewError("data query parameter is empty") + jsonMsg(c, "Invalid query:", err) + return + } + found, err := a.settingService.SearchDatafiles(searchString) + if err != nil { + jsonMsg(c, "Something went wrong!", err) + return + } + jsonObj(c, found, nil) +} diff --git a/web/controller/xui.go b/web/controller/xui.go index 1844181d..700bd52c 100644 --- a/web/controller/xui.go +++ b/web/controller/xui.go @@ -18,7 +18,7 @@ func NewXUIController(g *gin.RouterGroup) *XUIController { } func (a *XUIController) initRouter(g *gin.RouterGroup) { - g = g.Group("/xui") + g = g.Group("/panel") g.Use(a.checkLogin) g.GET("/", a.index) diff --git a/web/html/common/qrcode_modal.html b/web/html/common/qrcode_modal.html index 2bd2f00f..855c349a 100644 --- a/web/html/common/qrcode_modal.html +++ b/web/html/common/qrcode_modal.html @@ -7,7 +7,10 @@ {{ i18n "pages.inbounds.clickOnQRcode" }} - + + {{ i18n "pages.inbounds.email" }}: "[[ qrModal.clientName ]]" + +