Files
x-ui/x-ui.sh
2024-10-08 15:15:43 +02:00

1250 lines
37 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
red='\033[0;31m'
green='\033[0;32m'
yellow='\033[0;33m'
plain='\033[0m'
#Add some basic function here
function LOGD() {
echo -e "${yellow}[DEG] $* ${plain}"
}
function LOGE() {
echo -e "${red}[ERR] $* ${plain}"
}
function LOGI() {
echo -e "${green}[INF] $* ${plain}"
}
# 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 "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.')
if [[ "${release}" == "arch" ]]; then
echo "Your OS is Arch Linux"
elif [[ "${release}" == "parch" ]]; then
echo "Your OS is Parch Linux"
elif [[ "${release}" == "manjaro" ]]; then
echo "Your OS is Manjaro"
elif [[ "${release}" == "armbian" ]]; then
echo "Your OS is Armbian"
elif [[ "${release}" == "opensuse-tumbleweed" ]]; then
echo "Your OS is OpenSUSE Tumbleweed"
elif [[ "${release}" == "openEuler" ]]; then
if [[ ${os_version} -lt 2203 ]]; then
echo -e "${red} Please use OpenEuler 22.03 or higher ${plain}\n" && exit 1
fi
elif [[ "${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 2004 ]]; 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}" == "amzn" ]]; then
if [[ ${os_version} != "2023" ]]; then
echo -e "${red} Please use Amazon Linux 2023!${plain}\n" && exit 1
fi
elif [[ "${release}" == "debian" ]]; then
if [[ ${os_version} -lt 11 ]]; then
echo -e "${red} Please use Debian 11 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "almalinux" ]]; then
if [[ ${os_version} -lt 80 ]]; then
echo -e "${red} Please use AlmaLinux 8.0 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "rocky" ]]; then
if [[ ${os_version} -lt 8 ]]; then
echo -e "${red} Please use Rocky Linux 8 or higher ${plain}\n" && exit 1
fi
elif [[ "${release}" == "oracle" ]]; then
if [[ ${os_version} -lt 8 ]]; then
echo -e "${red} Please use Oracle Linux 8 or higher ${plain}\n" && exit 1
fi
else
echo -e "${red}Your operating system is not supported by this script.${plain}\n"
echo "Please ensure you are using one of the following supported operating systems:"
echo "- Ubuntu 20.04+"
echo "- Debian 11+"
echo "- CentOS 8+"
echo "- OpenEuler 22.03+"
echo "- Fedora 36+"
echo "- Arch Linux"
echo "- Parch Linux"
echo "- Manjaro"
echo "- Armbian"
echo "- AlmaLinux 8.0+"
echo "- Rocky Linux 8+"
echo "- Oracle Linux 8+"
echo "- OpenSUSE Tumbleweed"
echo "- Amazon Linux 2023"
exit 1
fi
confirm() {
if [[ $# > 1 ]]; then
echo && read -p "$1 [Default $2]: " temp
if [[ x"${temp}" == x"" ]]; then
temp=$2
fi
else
read -p "$1 [y/n]: " temp
fi
if [[ x"${temp}" == x"y" || x"${temp}" == x"Y" ]]; then
return 0
else
return 1
fi
}
confirm_restart() {
confirm "Restart the panel, Attention: Restarting the panel will also restart xray" "y"
if [[ $? == 0 ]]; then
restart
else
show_menu
fi
}
before_show_menu() {
echo && echo -n -e "${yellow}Press enter to return to the main menu: ${plain}" && read temp
show_menu
}
install() {
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/main/install.sh)
if [[ $? == 0 ]]; then
if [[ $# == 0 ]]; then
start
else
start 0
fi
fi
}
update() {
confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "n"
if [[ $? != 0 ]]; then
LOGE "Cancelled"
if [[ $# == 0 ]]; then
before_show_menu
fi
return 0
fi
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/main/install.sh)
if [[ $? == 0 ]]; then
LOGI "Update is complete, Panel has automatically restarted "
exit 0
fi
}
custom_version() {
echo "Enter the panel version (like 1.6.0):"
read panel_version
if [ -z "$panel_version" ]; then
echo "Panel version cannot be empty. Exiting."
exit 1
fi
download_link="https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh"
# Use the entered panel version in the download link
install_command="bash <(curl -Ls $download_link) $panel_version"
echo "Downloading and installing panel version $panel_version..."
eval $install_command
}
# Function to handle the deletion of the script file
delete_script() {
rm "$0" # Remove the script file itself
exit 1
}
uninstall() {
confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" " n"
if [[ $? != 0 ]]; then
if [[ $# == 0 ]]; then
show_menu
fi
return 0
fi
systemctl stop x-ui
systemctl disable x-ui
rm /etc/systemd/system/x-ui.service -f
systemctl daemon-reload
systemctl reset-failed
rm /etc/x-ui/ -rf
rm /usr/local/x-ui/ -rf
echo -e "\nUninstalled Successfully."
echo ""
echo -e "If you need to install this panel again, you can use below command:"
echo -e "${green}bash <(curl -Ls https://raw.githubusercontent.com/alireza0/x-ui/master/install.sh)${plain}"
echo ""
# Trap the SIGTERM signal
trap delete_script SIGTERM
delete_script
}
reset_user() {
confirm "Reset your username and password to admin?" "n"
if [[ $? != 0 ]]; then
if [[ $# == 0 ]]; then
show_menu
fi
return 0
fi
/usr/local/x-ui/x-ui setting -username admin -password admin
echo -e "Username and password have been reset to ${green}admin${plain}Please restart the panel now."
confirm_restart
}
gen_random_string() {
local length="$1"
local random_string=$(LC_ALL=C tr -dc 'a-zA-Z0-9' </dev/urandom | fold -w "$length" | head -n 1)
echo "$random_string"
}
reset_webbasepath() {
echo -e "${yellow}Resetting Web Base Path${plain}"
read -rp "Are you sure you want to reset the web base path? (y/n): " confirm
if [[ $confirm != "y" && $confirm != "Y" ]]; then
echo -e "${yellow}Operation canceled.${plain}"
return
fi
config_webBasePath=$(gen_random_string 10)
# Apply the new web base path setting
/usr/local/x-ui/x-ui setting -webBasePath "${config_webBasePath}" >/dev/null 2>&1
echo -e "Web base path has been reset to: ${green}${config_webBasePath}${plain}"
echo -e "${green}Please use the new web base path to access the panel.${plain}"
restart
}
reset_config() {
confirm "Are you sure you want to reset all panel settingsAccount data will not be lostUsername and password will not change" "n"
if [[ $? != 0 ]]; then
if [[ $# == 0 ]]; then
show_menu
fi
return 0
fi
/usr/local/x-ui/x-ui setting -reset
echo -e "All panel settings have been reset to defaultPlease restart the panel nowand use the default ${green}54321${plain} Port to Access the web Panel"
confirm_restart
}
check_config() {
info=$(/usr/local/x-ui/x-ui setting -show true)
if [[ $? != 0 ]]; then
LOGE "get current settings error,please check logs"
show_menu
fi
LOGI "${info}"
}
set_port() {
echo && echo -n -e "Enter port number[1-65535]: " && read port
if [[ -z "${port}" ]]; then
LOGD "Cancelled"
before_show_menu
else
/usr/local/x-ui/x-ui setting -port ${port}
echo -e "The port is setPlease restart the panel nowand use the new port ${green}${port}${plain} to access web panel"
confirm_restart
fi
}
start() {
check_status
if [[ $? == 0 ]]; then
echo ""
LOGI "Panel is runningNo need to start againIf you need to restart, please select restart"
else
systemctl start x-ui
sleep 2
check_status
if [[ $? == 0 ]]; then
LOGI "x-ui Started Successfully"
else
LOGE "panel Failed to startProbably because it takes longer than two seconds to startPlease check the log information later"
fi
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
stop() {
check_status
if [[ $? == 1 ]]; then
echo ""
LOGI "Panel stoppedNo need to stop again!"
else
systemctl stop x-ui
sleep 2
check_status
if [[ $? == 1 ]]; then
LOGI "x-ui and xray stopped successfully"
else
LOGE "Panel stop failedProbably because the stop time exceeds two secondsPlease check the log information later"
fi
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
restart() {
systemctl restart x-ui
sleep 2
check_status
if [[ $? == 0 ]]; then
LOGI "x-ui and xray Restarted successfully"
else
LOGE "Panel restart failedProbably because it takes longer than two seconds to startPlease check the log information later"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
status() {
systemctl status x-ui -l
if [[ $# == 0 ]]; then
before_show_menu
fi
}
enable() {
systemctl enable x-ui
if [[ $? == 0 ]]; then
LOGI "x-ui Set to boot automatically on startup successfully"
else
LOGE "x-ui Failed to set Autostart"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
disable() {
systemctl disable x-ui
if [[ $? == 0 ]]; then
LOGI "x-ui Autostart Cancelled successfully"
else
LOGE "x-ui Failed to cancel autostart"
fi
if [[ $# == 0 ]]; then
before_show_menu
fi
}
show_log() {
journalctl -u x-ui.service -e --no-pager -f
if [[ $# == 0 ]]; then
before_show_menu
fi
}
update_shell() {
wget -O /usr/bin/x-ui -N --no-check-certificate https://github.com/alireza0/x-ui/raw/main/x-ui.sh
if [[ $? != 0 ]]; then
echo ""
LOGE "Failed to download scriptPlease check whether the machine can connect Github"
before_show_menu
else
chmod +x /usr/bin/x-ui
LOGI "Upgrade script succeededPlease rerun the script" && exit 0
fi
}
# 0: running, 1: not running, 2: not installed
check_status() {
if [[ ! -f /etc/systemd/system/x-ui.service ]]; then
return 2
fi
temp=$(systemctl status x-ui | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1)
if [[ x"${temp}" == x"running" ]]; then
return 0
else
return 1
fi
}
check_enabled() {
temp=$(systemctl is-enabled x-ui)
if [[ x"${temp}" == x"enabled" ]]; then
return 0
else
return 1
fi
}
check_uninstall() {
check_status
if [[ $? != 2 ]]; then
echo ""
LOGE "Panel installedPlease do not reinstall"
if [[ $# == 0 ]]; then
before_show_menu
fi
return 1
else
return 0
fi
}
check_install() {
check_status
if [[ $? == 2 ]]; then
echo ""
LOGE "Please install the panel first"
if [[ $# == 0 ]]; then
before_show_menu
fi
return 1
else
return 0
fi
}
show_status() {
check_status
case $? in
0)
echo -e "Panel state: ${green}Running${plain}"
show_enable_status
;;
1)
echo -e "Panel state: ${yellow}Not Running${plain}"
show_enable_status
;;
2)
echo -e "Panel state: ${red}Not Installed${plain}"
;;
esac
show_xray_status
}
show_enable_status() {
check_enabled
if [[ $? == 0 ]]; then
echo -e "Start automatically: ${green}Yes${plain}"
else
echo -e "Start automatically: ${red}No${plain}"
fi
}
check_xray_status() {
count=$(ps -ef | grep "xray-linux" | grep -v "grep" | wc -l)
if [[ count -ne 0 ]]; then
return 0
else
return 1
fi
}
show_xray_status() {
check_xray_status
if [[ $? == 0 ]]; then
echo -e "xray state: ${green}Running${plain}"
else
echo -e "xray state: ${red}Not Running${plain}"
fi
}
install_acme() {
# Check if acme.sh is already installed
if command -v ~/.acme.sh/acme.sh &>/dev/null; then
LOGI "acme.sh is already installed."
return 0
fi
LOGI "Installing acme.sh..."
cd ~ || return 1 # Ensure you can change to the home directory
curl -s https://get.acme.sh | sh
if [ $? -ne 0 ]; then
LOGE "Installation of acme.sh failed."
return 1
else
LOGI "Installation of acme.sh succeeded."
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"
echo -e "${green}\t4.${plain} Show Existing Domains"
echo -e "${green}\t5.${plain} Set Cert paths for the panel"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
0)
show_menu
;;
1)
ssl_cert_issue
;;
2)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "No certificates found to revoke."
else
echo "Existing domains:"
echo "$domains"
read -p "Please enter a domain from the list to revoke the certificate: " domain
if echo "$domains" | grep -qw "$domain"; then
~/.acme.sh/acme.sh --revoke -d ${domain}
LOGI "Certificate revoked for domain: $domain"
else
echo "Invalid domain entered."
fi
fi
;;
3)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "No certificates found to renew."
else
echo "Existing domains:"
echo "$domains"
read -p "Please enter a domain from the list to renew the SSL certificate: " domain
if echo "$domains" | grep -qw "$domain"; then
~/.acme.sh/acme.sh --renew -d ${domain} --force
LOGI "Certificate forcefully renewed for domain: $domain"
else
echo "Invalid domain entered."
fi
fi
;;
4)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "No certificates found."
else
echo "Existing domains and their paths:"
for domain in $domains; do
local cert_path="/root/cert/${domain}/fullchain.pem"
local key_path="/root/cert/${domain}/privkey.pem"
if [[ -f "${cert_path}" && -f "${key_path}" ]]; then
echo -e "Domain: ${domain}"
echo -e "\tCertificate Path: ${cert_path}"
echo -e "\tPrivate Key Path: ${key_path}"
else
echo -e "Domain: ${domain} - Certificate or Key missing."
fi
done
fi
;;
5)
local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
if [ -z "$domains" ]; then
echo "No certificates found."
else
echo "Available domains:"
echo "$domains"
read -p "Please choose a domain to set the panel paths: " domain
if echo "$domains" | grep -qw "$domain"; then
local webCertFile="/root/cert/${domain}/fullchain.pem"
local webKeyFile="/root/cert/${domain}/privkey.pem"
if [[ -f "${webCertFile}" && -f "${webKeyFile}" ]]; then
/usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
echo "Panel paths set for domain: $domain"
echo " - Certificate File: $webCertFile"
echo " - Private Key File: $webKeyFile"
restart
else
echo "Certificate or private key not found for domain: $domain."
fi
else
echo "Invalid domain entered."
fi
fi
;;
*)
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 | armbian)
apt update && apt install socat -y
;;
centos | almalinux | rocky | oracle)
yum -y update && yum -y install socat
;;
fedora | amzn)
dnf -y update && dnf -y install socat
;;
arch | manjaro | parch)
pacman -Sy --noconfirm 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 to verify it
local domain=""
read -p "Please enter your domain name: " domain
LOGD "Your domain is: ${domain}, checking it..."
# check if there already exists a certificate
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 certificates for this domain. Cannot issue again. Current certificate details:"
LOGI "$certInfo"
exit 1
else
LOGI "Your domain is ready for issuing certificates now..."
fi
# create a directory for the certificate
certPath="/root/cert/${domain}"
if [ ! -d "$certPath" ]; then
mkdir -p "$certPath"
else
rm -rf "$certPath"
mkdir -p "$certPath"
fi
# get the port number for the standalone server
local WebPort=80
read -p "Please choose which port to use (default is 80): " WebPort
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
LOGE "Your input ${WebPort} is invalid, will use default port 80."
WebPort=80
fi
LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open."
# issue the certificate
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort}
if [ $? -ne 0 ]; then
LOGE "Issuing certificate failed, please check logs."
rm -rf ~/.acme.sh/${domain}
exit 1
else
LOGE "Issuing certificate succeeded, installing certificates..."
fi
# install the certificate
~/.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 "Installing certificate failed, exiting."
rm -rf ~/.acme.sh/${domain}
exit 1
else
LOGI "Installing certificate succeeded, enabling auto renew..."
fi
# enable auto-renew
~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then
LOGE "Auto renew failed, certificate details:"
ls -lah cert/*
chmod 755 $certPath/*
exit 1
else
LOGI "Auto renew succeeded, certificate details:"
ls -lah cert/*
chmod 755 $certPath/*
fi
# Prompt user to set panel paths after successful certificate installation
read -p "Would you like to set this certificate for the panel? (y/n): " setPanel
if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
local webCertFile="/root/cert/${domain}/fullchain.pem"
local webKeyFile="/root/cert/${domain}/privkey.pem"
if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
/usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
LOGI "Panel paths set for domain: $domain"
LOGI " - Certificate File: $webCertFile"
LOGI " - Private Key File: $webKeyFile"
restart
else
LOGE "Error: Certificate or private key file not found for domain: $domain."
fi
else
LOGI "Skipping panel path setting."
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
}
firewall_menu() {
echo -e "${green}\t1.${plain} Install Firewall & open ports"
echo -e "${green}\t2.${plain} Allowed List"
echo -e "${green}\t3.${plain} Delete Ports from List"
echo -e "${green}\t4.${plain} Disable Firewall"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
0)
show_menu
;;
1)
open_ports
;;
2)
sudo ufw status
;;
3)
delete_ports
;;
4)
sudo ufw disable
;;
*) echo "Invalid choice" ;;
esac
}
open_ports() {
if ! command -v ufw &>/dev/null; then
echo "ufw firewall is not installed. Installing now..."
apt-get update
apt-get install -y ufw
else
echo "ufw firewall is already installed"
fi
# Check if the firewall is inactive
if ufw status | grep -q "Status: active"; then
echo "firewall is already active"
else
# Open the necessary ports
ufw allow ssh
ufw allow http
ufw allow https
ufw allow 54321/tcp
# Enable the firewall
ufw --force enable
fi
# Prompt the user to enter a list of ports
read -p "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports
# Check if the input is valid
if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then
echo "Error: Invalid input. Please enter a comma-separated list of ports or a range of ports (e.g. 80,443,2053 or 400-500)." >&2
exit 1
fi
# Open the specified ports using ufw
IFS=',' read -ra PORT_LIST <<<"$ports"
for port in "${PORT_LIST[@]}"; do
if [[ $port == *-* ]]; then
# Split the range into start and end ports
start_port=$(echo $port | cut -d'-' -f1)
end_port=$(echo $port | cut -d'-' -f2)
# Loop through the range and open each port
for ((i = start_port; i <= end_port; i++)); do
ufw allow $i
done
else
ufw allow "$port"
fi
done
# Confirm that the ports are open
ufw status | grep $ports
}
delete_ports() {
# Prompt the user to enter the ports they want to delete
read -p "Enter the ports you want to delete (e.g. 80,443,2053 or range 400-500): " ports
# Check if the input is valid
if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then
echo "Error: Invalid input. Please enter a comma-separated list of ports or a range of ports (e.g. 80,443,2053 or 400-500)." >&2
exit 1
fi
# Delete the specified ports using ufw
IFS=',' read -ra PORT_LIST <<<"$ports"
for port in "${PORT_LIST[@]}"; do
if [[ $port == *-* ]]; then
# Split the range into start and end ports
start_port=$(echo $port | cut -d'-' -f1)
end_port=$(echo $port | cut -d'-' -f2)
# Loop through the range and delete each port
for ((i = start_port; i <= end_port; i++)); do
ufw delete allow $i
done
else
ufw delete allow "$port"
fi
done
# Confirm that the ports are deleted
echo "Deleted the specified ports:"
ufw status | grep $ports
}
bbr_menu() {
echo -e "${green}\t1.${plain} Enable BBR"
echo -e "${green}\t2.${plain} Disable BBR"
echo -e "${green}\t0.${plain} Back to Main Menu"
read -p "Choose an option: " choice
case "$choice" in
0)
show_menu
;;
1)
enable_bbr
;;
2)
disable_bbr
;;
*) echo "Invalid choice" ;;
esac
}
disable_bbr() {
if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${yellow}BBR is not currently enabled.${plain}"
exit 0
fi
# Replace BBR with CUBIC configurations
sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf
sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf
# Apply changes
sysctl -p
# Verify that BBR is replaced with CUBIC
if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then
echo -e "${green}BBR has been replaced with CUBIC successfully.${plain}"
else
echo -e "${red}Failed to replace BBR with CUBIC. Please check your system configuration.${plain}"
fi
}
enable_bbr() {
if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${green}BBR is already enabled!${plain}"
exit 0
fi
# Check the OS and install necessary packages
case "${release}" in
ubuntu | debian | armbian)
apt-get update && apt-get install -yqq --no-install-recommends ca-certificates
;;
centos | almalinux | rocky | oracle)
yum -y update && yum -y install ca-certificates
;;
fedora)
dnf -y update && dnf -y install ca-certificates
;;
arch | manjaro | parch)
pacman -Sy --noconfirm ca-certificates
;;
*)
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
exit 1
;;
esac
# Enable BBR
echo "net.core.default_qdisc=fq" | tee -a /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf
# Apply changes
sysctl -p
# Verify that BBR is enabled
if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then
echo -e "${green}BBR has been enabled successfully.${plain}"
else
echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}"
fi
}
update_geo() {
cd /usr/local/x-ui/bin
echo -e "${green}\t1.${plain} Update Geofiles [Recommended choice] "
echo -e "${green}\t2.${plain} Download from optional jsDelivr CDN "
echo -e "${green}\t0.${plain} Back To Main Menu "
read -p "Select: " select
case "$select" in
0)
show_menu
;;
1)
wget -N "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget -N "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" -O /tmp/wget && mv /tmp/wget geoip_IR.dat && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" -O /tmp/wget && mv /tmp/wget geosite_IR.dat && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
echo -e "${green}Files are updated.${plain}"
confirm_restart
;;
2)
wget -N "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat" && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget -N "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat" && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget "https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/geoip.dat" -O /tmp/wget && mv /tmp/wget geoip_IR.dat && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
wget "https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/geosite.dat" -O /tmp/wget && mv /tmp/wget geosite_IR.dat && echo -e "${green}Success${plain}\n" || echo -e "${red}Failure${plain}\n"
echo -e "${green}Files are updated.${plain}"
confirm_restart
;;
*)
LOGE "Please enter a correct number [0-2]\n"
update_geo
;;
esac
}
run_speedtest() {
# Check if Speedtest is already installed
if ! command -v speedtest &>/dev/null; then
# If not installed, install it
local pkg_manager=""
local speedtest_install_script=""
if command -v dnf &>/dev/null; then
pkg_manager="dnf"
speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
elif command -v yum &>/dev/null; then
pkg_manager="yum"
speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
elif command -v apt-get &>/dev/null; then
pkg_manager="apt-get"
speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
elif command -v apt &>/dev/null; then
pkg_manager="apt"
speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
fi
if [[ -z $pkg_manager ]]; then
echo "Error: Package manager not found. You may need to install Speedtest manually."
return 1
else
curl -s $speedtest_install_script | bash
$pkg_manager install -y speedtest
fi
fi
# Run Speedtest
speedtest
}
show_usage() {
echo "X-UI Control Menu Usage"
echo "------------------------------------------"
echo "SUBCOMMANDS:"
echo "x-ui - Admin Management Script"
echo "x-ui start - Start"
echo "x-ui stop - Stop"
echo "x-ui restart - Restart"
echo "x-ui status - Current Status"
echo "x-ui settings - Current Settings"
echo "x-ui enable - Enable Autostart on OS Startup"
echo "x-ui disable - Disable Autostart on OS Startup"
echo "x-ui log - Check Logs"
echo "x-ui update - Update"
echo "x-ui install - Install"
echo "x-ui uninstall - Uninstall"
echo "x-ui help - Control Menu Usage"
echo "------------------------------------------"
}
show_menu() {
echo -e "
${green}X-UI Admin Management Script ${plain}
————————————————
${green}0.${plain} Exit
————————————————
${green}1.${plain} Install
${green}2.${plain} Update
${green}3.${plain} Custom Version
${green}4.${plain} Uninstall
————————————————
${green}5.${plain} Reset Username and Password
${green}6.${plain} Reset Web Base Path
${green}7.${plain} Reset Panel Settings
${green}8.${plain} Set Panel Port
${green}9.${plain} View Panel Settings
————————————————
${green}10.${plain} Start
${green}11.${plain} Stop
${green}12.${plain} Restart
${green}13.${plain} Check State
${green}14.${plain} Check Logs
————————————————
${green}15.${plain} Enable Autostart
${green}16.${plain} Disable Autostart
————————————————
${green}17.${plain} SSL Certificate Management
${green}18.${plain} Cloudflare SSL Certificate
${green}19.${plain} Firewall Management
————————————————
${green}20.${plain} Enable or Disable BBR
${green}21.${plain} Update Geo Files
${green}22.${plain} Speedtest by Ookla
"
show_status
echo && read -p "Please enter your selection [0-21]: " num
case "${num}" in
0)
exit 0
;;
1)
check_uninstall && install
;;
2)
check_install && update
;;
3)
check_install && custom_version
;;
4)
check_install && uninstall
;;
5)
check_install && reset_user
;;
6)
check_install && reset_webbasepath
;;
7)
check_install && reset_config
;;
8)
check_install && set_port
;;
9)
check_install && check_config
;;
10)
check_install && start
;;
11)
check_install && stop
;;
12)
check_install && restart
;;
13)
check_install && status
;;
14)
check_install && show_log
;;
15)
check_install && enable
;;
16)
check_install && disable
;;
17)
ssl_cert_issue_main
;;
18)
ssl_cert_issue_CF
;;
19)
firewall_menu
;;
20)
bbr_menu
;;
21)
update_geo
;;
22)
run_speedtest
;;
*)
LOGE "Please enter the correct number [0-22]"
;;
esac
}
if [[ $# > 0 ]]; then
case $1 in
"start")
check_install 0 && start 0
;;
"stop")
check_install 0 && stop 0
;;
"restart")
check_install 0 && restart 0
;;
"status")
check_install 0 && status 0
;;
"settings")
check_install 0 && check_config 0
;;
"enable")
check_install 0 && enable 0
;;
"disable")
check_install 0 && disable 0
;;
"log")
check_install 0 && show_log 0
;;
"update")
check_install 0 && update 0
;;
"install")
check_uninstall 0 && install 0
;;
"uninstall")
check_install 0 && uninstall 0
;;
*) show_usage ;;
esac
else
show_menu
fi