├── install.sh
├── readme.md
└── x-ui.sh
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | red='\033[0;31m'
4 | green='\033[0;32m'
5 | blue='\033[0;34m'
6 | yellow='\033[0;33m'
7 | plain='\033[0m'
8 |
9 | cur_dir=$(pwd)
10 |
11 | # check root
12 | [[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1
13 |
14 | # Check OS and set release variable
15 | if [[ -f /etc/os-release ]]; then
16 | source /etc/os-release
17 | release=$ID
18 | elif [[ -f /usr/lib/os-release ]]; then
19 | source /usr/lib/os-release
20 | release=$ID
21 | else
22 | echo "Failed to check the system OS, please contact the author!" >&2
23 | exit 1
24 | fi
25 | echo "The OS release is: $release"
26 |
27 | arch() {
28 | case "$(uname -m)" in
29 | x86_64 | x64 | amd64) echo 'amd64' ;;
30 | i*86 | x86) echo '386' ;;
31 | armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
32 | armv7* | armv7 | arm) echo 'armv7' ;;
33 | armv6* | armv6) echo 'armv6' ;;
34 | armv5* | armv5) echo 'armv5' ;;
35 | s390x) echo 's390x' ;;
36 | *) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;;
37 | esac
38 | }
39 |
40 | echo "Arch: $(arch)"
41 |
42 | check_glibc_version() {
43 | glibc_version=$(ldd --version | head -n1 | awk '{print $NF}')
44 |
45 | required_version="2.15"
46 | if [[ "$(printf '%s\n' "$required_version" "$glibc_version" | sort -V | head -n1)" != "$required_version" ]]; then
47 | echo -e "${red}GLIBC version $glibc_version is too old! Required: 2.15 or higher${plain}"
48 | echo "Please upgrade to a newer version of your operating system to get a higher GLIBC version."
49 | exit 1
50 | fi
51 | echo "GLIBC version: $glibc_version (meets requirement of 2.15+)"
52 | }
53 | check_glibc_version
54 |
55 | install_base() {
56 | case "${release}" in
57 | ubuntu | debian | armbian)
58 | apt-get update && apt-get install -y -q wget curl tar tzdata
59 | ;;
60 | centos | almalinux | rocky | ol)
61 | yum -y update && yum install -y -q wget curl tar tzdata
62 | ;;
63 | fedora | amzn | virtuozzo)
64 | dnf -y update && dnf install -y -q wget curl tar tzdata
65 | ;;
66 | arch | manjaro | parch)
67 | pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata
68 | ;;
69 | opensuse-tumbleweed)
70 | zypper refresh && zypper -q install -y wget curl tar timezone
71 | ;;
72 | *)
73 | apt-get update && apt install -y -q wget curl tar tzdata
74 | ;;
75 | esac
76 | }
77 |
78 | gen_random_string() {
79 | local length="$1"
80 | local random_string=$(LC_ALL=C tr -dc 'a-zA-Z0-9' &2
34 | exit 1
35 | fi
36 | echo "The OS release is: $release"
37 |
38 | os_version=""
39 | os_version=$(grep "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.')
40 |
41 | # Declare Variables
42 | log_folder="${XUI_LOG_FOLDER:=/var/log}"
43 | iplimit_log_path="${log_folder}/3xipl.log"
44 | iplimit_banned_log_path="${log_folder}/3xipl-banned.log"
45 |
46 | confirm() {
47 | if [[ $# > 1 ]]; then
48 | echo && read -rp "$1 [Default $2]: " temp
49 | if [[ "${temp}" == "" ]]; then
50 | temp=$2
51 | fi
52 | else
53 | read -rp "$1 [y/n]: " temp
54 | fi
55 | if [[ "${temp}" == "y" || "${temp}" == "Y" ]]; then
56 | return 0
57 | else
58 | return 1
59 | fi
60 | }
61 |
62 | confirm_restart() {
63 | confirm "Restart the panel, Attention: Restarting the panel will also restart xray" "y"
64 | if [[ $? == 0 ]]; then
65 | restart
66 | else
67 | show_menu
68 | fi
69 | }
70 |
71 | before_show_menu() {
72 | echo && echo -n -e "${yellow}Press enter to return to the main menu: ${plain}" && read temp
73 | show_menu
74 | }
75 |
76 | install() {
77 | bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/install.sh)
78 | if [[ $? == 0 ]]; then
79 | if [[ $# == 0 ]]; then
80 | start
81 | else
82 | start 0
83 | fi
84 | fi
85 | }
86 |
87 | update() {
88 | confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "y"
89 | if [[ $? != 0 ]]; then
90 | LOGE "Cancelled"
91 | if [[ $# == 0 ]]; then
92 | before_show_menu
93 | fi
94 | return 0
95 | fi
96 | bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/install.sh)
97 | if [[ $? == 0 ]]; then
98 | LOGI "Update is complete, Panel has automatically restarted "
99 | before_show_menu
100 | fi
101 | }
102 |
103 | update_menu() {
104 | echo -e "${yellow}Updating Menu${plain}"
105 | confirm "This function will update the menu to the latest changes." "y"
106 | if [[ $? != 0 ]]; then
107 | LOGE "Cancelled"
108 | if [[ $# == 0 ]]; then
109 | before_show_menu
110 | fi
111 | return 0
112 | fi
113 |
114 | wget -O /usr/bin/x-ui https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/main/x-ui.sh
115 | chmod +x /usr/local/x-ui/x-ui.sh
116 | chmod +x /usr/bin/x-ui
117 |
118 | if [[ $? == 0 ]]; then
119 | echo -e "${green}Update successful. The panel has automatically restarted.${plain}"
120 | exit 0
121 | else
122 | echo -e "${red}Failed to update the menu.${plain}"
123 | return 1
124 | fi
125 | }
126 |
127 | legacy_version() {
128 | echo "Enter the panel version (like 2.4.0):"
129 | read tag_version
130 |
131 | if [ -z "$tag_version" ]; then
132 | echo "Panel version cannot be empty. Exiting."
133 | exit 1
134 | fi
135 | # Use the entered panel version in the download link
136 | install_command="bash <(curl -Ls "https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/v$tag_version/install.sh") v$tag_version"
137 |
138 | echo "Downloading and installing panel version $tag_version..."
139 | eval $install_command
140 | }
141 |
142 | # Function to handle the deletion of the script file
143 | delete_script() {
144 | rm "$0" # Remove the script file itself
145 | exit 1
146 | }
147 |
148 | uninstall() {
149 | confirm "Are you sure you want to uninstall the panel? xray will also uninstalled!" "n"
150 | if [[ $? != 0 ]]; then
151 | if [[ $# == 0 ]]; then
152 | show_menu
153 | fi
154 | return 0
155 | fi
156 | systemctl stop x-ui
157 | systemctl disable x-ui
158 | rm /etc/systemd/system/x-ui.service -f
159 | systemctl daemon-reload
160 | systemctl reset-failed
161 | rm /etc/x-ui/ -rf
162 | rm /usr/local/x-ui/ -rf
163 |
164 | echo ""
165 | echo -e "Uninstalled Successfully.\n"
166 | echo "If you need to install this panel again, you can use below command:"
167 | echo -e "${green}bash <(curl -Ls https://gh-proxy.com/https://raw.githubusercontent.com/GH6324/3xui-cn/master/install.sh)${plain}"
168 | echo ""
169 | # Trap the SIGTERM signal
170 | trap delete_script SIGTERM
171 | delete_script
172 | }
173 |
174 | reset_user() {
175 | confirm "Are you sure to reset the username and password of the panel?" "n"
176 | if [[ $? != 0 ]]; then
177 | if [[ $# == 0 ]]; then
178 | show_menu
179 | fi
180 | return 0
181 | fi
182 | read -rp "Please set the login username [default is a random username]: " config_account
183 | [[ -z $config_account ]] && config_account=$(date +%s%N | md5sum | cut -c 1-8)
184 | read -rp "Please set the login password [default is a random password]: " config_password
185 | [[ -z $config_password ]] && config_password=$(date +%s%N | md5sum | cut -c 1-8)
186 | /usr/local/x-ui/x-ui setting -username ${config_account} -password ${config_password} >/dev/null 2>&1
187 | /usr/local/x-ui/x-ui setting -remove_secret >/dev/null 2>&1
188 | echo -e "Panel login username has been reset to: ${green} ${config_account} ${plain}"
189 | echo -e "Panel login password has been reset to: ${green} ${config_password} ${plain}"
190 | echo -e "${yellow} Panel login secret token disabled ${plain}"
191 | echo -e "${green} Please use the new login username and password to access the X-UI panel. Also remember them! ${plain}"
192 | confirm_restart
193 | }
194 |
195 | gen_random_string() {
196 | local length="$1"
197 | local random_string=$(LC_ALL=C tr -dc 'a-zA-Z0-9' /dev/null 2>&1
214 |
215 | echo -e "Web base path has been reset to: ${green}${config_webBasePath}${plain}"
216 | echo -e "${green}Please use the new web base path to access the panel.${plain}"
217 | restart
218 | }
219 |
220 | reset_config() {
221 | confirm "Are you sure you want to reset all panel settings, Account data will not be lost, Username and password will not change" "n"
222 | if [[ $? != 0 ]]; then
223 | if [[ $# == 0 ]]; then
224 | show_menu
225 | fi
226 | return 0
227 | fi
228 | /usr/local/x-ui/x-ui setting -reset
229 | echo -e "All panel settings have been reset to default."
230 | restart
231 | }
232 |
233 | check_config() {
234 | local info=$(/usr/local/x-ui/x-ui setting -show true)
235 | if [[ $? != 0 ]]; then
236 | LOGE "get current settings error, please check logs"
237 | show_menu
238 | return
239 | fi
240 | LOGI "${info}"
241 |
242 | local existing_webBasePath=$(echo "$info" | grep -Eo 'webBasePath: .+' | awk '{print $2}')
243 | local existing_port=$(echo "$info" | grep -Eo 'port: .+' | awk '{print $2}')
244 | local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}')
245 | local server_ip=$(curl -s https://api.ipify.org)
246 |
247 | if [[ -n "$existing_cert" ]]; then
248 | local domain=$(basename "$(dirname "$existing_cert")")
249 |
250 | if [[ "$domain" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
251 | echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}"
252 | else
253 | echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}"
254 | fi
255 | else
256 | echo -e "${green}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}"
257 | fi
258 | }
259 |
260 | set_port() {
261 | echo && echo -n -e "Enter port number[1-65535]: " && read port
262 | if [[ -z "${port}" ]]; then
263 | LOGD "Cancelled"
264 | before_show_menu
265 | else
266 | /usr/local/x-ui/x-ui setting -port ${port}
267 | echo -e "The port is set, Please restart the panel now, and use the new port ${green}${port}${plain} to access web panel"
268 | confirm_restart
269 | fi
270 | }
271 |
272 | start() {
273 | check_status
274 | if [[ $? == 0 ]]; then
275 | echo ""
276 | LOGI "Panel is running, No need to start again, If you need to restart, please select restart"
277 | else
278 | systemctl start x-ui
279 | sleep 2
280 | check_status
281 | if [[ $? == 0 ]]; then
282 | LOGI "x-ui Started Successfully"
283 | else
284 | LOGE "panel Failed to start, Probably because it takes longer than two seconds to start, Please check the log information later"
285 | fi
286 | fi
287 |
288 | if [[ $# == 0 ]]; then
289 | before_show_menu
290 | fi
291 | }
292 |
293 | stop() {
294 | check_status
295 | if [[ $? == 1 ]]; then
296 | echo ""
297 | LOGI "Panel stopped, No need to stop again!"
298 | else
299 | systemctl stop x-ui
300 | sleep 2
301 | check_status
302 | if [[ $? == 1 ]]; then
303 | LOGI "x-ui and xray stopped successfully"
304 | else
305 | LOGE "Panel stop failed, Probably because the stop time exceeds two seconds, Please check the log information later"
306 | fi
307 | fi
308 |
309 | if [[ $# == 0 ]]; then
310 | before_show_menu
311 | fi
312 | }
313 |
314 | restart() {
315 | systemctl restart x-ui
316 | sleep 2
317 | check_status
318 | if [[ $? == 0 ]]; then
319 | LOGI "x-ui and xray Restarted successfully"
320 | else
321 | LOGE "Panel restart failed, Probably because it takes longer than two seconds to start, Please check the log information later"
322 | fi
323 | if [[ $# == 0 ]]; then
324 | before_show_menu
325 | fi
326 | }
327 |
328 | status() {
329 | systemctl status x-ui -l
330 | if [[ $# == 0 ]]; then
331 | before_show_menu
332 | fi
333 | }
334 |
335 | enable() {
336 | systemctl enable x-ui
337 | if [[ $? == 0 ]]; then
338 | LOGI "x-ui Set to boot automatically on startup successfully"
339 | else
340 | LOGE "x-ui Failed to set Autostart"
341 | fi
342 |
343 | if [[ $# == 0 ]]; then
344 | before_show_menu
345 | fi
346 | }
347 |
348 | disable() {
349 | systemctl disable x-ui
350 | if [[ $? == 0 ]]; then
351 | LOGI "x-ui Autostart Cancelled successfully"
352 | else
353 | LOGE "x-ui Failed to cancel autostart"
354 | fi
355 |
356 | if [[ $# == 0 ]]; then
357 | before_show_menu
358 | fi
359 | }
360 |
361 | show_log() {
362 | echo -e "${green}\t1.${plain} Debug Log"
363 | echo -e "${green}\t2.${plain} Clear All logs"
364 | echo -e "${green}\t0.${plain} Back to Main Menu"
365 | read -rp "Choose an option: " choice
366 |
367 | case "$choice" in
368 | 0)
369 | show_menu
370 | ;;
371 | 1)
372 | journalctl -u x-ui -e --no-pager -f -p debug
373 | if [[ $# == 0 ]]; then
374 | before_show_menu
375 | fi
376 | ;;
377 | 2)
378 | sudo journalctl --rotate
379 | sudo journalctl --vacuum-time=1s
380 | echo "All Logs cleared."
381 | restart
382 | ;;
383 | *)
384 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
385 | show_log
386 | ;;
387 | esac
388 | }
389 |
390 | show_banlog() {
391 | local system_log="/var/log/fail2ban.log"
392 |
393 | echo -e "${green}Checking ban logs...${plain}\n"
394 |
395 | if ! systemctl is-active --quiet fail2ban; then
396 | echo -e "${red}Fail2ban service is not running!${plain}\n"
397 | return 1
398 | fi
399 |
400 | if [[ -f "$system_log" ]]; then
401 | echo -e "${green}Recent system ban activities from fail2ban.log:${plain}"
402 | grep "3x-ipl" "$system_log" | grep -E "Ban|Unban" | tail -n 10 || echo -e "${yellow}No recent system ban activities found${plain}"
403 | echo ""
404 | fi
405 |
406 | if [[ -f "${iplimit_banned_log_path}" ]]; then
407 | echo -e "${green}3X-IPL ban log entries:${plain}"
408 | if [[ -s "${iplimit_banned_log_path}" ]]; then
409 | grep -v "INIT" "${iplimit_banned_log_path}" | tail -n 10 || echo -e "${yellow}No ban entries found${plain}"
410 | else
411 | echo -e "${yellow}Ban log file is empty${plain}"
412 | fi
413 | else
414 | echo -e "${red}Ban log file not found at: ${iplimit_banned_log_path}${plain}"
415 | fi
416 |
417 | echo -e "\n${green}Current jail status:${plain}"
418 | fail2ban-client status 3x-ipl || echo -e "${yellow}Unable to get jail status${plain}"
419 | }
420 |
421 | bbr_menu() {
422 | echo -e "${green}\t1.${plain} Enable BBR"
423 | echo -e "${green}\t2.${plain} Disable BBR"
424 | echo -e "${green}\t0.${plain} Back to Main Menu"
425 | read -rp "Choose an option: " choice
426 | case "$choice" in
427 | 0)
428 | show_menu
429 | ;;
430 | 1)
431 | enable_bbr
432 | bbr_menu
433 | ;;
434 | 2)
435 | disable_bbr
436 | bbr_menu
437 | ;;
438 | *)
439 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
440 | bbr_menu
441 | ;;
442 | esac
443 | }
444 |
445 | disable_bbr() {
446 |
447 | if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
448 | echo -e "${yellow}BBR is not currently enabled.${plain}"
449 | before_show_menu
450 | fi
451 |
452 | # Replace BBR with CUBIC configurations
453 | sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf
454 | sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf
455 |
456 | # Apply changes
457 | sysctl -p
458 |
459 | # Verify that BBR is replaced with CUBIC
460 | if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then
461 | echo -e "${green}BBR has been replaced with CUBIC successfully.${plain}"
462 | else
463 | echo -e "${red}Failed to replace BBR with CUBIC. Please check your system configuration.${plain}"
464 | fi
465 | }
466 |
467 | enable_bbr() {
468 | if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
469 | echo -e "${green}BBR is already enabled!${plain}"
470 | before_show_menu
471 | fi
472 |
473 | # Check the OS and install necessary packages
474 | case "${release}" in
475 | ubuntu | debian | armbian)
476 | apt-get update && apt-get install -yqq --no-install-recommends ca-certificates
477 | ;;
478 | centos | almalinux | rocky | ol)
479 | yum -y update && yum -y install ca-certificates
480 | ;;
481 | fedora | amzn | virtuozzo)
482 | dnf -y update && dnf -y install ca-certificates
483 | ;;
484 | arch | manjaro | parch)
485 | pacman -Sy --noconfirm ca-certificates
486 | ;;
487 | *)
488 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
489 | exit 1
490 | ;;
491 | esac
492 |
493 | # Enable BBR
494 | echo "net.core.default_qdisc=fq" | tee -a /etc/sysctl.conf
495 | echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf
496 |
497 | # Apply changes
498 | sysctl -p
499 |
500 | # Verify that BBR is enabled
501 | if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then
502 | echo -e "${green}BBR has been enabled successfully.${plain}"
503 | else
504 | echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}"
505 | fi
506 | }
507 |
508 | update_shell() {
509 | wget -O /usr/bin/x-ui -N https://gh-proxy.com/https://github.com/GH6324/3xui-cn/raw/main/x-ui.sh
510 | if [[ $? != 0 ]]; then
511 | echo ""
512 | LOGE "Failed to download script, Please check whether the machine can connect Github"
513 | before_show_menu
514 | else
515 | chmod +x /usr/bin/x-ui
516 | LOGI "Upgrade script succeeded, Please rerun the script"
517 | before_show_menu
518 | fi
519 | }
520 |
521 | # 0: running, 1: not running, 2: not installed
522 | check_status() {
523 | if [[ ! -f /etc/systemd/system/x-ui.service ]]; then
524 | return 2
525 | fi
526 | temp=$(systemctl status x-ui | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1)
527 | if [[ "${temp}" == "running" ]]; then
528 | return 0
529 | else
530 | return 1
531 | fi
532 | }
533 |
534 | check_enabled() {
535 | temp=$(systemctl is-enabled x-ui)
536 | if [[ "${temp}" == "enabled" ]]; then
537 | return 0
538 | else
539 | return 1
540 | fi
541 | }
542 |
543 | check_uninstall() {
544 | check_status
545 | if [[ $? != 2 ]]; then
546 | echo ""
547 | LOGE "Panel installed, Please do not reinstall"
548 | if [[ $# == 0 ]]; then
549 | before_show_menu
550 | fi
551 | return 1
552 | else
553 | return 0
554 | fi
555 | }
556 |
557 | check_install() {
558 | check_status
559 | if [[ $? == 2 ]]; then
560 | echo ""
561 | LOGE "Please install the panel first"
562 | if [[ $# == 0 ]]; then
563 | before_show_menu
564 | fi
565 | return 1
566 | else
567 | return 0
568 | fi
569 | }
570 |
571 | show_status() {
572 | check_status
573 | case $? in
574 | 0)
575 | echo -e "Panel state: ${green}Running${plain}"
576 | show_enable_status
577 | ;;
578 | 1)
579 | echo -e "Panel state: ${yellow}Not Running${plain}"
580 | show_enable_status
581 | ;;
582 | 2)
583 | echo -e "Panel state: ${red}Not Installed${plain}"
584 | ;;
585 | esac
586 | show_xray_status
587 | }
588 |
589 | show_enable_status() {
590 | check_enabled
591 | if [[ $? == 0 ]]; then
592 | echo -e "Start automatically: ${green}Yes${plain}"
593 | else
594 | echo -e "Start automatically: ${red}No${plain}"
595 | fi
596 | }
597 |
598 | check_xray_status() {
599 | count=$(ps -ef | grep "xray-linux" | grep -v "grep" | wc -l)
600 | if [[ count -ne 0 ]]; then
601 | return 0
602 | else
603 | return 1
604 | fi
605 | }
606 |
607 | show_xray_status() {
608 | check_xray_status
609 | if [[ $? == 0 ]]; then
610 | echo -e "xray state: ${green}Running${plain}"
611 | else
612 | echo -e "xray state: ${red}Not Running${plain}"
613 | fi
614 | }
615 |
616 | firewall_menu() {
617 | echo -e "${green}\t1.${plain} ${green}Install${plain} Firewall"
618 | echo -e "${green}\t2.${plain} Port List [numbered]"
619 | echo -e "${green}\t3.${plain} ${green}Open${plain} Ports"
620 | echo -e "${green}\t4.${plain} ${red}Delete${plain} Ports from List"
621 | echo -e "${green}\t5.${plain} ${green}Enable${plain} Firewall"
622 | echo -e "${green}\t6.${plain} ${red}Disable${plain} Firewall"
623 | echo -e "${green}\t7.${plain} Firewall Status"
624 | echo -e "${green}\t0.${plain} Back to Main Menu"
625 | read -rp "Choose an option: " choice
626 | case "$choice" in
627 | 0)
628 | show_menu
629 | ;;
630 | 1)
631 | install_firewall
632 | firewall_menu
633 | ;;
634 | 2)
635 | ufw status numbered
636 | firewall_menu
637 | ;;
638 | 3)
639 | open_ports
640 | firewall_menu
641 | ;;
642 | 4)
643 | delete_ports
644 | firewall_menu
645 | ;;
646 | 5)
647 | ufw enable
648 | firewall_menu
649 | ;;
650 | 6)
651 | ufw disable
652 | firewall_menu
653 | ;;
654 | 7)
655 | ufw status verbose
656 | firewall_menu
657 | ;;
658 | *)
659 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
660 | firewall_menu
661 | ;;
662 | esac
663 | }
664 |
665 | install_firewall() {
666 | if ! command -v ufw &>/dev/null; then
667 | echo "ufw firewall is not installed. Installing now..."
668 | apt-get update
669 | apt-get install -y ufw
670 | else
671 | echo "ufw firewall is already installed"
672 | fi
673 |
674 | # Check if the firewall is inactive
675 | if ufw status | grep -q "Status: active"; then
676 | echo "Firewall is already active"
677 | else
678 | echo "Activating firewall..."
679 | # Open the necessary ports
680 | ufw allow ssh
681 | ufw allow http
682 | ufw allow https
683 | ufw allow 2053/tcp #webPort
684 | ufw allow 2096/tcp #subport
685 |
686 | # Enable the firewall
687 | ufw --force enable
688 | fi
689 | }
690 |
691 | open_ports() {
692 | # Prompt the user to enter the ports they want to open
693 | read -rp "Enter the ports you want to open (e.g. 80,443,2053 or range 400-500): " ports
694 |
695 | # Check if the input is valid
696 | if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then
697 | 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
698 | exit 1
699 | fi
700 |
701 | # Open the specified ports using ufw
702 | IFS=',' read -ra PORT_LIST <<<"$ports"
703 | for port in "${PORT_LIST[@]}"; do
704 | if [[ $port == *-* ]]; then
705 | # Split the range into start and end ports
706 | start_port=$(echo $port | cut -d'-' -f1)
707 | end_port=$(echo $port | cut -d'-' -f2)
708 | # Open the port range
709 | ufw allow $start_port:$end_port/tcp
710 | ufw allow $start_port:$end_port/udp
711 | else
712 | # Open the single port
713 | ufw allow "$port"
714 | fi
715 | done
716 |
717 | # Confirm that the ports are opened
718 | echo "Opened the specified ports:"
719 | for port in "${PORT_LIST[@]}"; do
720 | if [[ $port == *-* ]]; then
721 | start_port=$(echo $port | cut -d'-' -f1)
722 | end_port=$(echo $port | cut -d'-' -f2)
723 | # Check if the port range has been successfully opened
724 | (ufw status | grep -q "$start_port:$end_port") && echo "$start_port-$end_port"
725 | else
726 | # Check if the individual port has been successfully opened
727 | (ufw status | grep -q "$port") && echo "$port"
728 | fi
729 | done
730 | }
731 |
732 | delete_ports() {
733 | # Display current rules with numbers
734 | echo "Current UFW rules:"
735 | ufw status numbered
736 |
737 | # Ask the user how they want to delete rules
738 | echo "Do you want to delete rules by:"
739 | echo "1) Rule numbers"
740 | echo "2) Ports"
741 | read -rp "Enter your choice (1 or 2): " choice
742 |
743 | if [[ $choice -eq 1 ]]; then
744 | # Deleting by rule numbers
745 | read -rp "Enter the rule numbers you want to delete (1, 2, etc.): " rule_numbers
746 |
747 | # Validate the input
748 | if ! [[ $rule_numbers =~ ^([0-9]+)(,[0-9]+)*$ ]]; then
749 | echo "Error: Invalid input. Please enter a comma-separated list of rule numbers." >&2
750 | exit 1
751 | fi
752 |
753 | # Split numbers into an array
754 | IFS=',' read -ra RULE_NUMBERS <<<"$rule_numbers"
755 | for rule_number in "${RULE_NUMBERS[@]}"; do
756 | # Delete the rule by number
757 | ufw delete "$rule_number" || echo "Failed to delete rule number $rule_number"
758 | done
759 |
760 | echo "Selected rules have been deleted."
761 |
762 | elif [[ $choice -eq 2 ]]; then
763 | # Deleting by ports
764 | read -rp "Enter the ports you want to delete (e.g. 80,443,2053 or range 400-500): " ports
765 |
766 | # Validate the input
767 | if ! [[ $ports =~ ^([0-9]+|[0-9]+-[0-9]+)(,([0-9]+|[0-9]+-[0-9]+))*$ ]]; then
768 | 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
769 | exit 1
770 | fi
771 |
772 | # Split ports into an array
773 | IFS=',' read -ra PORT_LIST <<<"$ports"
774 | for port in "${PORT_LIST[@]}"; do
775 | if [[ $port == *-* ]]; then
776 | # Split the port range
777 | start_port=$(echo $port | cut -d'-' -f1)
778 | end_port=$(echo $port | cut -d'-' -f2)
779 | # Delete the port range
780 | ufw delete allow $start_port:$end_port/tcp
781 | ufw delete allow $start_port:$end_port/udp
782 | else
783 | # Delete a single port
784 | ufw delete allow "$port"
785 | fi
786 | done
787 |
788 | # Confirmation of deletion
789 | echo "Deleted the specified ports:"
790 | for port in "${PORT_LIST[@]}"; do
791 | if [[ $port == *-* ]]; then
792 | start_port=$(echo $port | cut -d'-' -f1)
793 | end_port=$(echo $port | cut -d'-' -f2)
794 | # Check if the port range has been deleted
795 | (ufw status | grep -q "$start_port:$end_port") || echo "$start_port-$end_port"
796 | else
797 | # Check if the individual port has been deleted
798 | (ufw status | grep -q "$port") || echo "$port"
799 | fi
800 | done
801 | else
802 | echo "${red}Error:${plain} Invalid choice. Please enter 1 or 2." >&2
803 | exit 1
804 | fi
805 | }
806 |
807 | update_geo() {
808 | echo -e "${green}\t1.${plain} Loyalsoldier (geoip.dat, geosite.dat)"
809 | echo -e "${green}\t2.${plain} chocolate4u (geoip_IR.dat, geosite_IR.dat)"
810 | echo -e "${green}\t3.${plain} runetfreedom (geoip_RU.dat, geosite_RU.dat)"
811 | echo -e "${green}\t0.${plain} Back to Main Menu"
812 | read -rp "Choose an option: " choice
813 |
814 | cd /usr/local/x-ui/bin
815 |
816 | case "$choice" in
817 | 0)
818 | show_menu
819 | ;;
820 | 1)
821 | systemctl stop x-ui
822 | rm -f geoip.dat geosite.dat
823 | wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat
824 | wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat
825 | echo -e "${green}Loyalsoldier datasets have been updated successfully!${plain}"
826 | restart
827 | ;;
828 | 2)
829 | systemctl stop x-ui
830 | rm -f geoip_IR.dat geosite_IR.dat
831 | wget -O geoip_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat
832 | wget -O geosite_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
833 | echo -e "${green}chocolate4u datasets have been updated successfully!${plain}"
834 | restart
835 | ;;
836 | 3)
837 | systemctl stop x-ui
838 | rm -f geoip_RU.dat geosite_RU.dat
839 | wget -O geoip_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat
840 | wget -O geosite_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat
841 | echo -e "${green}runetfreedom datasets have been updated successfully!${plain}"
842 | restart
843 | ;;
844 | *)
845 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
846 | update_geo
847 | ;;
848 | esac
849 |
850 | before_show_menu
851 | }
852 |
853 | install_acme() {
854 | # Check if acme.sh is already installed
855 | if command -v ~/.acme.sh/acme.sh &>/dev/null; then
856 | LOGI "acme.sh is already installed."
857 | return 0
858 | fi
859 |
860 | LOGI "Installing acme.sh..."
861 | cd ~ || return 1 # Ensure you can change to the home directory
862 |
863 | curl -s https://get.acme.sh | sh
864 | if [ $? -ne 0 ]; then
865 | LOGE "Installation of acme.sh failed."
866 | return 1
867 | else
868 | LOGI "Installation of acme.sh succeeded."
869 | fi
870 |
871 | return 0
872 | }
873 |
874 | ssl_cert_issue_main() {
875 | echo -e "${green}\t1.${plain} Get SSL"
876 | echo -e "${green}\t2.${plain} Revoke"
877 | echo -e "${green}\t3.${plain} Force Renew"
878 | echo -e "${green}\t4.${plain} Show Existing Domains"
879 | echo -e "${green}\t5.${plain} Set Cert paths for the panel"
880 | echo -e "${green}\t0.${plain} Back to Main Menu"
881 |
882 | read -rp "Choose an option: " choice
883 | case "$choice" in
884 | 0)
885 | show_menu
886 | ;;
887 | 1)
888 | ssl_cert_issue
889 | ssl_cert_issue_main
890 | ;;
891 | 2)
892 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
893 | if [ -z "$domains" ]; then
894 | echo "No certificates found to revoke."
895 | else
896 | echo "Existing domains:"
897 | echo "$domains"
898 | read -rp "Please enter a domain from the list to revoke the certificate: " domain
899 | if echo "$domains" | grep -qw "$domain"; then
900 | ~/.acme.sh/acme.sh --revoke -d ${domain}
901 | LOGI "Certificate revoked for domain: $domain"
902 | else
903 | echo "Invalid domain entered."
904 | fi
905 | fi
906 | ssl_cert_issue_main
907 | ;;
908 | 3)
909 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
910 | if [ -z "$domains" ]; then
911 | echo "No certificates found to renew."
912 | else
913 | echo "Existing domains:"
914 | echo "$domains"
915 | read -rp "Please enter a domain from the list to renew the SSL certificate: " domain
916 | if echo "$domains" | grep -qw "$domain"; then
917 | ~/.acme.sh/acme.sh --renew -d ${domain} --force
918 | LOGI "Certificate forcefully renewed for domain: $domain"
919 | else
920 | echo "Invalid domain entered."
921 | fi
922 | fi
923 | ssl_cert_issue_main
924 | ;;
925 | 4)
926 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
927 | if [ -z "$domains" ]; then
928 | echo "No certificates found."
929 | else
930 | echo "Existing domains and their paths:"
931 | for domain in $domains; do
932 | local cert_path="/root/cert/${domain}/fullchain.pem"
933 | local key_path="/root/cert/${domain}/privkey.pem"
934 | if [[ -f "${cert_path}" && -f "${key_path}" ]]; then
935 | echo -e "Domain: ${domain}"
936 | echo -e "\tCertificate Path: ${cert_path}"
937 | echo -e "\tPrivate Key Path: ${key_path}"
938 | else
939 | echo -e "Domain: ${domain} - Certificate or Key missing."
940 | fi
941 | done
942 | fi
943 | ssl_cert_issue_main
944 | ;;
945 | 5)
946 | local domains=$(find /root/cert/ -mindepth 1 -maxdepth 1 -type d -exec basename {} \;)
947 | if [ -z "$domains" ]; then
948 | echo "No certificates found."
949 | else
950 | echo "Available domains:"
951 | echo "$domains"
952 | read -rp "Please choose a domain to set the panel paths: " domain
953 |
954 | if echo "$domains" | grep -qw "$domain"; then
955 | local webCertFile="/root/cert/${domain}/fullchain.pem"
956 | local webKeyFile="/root/cert/${domain}/privkey.pem"
957 |
958 | if [[ -f "${webCertFile}" && -f "${webKeyFile}" ]]; then
959 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
960 | echo "Panel paths set for domain: $domain"
961 | echo " - Certificate File: $webCertFile"
962 | echo " - Private Key File: $webKeyFile"
963 | restart
964 | else
965 | echo "Certificate or private key not found for domain: $domain."
966 | fi
967 | else
968 | echo "Invalid domain entered."
969 | fi
970 | fi
971 | ssl_cert_issue_main
972 | ;;
973 |
974 | *)
975 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
976 | ssl_cert_issue_main
977 | ;;
978 | esac
979 | }
980 |
981 | ssl_cert_issue() {
982 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
983 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
984 | # check for acme.sh first
985 | if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
986 | echo "acme.sh could not be found. we will install it"
987 | install_acme
988 | if [ $? -ne 0 ]; then
989 | LOGE "install acme failed, please check logs"
990 | exit 1
991 | fi
992 | fi
993 |
994 | # install socat second
995 | case "${release}" in
996 | ubuntu | debian | armbian)
997 | apt update && apt install socat -y
998 | ;;
999 | centos | almalinux | rocky | ol)
1000 | yum -y update && yum -y install socat
1001 | ;;
1002 | fedora | amzn | virtuozzo)
1003 | dnf -y update && dnf -y install socat
1004 | ;;
1005 | arch | manjaro | parch)
1006 | pacman -Sy --noconfirm socat
1007 | ;;
1008 | *)
1009 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
1010 | exit 1
1011 | ;;
1012 | esac
1013 | if [ $? -ne 0 ]; then
1014 | LOGE "install socat failed, please check logs"
1015 | exit 1
1016 | else
1017 | LOGI "install socat succeed..."
1018 | fi
1019 |
1020 | # get the domain here, and we need to verify it
1021 | local domain=""
1022 | read -rp "Please enter your domain name: " domain
1023 | LOGD "Your domain is: ${domain}, checking it..."
1024 |
1025 | # check if there already exists a certificate
1026 | local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
1027 | if [ "${currentCert}" == "${domain}" ]; then
1028 | local certInfo=$(~/.acme.sh/acme.sh --list)
1029 | LOGE "System already has certificates for this domain. Cannot issue again. Current certificate details:"
1030 | LOGI "$certInfo"
1031 | exit 1
1032 | else
1033 | LOGI "Your domain is ready for issuing certificates now..."
1034 | fi
1035 |
1036 | # create a directory for the certificate
1037 | certPath="/root/cert/${domain}"
1038 | if [ ! -d "$certPath" ]; then
1039 | mkdir -p "$certPath"
1040 | else
1041 | rm -rf "$certPath"
1042 | mkdir -p "$certPath"
1043 | fi
1044 |
1045 | # get the port number for the standalone server
1046 | local WebPort=80
1047 | read -rp "Please choose which port to use (default is 80): " WebPort
1048 | if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
1049 | LOGE "Your input ${WebPort} is invalid, will use default port 80."
1050 | WebPort=80
1051 | fi
1052 | LOGI "Will use port: ${WebPort} to issue certificates. Please make sure this port is open."
1053 |
1054 | # issue the certificate
1055 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
1056 | ~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport ${WebPort} --force
1057 | if [ $? -ne 0 ]; then
1058 | LOGE "Issuing certificate failed, please check logs."
1059 | rm -rf ~/.acme.sh/${domain}
1060 | exit 1
1061 | else
1062 | LOGE "Issuing certificate succeeded, installing certificates..."
1063 | fi
1064 |
1065 | reloadCmd="x-ui restart"
1066 |
1067 | LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart"
1068 | LOGI "This command will run on every certificate issue and renew."
1069 | read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd
1070 | if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then
1071 | echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart"
1072 | echo -e "${green}\t2.${plain} Input your own command"
1073 | echo -e "${green}\t0.${plain} Keep default reloadcmd"
1074 | read -rp "Choose an option: " choice
1075 | case "$choice" in
1076 | 1)
1077 | LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart"
1078 | reloadCmd="systemctl reload nginx ; x-ui restart"
1079 | ;;
1080 | 2)
1081 | LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails"
1082 | read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd
1083 | LOGI "Your reloadcmd is: ${reloadCmd}"
1084 | ;;
1085 | *)
1086 | LOGI "Keep default reloadcmd"
1087 | ;;
1088 | esac
1089 | fi
1090 |
1091 | # install the certificate
1092 | ~/.acme.sh/acme.sh --installcert -d ${domain} \
1093 | --key-file /root/cert/${domain}/privkey.pem \
1094 | --fullchain-file /root/cert/${domain}/fullchain.pem --reloadcmd "${reloadCmd}"
1095 |
1096 | if [ $? -ne 0 ]; then
1097 | LOGE "Installing certificate failed, exiting."
1098 | rm -rf ~/.acme.sh/${domain}
1099 | exit 1
1100 | else
1101 | LOGI "Installing certificate succeeded, enabling auto renew..."
1102 | fi
1103 |
1104 | # enable auto-renew
1105 | ~/.acme.sh/acme.sh --upgrade --auto-upgrade
1106 | if [ $? -ne 0 ]; then
1107 | LOGE "Auto renew failed, certificate details:"
1108 | ls -lah cert/*
1109 | chmod 755 $certPath/*
1110 | exit 1
1111 | else
1112 | LOGI "Auto renew succeeded, certificate details:"
1113 | ls -lah cert/*
1114 | chmod 755 $certPath/*
1115 | fi
1116 |
1117 | # Prompt user to set panel paths after successful certificate installation
1118 | read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel
1119 | if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
1120 | local webCertFile="/root/cert/${domain}/fullchain.pem"
1121 | local webKeyFile="/root/cert/${domain}/privkey.pem"
1122 |
1123 | if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
1124 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
1125 | LOGI "Panel paths set for domain: $domain"
1126 | LOGI " - Certificate File: $webCertFile"
1127 | LOGI " - Private Key File: $webKeyFile"
1128 | echo -e "${green}Access URL: https://${domain}:${existing_port}${existing_webBasePath}${plain}"
1129 | restart
1130 | else
1131 | LOGE "Error: Certificate or private key file not found for domain: $domain."
1132 | fi
1133 | else
1134 | LOGI "Skipping panel path setting."
1135 | fi
1136 | }
1137 |
1138 | ssl_cert_issue_CF() {
1139 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
1140 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
1141 | LOGI "****** Instructions for Use ******"
1142 | LOGI "Follow the steps below to complete the process:"
1143 | LOGI "1. Cloudflare Registered E-mail."
1144 | LOGI "2. Cloudflare Global API Key."
1145 | LOGI "3. The Domain Name."
1146 | LOGI "4. Once the certificate is issued, you will be prompted to set the certificate for the panel (optional)."
1147 | LOGI "5. The script also supports automatic renewal of the SSL certificate after installation."
1148 |
1149 | confirm "Do you confirm the information and wish to proceed? [y/n]" "y"
1150 |
1151 | if [ $? -eq 0 ]; then
1152 | # Check for acme.sh first
1153 | if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
1154 | echo "acme.sh could not be found. We will install it."
1155 | install_acme
1156 | if [ $? -ne 0 ]; then
1157 | LOGE "Install acme failed, please check logs."
1158 | exit 1
1159 | fi
1160 | fi
1161 |
1162 | CF_Domain=""
1163 |
1164 | LOGD "Please set a domain name:"
1165 | read -rp "Input your domain here: " CF_Domain
1166 | LOGD "Your domain name is set to: ${CF_Domain}"
1167 |
1168 | # Set up Cloudflare API details
1169 | CF_GlobalKey=""
1170 | CF_AccountEmail=""
1171 | LOGD "Please set the API key:"
1172 | read -rp "Input your key here: " CF_GlobalKey
1173 | LOGD "Your API key is: ${CF_GlobalKey}"
1174 |
1175 | LOGD "Please set up registered email:"
1176 | read -rp "Input your email here: " CF_AccountEmail
1177 | LOGD "Your registered email address is: ${CF_AccountEmail}"
1178 |
1179 | # Set the default CA to Let's Encrypt
1180 | ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
1181 | if [ $? -ne 0 ]; then
1182 | LOGE "Default CA, Let'sEncrypt fail, script exiting..."
1183 | exit 1
1184 | fi
1185 |
1186 | export CF_Key="${CF_GlobalKey}"
1187 | export CF_Email="${CF_AccountEmail}"
1188 |
1189 | # Issue the certificate using Cloudflare DNS
1190 | ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} --log --force
1191 | if [ $? -ne 0 ]; then
1192 | LOGE "Certificate issuance failed, script exiting..."
1193 | exit 1
1194 | else
1195 | LOGI "Certificate issued successfully, Installing..."
1196 | fi
1197 |
1198 | # Install the certificate
1199 | certPath="/root/cert/${CF_Domain}"
1200 | if [ -d "$certPath" ]; then
1201 | rm -rf ${certPath}
1202 | fi
1203 |
1204 | mkdir -p ${certPath}
1205 | if [ $? -ne 0 ]; then
1206 | LOGE "Failed to create directory: ${certPath}"
1207 | exit 1
1208 | fi
1209 |
1210 | reloadCmd="x-ui restart"
1211 |
1212 | LOGI "Default --reloadcmd for ACME is: ${yellow}x-ui restart"
1213 | LOGI "This command will run on every certificate issue and renew."
1214 | read -rp "Would you like to modify --reloadcmd for ACME? (y/n): " setReloadcmd
1215 | if [[ "$setReloadcmd" == "y" || "$setReloadcmd" == "Y" ]]; then
1216 | echo -e "\n${green}\t1.${plain} Preset: systemctl reload nginx ; x-ui restart"
1217 | echo -e "${green}\t2.${plain} Input your own command"
1218 | echo -e "${green}\t0.${plain} Keep default reloadcmd"
1219 | read -rp "Choose an option: " choice
1220 | case "$choice" in
1221 | 1)
1222 | LOGI "Reloadcmd is: systemctl reload nginx ; x-ui restart"
1223 | reloadCmd="systemctl reload nginx ; x-ui restart"
1224 | ;;
1225 | 2)
1226 | LOGD "It's recommended to put x-ui restart at the end, so it won't raise an error if other services fails"
1227 | read -rp "Please enter your reloadcmd (example: systemctl reload nginx ; x-ui restart): " reloadCmd
1228 | LOGI "Your reloadcmd is: ${reloadCmd}"
1229 | ;;
1230 | *)
1231 | LOGI "Keep default reloadcmd"
1232 | ;;
1233 | esac
1234 | fi
1235 | ~/.acme.sh/acme.sh --installcert -d ${CF_Domain} -d *.${CF_Domain} \
1236 | --key-file ${certPath}/privkey.pem \
1237 | --fullchain-file ${certPath}/fullchain.pem --reloadcmd "${reloadCmd}"
1238 |
1239 | if [ $? -ne 0 ]; then
1240 | LOGE "Certificate installation failed, script exiting..."
1241 | exit 1
1242 | else
1243 | LOGI "Certificate installed successfully, Turning on automatic updates..."
1244 | fi
1245 |
1246 | # Enable auto-update
1247 | ~/.acme.sh/acme.sh --upgrade --auto-upgrade
1248 | if [ $? -ne 0 ]; then
1249 | LOGE "Auto update setup failed, script exiting..."
1250 | exit 1
1251 | else
1252 | LOGI "The certificate is installed and auto-renewal is turned on. Specific information is as follows:"
1253 | ls -lah ${certPath}/*
1254 | chmod 755 ${certPath}/*
1255 | fi
1256 |
1257 | # Prompt user to set panel paths after successful certificate installation
1258 | read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel
1259 | if [[ "$setPanel" == "y" || "$setPanel" == "Y" ]]; then
1260 | local webCertFile="${certPath}/fullchain.pem"
1261 | local webKeyFile="${certPath}/privkey.pem"
1262 |
1263 | if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
1264 | /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile"
1265 | LOGI "Panel paths set for domain: $CF_Domain"
1266 | LOGI " - Certificate File: $webCertFile"
1267 | LOGI " - Private Key File: $webKeyFile"
1268 | echo -e "${green}Access URL: https://${CF_Domain}:${existing_port}${existing_webBasePath}${plain}"
1269 | restart
1270 | else
1271 | LOGE "Error: Certificate or private key file not found for domain: $CF_Domain."
1272 | fi
1273 | else
1274 | LOGI "Skipping panel path setting."
1275 | fi
1276 | else
1277 | show_menu
1278 | fi
1279 | }
1280 |
1281 | run_speedtest() {
1282 | # Check if Speedtest is already installed
1283 | if ! command -v speedtest &>/dev/null; then
1284 | # If not installed, determine installation method
1285 | if command -v snap &>/dev/null; then
1286 | # Use snap to install Speedtest
1287 | echo "Installing Speedtest using snap..."
1288 | snap install speedtest
1289 | else
1290 | # Fallback to using package managers
1291 | local pkg_manager=""
1292 | local speedtest_install_script=""
1293 |
1294 | if command -v dnf &>/dev/null; then
1295 | pkg_manager="dnf"
1296 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
1297 | elif command -v yum &>/dev/null; then
1298 | pkg_manager="yum"
1299 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.rpm.sh"
1300 | elif command -v apt-get &>/dev/null; then
1301 | pkg_manager="apt-get"
1302 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
1303 | elif command -v apt &>/dev/null; then
1304 | pkg_manager="apt"
1305 | speedtest_install_script="https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh"
1306 | fi
1307 |
1308 | if [[ -z $pkg_manager ]]; then
1309 | echo "Error: Package manager not found. You may need to install Speedtest manually."
1310 | return 1
1311 | else
1312 | echo "Installing Speedtest using $pkg_manager..."
1313 | curl -s $speedtest_install_script | bash
1314 | $pkg_manager install -y speedtest
1315 | fi
1316 | fi
1317 | fi
1318 |
1319 | speedtest
1320 | }
1321 |
1322 | create_iplimit_jails() {
1323 | # Use default bantime if not passed => 30 minutes
1324 | local bantime="${1:-30}"
1325 |
1326 | # Uncomment 'allowipv6 = auto' in fail2ban.conf
1327 | sed -i 's/#allowipv6 = auto/allowipv6 = auto/g' /etc/fail2ban/fail2ban.conf
1328 |
1329 | # On Debian 12+ fail2ban's default backend should be changed to systemd
1330 | if [[ "${release}" == "debian" && ${os_version} -ge 12 ]]; then
1331 | sed -i '0,/action =/s/backend = auto/backend = systemd/' /etc/fail2ban/jail.conf
1332 | fi
1333 |
1334 | cat << EOF > /etc/fail2ban/jail.d/3x-ipl.conf
1335 | [3x-ipl]
1336 | enabled=true
1337 | backend=auto
1338 | filter=3x-ipl
1339 | action=3x-ipl
1340 | logpath=${iplimit_log_path}
1341 | maxretry=2
1342 | findtime=32
1343 | bantime=${bantime}m
1344 | EOF
1345 |
1346 | cat << EOF > /etc/fail2ban/filter.d/3x-ipl.conf
1347 | [Definition]
1348 | datepattern = ^%%Y/%%m/%%d %%H:%%M:%%S
1349 | failregex = \[LIMIT_IP\]\s*Email\s*=\s*.+\s*\|\|\s*SRC\s*=\s*
1350 | ignoreregex =
1351 | EOF
1352 |
1353 | cat << EOF > /etc/fail2ban/action.d/3x-ipl.conf
1354 | [INCLUDES]
1355 | before = iptables-allports.conf
1356 |
1357 | [Definition]
1358 | actionstart = -N f2b-
1359 | -A f2b- -j
1360 | -I -p -j f2b-
1361 |
1362 | actionstop = -D -p -j f2b-
1363 |
1364 | -X f2b-
1365 |
1366 | actioncheck = -n -L | grep -q 'f2b-[ \t]'
1367 |
1368 | actionban = -I f2b- 1 -s -j
1369 | echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") BAN [Email] = [IP] = banned for seconds." >> ${iplimit_banned_log_path}
1370 |
1371 | actionunban = -D f2b- -s -j
1372 | echo "\$(date +"%%Y/%%m/%%d %%H:%%M:%%S") UNBAN [Email] = [IP] = unbanned." >> ${iplimit_banned_log_path}
1373 |
1374 | [Init]
1375 | name = default
1376 | protocol = tcp
1377 | chain = INPUT
1378 | EOF
1379 |
1380 | echo -e "${green}Ip Limit jail files created with a bantime of ${bantime} minutes.${plain}"
1381 | }
1382 |
1383 | iplimit_remove_conflicts() {
1384 | local jail_files=(
1385 | /etc/fail2ban/jail.conf
1386 | /etc/fail2ban/jail.local
1387 | )
1388 |
1389 | for file in "${jail_files[@]}"; do
1390 | # Check for [3x-ipl] config in jail file then remove it
1391 | if test -f "${file}" && grep -qw '3x-ipl' ${file}; then
1392 | sed -i "/\[3x-ipl\]/,/^$/d" ${file}
1393 | echo -e "${yellow}Removing conflicts of [3x-ipl] in jail (${file})!${plain}\n"
1394 | fi
1395 | done
1396 | }
1397 |
1398 | ip_validation() {
1399 | ipv6_regex="^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$"
1400 | ipv4_regex="^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)$"
1401 | }
1402 |
1403 | iplimit_main() {
1404 | echo -e "\n${green}\t1.${plain} Install Fail2ban and configure IP Limit"
1405 | echo -e "${green}\t2.${plain} Change Ban Duration"
1406 | echo -e "${green}\t3.${plain} Unban Everyone"
1407 | echo -e "${green}\t4.${plain} Ban Logs"
1408 | echo -e "${green}\t5.${plain} Ban an IP Address"
1409 | echo -e "${green}\t6.${plain} Unban an IP Address"
1410 | echo -e "${green}\t7.${plain} Real-Time Logs"
1411 | echo -e "${green}\t8.${plain} Service Status"
1412 | echo -e "${green}\t9.${plain} Service Restart"
1413 | echo -e "${green}\t10.${plain} Uninstall Fail2ban and IP Limit"
1414 | echo -e "${green}\t0.${plain} Back to Main Menu"
1415 | read -rp "Choose an option: " choice
1416 | case "$choice" in
1417 | 0)
1418 | show_menu
1419 | ;;
1420 | 1)
1421 | confirm "Proceed with installation of Fail2ban & IP Limit?" "y"
1422 | if [[ $? == 0 ]]; then
1423 | install_iplimit
1424 | else
1425 | iplimit_main
1426 | fi
1427 | ;;
1428 | 2)
1429 | read -rp "Please enter new Ban Duration in Minutes [default 30]: " NUM
1430 | if [[ $NUM =~ ^[0-9]+$ ]]; then
1431 | create_iplimit_jails ${NUM}
1432 | systemctl restart fail2ban
1433 | else
1434 | echo -e "${red}${NUM} is not a number! Please, try again.${plain}"
1435 | fi
1436 | iplimit_main
1437 | ;;
1438 | 3)
1439 | confirm "Proceed with Unbanning everyone from IP Limit jail?" "y"
1440 | if [[ $? == 0 ]]; then
1441 | fail2ban-client reload --restart --unban 3x-ipl
1442 | truncate -s 0 "${iplimit_banned_log_path}"
1443 | echo -e "${green}All users Unbanned successfully.${plain}"
1444 | iplimit_main
1445 | else
1446 | echo -e "${yellow}Cancelled.${plain}"
1447 | fi
1448 | iplimit_main
1449 | ;;
1450 | 4)
1451 | show_banlog
1452 | iplimit_main
1453 | ;;
1454 | 5)
1455 | read -rp "Enter the IP address you want to ban: " ban_ip
1456 | ip_validation
1457 | if [[ $ban_ip =~ $ipv4_regex || $ban_ip =~ $ipv6_regex ]]; then
1458 | fail2ban-client set 3x-ipl banip "$ban_ip"
1459 | echo -e "${green}IP Address ${ban_ip} has been banned successfully.${plain}"
1460 | else
1461 | echo -e "${red}Invalid IP address format! Please try again.${plain}"
1462 | fi
1463 | iplimit_main
1464 | ;;
1465 | 6)
1466 | read -rp "Enter the IP address you want to unban: " unban_ip
1467 | ip_validation
1468 | if [[ $unban_ip =~ $ipv4_regex || $unban_ip =~ $ipv6_regex ]]; then
1469 | fail2ban-client set 3x-ipl unbanip "$unban_ip"
1470 | echo -e "${green}IP Address ${unban_ip} has been unbanned successfully.${plain}"
1471 | else
1472 | echo -e "${red}Invalid IP address format! Please try again.${plain}"
1473 | fi
1474 | iplimit_main
1475 | ;;
1476 | 7)
1477 | tail -f /var/log/fail2ban.log
1478 | iplimit_main
1479 | ;;
1480 | 8)
1481 | service fail2ban status
1482 | iplimit_main
1483 | ;;
1484 | 9)
1485 | systemctl restart fail2ban
1486 | iplimit_main
1487 | ;;
1488 | 10)
1489 | remove_iplimit
1490 | iplimit_main
1491 | ;;
1492 | *)
1493 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
1494 | iplimit_main
1495 | ;;
1496 | esac
1497 | }
1498 |
1499 | install_iplimit() {
1500 | if ! command -v fail2ban-client &>/dev/null; then
1501 | echo -e "${green}Fail2ban is not installed. Installing now...!${plain}\n"
1502 |
1503 | # Check the OS and install necessary packages
1504 | case "${release}" in
1505 | ubuntu)
1506 | if [[ "${os_version}" -ge 24 ]]; then
1507 | apt update && apt install python3-pip -y
1508 | python3 -m pip install pyasynchat --break-system-packages
1509 | fi
1510 | apt update && apt install fail2ban -y
1511 | ;;
1512 | debian | armbian)
1513 | apt update && apt install fail2ban -y
1514 | ;;
1515 | centos | almalinux | rocky | ol)
1516 | yum update -y && yum install epel-release -y
1517 | yum -y install fail2ban
1518 | ;;
1519 | fedora | amzn | virtuozzo)
1520 | dnf -y update && dnf -y install fail2ban
1521 | ;;
1522 | arch | manjaro | parch)
1523 | pacman -Syu --noconfirm fail2ban
1524 | ;;
1525 | *)
1526 | echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n"
1527 | exit 1
1528 | ;;
1529 | esac
1530 |
1531 | if ! command -v fail2ban-client &>/dev/null; then
1532 | echo -e "${red}Fail2ban installation failed.${plain}\n"
1533 | exit 1
1534 | fi
1535 |
1536 | echo -e "${green}Fail2ban installed successfully!${plain}\n"
1537 | else
1538 | echo -e "${yellow}Fail2ban is already installed.${plain}\n"
1539 | fi
1540 |
1541 | echo -e "${green}Configuring IP Limit...${plain}\n"
1542 |
1543 | # make sure there's no conflict for jail files
1544 | iplimit_remove_conflicts
1545 |
1546 | # Check if log file exists
1547 | if ! test -f "${iplimit_banned_log_path}"; then
1548 | touch ${iplimit_banned_log_path}
1549 | fi
1550 |
1551 | # Check if service log file exists so fail2ban won't return error
1552 | if ! test -f "${iplimit_log_path}"; then
1553 | touch ${iplimit_log_path}
1554 | fi
1555 |
1556 | # Create the iplimit jail files
1557 | # we didn't pass the bantime here to use the default value
1558 | create_iplimit_jails
1559 |
1560 | # Launching fail2ban
1561 | if ! systemctl is-active --quiet fail2ban; then
1562 | systemctl start fail2ban
1563 | else
1564 | systemctl restart fail2ban
1565 | fi
1566 | systemctl enable fail2ban
1567 |
1568 | echo -e "${green}IP Limit installed and configured successfully!${plain}\n"
1569 | before_show_menu
1570 | }
1571 |
1572 | remove_iplimit() {
1573 | echo -e "${green}\t1.${plain} Only remove IP Limit configurations"
1574 | echo -e "${green}\t2.${plain} Uninstall Fail2ban and IP Limit"
1575 | echo -e "${green}\t0.${plain} Back to Main Menu"
1576 | read -rp "Choose an option: " num
1577 | case "$num" in
1578 | 1)
1579 | rm -f /etc/fail2ban/filter.d/3x-ipl.conf
1580 | rm -f /etc/fail2ban/action.d/3x-ipl.conf
1581 | rm -f /etc/fail2ban/jail.d/3x-ipl.conf
1582 | systemctl restart fail2ban
1583 | echo -e "${green}IP Limit removed successfully!${plain}\n"
1584 | before_show_menu
1585 | ;;
1586 | 2)
1587 | rm -rf /etc/fail2ban
1588 | systemctl stop fail2ban
1589 | case "${release}" in
1590 | ubuntu | debian | armbian)
1591 | apt-get remove -y fail2ban
1592 | apt-get purge -y fail2ban -y
1593 | apt-get autoremove -y
1594 | ;;
1595 | centos | almalinux | rocky | ol)
1596 | yum remove fail2ban -y
1597 | yum autoremove -y
1598 | ;;
1599 | fedora | amzn | virtuozzo)
1600 | dnf remove fail2ban -y
1601 | dnf autoremove -y
1602 | ;;
1603 | arch | manjaro | parch)
1604 | pacman -Rns --noconfirm fail2ban
1605 | ;;
1606 | *)
1607 | echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n"
1608 | exit 1
1609 | ;;
1610 | esac
1611 | echo -e "${green}Fail2ban and IP Limit removed successfully!${plain}\n"
1612 | before_show_menu
1613 | ;;
1614 | 0)
1615 | show_menu
1616 | ;;
1617 | *)
1618 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
1619 | remove_iplimit
1620 | ;;
1621 | esac
1622 | }
1623 |
1624 | SSH_port_forwarding() {
1625 | local server_ip=$(curl -s https://api.ipify.org)
1626 | local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}')
1627 | local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}')
1628 | local existing_listenIP=$(/usr/local/x-ui/x-ui setting -getListen true | grep -Eo 'listenIP: .+' | awk '{print $2}')
1629 | local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}')
1630 | local existing_key=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'key: .+' | awk '{print $2}')
1631 |
1632 | local config_listenIP=""
1633 | local listen_choice=""
1634 |
1635 | if [[ -n "$existing_cert" && -n "$existing_key" ]]; then
1636 | echo -e "${green}Panel is secure with SSL.${plain}"
1637 | before_show_menu
1638 | fi
1639 | if [[ -z "$existing_cert" && -z "$existing_key" && (-z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0") ]]; then
1640 | echo -e "\n${red}Warning: No Cert and Key found! The panel is not secure.${plain}"
1641 | echo "Please obtain a certificate or set up SSH port forwarding."
1642 | fi
1643 |
1644 | if [[ -n "$existing_listenIP" && "$existing_listenIP" != "0.0.0.0" && (-z "$existing_cert" && -z "$existing_key") ]]; then
1645 | echo -e "\n${green}Current SSH Port Forwarding Configuration:${plain}"
1646 | echo -e "Standard SSH command:"
1647 | echo -e "${yellow}ssh -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}"
1648 | echo -e "\nIf using SSH key:"
1649 | echo -e "${yellow}ssh -i -L 2222:${existing_listenIP}:${existing_port} root@${server_ip}${plain}"
1650 | echo -e "\nAfter connecting, access the panel at:"
1651 | echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}"
1652 | fi
1653 |
1654 | echo -e "\nChoose an option:"
1655 | echo -e "${green}1.${plain} Set listen IP"
1656 | echo -e "${green}2.${plain} Clear listen IP"
1657 | echo -e "${green}0.${plain} Back to Main Menu"
1658 | read -rp "Choose an option: " num
1659 |
1660 | case "$num" in
1661 | 1)
1662 | if [[ -z "$existing_listenIP" || "$existing_listenIP" == "0.0.0.0" ]]; then
1663 | echo -e "\nNo listenIP configured. Choose an option:"
1664 | echo -e "1. Use default IP (127.0.0.1)"
1665 | echo -e "2. Set a custom IP"
1666 | read -rp "Select an option (1 or 2): " listen_choice
1667 |
1668 | config_listenIP="127.0.0.1"
1669 | [[ "$listen_choice" == "2" ]] && read -rp "Enter custom IP to listen on: " config_listenIP
1670 |
1671 | /usr/local/x-ui/x-ui setting -listenIP "${config_listenIP}" >/dev/null 2>&1
1672 | echo -e "${green}listen IP has been set to ${config_listenIP}.${plain}"
1673 | echo -e "\n${green}SSH Port Forwarding Configuration:${plain}"
1674 | echo -e "Standard SSH command:"
1675 | echo -e "${yellow}ssh -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
1676 | echo -e "\nIf using SSH key:"
1677 | echo -e "${yellow}ssh -i -L 2222:${config_listenIP}:${existing_port} root@${server_ip}${plain}"
1678 | echo -e "\nAfter connecting, access the panel at:"
1679 | echo -e "${yellow}http://localhost:2222${existing_webBasePath}${plain}"
1680 | restart
1681 | else
1682 | config_listenIP="${existing_listenIP}"
1683 | echo -e "${green}Current listen IP is already set to ${config_listenIP}.${plain}"
1684 | fi
1685 | ;;
1686 | 2)
1687 | /usr/local/x-ui/x-ui setting -listenIP 0.0.0.0 >/dev/null 2>&1
1688 | echo -e "${green}Listen IP has been cleared.${plain}"
1689 | restart
1690 | ;;
1691 | 0)
1692 | show_menu
1693 | ;;
1694 | *)
1695 | echo -e "${red}Invalid option. Please select a valid number.${plain}\n"
1696 | SSH_port_forwarding
1697 | ;;
1698 | esac
1699 | }
1700 |
1701 | show_usage() {
1702 | echo -e "┌───────────────────────────────────────────────────────┐
1703 | │ ${blue}x-ui control menu usages (subcommands):${plain} │
1704 | │ │
1705 | │ ${blue}x-ui${plain} - Admin Management Script │
1706 | │ ${blue}x-ui start${plain} - Start │
1707 | │ ${blue}x-ui stop${plain} - Stop │
1708 | │ ${blue}x-ui restart${plain} - Restart │
1709 | │ ${blue}x-ui status${plain} - Current Status │
1710 | │ ${blue}x-ui settings${plain} - Current Settings │
1711 | │ ${blue}x-ui enable${plain} - Enable Autostart on OS Startup │
1712 | │ ${blue}x-ui disable${plain} - Disable Autostart on OS Startup │
1713 | │ ${blue}x-ui log${plain} - Check logs │
1714 | │ ${blue}x-ui banlog${plain} - Check Fail2ban ban logs │
1715 | │ ${blue}x-ui update${plain} - Update │
1716 | │ ${blue}x-ui legacy${plain} - legacy version │
1717 | │ ${blue}x-ui install${plain} - Install │
1718 | │ ${blue}x-ui uninstall${plain} - Uninstall │
1719 | └───────────────────────────────────────────────────────┘"
1720 | }
1721 |
1722 | show_menu() {
1723 | echo -e "
1724 | ╔────────────────────────────────────────────────╗
1725 | │ ${green}3X-UI Panel Management Script${plain} │
1726 | │ ${green}0.${plain} Exit Script │
1727 | │────────────────────────────────────────────────│
1728 | │ ${green}1.${plain} Install │
1729 | │ ${green}2.${plain} Update │
1730 | │ ${green}3.${plain} Update Menu │
1731 | │ ${green}4.${plain} Legacy Version │
1732 | │ ${green}5.${plain} Uninstall │
1733 | │────────────────────────────────────────────────│
1734 | │ ${green}6.${plain} Reset Username & Password & Secret Token │
1735 | │ ${green}7.${plain} Reset Web Base Path │
1736 | │ ${green}8.${plain} Reset Settings │
1737 | │ ${green}9.${plain} Change Port │
1738 | │ ${green}10.${plain} View Current Settings │
1739 | │────────────────────────────────────────────────│
1740 | │ ${green}11.${plain} Start │
1741 | │ ${green}12.${plain} Stop │
1742 | │ ${green}13.${plain} Restart │
1743 | │ ${green}14.${plain} Check Status │
1744 | │ ${green}15.${plain} Logs Management │
1745 | │────────────────────────────────────────────────│
1746 | │ ${green}16.${plain} Enable Autostart │
1747 | │ ${green}17.${plain} Disable Autostart │
1748 | │────────────────────────────────────────────────│
1749 | │ ${green}18.${plain} SSL Certificate Management │
1750 | │ ${green}19.${plain} Cloudflare SSL Certificate │
1751 | │ ${green}20.${plain} IP Limit Management │
1752 | │ ${green}21.${plain} Firewall Management │
1753 | │ ${green}22.${plain} SSH Port Forwarding Management │
1754 | │────────────────────────────────────────────────│
1755 | │ ${green}23.${plain} Enable BBR │
1756 | │ ${green}24.${plain} Update Geo Files │
1757 | │ ${green}25.${plain} Speedtest by Ookla │
1758 | ╚────────────────────────────────────────────────╝
1759 | "
1760 | show_status
1761 | echo && read -rp "Please enter your selection [0-25]: " num
1762 |
1763 | case "${num}" in
1764 | 0)
1765 | exit 0
1766 | ;;
1767 | 1)
1768 | check_uninstall && install
1769 | ;;
1770 | 2)
1771 | check_install && update
1772 | ;;
1773 | 3)
1774 | check_install && update_menu
1775 | ;;
1776 | 4)
1777 | check_install && legacy_version
1778 | ;;
1779 | 5)
1780 | check_install && uninstall
1781 | ;;
1782 | 6)
1783 | check_install && reset_user
1784 | ;;
1785 | 7)
1786 | check_install && reset_webbasepath
1787 | ;;
1788 | 8)
1789 | check_install && reset_config
1790 | ;;
1791 | 9)
1792 | check_install && set_port
1793 | ;;
1794 | 10)
1795 | check_install && check_config
1796 | ;;
1797 | 11)
1798 | check_install && start
1799 | ;;
1800 | 12)
1801 | check_install && stop
1802 | ;;
1803 | 13)
1804 | check_install && restart
1805 | ;;
1806 | 14)
1807 | check_install && status
1808 | ;;
1809 | 15)
1810 | check_install && show_log
1811 | ;;
1812 | 16)
1813 | check_install && enable
1814 | ;;
1815 | 17)
1816 | check_install && disable
1817 | ;;
1818 | 18)
1819 | ssl_cert_issue_main
1820 | ;;
1821 | 19)
1822 | ssl_cert_issue_CF
1823 | ;;
1824 | 20)
1825 | iplimit_main
1826 | ;;
1827 | 21)
1828 | firewall_menu
1829 | ;;
1830 | 22)
1831 | SSH_port_forwarding
1832 | ;;
1833 | 23)
1834 | bbr_menu
1835 | ;;
1836 | 24)
1837 | update_geo
1838 | ;;
1839 | 25)
1840 | run_speedtest
1841 | ;;
1842 | *)
1843 | LOGE "Please enter the correct number [0-25]"
1844 | ;;
1845 | esac
1846 | }
1847 |
1848 | if [[ $# > 0 ]]; then
1849 | case $1 in
1850 | "start")
1851 | check_install 0 && start 0
1852 | ;;
1853 | "stop")
1854 | check_install 0 && stop 0
1855 | ;;
1856 | "restart")
1857 | check_install 0 && restart 0
1858 | ;;
1859 | "status")
1860 | check_install 0 && status 0
1861 | ;;
1862 | "settings")
1863 | check_install 0 && check_config 0
1864 | ;;
1865 | "enable")
1866 | check_install 0 && enable 0
1867 | ;;
1868 | "disable")
1869 | check_install 0 && disable 0
1870 | ;;
1871 | "log")
1872 | check_install 0 && show_log 0
1873 | ;;
1874 | "banlog")
1875 | check_install 0 && show_banlog 0
1876 | ;;
1877 | "update")
1878 | check_install 0 && update 0
1879 | ;;
1880 | "legacy")
1881 | check_install 0 && legacy_version 0
1882 | ;;
1883 | "install")
1884 | check_uninstall 0 && install 0
1885 | ;;
1886 | "uninstall")
1887 | check_install 0 && uninstall 0
1888 | ;;
1889 | *) show_usage ;;
1890 | esac
1891 | else
1892 | show_menu
1893 | fi
1894 |
--------------------------------------------------------------------------------