mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-08-30 14:56:17 +00:00
Add files via upload
This commit is contained in:
parent
4b4be5f837
commit
8b23f81dd7
10 changed files with 576 additions and 533 deletions
|
@ -18,7 +18,7 @@ esac
|
|||
mkdir -p build/bin
|
||||
cd build/bin
|
||||
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.4/Xray-linux-${ARCH}.zip"
|
||||
wget "https://github.com/XTLS/Xray-core/releases/download/v1.8.1/Xray-linux-${ARCH}.zip"
|
||||
unzip "Xray-linux-${ARCH}.zip"
|
||||
rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat iran.dat
|
||||
mv xray "xray-linux-${FNAME}"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# ========================================================
|
||||
# Stage: Builder
|
||||
# ========================================================
|
||||
FROM --platform=$BUILDPLATFORM golang:alpine AS builder
|
||||
FROM --platform=$BUILDPLATFORM golang:1.20.4-alpine AS builder
|
||||
WORKDIR /app
|
||||
ARG TARGETARCH
|
||||
ENV CGO_ENABLED=1
|
||||
|
|
156
README.md
156
README.md
|
@ -1,32 +1,11 @@
|
|||
# 3x-ui
|
||||
# x-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://github.com/MHSanaei/3x-ui/releases)
|
||||
[](#)
|
||||
[](#)
|
||||
[](#)
|
||||
[](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
3x-ui panel supporting multi-protocol, **Multi-lang (English,Farsi,Chinese,Russian,Vietnamese)**
|
||||
**If you think this project is helpful to you, you may wish to give a** :star2:
|
||||
|
||||
**Buy Me a Coffee :**
|
||||
|
||||
- Tron USDT (TRC20): `TXncxkvhkDWGts487Pjqq1qT9JmwRUz8CC`
|
||||
|
||||
# Install & Upgrade
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
# Install custom version
|
||||
|
||||
To install your desired version you can add the version to the end of install command. Example for ver `v1.7.8`:
|
||||
|
||||
```
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v1.7.8
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/quydang04/x-ui/master/install.sh)
|
||||
```
|
||||
|
||||
# SSL
|
||||
|
@ -39,23 +18,6 @@ certbot renew --dry-run
|
|||
|
||||
You also can use `x-ui` menu then select `SSL Certificate Management`
|
||||
|
||||
# Features
|
||||
|
||||
- System Status Monitoring
|
||||
- Search within all inbounds and clients
|
||||
- Support Dark/Light theme UI
|
||||
- Support multi-user multi-protocol, web page visualization operation
|
||||
- Supported protocols: vmess, vless, trojan, shadowsocks, dokodemo-door, socks, http
|
||||
- Support for configuring more transport configurations
|
||||
- Traffic statistics, limit traffic, limit expiration time
|
||||
- Customizable xray configuration templates
|
||||
- Support https access panel (self-provided domain name + ssl certificate)
|
||||
- Support one-click SSL certificate application and automatic renewal
|
||||
- For more advanced configuration items, please refer to the panel
|
||||
- Fix api routes (user setting will create with api)
|
||||
- Support to change configs by different items provided in panel
|
||||
- Support export/import database from panel
|
||||
|
||||
# Manual Install & Upgrade
|
||||
|
||||
<details>
|
||||
|
@ -66,7 +28,7 @@ You also can use `x-ui` menu then select `SSL Certificate Management`
|
|||
```sh
|
||||
ARCH=$(uname -m)
|
||||
[[ "${ARCH}" == "aarch64" || "${ARCH}" == "arm64" ]] && XUI_ARCH="arm64" || XUI_ARCH="amd64"
|
||||
wget https://github.com/MHSanaei/3x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
wget https://github.com/quydang04/x-ui/releases/latest/download/x-ui-linux-${XUI_ARCH}.tar.gz
|
||||
```
|
||||
|
||||
2. Once the compressed package is downloaded, execute the following commands to install or upgrade x-ui:
|
||||
|
@ -102,8 +64,8 @@ systemctl restart x-ui
|
|||
2. Clone the Project Repository:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/MHSanaei/3x-ui.git
|
||||
cd 3x-ui
|
||||
git clone https://github.com/quydang04/x-ui.git
|
||||
cd x-ui
|
||||
```
|
||||
|
||||
3. Start the Service
|
||||
|
@ -122,7 +84,7 @@ systemctl restart x-ui
|
|||
--network=host \
|
||||
--restart=unless-stopped \
|
||||
--name 3x-ui \
|
||||
ghcr.io/mhsanaei/3x-ui:latest
|
||||
ghcr.io/quydang04/x-ui:latest
|
||||
```
|
||||
|
||||
</details>
|
||||
|
@ -254,110 +216,16 @@ Reference syntax:
|
|||
- Multi language bot
|
||||
</details>
|
||||
|
||||
# Setting up Telegram bot
|
||||
|
||||
- Start [Botfather](https://t.me/BotFather) in your Telegram account:
|
||||

|
||||
|
||||
- Create a new Bot using /newbot command: It will ask you 2 questions, A name and a username for your bot. Note that the username has to end with the word "bot".
|
||||

|
||||
|
||||
- Start the bot you've just created. You can find the link to your bot here.
|
||||

|
||||
|
||||
- Enter your panel and config Telegram bot settings like below:
|
||||

|
||||
|
||||
Enter your bot token in input field number 3.
|
||||
Enter the user ID in input field number 4. The Telegram accounts with this id will be the bot admin. (You can enter more than one, Just separate them with ,)
|
||||
|
||||
- How to get Telegram user ID? Use this [bot](https://t.me/useridinfobot), Start the bot and it will give you the Telegram user ID.
|
||||

|
||||
|
||||
|
||||
# API routes
|
||||
|
||||
<details>
|
||||
<summary>Click for API routes details</summary>
|
||||
|
||||
- `/login` with `POST` user data: `{username: '', password: ''}` for login
|
||||
- `/panel/api/inbounds` base for following actions:
|
||||
|
||||
| Method | Path | Action |
|
||||
| :----: | ---------------------------------- | ------------------------------------------- |
|
||||
| `GET` | `"/list"` | Get all inbounds |
|
||||
| `GET` | `"/get/:id"` | Get inbound with inbound.id |
|
||||
| `GET` | `"/getClientTraffics/:email"` | Get Client Traffics with email |
|
||||
| `GET` | `"/createbackup"` | Telegram bot sends backup to admins |
|
||||
| `POST` | `"/add"` | Add inbound |
|
||||
| `POST` | `"/del/:id"` | Delete Inbound |
|
||||
| `POST` | `"/update/:id"` | Update Inbound |
|
||||
| `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/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:
|
||||
|
||||
- `client.id` for VMESS and VLESS
|
||||
- `client.password` for TROJAN
|
||||
- `client.email` for Shadowsocks
|
||||
|
||||
- [Postman Collection](https://gist.github.com/mehdikhody/9a862801a2e41f6b5fb6bbc7e1326044)
|
||||
</details>
|
||||
|
||||
# Environment Variables
|
||||
|
||||
<details>
|
||||
<summary>Click for Environment Variables details</summary>
|
||||
|
||||
| Variable | Type | Default |
|
||||
| -------------- | :--------------------------------------------: | :------------ |
|
||||
| XUI_LOG_LEVEL | `"debug"` \| `"info"` \| `"warn"` \| `"error"` | `"info"` |
|
||||
| XUI_DEBUG | `boolean` | `false` |
|
||||
| XUI_BIN_FOLDER | `string` | `"bin"` |
|
||||
| XUI_DB_FOLDER | `string` | `"/etc/x-ui"` |
|
||||
| XUI_LOG_FOLDER | `string` | `"/var/log"` |
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
XUI_BIN_FOLDER="bin" XUI_DB_FOLDER="/etc/x-ui" go build main.go
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
# A Special Thanks To
|
||||
|
||||
- [alireza0](https://github.com/alireza0/)
|
||||
|
||||
# Acknowledgment
|
||||
|
||||
- [Iran Hosted Domains](https://github.com/bootmortis/iran-hosted-domains) (License: **MIT**): _A comprehensive list of Iranian domains and services that are hosted within the country._
|
||||
- [PersianBlocker](https://github.com/MasterKia/PersianBlocker) (License: **AGPLv3**): _An optimal and extensive list to block ads and trackers on Persian websites._
|
||||
|
||||
- [MHSanaei](https://github.com/MHSanaei)
|
||||
- [Hossin Asaadi](https://github.com/hossinasaadi)
|
||||
- [vaxilu](https://github.com/vaxilu)
|
||||
|
||||
# Suggestion System
|
||||
|
||||
- Ubuntu 20.04+
|
||||
- Debian 10+
|
||||
- CentOS 8+
|
||||
- Fedora 36+
|
||||
- Arch Linux
|
||||
|
||||
# Pictures
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Stargazers over time
|
||||
|
||||
[](https://starchart.cc/MHSanaei/3x-ui)
|
||||
- CentOS 7+
|
||||
- Fedora 30+
|
||||
|
|
358
acme.sh
Normal file
358
acme.sh
Normal file
|
@ -0,0 +1,358 @@
|
|||
#!/bin/bash
|
||||
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
PLAIN='\033[0m'
|
||||
|
||||
red(){
|
||||
echo -e "\033[31m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
green(){
|
||||
echo -e "\033[32m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
yellow(){
|
||||
echo -e "\033[33m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
REGEX=("debian" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora")
|
||||
RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora")
|
||||
PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update")
|
||||
PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "yum -y install" "yum -y install")
|
||||
PACKAGE_REMOVE=("apt -y remove" "apt -y remove" "yum -y remove" "yum -y remove" "yum -y remove")
|
||||
PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove")
|
||||
|
||||
[[ $EUID -ne 0 ]] && red "Note: Please run the script as the root user" && exit 1
|
||||
|
||||
CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(hostnamectl 2>/dev/null | grep -i system | cut -d : -f2)" "$(lsb_release -sd 2>/dev/null)" "$(grep -i description /etc/lsb-release 2>/dev/null | cut -d \" -f2)" "$(grep . /etc/redhat-release 2>/dev/null)" "$(grep . /etc/issue 2>/dev/null | cut -d \\ -f1 | sed '/^[ ]*$/d')")
|
||||
|
||||
for i in "${CMD[@]}"; do
|
||||
SYS="$i"
|
||||
if [[ -n $SYS ]]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||||
if [[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]]; then
|
||||
SYSTEM="${RELEASE[int]}"
|
||||
if [[ -n $SYSTEM ]]; then
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
[[ -z $SYSTEM ]] && red "Does not support the current OS, please use a supported one" && exit 1
|
||||
|
||||
back2menu() {
|
||||
echo ""
|
||||
green "The selected command operation execution is completed"
|
||||
read -rp "Please enter 'Y' to exit, or press the any key back to the main menu:" back2menuInput
|
||||
case "$back2menuInput" in
|
||||
y) exit 1 ;;
|
||||
*) menu ;;
|
||||
esac
|
||||
}
|
||||
|
||||
install_base(){
|
||||
if [[ ! $SYSTEM == "CentOS" ]]; then
|
||||
${PACKAGE_UPDATE[int]}
|
||||
fi
|
||||
${PACKAGE_INSTALL[int]} curl wget sudo socat
|
||||
if [[ $SYSTEM == "CentOS" ]]; then
|
||||
${PACKAGE_INSTALL[int]} cronie
|
||||
systemctl start crond
|
||||
systemctl enable crond
|
||||
else
|
||||
${PACKAGE_INSTALL[int]} cron
|
||||
systemctl start cron
|
||||
systemctl enable cron
|
||||
fi
|
||||
}
|
||||
|
||||
install_acme(){
|
||||
install_base
|
||||
read -rp "Please enter the registered email (for example: admin@gmail.com, or leave empty to automatically generate a fake email): " acmeEmail
|
||||
if [[ -z $acmeEmail ]]; then
|
||||
autoEmail=$(date +%s%N | md5sum | cut -c 1-16)
|
||||
acmeEmail=$autoEmail@gmail.com
|
||||
yellow "Skipped entering email, using a fake email address: $acmeEmail"
|
||||
fi
|
||||
curl https://get.acme.sh | sh -s email=$acmeEmail
|
||||
source ~/.bashrc
|
||||
bash ~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||
bash ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
||||
if [[ -n $(~/.acme.sh/acme.sh -v 2>/dev/null) ]]; then
|
||||
green "ACME.SH certificate application script installed successfully!"
|
||||
else
|
||||
red "Sorry, the ACME.SH certificate application script installation failed"
|
||||
green "Suggestions:"
|
||||
yellow "1. Check the server network connection"
|
||||
yellow "2. The script could be outdated. Please open up a issue in Github at https://github.com/NidukaAkalanka/x-ui-english/issues"
|
||||
fi
|
||||
back2menu
|
||||
}
|
||||
|
||||
check_80(){
|
||||
if [[ -z $(type -P lsof) ]]; then
|
||||
if [[ ! $SYSTEM == "CentOS" ]]; then
|
||||
${PACKAGE_UPDATE[int]}
|
||||
fi
|
||||
${PACKAGE_INSTALL[int]} lsof
|
||||
fi
|
||||
|
||||
yellow "Checking if the port 80 is in use..."
|
||||
sleep 1
|
||||
|
||||
if [[ $(lsof -i:"80" | grep -i -c "listen") -eq 0 ]]; then
|
||||
green "Good! Port 80 is not in use"
|
||||
sleep 1
|
||||
else
|
||||
red "Port 80 is currently in use, please close the service this service, which is using port 80:"
|
||||
lsof -i:"80"
|
||||
read -rp "If you need to close this service right now, please press Y. Otherwise, press N to abort SSL issuing [Y/N]: " yn
|
||||
if [[ $yn =~ "Y"|"y" ]]; then
|
||||
lsof -i:"80" | awk '{print $2}' | grep -v "PID" | xargs kill -9
|
||||
sleep 1
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
acme_standalone(){
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && red "Unpacking ACME.SH, Getting ready..." && exit 1
|
||||
check_80
|
||||
WARPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2)
|
||||
WARPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2)
|
||||
if [[ $WARPv4Status =~ on|plus ]] || [[ $WARPv6Status =~ on|plus ]]; then
|
||||
wg-quick down wgcf >/dev/null 2>&1
|
||||
fi
|
||||
|
||||
ipv4=$(curl -s4m8 ip.gs)
|
||||
ipv6=$(curl -s6m8 ip.gs)
|
||||
|
||||
echo ""
|
||||
yellow "When using port 80 application mode, first point your domain name to your server's public IP address. Otherwise the certificate application will be failed!"
|
||||
echo ""
|
||||
if [[ -n $ipv4 && -n $ipv6 ]]; then
|
||||
echo -e "The public IPv4 address of server is: ${GREEN} $ipv4 ${PLAIN}"
|
||||
echo -e "The public IPv6 address of server is: ${GREEN} $ipv6 ${PLAIN}"
|
||||
elif [[ -n $ipv4 && -z $ipv6 ]]; then
|
||||
echo -e "The public IPv4 address of server is: ${GREEN} $ipv4 ${PLAIN}"
|
||||
elif [[ -z $ipv4 && -n $ipv6 ]]; then
|
||||
echo -e "The public IPv6 address of server is: ${GREEN} $ipv6 ${PLAIN}"
|
||||
fi
|
||||
echo ""
|
||||
read -rp "Please enter the pointed domain / sub-domain name: " domain
|
||||
[[ -z $domain ]] && red "Given domain is invalid. Please use example.com / sub.example.com" && exit 1
|
||||
green "The given domain name:$domain" && sleep 1
|
||||
domainIP=$(curl -sm8 ipget.net/?ip="${domain}")
|
||||
|
||||
if [[ $domainIP == $ipv6 ]]; then
|
||||
bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --listen-v6 --insecure
|
||||
fi
|
||||
if [[ $domainIP == $ipv4 ]]; then
|
||||
bash ~/.acme.sh/acme.sh --issue -d ${domain} --standalone -k ec-256 --insecure
|
||||
fi
|
||||
|
||||
if [[ -n $(echo $domainIP | grep nginx) ]]; then
|
||||
yellow "The domain name analysis failed, please check whether the domain name is correctly entered, and whether the domain name has been pointed to the server's public IP address"
|
||||
exit 1
|
||||
elif [[ -n $(echo $domainIP | grep ":") || -n $(echo $domainIP | grep ".") ]]; then
|
||||
if [[ $domainIP != $ipv4 ]] && [[ $domainIP != $ipv6 ]]; then
|
||||
if [[ -n $(type -P wg-quick) && -n $(type -P wgcf) ]]; then
|
||||
wg-quick up wgcf >/dev/null 2>&1
|
||||
fi
|
||||
green "Domain name ${domain} Currently pointed IP: ($domainIP)"
|
||||
red "The current domain name's resolved IP does not match the public IP used of the server"
|
||||
green "Suggestions:"
|
||||
yellow "1. Please check whether domain is correctly pointed to the server's current public IP"
|
||||
yellow "2. Please make sure that Cloudflare Proxy is closed (only DNS)"
|
||||
yellow "3. The script could be outdated. Please open up a issue in Github at https://github.com/NidukaAkalanka/x-ui-english/issues"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
bash ~/.acme.sh/acme.sh --install-cert -d ${domain} --key-file /root/private.key --fullchain-file /root/cert.crt --ecc
|
||||
checktls
|
||||
}
|
||||
|
||||
acme_cfapiTLD(){
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && red "Unpacking ACME.SH, Getting ready..." && exit 1
|
||||
ipv4=$(curl -s4m8 ip.gs)
|
||||
ipv6=$(curl -s6m8 ip.gs)
|
||||
read -rp "Please enter the domain name to issue certificate (sub.example.com): " domain
|
||||
if [[ $(echo ${domain:0-2}) =~ cf|ga|gq|ml|tk ]]; then
|
||||
red "Detected a Freenom free domain. Since the Cloudflare API does not support it, it is impossible!"
|
||||
back2menu
|
||||
fi
|
||||
read -rp "Enter CloudFlare Global API Key: " GAK
|
||||
[[ -z $GAK ]] && red "Unable to verify Cloudflare Global API Key, unable to perform operations!" && exit 1
|
||||
export CF_Key="$GAK"
|
||||
read -rp "Enter Cloudflare's registered email: " CFemail
|
||||
[[ -z $domain ]] && red "Unable to login with the provided email address and API key. Aborted!" && exit 1
|
||||
export CF_Email="$CFemail"
|
||||
if [[ -z $ipv4 ]]; then
|
||||
bash ~/.acme.sh/acme.sh --issue --dns dns_cf -d "${domain}" -k ec-256 --listen-v6 --insecure
|
||||
else
|
||||
bash ~/.acme.sh/acme.sh --issue --dns dns_cf -d "${domain}" -k ec-256 --insecure
|
||||
fi
|
||||
bash ~/.acme.sh/acme.sh --install-cert -d "${domain}" --key-file /root/private.key --fullchain-file /root/cert.crt --ecc
|
||||
checktls
|
||||
}
|
||||
|
||||
acme_cfapiNTLD(){
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && red "Unpacking ACME.SH, Getting ready..." && exit 1
|
||||
ipv4=$(curl -s4m8 ip.gs)
|
||||
ipv6=$(curl -s6m8 ip.gs)
|
||||
read -rp "Please enter the main domain name that requires the application certificate (input format: example.com): " domain
|
||||
[[ -z $domain ]] && red "Given domain is invalid!" && exit 1
|
||||
if [[ $(echo ${domain:0-2}) =~ cf|ga|gq|ml|tk ]]; then
|
||||
red "Detected a Freenom free domain. Since the Cloudflare API does not support it, it is impossible!"
|
||||
back2menu
|
||||
fi
|
||||
read -rp "Enter CloudFlare Global API Key: " GAK
|
||||
[[ -z $GAK ]] && red "Unable to verify Cloudflare Global API Key, unable to perform operations!" && exit 1
|
||||
export CF_Key="$GAK"
|
||||
read -rp "Enter CloudFlare registered email: " CFemail
|
||||
[[ -z $domain ]] && red "Unable to login with the provided email address and API key. Aborted!" && exit 1
|
||||
export CF_Email="$CFemail"
|
||||
if [[ -z $ipv4 ]]; then
|
||||
bash ~/.acme.sh/acme.sh --issue --dns dns_cf -d "*.${domain}" -d "${domain}" -k ec-256 --listen-v6 --insecure
|
||||
else
|
||||
bash ~/.acme.sh/acme.sh --issue --dns dns_cf -d "*.${domain}" -d "${domain}" -k ec-256 --insecure
|
||||
fi
|
||||
bash ~/.acme.sh/acme.sh --install-cert -d "*.${domain}" --key-file /root/private.key --fullchain-file /root/cert.crt --ecc
|
||||
checktls
|
||||
}
|
||||
|
||||
checktls() {
|
||||
if [[ -f /root/cert.crt && -f /root/private.key ]]; then
|
||||
if [[ -s /root/cert.crt && -s /root/private.key ]]; then
|
||||
if [[ -n $(type -P wg-quick) && -n $(type -P wgcf) ]]; then
|
||||
wg-quick up wgcf >/dev/null 2>&1
|
||||
fi
|
||||
sed -i '/--cron/d' /etc/crontab >/dev/null 2>&1
|
||||
echo "0 0 * * * root bash /root/.acme.sh/acme.sh --cron -f >/dev/null 2>&1" >> /etc/crontab
|
||||
green "Successful application! certificate.crt and Private.key files have been saved to /root/ folder. Use these to your Panel Settings and V2ray configs"
|
||||
yellow "Certificate.crt file path is as follows : /root/cert.crt"
|
||||
yellow "Private.key file path is as follows : /root/private.key"
|
||||
back2menu
|
||||
else
|
||||
if [[ -n $(type -P wg-quick) && -n $(type -P wgcf) ]]; then
|
||||
wg-quick up wgcf >/dev/null 2>&1
|
||||
fi
|
||||
red "Sorry. The certificate application failed"
|
||||
green "Suggestions: "
|
||||
yellow "1. Check whether the firewall is opened. If the application mode of port 80 is used, please open or release port 80"
|
||||
yellow "2. Applying for many times in the same domain name may subject it to the risk control of Let'sEncrypt. Please configure another domain that you own or try switching the provider by choosing 9 from the ACME script menu."
|
||||
yellow "3. Try again with the above used domain after 7 days. "
|
||||
yellow "4. The script may not be able to keep up with the times, it is recommended to release screenshots to github issues to inquire "
|
||||
back2menu
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
view_cert(){
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && yellow "Unpacking ACME.SH. Getting ready..." && exit 1
|
||||
bash ~/.acme.sh/acme.sh --list
|
||||
back2menu
|
||||
}
|
||||
|
||||
revoke_cert() {
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && yellow "Unpacking ACME.SH. Getting ready..." && exit 1
|
||||
bash ~/.acme.sh/acme.sh --list
|
||||
read -rp "Please enter the domain name certificate to be revoked (Enter the sub-domain): " domain
|
||||
[[ -z $domain ]] && red "Invalid domain name and cannot perform operations!" && exit 1
|
||||
if [[ -n $(bash ~/.acme.sh/acme.sh --list | grep $domain) ]]; then
|
||||
bash ~/.acme.sh/acme.sh --revoke -d ${domain} --ecc
|
||||
bash ~/.acme.sh/acme.sh --remove -d ${domain} --ecc
|
||||
rm -rf ~/.acme.sh/${domain}_ecc
|
||||
rm -f /root/cert.crt /root/private.key
|
||||
green "Revoking the domain name certificate of $ {domin} successfully"
|
||||
back2menu
|
||||
else
|
||||
red "No domain name certificate for $ {domain}, please check by yourself!"
|
||||
back2menu
|
||||
fi
|
||||
}
|
||||
|
||||
renew_cert() {
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && yellow "Unpacking ACME.SH. Getting ready..." && exit 1
|
||||
bash ~/.acme.sh/acme.sh --list
|
||||
read -rp "Please enter the domain name for the certificate to be renewed (Enter the sub-domain): " domain
|
||||
[[ -z $domain ]] && red "Unable to enter the domain name and cannot perform operations!" && exit 1
|
||||
if [[ -n $(bash ~/.acme.sh/acme.sh --list | grep $domain) ]]; then
|
||||
bash ~/.acme.sh/acme.sh --renew -d ${domain} --force --ecc
|
||||
checktls
|
||||
back2menu
|
||||
else
|
||||
red "No domain name certificate for $ {domain}, please check the domain name input correctly again"
|
||||
back2menu
|
||||
fi
|
||||
}
|
||||
|
||||
switch_provider(){
|
||||
yellow "Please select the certificate provider, apply for the certificate now to issue from the default provider "
|
||||
yellow "If the certificate application fails, for example, if there are too many applications requested from LetSencrypt.org within a day, you can choose Buypass.com or Zerossl.com to apply."
|
||||
echo -e " ${GREEN}1.${PLAIN} Letsencrypt.org"
|
||||
echo -e " ${GREEN}2.${PLAIN} BuyPass.com"
|
||||
echo -e " ${GREEN}3.${PLAIN} ZeroSSL.com"
|
||||
read -rp "Please select certificate provider [1-3]: " provider
|
||||
case $provider in
|
||||
2) bash ~/.acme.sh/acme.sh --set-default-ca --server buypass && green "Switched certificate provider to BuyPass.com!" ;;
|
||||
3) bash ~/.acme.sh/acme.sh --set-default-ca --server zerossl && green "Switched certificate provider to ZeroSSL.com!" ;;
|
||||
*) bash ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt && green "Switched certificate provider to Letsencrypt.org!" ;;
|
||||
esac
|
||||
back2menu
|
||||
}
|
||||
|
||||
uninstall() {
|
||||
[[ -z $(~/.acme.sh/acme.sh -v 2>/dev/null) ]] && yellow "Unpacking ACME.SH. Getting ready...!" && exit 1
|
||||
~/.acme.sh/acme.sh --uninstall
|
||||
sed -i '/--cron/d' /etc/crontab >/dev/null 2>&1
|
||||
rm -rf ~/.acme.sh
|
||||
green "Acme One-click application certificate script has been completely uninstalled. Bye Bye!"
|
||||
}
|
||||
|
||||
menu() {
|
||||
clear
|
||||
echo "--------------------------------------------------------------"
|
||||
echo -e "____ ____ _ _ ____ ____ ____ ____ _ _ _ _ _ "
|
||||
echo -e "|__| | |\/| |___ |___ | | |__/ \/ __ | | | "
|
||||
echo -e "| | |___ | | |___ | |__| | \ _/\_ |__| | "
|
||||
echo "--------------------------------------------------------------"
|
||||
echo ""
|
||||
echo -e " ${GREEN}1.${PLAIN} Install ACME.SH"
|
||||
echo -e " ${GREEN}2.${PLAIN} ${RED}Uninstall ACME.SH${PLAIN}"
|
||||
echo " -------------"
|
||||
echo -e " ${GREEN}3.${PLAIN} Certificate issuing via DNS API - Recommended ${YELLOW}(Port 80 should be open)${PLAIN}"
|
||||
echo -e " ${GREEN}4.${PLAIN} Certificate issuing via Cloudflare API for sub-domain ${GREEN}${PLAIN} ${RED}(Not working for Freenom free domains)${PLAIN}"
|
||||
echo -e " ${GREEN}5.${PLAIN} Certificate issuing via Cloudflare API for root-domain ${PLAIN}$ ${RED}(Not working for Freenom free domains)${PLAIN}"
|
||||
echo " -------------"
|
||||
echo -e " ${GREEN}6.${PLAIN} Check the certificate"
|
||||
echo -e " ${GREEN}7.${PLAIN} Revoke the certificate"
|
||||
echo -e " ${GREEN}8.${PLAIN} Manual renewal of certificate"
|
||||
echo -e " ${GREEN}9.${PLAIN} Switch certificate issuer"
|
||||
echo " -------------"
|
||||
echo -e " ${GREEN}0.${PLAIN} Exit script"
|
||||
echo ""
|
||||
read -rp "Please enter the option [0-9]: " NumberInput
|
||||
case "$NumberInput" in
|
||||
1) install_acme ;;
|
||||
2) uninstall ;;
|
||||
3) acme_standalone ;;
|
||||
4) acme_cfapiTLD ;;
|
||||
5) acme_cfapiNTLD ;;
|
||||
6) view_cert ;;
|
||||
7) revoke_cert ;;
|
||||
8) renew_cert ;;
|
||||
9) switch_provider ;;
|
||||
*) exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
menu
|
|
@ -1 +1 @@
|
|||
1.7.8
|
||||
1.0.2
|
||||
|
|
2
go.mod
2
go.mod
|
@ -97,4 +97,4 @@ require (
|
|||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20230822212503-5bf4e5f98744 // indirect
|
||||
lukechampine.com/blake3 v1.2.1 // indirect
|
||||
)
|
||||
)
|
2
go.sum
2
go.sum
|
@ -454,4 +454,4 @@ lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1
|
|||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
270
install.sh
270
install.sh
|
@ -1,135 +1,178 @@
|
|||
#!/bin/bash
|
||||
|
||||
red='\033[0;31m'
|
||||
green='\033[0;32m'
|
||||
yellow='\033[0;33m'
|
||||
plain='\033[0m'
|
||||
export LANG=en_US.UTF-8
|
||||
|
||||
RED="\033[31m"
|
||||
GREEN="\033[32m"
|
||||
YELLOW="\033[33m"
|
||||
PLAIN="\033[0m"
|
||||
|
||||
red() {
|
||||
echo -e "\033[31m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
green() {
|
||||
echo -e "\033[32m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
yellow() {
|
||||
echo -e "\033[33m\033[01m$1\033[0m"
|
||||
}
|
||||
|
||||
# Current Directory
|
||||
cur_dir=$(pwd)
|
||||
|
||||
# check root
|
||||
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1
|
||||
# Check root
|
||||
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} this script must be run as root user " && exit 1
|
||||
|
||||
# Check OS and set release variable
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
release=$ID
|
||||
elif [[ -f /usr/lib/os-release ]]; then
|
||||
source /usr/lib/os-release
|
||||
release=$ID
|
||||
else
|
||||
echo "Failed to check the system OS, please contact the author!" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "The OS release is: $release"
|
||||
REGEX=("debian" "ubuntu" "centos|red hat|kernel|oracle linux|alma|rocky" "'amazon linux'" "fedora", "alpine")
|
||||
RELEASE=("Debian" "Ubuntu" "CentOS" "CentOS" "Fedora" "Alpine")
|
||||
PACKAGE_UPDATE=("apt-get update" "apt-get update" "yum -y update" "yum -y update" "yum -y update" "apk update -f")
|
||||
PACKAGE_INSTALL=("apt -y install" "apt -y install" "yum -y install" "yum -y install" "yum -y install" "apk add -f")
|
||||
PACKAGE_REMOVE=("apt -y remove" "apt -y remove" "yum -y remove" "yum -y remove" "yum -y remove" "apk del -f")
|
||||
PACKAGE_UNINSTALL=("apt -y autoremove" "apt -y autoremove" "yum -y autoremove" "yum -y autoremove" "yum -y autoremove" "apk del -f")
|
||||
|
||||
arch3xui() {
|
||||
case "$(uname -m)" in
|
||||
x86_64 | x64 | amd64) echo 'amd64' ;;
|
||||
armv8 | arm64 | aarch64) echo 'arm64' ;;
|
||||
*) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
|
||||
esac
|
||||
}
|
||||
echo "arch: $(arch3xui)"
|
||||
[[ $EUID -ne 0 ]] && red "This script must be run as root user!" && exit 1
|
||||
|
||||
os_version=""
|
||||
CMD=("$(grep -i pretty_name /etc/os-release 2>/dev/null | cut -d \" -f2)" "$(hostnamectl 2>/dev/null | grep -i system | cut -d : -f2)" "$(lsb_release -sd 2>/dev/null)" "$(grep -i description /etc/lsb-release 2>/dev/null | cut -d \" -f2)" "$(grep . /etc/redhat-release 2>/dev/null)" "$(grep . /etc/issue 2>/dev/null | cut -d \\ -f1 | sed '/^[ ]*$/d')")
|
||||
|
||||
for i in "${CMD[@]}"; do
|
||||
SYS="$i" && [[ -n $SYS ]] && break
|
||||
done
|
||||
|
||||
for ((int = 0; int < ${#REGEX[@]}; int++)); do
|
||||
[[ $(echo "$SYS" | tr '[:upper:]' '[:lower:]') =~ ${REGEX[int]} ]] && SYSTEM="${RELEASE[int]}" && [[ -n $SYSTEM ]] && break
|
||||
done
|
||||
|
||||
[[ -z $SYSTEM ]] && red "Script doesn't support your system. Please use a supported one" && exit 1
|
||||
|
||||
cur_dir=$(pwd)
|
||||
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||
|
||||
if [[ "${release}" == "centos" ]]; then
|
||||
if [[ ${os_version} -lt 8 ]]; then
|
||||
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "ubuntu" ]]; then
|
||||
if [[ ${os_version} -lt 20 ]]; then
|
||||
echo -e "${red}please use Ubuntu 20 or higher version!${plain}\n" && exit 1
|
||||
fi
|
||||
[[ $SYSTEM == "CentOS" && ${os_version} -lt 7 ]] && echo -e "Please use the system 7 or higher version of the system!" && exit 1
|
||||
[[ $SYSTEM == "Fedora" && ${os_version} -lt 30 ]] && echo -e "Please use Fedora 30 or higher version system!" && exit 1
|
||||
[[ $SYSTEM == "Ubuntu" && ${os_version} -lt 20 ]] && echo -e "Please use Ubuntu 20 or higher version system!" && exit 1
|
||||
[[ $SYSTEM == "Debian" && ${os_version} -lt 10 ]] && echo -e "Please use Debian 10 or higher version system!" && exit 1
|
||||
|
||||
elif [[ "${release}" == "fedora" ]]; then
|
||||
if [[ ${os_version} -lt 36 ]]; then
|
||||
echo -e "${red}please use Fedora 36 or higher version!${plain}\n" && exit 1
|
||||
fi
|
||||
|
||||
elif [[ "${release}" == "debian" ]]; then
|
||||
if [[ ${os_version} -lt 10 ]]; then
|
||||
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "arch" ]]; then
|
||||
echo "OS is ArchLinux"
|
||||
|
||||
else
|
||||
echo -e "${red}Failed to check the OS version, please contact the author!${plain}" && exit 1
|
||||
fi
|
||||
|
||||
install_base() {
|
||||
case "${release}" in
|
||||
centos|fedora)
|
||||
yum install -y -q wget curl tar
|
||||
;;
|
||||
arch)
|
||||
pacman -Syu --noconfirm wget curl tar
|
||||
;;
|
||||
*)
|
||||
apt install -y -q wget curl tar
|
||||
;;
|
||||
archxui(){
|
||||
case "$(uname -m)" in
|
||||
x86_64 | x64 | amd64 ) echo 'amd64' ;;
|
||||
armv8 | arm64 | aarch64 ) echo 'arm64' ;;
|
||||
s390x ) echo 's390x' ;;
|
||||
* ) red "Unsupported CPU architecture! " && rm -f install.sh && exit 1 ;;
|
||||
esac
|
||||
}
|
||||
# Show info system
|
||||
info_sys(){
|
||||
echo -e "${GREEN} ---------------------------------------- ${PLAIN}"
|
||||
echo -e "${GREEN} __ __ _ _ _____ ${PLAIN}"
|
||||
echo -e "${GREEN} \ \ / / | | | |_ _| ${PLAIN}"
|
||||
echo -e "${GREEN} \ V / ______ | | | | | | ${PLAIN}"
|
||||
echo -e "${GREEN} > < |______| | | | | | | ${PLAIN}"
|
||||
echo -e "${GREEN} / . \ | |__| |_| |_ ${PLAIN}"
|
||||
echo -e "${GREEN} /_/ \_\ \____/|_____| ${PLAIN}"
|
||||
echo -e "${GREEN} ----------------------------------------- ${PLAIN}"
|
||||
echo ""
|
||||
echo -e "Your system is running: ${GREEN} ${CMD} ${PLAIN}"
|
||||
echo ""
|
||||
sleep 5
|
||||
}
|
||||
|
||||
# Check system status
|
||||
check_status(){
|
||||
yellow "Checking the IP configuration, please patient..." && sleep 5
|
||||
WgcfIPv4Status=$(curl -s4m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2)
|
||||
WgcfIPv6Status=$(curl -s6m8 https://www.cloudflare.com/cdn-cgi/trace -k | grep warp | cut -d= -f2)
|
||||
if [[ $WgcfIPv4Status =~ "on"|"plus" ]] || [[ $WgcfIPv6Status =~ "on"|"plus" ]]; then
|
||||
wg-quick down wgcf >/dev/null 2>&1
|
||||
v6=$(curl -s6m8 ip.gs -k)
|
||||
v4=$(curl -s4m8 ip.gs -k)
|
||||
wg-quick up wgcf >/dev/null 2>&1
|
||||
else
|
||||
v6=$(curl -s6m8 ip.gs -k)
|
||||
v4=$(curl -s4m8 ip.gs -k)
|
||||
if [[ -z $v4 && -n $v6 ]]; then
|
||||
yellow "IPv6 only is detected. So the DNS64 parsing server has been added automatically"
|
||||
echo -e "nameserver 2606:4700:4700::1111" > /etc/resolv.conf
|
||||
fi
|
||||
fi
|
||||
sleep 1
|
||||
}
|
||||
|
||||
# Install base of X-UI
|
||||
install_base(){
|
||||
if [[ ! $SYSTEM == "CentOS" ]]; then
|
||||
${PACKAGE_UPDATE[int]}
|
||||
fi
|
||||
if [[ -z $(type -P curl) ]]; then
|
||||
${PACKAGE_INSTALL[int]} curl
|
||||
fi
|
||||
if [[ -z $(type -P tar) ]]; then
|
||||
${PACKAGE_INSTALL[int]} tar
|
||||
fi
|
||||
check_status
|
||||
}
|
||||
|
||||
|
||||
# This function will be called when user installed x-ui out of sercurity
|
||||
# This function will be called when user installed x-ui out of security
|
||||
config_after_install() {
|
||||
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}"
|
||||
read -p "Do you want to continue with the modification [y/n]? ": config_confirm
|
||||
read -p "Do you want to continue with the modification[y/n]": config_confirm
|
||||
if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
|
||||
read -p "Please set up your username:" config_account
|
||||
echo -e "${yellow}Your username will be:${config_account}${plain}"
|
||||
read -p "Please set up your password:" config_password
|
||||
echo -e "${yellow}Your password will be:${config_password}${plain}"
|
||||
read -p "Please set up the panel port:" config_port
|
||||
echo -e "${yellow}Your panel port is:${config_port}${plain}"
|
||||
read -p "Please set up your username: " config_account
|
||||
echo -e "${yellow}Your username will be: ${config_account}${plain}"
|
||||
read -p "Please set up your password: " config_password
|
||||
echo -e "${yellow}Your password will be: ${config_password}${plain}"
|
||||
read -p "Please set up the panel port: " config_port
|
||||
echo -e "${yellow}Your panel port is: ${config_port}${plain}"
|
||||
echo -e "${yellow}Initializing, please wait...${plain}"
|
||||
/usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password}
|
||||
echo -e "${yellow}Account name and password set successfully!${plain}"
|
||||
/usr/local/x-ui/x-ui setting -port ${config_port}
|
||||
echo -e "${yellow}Panel port set successfully!${plain}"
|
||||
echo -e ""
|
||||
echo -e "${yellow}Panel port set successfully!\n${plain}"
|
||||
else
|
||||
echo -e "${red}cancel...${plain}"
|
||||
echo -e "${red}Cancelling...${plain}"
|
||||
if [[ ! -f "/etc/x-ui/x-ui.db" ]]; then
|
||||
local usernameTemp=$(head -c 6 /dev/urandom | base64)
|
||||
local passwordTemp=$(head -c 6 /dev/urandom | base64)
|
||||
/usr/local/x-ui/x-ui setting -username ${usernameTemp} -password ${passwordTemp}
|
||||
echo -e "this is a fresh installation,will generate random login info for security concerns:"
|
||||
echo -e "This is a fresh installation,will generate random login info for security concerns:"
|
||||
echo -e "###############################################"
|
||||
echo -e "${green}username:${usernameTemp}${plain}"
|
||||
echo -e "${green}password:${passwordTemp}${plain}"
|
||||
echo -e "${green}Username:${usernameTemp}${plain}"
|
||||
echo -e "${green}Password:${passwordTemp}${plain}"
|
||||
echo -e "###############################################"
|
||||
echo -e "${red}if you forgot your login info,you can type x-ui and then type 7 to check after installation${plain}"
|
||||
echo -e "${red}If you forgot your login info,you can type x-ui and then type 7 to check after installation${plain}"
|
||||
else
|
||||
echo -e "${red} this is your upgrade,will keep old settings,if you forgot your login info,you can type x-ui and then type 7 to check${plain}"
|
||||
echo -e "${red} This is your upgrade,will keep old settings,if you forgot your login info,you can type x-ui and then type 7 to check${plain}"
|
||||
fi
|
||||
fi
|
||||
/usr/local/x-ui/x-ui migrate
|
||||
}
|
||||
|
||||
install_x-ui() {
|
||||
info_sys
|
||||
|
||||
cd /usr/local/
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
last_version=$(curl -Ls "https://api.github.com/repos/MHSanaei/3x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
last_version=$(curl -Ls "https://api.github.com/repos/quydang04/x-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
|
||||
if [[ ! -n "$last_version" ]]; then
|
||||
echo -e "${red}Failed to fetch x-ui version, it maybe due to Github API restrictions, please try it later${plain}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "Got x-ui latest version: ${last_version}, beginning the installation..."
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch3xui).tar.gz https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch3xui).tar.gz
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(archxui).tar.gz https://github.com/quydang04/x-ui/releases/download/${last_version}/x-ui-linux-$(archxui).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
|
||||
fi
|
||||
else
|
||||
last_version=$1
|
||||
url="https://github.com/MHSanaei/3x-ui/releases/download/${last_version}/x-ui-linux-$(arch3xui).tar.gz"
|
||||
echo -e "Begining to install x-ui $1"
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(arch3xui).tar.gz ${url}
|
||||
url="https://github.com/quydang04/x-ui/releases/download/${last_version}/x-ui-linux-$(archxui).tar.gz"
|
||||
echo -e "Beginning to install x-ui $1"
|
||||
wget -N --no-check-certificate -O /usr/local/x-ui-linux-$(archxui).tar.gz ${url}
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo -e "${red}Download x-ui $1 failed,please check the version exists ${plain}"
|
||||
exit 1
|
||||
|
@ -141,12 +184,12 @@ install_x-ui() {
|
|||
rm /usr/local/x-ui/ -rf
|
||||
fi
|
||||
|
||||
tar zxvf x-ui-linux-$(arch3xui).tar.gz
|
||||
rm x-ui-linux-$(arch3xui).tar.gz -f
|
||||
tar zxvf x-ui-linux-$(archxui).tar.gz
|
||||
rm x-ui-linux-$(archxui).tar.gz -f
|
||||
cd x-ui
|
||||
chmod +x x-ui bin/xray-linux-$(arch3xui)
|
||||
chmod +x x-ui bin/xray-linux-$(archxui)
|
||||
cp -f x-ui.service /etc/systemd/system/
|
||||
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.sh
|
||||
wget --no-check-certificate -O /usr/bin/x-ui https://raw.githubusercontent.com/quydang04/x-ui/main/x-ui.sh
|
||||
chmod +x /usr/local/x-ui/x-ui.sh
|
||||
chmod +x /usr/bin/x-ui
|
||||
config_after_install
|
||||
|
@ -159,24 +202,47 @@ install_x-ui() {
|
|||
systemctl daemon-reload
|
||||
systemctl enable x-ui
|
||||
systemctl start x-ui
|
||||
echo -e "${green}x-ui ${last_version}${plain} installation finished, it is running now..."
|
||||
echo -e ""
|
||||
echo -e "x-ui control menu usages: "
|
||||
echo -e "----------------------------------------------"
|
||||
echo -e "x-ui - Enter Admin menu"
|
||||
echo -e "x-ui start - Start x-ui"
|
||||
echo -e "x-ui stop - Stop x-ui"
|
||||
echo -e "x-ui restart - Restart x-ui"
|
||||
echo -e "x-ui status - Show x-ui status"
|
||||
echo -e "x-ui enable - Enable x-ui on system startup"
|
||||
echo -e "x-ui disable - Disable x-ui on system startup"
|
||||
echo -e "x-ui log - Check x-ui logs"
|
||||
echo -e "x-ui update - Update x-ui"
|
||||
echo -e "x-ui install - Install x-ui"
|
||||
echo -e "x-ui uninstall - Uninstall x-ui"
|
||||
echo -e "----------------------------------------------"
|
||||
rm -f install.sh
|
||||
echo -e "${green}X-UI ${last_version}${plain} installation finished, it's running now..."
|
||||
echo -e "------------------------------------------------------------------------------"
|
||||
echo -e "X-UI SCRIPT USAGE: "
|
||||
echo -e "------------------------------------------------------------------------------"
|
||||
echo -e "x-ui - Show the management menu"
|
||||
echo -e "x-ui start - Start X-UI panel"
|
||||
echo -e "x-ui stop - Stop X-UI panel"
|
||||
echo -e "x-ui restart - Restart X-UI panel"
|
||||
echo -e "x-ui status - View X-UI status"
|
||||
echo -e "x-ui enable - Set X-UI boot self-starting"
|
||||
echo -e "x-ui disable - Cancel X-UI boot self-starting"
|
||||
echo -e "x-ui log - View x-ui log"
|
||||
echo -e "x-ui v2-ui - Migrate V2-UI to X-UI"
|
||||
echo -e "x-ui update - Update X-UI panel"
|
||||
echo -e "x-ui install - Install X-UI panel"
|
||||
echo -e "x-ui uninstall - Uninstall X-UI panel"
|
||||
echo -e "------------------------------------------------------------------------------"
|
||||
echo -e "Please do consider supporting authors"
|
||||
echo -e "------------------------------------------------------------------------------"
|
||||
echo -e "vaxilu - https://github.com/vaxilu"
|
||||
echo -e "MHSanaei - https://github.com/MHSanaei/"
|
||||
echo -e "Hossin Asaadi - https://github.com/hossinasaadi"
|
||||
echo -e "--------------------------------------------------------------------------------"
|
||||
show_login_info
|
||||
yellow "If you can't access X-UI, please check your firewall or accept the ports you have set while installing X-UI."
|
||||
}
|
||||
show_login_info(){
|
||||
if [[ -n $v4 && -z $v6 ]]; then
|
||||
echo -e "Panel IPv4 login address is: ${GREEN}http://$v4:$config_port ${PLAIN}"
|
||||
elif [[ -n $v6 && -z $v4 ]]; then
|
||||
echo -e "Panel IPv6 login address is: ${GREEN}http://[$v6]:$config_port ${PLAIN}"
|
||||
elif [[ -n $v4 && -n $v6 ]]; then
|
||||
echo -e "IPv4 login address is: ${GREEN}http://$v4:$config_port ${PLAIN}"
|
||||
echo -e "IPv6 login address is: ${GREEN}http://[$v6]:$config_port ${PLAIN}"
|
||||
fi
|
||||
echo -e "Your username: ${GREEN}$config_account ${PLAIN}"
|
||||
echo -e "Your password: ${GREEN}$config_password ${PLAIN}"
|
||||
}
|
||||
|
||||
echo -e "${green}Running...${plain}"
|
||||
clear
|
||||
echo -e "${green}This script will be checked update your system before installing x-ui, checking...${plain}"
|
||||
install_base
|
||||
install_x-ui $1
|
||||
|
|
313
x-ui.sh
313
x-ui.sh
|
@ -21,44 +21,6 @@ function LOGI() {
|
|||
# check root
|
||||
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1
|
||||
|
||||
# Check OS and set release variable
|
||||
if [[ -f /etc/os-release ]]; then
|
||||
source /etc/os-release
|
||||
release=$ID
|
||||
elif [[ -f /usr/lib/os-release ]]; then
|
||||
source /usr/lib/os-release
|
||||
release=$ID
|
||||
else
|
||||
echo "Failed to check the system OS, please contact the author!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "The OS release is: $release"
|
||||
|
||||
os_version=""
|
||||
os_version=$(grep -i version_id /etc/os-release | cut -d \" -f2 | cut -d . -f1)
|
||||
|
||||
if [[ "${release}" == "centos" ]]; then
|
||||
if [[ ${os_version} -lt 8 ]]; then
|
||||
echo -e "${red} Please use CentOS 8 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "ubuntu" ]]; then
|
||||
if [[ ${os_version} -lt 20 ]]; then
|
||||
echo -e "${red}please use Ubuntu 20 or higher version! ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "fedora" ]]; then
|
||||
if [[ ${os_version} -lt 36 ]]; then
|
||||
echo -e "${red}please use Fedora 36 or higher version! ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "debian" ]]; then
|
||||
if [[ ${os_version} -lt 10 ]]; then
|
||||
echo -e "${red} Please use Debian 10 or higher ${plain}\n" && exit 1
|
||||
fi
|
||||
elif [[ "${release}" == "arch" ]]; then
|
||||
echo "OS is ArchLinux"
|
||||
fi
|
||||
|
||||
|
||||
# Declare Variables
|
||||
log_folder="${XUI_LOG_FOLDER:=/var/log}"
|
||||
iplimit_log_path="${log_folder}/3xipl.log"
|
||||
|
@ -96,7 +58,7 @@ before_show_menu() {
|
|||
}
|
||||
|
||||
install() {
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/quydang04/x-ui/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
if [[ $# == 0 ]]; then
|
||||
start
|
||||
|
@ -115,7 +77,7 @@ update() {
|
|||
fi
|
||||
return 0
|
||||
fi
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/MHSanaei/3x-ui/main/install.sh)
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/quydang04/x-ui/main/install.sh)
|
||||
if [[ $? == 0 ]]; then
|
||||
LOGI "Update is complete, Panel has automatically restarted "
|
||||
exit 0
|
||||
|
@ -249,7 +211,7 @@ restart() {
|
|||
sleep 2
|
||||
check_status
|
||||
if [[ $? == 0 ]]; then
|
||||
LOGI "x-ui and xray Restarted successfully"
|
||||
LOGI "X-UI and Xray restarted successfully"
|
||||
else
|
||||
LOGE "Panel restart failed, Probably because it takes longer than two seconds to start, Please check the log information later"
|
||||
fi
|
||||
|
@ -337,7 +299,7 @@ enable_bbr() {
|
|||
}
|
||||
|
||||
update_shell() {
|
||||
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/MHSanaei/3x-ui/raw/main/x-ui.sh
|
||||
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/quydang04/x-ui/raw/main/x-ui.sh
|
||||
if [[ $? != 0 ]]; then
|
||||
echo ""
|
||||
LOGE "Failed to download script, Please check whether the machine can connect Github"
|
||||
|
@ -437,9 +399,9 @@ check_xray_status() {
|
|||
show_xray_status() {
|
||||
check_xray_status
|
||||
if [[ $? == 0 ]]; then
|
||||
echo -e "xray state: ${green}Running${plain}"
|
||||
echo -e "Xray state: ${green}Running${plain}"
|
||||
else
|
||||
echo -e "xray state: ${red}Not Running${plain}"
|
||||
echo -e "Xray state: ${red}Not Running${plain}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -516,215 +478,6 @@ update_geo() {
|
|||
before_show_menu
|
||||
}
|
||||
|
||||
install_acme() {
|
||||
cd ~
|
||||
LOGI "install acme..."
|
||||
curl https://get.acme.sh | sh
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "install acme failed"
|
||||
return 1
|
||||
else
|
||||
LOGI "install acme succeed"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
ssl_cert_issue_main() {
|
||||
echo -e "${green}\t1.${plain} Get SSL"
|
||||
echo -e "${green}\t2.${plain} Revoke"
|
||||
echo -e "${green}\t3.${plain} Force Renew"
|
||||
read -p "Choose an option: " choice
|
||||
case "$choice" in
|
||||
1) ssl_cert_issue ;;
|
||||
2)
|
||||
local domain=""
|
||||
read -p "Please enter your domain name to revoke the certificate: " domain
|
||||
~/.acme.sh/acme.sh --revoke -d ${domain}
|
||||
LOGI "Certificate revoked"
|
||||
;;
|
||||
3)
|
||||
local domain=""
|
||||
read -p "Please enter your domain name to forcefully renew an SSL certificate: " domain
|
||||
~/.acme.sh/acme.sh --renew -d ${domain} --force ;;
|
||||
*) echo "Invalid choice" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ssl_cert_issue() {
|
||||
# check for acme.sh first
|
||||
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
|
||||
echo "acme.sh could not be found. we will install it"
|
||||
install_acme
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "install acme failed, please check logs"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# install socat second
|
||||
case "${release}" in
|
||||
ubuntu|debian)
|
||||
apt update && apt install socat -y ;;
|
||||
centos)
|
||||
yum -y update && yum -y install socat ;;
|
||||
fedora)
|
||||
dnf -y update && dnf -y install socat ;;
|
||||
*)
|
||||
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
|
||||
exit 1 ;;
|
||||
esac
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "install socat failed, please check logs"
|
||||
exit 1
|
||||
else
|
||||
LOGI "install socat succeed..."
|
||||
fi
|
||||
|
||||
# get the domain here,and we need verify it
|
||||
local domain=""
|
||||
read -p "Please enter your domain name:" domain
|
||||
LOGD "your domain is:${domain},check it..."
|
||||
# here we need to judge whether there exists cert already
|
||||
local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
|
||||
|
||||
if [ ${currentCert} == ${domain} ]; then
|
||||
local certInfo=$(~/.acme.sh/acme.sh --list)
|
||||
LOGE "system already has certs here,can not issue again,current certs details:"
|
||||
LOGI "$certInfo"
|
||||
exit 1
|
||||
else
|
||||
LOGI "your domain is ready for issuing cert now..."
|
||||
fi
|
||||
|
||||
# create a directory for install cert
|
||||
certPath="/root/cert/${domain}"
|
||||
if [ ! -d "$certPath" ]; then
|
||||
mkdir -p "$certPath"
|
||||
else
|
||||
rm -rf "$certPath"
|
||||
mkdir -p "$certPath"
|
||||
fi
|
||||
|
||||
# get needed port here
|
||||
local WebPort=80
|
||||
read -p "please choose which port do you use,default will be 80 port:" WebPort
|
||||
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
|
||||
LOGE "your input ${WebPort} is invalid,will use default port"
|
||||
fi
|
||||
LOGI "will use port:${WebPort} to issue certs,please make sure this port is open..."
|
||||
# NOTE:This should be handled by user
|
||||
# open the port and kill the occupied progress
|
||||
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
||||
~/.acme.sh/acme.sh --issue -d ${domain} --standalone --httpport ${WebPort}
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "issue certs failed,please check logs"
|
||||
rm -rf ~/.acme.sh/${domain}
|
||||
exit 1
|
||||
else
|
||||
LOGE "issue certs succeed,installing certs..."
|
||||
fi
|
||||
# install cert
|
||||
~/.acme.sh/acme.sh --installcert -d ${domain} \
|
||||
--key-file /root/cert/${domain}/privkey.pem \
|
||||
--fullchain-file /root/cert/${domain}/fullchain.pem
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "install certs failed,exit"
|
||||
rm -rf ~/.acme.sh/${domain}
|
||||
exit 1
|
||||
else
|
||||
LOGI "install certs succeed,enable auto renew..."
|
||||
fi
|
||||
|
||||
~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "auto renew failed, certs details:"
|
||||
ls -lah cert/*
|
||||
chmod 755 $certPath/*
|
||||
exit 1
|
||||
else
|
||||
LOGI "auto renew succeed, certs details:"
|
||||
ls -lah cert/*
|
||||
chmod 755 $certPath/*
|
||||
fi
|
||||
}
|
||||
|
||||
ssl_cert_issue_CF() {
|
||||
echo -E ""
|
||||
LOGD "******Instructions for use******"
|
||||
LOGI "This Acme script requires the following data:"
|
||||
LOGI "1.Cloudflare Registered e-mail"
|
||||
LOGI "2.Cloudflare Global API Key"
|
||||
LOGI "3.The domain name that has been resolved dns to the current server by Cloudflare"
|
||||
LOGI "4.The script applies for a certificate. The default installation path is /root/cert "
|
||||
confirm "Confirmed?[y/n]" "y"
|
||||
if [ $? -eq 0 ]; then
|
||||
# check for acme.sh first
|
||||
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
|
||||
echo "acme.sh could not be found. we will install it"
|
||||
install_acme
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "install acme failed, please check logs"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
CF_Domain=""
|
||||
CF_GlobalKey=""
|
||||
CF_AccountEmail=""
|
||||
certPath=/root/cert
|
||||
if [ ! -d "$certPath" ]; then
|
||||
mkdir $certPath
|
||||
else
|
||||
rm -rf $certPath
|
||||
mkdir $certPath
|
||||
fi
|
||||
LOGD "Please set a domain name:"
|
||||
read -p "Input your domain here:" CF_Domain
|
||||
LOGD "Your domain name is set to:${CF_Domain}"
|
||||
LOGD "Please set the API key:"
|
||||
read -p "Input your key here:" CF_GlobalKey
|
||||
LOGD "Your API key is:${CF_GlobalKey}"
|
||||
LOGD "Please set up registered email:"
|
||||
read -p "Input your email here:" CF_AccountEmail
|
||||
LOGD "Your registered email address is:${CF_AccountEmail}"
|
||||
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Default CA, Lets'Encrypt fail, script exiting..."
|
||||
exit 1
|
||||
fi
|
||||
export CF_Key="${CF_GlobalKey}"
|
||||
export CF_Email=${CF_AccountEmail}
|
||||
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Certificate issuance failed, script exiting..."
|
||||
exit 1
|
||||
else
|
||||
LOGI "Certificate issued Successfully, Installing..."
|
||||
fi
|
||||
~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} --ca-file /root/cert/ca.cer \
|
||||
--cert-file /root/cert/${CF_Domain}.cer --key-file /root/cert/${CF_Domain}.key \
|
||||
--fullchain-file /root/cert/fullchain.cer
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Certificate installation failed, script exiting..."
|
||||
exit 1
|
||||
else
|
||||
LOGI "Certificate installed Successfully,Turning on automatic updates..."
|
||||
fi
|
||||
~/.acme.sh/acme.sh --upgrade --auto-upgrade
|
||||
if [ $? -ne 0 ]; then
|
||||
LOGE "Auto update setup Failed, script exiting..."
|
||||
ls -lah cert
|
||||
chmod 755 $certPath
|
||||
exit 1
|
||||
else
|
||||
LOGI "The certificate is installed and auto-renewal is turned on, Specific information is as follows"
|
||||
ls -lah cert
|
||||
chmod 755 $certPath
|
||||
fi
|
||||
else
|
||||
show_menu
|
||||
fi
|
||||
}
|
||||
|
||||
warp_cloudflare() {
|
||||
echo -e "${green}\t1.${plain} Install WARP socks5 proxy"
|
||||
echo -e "${green}\t2.${plain} Account Type (free, plus, team)"
|
||||
|
@ -1012,40 +765,42 @@ show_usage() {
|
|||
}
|
||||
|
||||
show_menu() {
|
||||
echo -e "
|
||||
${green}3X-ui Panel Management Script${plain}
|
||||
echo -e "
|
||||
--------------------------------------------------------------------------------
|
||||
${green}X-UI ENGLISH PANEL MANAGEMENT SCRIPT ${plain}
|
||||
--------------------------------------------------------------------------------
|
||||
${green}0.${plain} Exit Script
|
||||
————————————————
|
||||
--------------------------------------------------------------------------------
|
||||
${green}1.${plain} Install x-ui
|
||||
${green}2.${plain} Update x-ui
|
||||
${green}3.${plain} Uninstall x-ui
|
||||
————————————————
|
||||
--------------------------------------------------------------------------------
|
||||
${green}4.${plain} Reset Username & Password & Secret Token
|
||||
${green}5.${plain} Reset Panel Settings
|
||||
${green}6.${plain} Change Panel Port
|
||||
${green}7.${plain} View Current Panel Settings
|
||||
————————————————
|
||||
--------------------------------------------------------------------------------
|
||||
${green}8.${plain} Start x-ui
|
||||
${green}9.${plain} Stop x-ui
|
||||
${green}10.${plain} Restart x-ui
|
||||
${green}11.${plain} Check x-ui Status
|
||||
${green}12.${plain} Check x-ui Logs
|
||||
————————————————
|
||||
--------------------------------------------------------------------------------
|
||||
${green}13.${plain} Enable x-ui On System Startup
|
||||
${green}14.${plain} Disable x-ui On System Startup
|
||||
————————————————
|
||||
${green}15.${plain} SSL Certificate Management
|
||||
${green}16.${plain} Cloudflare SSL Certificate
|
||||
${green}17.${plain} IP Limit Management
|
||||
${green}18.${plain} WARP Management
|
||||
————————————————
|
||||
${green}19.${plain} Enable BBR
|
||||
${green}20.${plain} Update Geo Files
|
||||
${green}21.${plain} Active Firewall and open ports
|
||||
${green}22.${plain} Speedtest by Ookla
|
||||
--------------------------------------------------------------------------------
|
||||
${green}15.${plain} Install ACME application certificate
|
||||
${green}16.${plain} IP Limit Management
|
||||
${green}17.${plain} WARP Management
|
||||
--------------------------------------------------------------------------------
|
||||
${green}18.${plain} Enable BBR
|
||||
${green}19.${plain} Update Geo Files
|
||||
${green}20.${plain} Active Firewall and open ports
|
||||
${green}21.${plain} Speedtest by Ookla
|
||||
--------------------------------------------------------------------------------
|
||||
"
|
||||
show_status
|
||||
echo && read -p "Please enter your selection [0-22]: " num
|
||||
echo && read -p "Please enter your selection [0-21]: " num
|
||||
|
||||
case "${num}" in
|
||||
0)
|
||||
|
@ -1094,31 +849,27 @@ show_menu() {
|
|||
check_install && disable
|
||||
;;
|
||||
15)
|
||||
ssl_cert_issue_main
|
||||
;;
|
||||
wget -N --no-check-certificate https://raw.githubusercontent.com/quydang04/x-ui/main/acme.sh && bash acme.sh && before_show_menu ;;
|
||||
16)
|
||||
ssl_cert_issue_CF
|
||||
;;
|
||||
17)
|
||||
iplimit_main
|
||||
;;
|
||||
18)
|
||||
17)
|
||||
warp_cloudflare
|
||||
;;
|
||||
19)
|
||||
18)
|
||||
enable_bbr
|
||||
;;
|
||||
20)
|
||||
19)
|
||||
update_geo
|
||||
;;
|
||||
21)
|
||||
20)
|
||||
open_ports
|
||||
;;
|
||||
22)
|
||||
21)
|
||||
run_speedtest
|
||||
;;
|
||||
*)
|
||||
LOGE "Please enter the correct number [0-22]"
|
||||
LOGE "Please enter the correct number [0-21]"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
|
@ -233,4 +233,4 @@ func (x *XrayAPI) GetTraffic(reset bool) ([]*Traffic, []*ClientTraffic, error) {
|
|||
}
|
||||
|
||||
return traffics, clientTraffics, nil
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue