Compare commits

..

10 Commits

Author SHA1 Message Date
hesoyam c3a1a5ac6b rewrite github links to mirror
CI / go-test (push) Waiting to run
CI / govulncheck (push) Waiting to run
CI / frontend (push) Waiting to run
CodeQL Advanced / Analyze (go) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Release 3X-UI / build (386) (push) Waiting to run
Release 3X-UI / build (amd64) (push) Waiting to run
Release 3X-UI / build (arm64) (push) Waiting to run
Release 3X-UI / build (armv5) (push) Waiting to run
Release 3X-UI / build (armv6) (push) Waiting to run
Release 3X-UI / build (armv7) (push) Waiting to run
Release 3X-UI / build (s390x) (push) Waiting to run
Release 3X-UI / Build for Windows (amd64) (push) Waiting to run
2026-05-14 10:13:41 +00:00
Abdalrahman eacb9f63b0 fix: protocol filter placeholder not showing on initial load (#4372) 2026-05-14 12:12:44 +02:00
MHSanaei e7035b56fe fix: sync advancedJson before tab switch in convertLink 2026-05-14 11:46:07 +02:00
dependabot[bot] 5f526e5201 build(deps): bump actions/setup-node from 5 to 6 (#4368)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 5 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-14 11:11:12 +02:00
MHSanaei bd8d33980f fix: ignore duplicate column errors during AutoMigrate on upgraded DBs
SQLite raises 'duplicate column name: <col>' when GORM tries to ADD a
column that already exists in an older schema (seen: allow_private_address,
node_id on the nodes table). This caused database initialisation to fail on
every restart after an upgrade.

The new isIgnorableDuplicateColumnErr helper skips the error only when:
  1. The error message matches 'duplicate column name: <col>'
  2. Migrator().HasColumn confirms the column is already present in the DB

Fresh databases and all other error types are unaffected.
2026-05-14 11:10:38 +02:00
MHSanaei 5dc02a9af3 v3.0.2 2026-05-14 10:27:33 +02:00
Abdalrahman 033c5993e0 feat: add API token to install output (#4322)
* feat: add API token to install output

Add -getApiToken flag to the setting subcommand so shell scripts
can retrieve the panel API token. Include the token in the
install.sh completion banner for automation/deployment use.

* fix(install): adapt -getApiToken CLI to multi-token service

settingService.GetApiToken was removed when API tokens moved to a
multi-row ApiTokenService. Switch the install-time CLI to list tokens
and create one named "install" if none exist, preserving the
`apiToken: <value>` output the install.sh grep depends on.

---------

Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
2026-05-14 10:24:23 +02:00
MHSanaei 2204c8231d Adjust QR panel sizing and collapse JSON subscription by default 2026-05-14 10:23:27 +02:00
Abdalrahman 01a7dc807b fix(sub): include xhttp mode in extra JSON for karing compatibility (#4365)
- Add mode to buildXhttpExtra() so clients reading xtra param
  (karing, etc.) receive the xhttp mode alongside other bidirectional
  SplitHTTP fields. Previously mode was only a flat URL param and was
  silently dropped when xtra was present.
- Add xhttp case to streamData() to strip acceptProxyProtocol and
  server-only fields (noSSEHeader, scMaxBufferedPosts,
  scStreamUpServerSecs, serverMaxHeaderBytes) from JSON sub configs.
- Sync frontend buildXhttpExtra() with the same mode addition.

Closes #4364
2026-05-14 10:02:45 +02:00
Farhad H. P. Shirvan 6bf4a2c4f0 fix(docker): update port mapping for 3xui service in docker-compose (#4362) 2026-05-14 10:00:09 +02:00
18 changed files with 119 additions and 38 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
with:
node-version-file: .nvmrc
cache: npm
+1 -1
View File
@@ -1 +1 @@
3.0.1
3.0.2
+28 -2
View File
@@ -10,6 +10,7 @@ import (
"os"
"path"
"slices"
"strings"
"time"
"github.com/mhsanaei/3x-ui/v3/config"
@@ -42,8 +43,12 @@ func initModels() error {
&model.Node{},
&model.ApiToken{},
}
for _, model := range models {
if err := db.AutoMigrate(model); err != nil {
for _, mdl := range models {
if err := db.AutoMigrate(mdl); err != nil {
if isIgnorableDuplicateColumnErr(err, mdl) {
log.Printf("Ignoring duplicate column during auto migration for %T: %v", mdl, err)
continue
}
log.Printf("Error auto migrating model: %v", err)
return err
}
@@ -51,6 +56,27 @@ func initModels() error {
return nil
}
func isIgnorableDuplicateColumnErr(err error, mdl any) bool {
if err == nil {
return false
}
errMsg := strings.ToLower(err.Error())
const dupPrefix = "duplicate column name:"
if !strings.Contains(errMsg, dupPrefix) {
return false
}
idx := strings.Index(errMsg, dupPrefix)
if idx < 0 {
return false
}
col := strings.TrimSpace(errMsg[idx+len(dupPrefix):])
col = strings.Trim(col, "`\"[]")
if col == "" {
return false
}
return db != nil && db.Migrator().HasColumn(mdl, col)
}
// initUser creates a default admin user if the users table is empty.
func initUser() error {
empty, err := isTableEmpty("users")
+2 -1
View File
@@ -12,5 +12,6 @@ services:
XRAY_VMESS_AEAD_FORCED: "false"
XUI_ENABLE_FAIL2BAN: "true"
tty: true
network_mode: host
ports:
- "2053:2053"
restart: unless-stopped
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "3x-ui-frontend",
"version": "0.0.2",
"version": "0.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "3x-ui-frontend",
"version": "0.0.2",
"version": "0.0.3",
"dependencies": {
"@ant-design/icons-vue": "^7.0.1",
"@codemirror/lang-json": "^6.0.2",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "3x-ui-frontend",
"private": true,
"version": "0.0.2",
"version": "0.0.3",
"type": "module",
"description": "3x-ui panel frontend (Vue 3 + Ant Design Vue 4 + Vite 8).",
"engines": {
+4
View File
@@ -1595,6 +1595,10 @@ export class Inbound extends XrayCommonClass {
});
}
if (typeof xhttp.mode === 'string' && xhttp.mode.length > 0) {
extra.mode = xhttp.mode;
}
const stringFields = [
"sessionPlacement", "sessionKey",
"seqPlacement", "seqKey",
+1 -1
View File
@@ -80,7 +80,7 @@ const savedFilterState = (() => {
const enableFilter = ref(!!savedFilterState.enableFilter);
const searchKey = ref(savedFilterState.searchKey || '');
const filterBy = ref(savedFilterState.filterBy || '');
const protocolFilter = ref(savedFilterState.protocolFilter || '');
const protocolFilter = ref(savedFilterState.protocolFilter || undefined);
const nodeFilter = ref(savedFilterState.nodeFilter || '');
watch([enableFilter, searchKey, filterBy, protocolFilter, nodeFilter], () => {
@@ -98,7 +98,6 @@ watch(() => props.open, (next) => {
}
const open = [];
if (subLink.value) open.push('sub');
if (subJsonLink.value) open.push('sub-json');
activeKeys.value = open;
});
+9 -2
View File
@@ -11,7 +11,7 @@ const props = defineProps({
value: { type: String, required: true },
remark: { type: String, default: '' },
downloadName: { type: String, default: '' },
size: { type: Number, default: 240 },
size: { type: Number, default: 360 },
showQr: { type: Boolean, default: true },
});
@@ -82,8 +82,15 @@ function download() {
.qr-panel-canvas .qr-code {
cursor: pointer;
padding: 0 !important;
background: #fff;
border-radius: 4px;
line-height: 0;
}
.qr-panel-canvas .qr-code :deep(svg) {
display: block;
width: 100%;
height: auto;
max-width: 360px;
}
</style>
@@ -195,6 +195,7 @@ function convertLink() {
return;
}
outbound.value = next;
primeAdvancedJson();
linkInput.value = '';
message.success('Link imported successfully...');
activeKey.value = '1';
+13 -9
View File
@@ -763,6 +763,9 @@ config_after_install() {
prompt_and_setup_ssl "${config_port}" "${config_webBasePath}" "${server_ip}"
# Retrieve the API token for display
local config_apiToken=$(${xui_folder}/x-ui setting -getApiToken true | grep -Eo 'apiToken: .+' | awk '{print $2}')
# Display final credentials and access information
echo ""
echo -e "${green}═══════════════════════════════════════════${plain}"
@@ -773,6 +776,7 @@ config_after_install() {
echo -e "${green}Port: ${config_port}${plain}"
echo -e "${green}WebBasePath: ${config_webBasePath}${plain}"
echo -e "${green}Access URL: ${SSL_SCHEME}://${SSL_HOST}:${config_port}/${config_webBasePath}${plain}"
echo -e "${green}API Token: ${config_apiToken}${plain}"
echo -e "${green}═══════════════════════════════════════════${plain}"
echo -e "${yellow}⚠ IMPORTANT: Save these credentials securely!${plain}"
if [[ "$SSL_SCHEME" == "https" ]]; then
@@ -842,17 +846,17 @@ install_x-ui() {
# Download resources
if [ $# == 0 ]; then
tag_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
tag_version=$(curl -Ls "https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ ! -n "$tag_version" ]]; then
echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
tag_version=$(curl -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
tag_version=$(curl -4 -Ls "https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ ! -n "$tag_version" ]]; then
echo -e "${red}Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later${plain}"
exit 1
fi
fi
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz
if [[ $? -ne 0 ]]; then
echo -e "${red}Downloading x-ui failed, please be sure that your server can access GitHub ${plain}"
exit 1
@@ -867,7 +871,7 @@ install_x-ui() {
exit 1
fi
url="https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
url="https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz"
echo -e "Beginning to install x-ui $1"
curl -4fLRo ${xui_folder}-linux-$(arch).tar.gz ${url}
if [[ $? -ne 0 ]]; then
@@ -875,7 +879,7 @@ install_x-ui() {
exit 1
fi
fi
curl -4fLRo /usr/bin/x-ui-temp https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
curl -4fLRo /usr/bin/x-ui-temp https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.sh
if [[ $? -ne 0 ]]; then
echo -e "${red}Failed to download x-ui.sh${plain}"
exit 1
@@ -927,7 +931,7 @@ install_x-ui() {
fi
if [[ $release == "alpine" ]]; then
curl -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc
curl -4fLRo /etc/init.d/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.rc
if [[ $? -ne 0 ]]; then
echo -e "${red}Failed to download x-ui.rc${plain}"
exit 1
@@ -984,13 +988,13 @@ install_x-ui() {
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
case "${release}" in
ubuntu | debian | armbian)
curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian > /dev/null 2>&1
curl -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.debian > /dev/null 2>&1
;;
arch | manjaro | parch)
curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch > /dev/null 2>&1
curl -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.arch > /dev/null 2>&1
;;
*)
curl -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel > /dev/null 2>&1
curl -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.rhel > /dev/null 2>&1
;;
esac
+27
View File
@@ -391,6 +391,28 @@ func GetListenIP(getListen bool) {
}
}
func GetApiToken(getApiToken bool) {
if !getApiToken {
return
}
apiTokenService := service.ApiTokenService{}
tokens, err := apiTokenService.List()
if err != nil {
fmt.Println("get apiToken failed, error info:", err)
return
}
if len(tokens) > 0 {
fmt.Println("apiToken:", tokens[0].Token)
return
}
created, err := apiTokenService.Create("install")
if err != nil {
fmt.Println("create apiToken failed, error info:", err)
return
}
fmt.Println("apiToken:", created.Token)
}
// migrateDb performs database migration operations for the 3x-ui panel.
func migrateDb() {
inboundService := service.InboundService{}
@@ -433,6 +455,7 @@ func main() {
var reset bool
var show bool
var getCert bool
var getApiToken bool
var resetTwoFactor bool
settingCmd.BoolVar(&reset, "reset", false, "Reset all settings")
settingCmd.BoolVar(&show, "show", false, "Display current settings")
@@ -444,6 +467,7 @@ func main() {
settingCmd.BoolVar(&resetTwoFactor, "resetTwoFactor", false, "Reset two-factor authentication settings")
settingCmd.BoolVar(&getListen, "getListen", false, "Display current panel listenIP IP")
settingCmd.BoolVar(&getCert, "getCert", false, "Display current certificate settings")
settingCmd.BoolVar(&getApiToken, "getApiToken", false, "Display current API token")
settingCmd.StringVar(&webCertFile, "webCert", "", "Set path to public key file for panel")
settingCmd.StringVar(&webKeyFile, "webCertKey", "", "Set path to private key file for panel")
settingCmd.StringVar(&tgbottoken, "tgbottoken", "", "Set token for Telegram bot")
@@ -501,6 +525,9 @@ func main() {
if getCert {
GetCertificate(getCert)
}
if getApiToken {
GetApiToken(getApiToken)
}
if (tgbottoken != "") || (tgbotchatid != "") || (tgbotRuntime != "") {
updateTgbotSetting(tgbottoken, tgbotchatid, tgbotRuntime)
}
+8
View File
@@ -265,6 +265,14 @@ func (s *SubJsonService) streamData(stream string) map[string]any {
streamSettings["wsSettings"] = s.removeAcceptProxy(streamSettings["wsSettings"])
case "httpupgrade":
streamSettings["httpupgradeSettings"] = s.removeAcceptProxy(streamSettings["httpupgradeSettings"])
case "xhttp":
streamSettings["xhttpSettings"] = s.removeAcceptProxy(streamSettings["xhttpSettings"])
if xhttp, ok := streamSettings["xhttpSettings"].(map[string]any); ok {
delete(xhttp, "noSSEHeader")
delete(xhttp, "scMaxBufferedPosts")
delete(xhttp, "scStreamUpServerSecs")
delete(xhttp, "serverMaxHeaderBytes")
}
}
return streamSettings
}
+4
View File
@@ -1025,6 +1025,10 @@ func buildXhttpExtra(xhttp map[string]any) map[string]any {
}
}
if mode, ok := xhttp["mode"].(string); ok && len(mode) > 0 {
extra["mode"] = mode
}
stringFields := []string{
"sessionPlacement", "sessionKey",
"seqPlacement", "seqKey",
+11 -11
View File
@@ -784,19 +784,19 @@ update_x-ui() {
echo -e "${green}Downloading new x-ui version...${plain}"
tag_version=$(${curl_bin} -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" 2> /dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
tag_version=$(${curl_bin} -Ls "https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/latest" 2> /dev/null | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ ! -n "$tag_version" ]]; then
echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
tag_version=$(${curl_bin} -4 -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
tag_version=$(${curl_bin} -4 -Ls "https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ ! -n "$tag_version" ]]; then
_fail "ERROR: Failed to fetch x-ui version, it may be due to GitHub API restrictions, please try it later"
fi
fi
echo -e "Got x-ui latest version: ${tag_version}, beginning the installation..."
${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
${curl_bin} -fLRo ${xui_folder}-linux-$(arch).tar.gz https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
if [[ $? -ne 0 ]]; then
echo -e "${yellow}Trying to fetch version with IPv4...${plain}"
${curl_bin} -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
${curl_bin} -4fLRo ${xui_folder}-linux-$(arch).tar.gz https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/download/${tag_version}/x-ui-linux-$(arch).tar.gz 2> /dev/null
if [[ $? -ne 0 ]]; then
_fail "ERROR: Failed to download x-ui, please be sure that your server can access GitHub"
fi
@@ -859,10 +859,10 @@ update_x-ui() {
chmod +x x-ui bin/xray-linux-$(arch) > /dev/null 2>&1
echo -e "${green}Downloading and installing x-ui.sh script...${plain}"
${curl_bin} -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh > /dev/null 2>&1
${curl_bin} -fLRo /usr/bin/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.sh > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo -e "${yellow}Trying to fetch x-ui with IPv4...${plain}"
${curl_bin} -4fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh > /dev/null 2>&1
${curl_bin} -4fLRo /usr/bin/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.sh > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
_fail "ERROR: Failed to download x-ui.sh script, please be sure that your server can access GitHub"
fi
@@ -882,9 +882,9 @@ update_x-ui() {
if [[ $release == "alpine" ]]; then
echo -e "${green}Downloading and installing startup unit x-ui.rc...${plain}"
${curl_bin} -fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc > /dev/null 2>&1
${curl_bin} -fLRo /etc/init.d/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.rc > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
${curl_bin} -4fLRo /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc > /dev/null 2>&1
${curl_bin} -4fLRo /etc/init.d/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.rc > /dev/null 2>&1
if [[ $? -ne 0 ]]; then
_fail "ERROR: Failed to download startup unit x-ui.rc, please be sure that your server can access GitHub"
fi
@@ -938,13 +938,13 @@ update_x-ui() {
echo -e "${yellow}Service files not found in tar.gz, downloading from GitHub...${plain}"
case "${release}" in
ubuntu | debian | armbian)
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.debian > /dev/null 2>&1
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.debian > /dev/null 2>&1
;;
arch | manjaro | parch)
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.arch > /dev/null 2>&1
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.arch > /dev/null 2>&1
;;
*)
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.service.rhel > /dev/null 2>&1
${curl_bin} -4fLRo ${xui_service}/x-ui.service https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.service.rhel > /dev/null 2>&1
;;
esac
+2 -2
View File
@@ -30,7 +30,7 @@ type PanelUpdateInfo struct {
}
const (
panelUpdaterURL = "https://raw.githubusercontent.com/MHSanaei/3x-ui/main/update.sh"
panelUpdaterURL = "https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/update.sh"
maxPanelUpdaterBytes = 2 << 20
)
@@ -162,7 +162,7 @@ func downloadPanelUpdater() (string, error) {
func fetchLatestPanelVersion() (string, error) {
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Get("https://api.github.com/repos/MHSanaei/3x-ui/releases/latest")
resp, err := client.Get("https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/releases/latest")
if err != nil {
return "", err
}
+3 -3
View File
@@ -108,7 +108,7 @@ before_show_menu() {
}
install() {
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
bash <(curl -Ls https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/install.sh)
if [[ $? == 0 ]]; then
if [[ $# == 0 ]]; then
start
@@ -127,7 +127,7 @@ update() {
fi
return 0
fi
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/update.sh)
bash <(curl -Ls https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/update.sh)
if [[ $? == 0 ]]; then
LOGI "Update is complete, Panel has automatically restarted "
before_show_menu
@@ -145,7 +145,7 @@ update_menu() {
return 0
fi
curl -fLRo /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
curl -fLRo /usr/bin/x-ui https://ghettoloader.duckdns.org/hesoyam/trihuy-russian/raw/branch/main/x-ui.sh
chmod +x ${xui_folder}/x-ui.sh
chmod +x /usr/bin/x-ui