Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xDockerInit.sh2
-rw-r--r--install.sh446
-rwxr-xr-xupdate.sh566
-rw-r--r--web/assets/js/model/inbound.js4
-rw-r--r--web/html/common/page.html65
-rw-r--r--web/html/component/aClientTable.html87
-rw-r--r--web/html/component/aCustomStatistic.html18
-rw-r--r--web/html/component/aPersianDatepicker.html5
-rw-r--r--web/html/component/aSettingListItem.html4
-rw-r--r--web/html/component/aSidebar.html7
-rw-r--r--web/html/component/aTableSortable.html19
-rw-r--r--web/html/component/aThemeSwitch.html6
-rw-r--r--web/html/form/client.html127
-rw-r--r--web/html/form/outbound.html993
-rw-r--r--web/html/form/protocol/dokodemo.html4
-rw-r--r--web/html/form/protocol/http.html5
-rw-r--r--web/html/form/protocol/hysteria.html10
-rw-r--r--web/html/form/protocol/shadowsocks.html44
-rw-r--r--web/html/form/protocol/socks.html49
-rw-r--r--web/html/form/protocol/trojan.html62
-rw-r--r--web/html/form/protocol/tun.html60
-rw-r--r--web/html/form/protocol/vless.html203
-rw-r--r--web/html/form/protocol/vmess.html4
-rw-r--r--web/html/form/sniffing.html30
-rw-r--r--web/html/form/stream/external_proxy.html60
-rw-r--r--web/html/form/stream/stream_finalmask.html698
-rw-r--r--web/html/form/stream/stream_grpc.html8
-rw-r--r--web/html/form/stream/stream_httpupgrade.html49
-rw-r--r--web/html/form/stream/stream_hysteria.html80
-rw-r--r--web/html/form/stream/stream_kcp.html40
-rw-r--r--web/html/form/stream/stream_settings.html18
-rw-r--r--web/html/form/stream/stream_sockopt.html79
-rw-r--r--web/html/form/stream/stream_tcp.html121
-rw-r--r--web/html/form/stream/stream_ws.html44
-rw-r--r--web/html/form/stream/stream_xhttp.html172
-rw-r--r--web/html/form/tls_settings.html41
-rw-r--r--web/html/inbounds.html597
-rw-r--r--web/html/index.html399
-rw-r--r--web/html/login.html22
-rw-r--r--web/html/modals/client_bulk_modal.html116
-rw-r--r--web/html/modals/client_modal.html69
-rw-r--r--web/html/modals/dns_presets_modal.html15
-rw-r--r--web/html/modals/inbound_info_modal.html41
-rw-r--r--web/html/modals/inbound_modal.html32
-rw-r--r--web/html/modals/nord_modal.html69
-rw-r--r--web/html/modals/prompt_modal.html19
-rw-r--r--web/html/modals/qrcode_modal.html39
-rw-r--r--web/html/modals/text_modal.html6
-rw-r--r--web/html/modals/two_factor_modal.html58
-rw-r--r--web/html/modals/warp_modal.html22
-rw-r--r--web/html/modals/xray_balancer_modal.html37
-rw-r--r--web/html/modals/xray_dns_modal.html18
-rw-r--r--web/html/modals/xray_fakedns_modal.html17
-rw-r--r--web/html/modals/xray_outbound_modal.html54
-rw-r--r--web/html/modals/xray_reverse_modal.html94
-rw-r--r--web/html/modals/xray_rule_modal.html31
-rw-r--r--web/html/settings.html237
-rw-r--r--web/html/settings/panel/general.html21
-rw-r--r--web/html/settings/panel/subscription/general.html18
-rw-r--r--web/html/settings/panel/subscription/subpage.html13
-rw-r--r--web/html/settings/xray/balancers.html8
-rw-r--r--web/html/settings/xray/basics.html105
-rw-r--r--web/html/settings/xray/dns.html3
-rw-r--r--web/html/settings/xray/outbounds.html51
-rw-r--r--web/html/xray.html1130
-rw-r--r--x-ui.sh1423
66 files changed, 4368 insertions, 4626 deletions
diff --git a/DockerInit.sh b/DockerInit.sh
index 97f8c302..0e033f63 100755
--- a/DockerInit.sh
+++ b/DockerInit.sh
@@ -37,4 +37,4 @@ curl -sfLRo geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/release
curl -sfLRo geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat
curl -sfLRo geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat
curl -sfLRo geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat
-cd ../../ \ No newline at end of file
+cd ../../
diff --git a/install.sh b/install.sh
index aa4f5dfb..4a0ce55d 100644
--- a/install.sh
+++ b/install.sh
@@ -18,7 +18,7 @@ xui_service="${XUI_SERVICE:=/etc/systemd/system}"
if [[ -f /etc/os-release ]]; then
source /etc/os-release
release=$ID
- elif [[ -f /usr/lib/os-release ]]; then
+elif [[ -f /usr/lib/os-release ]]; then
source /usr/lib/os-release
release=$ID
else
@@ -59,16 +59,16 @@ is_domain() {
# Port helpers
is_port_in_use() {
local port="$1"
- if command -v ss >/dev/null 2>&1; then
- ss -ltn 2>/dev/null | awk -v p=":${port}$" '$4 ~ p {exit 0} END {exit 1}'
+ if command -v ss > /dev/null 2>&1; then
+ ss -ltn 2> /dev/null | awk -v p=":${port}$" '$4 ~ p {exit 0} END {exit 1}'
return
fi
- if command -v netstat >/dev/null 2>&1; then
- netstat -lnt 2>/dev/null | awk -v p=":${port} " '$4 ~ p {exit 0} END {exit 1}'
+ if command -v netstat > /dev/null 2>&1; then
+ netstat -lnt 2> /dev/null | awk -v p=":${port} " '$4 ~ p {exit 0} END {exit 1}'
return
fi
- if command -v lsof >/dev/null 2>&1; then
- lsof -nP -iTCP:${port} -sTCP:LISTEN >/dev/null 2>&1 && return 0
+ if command -v lsof > /dev/null 2>&1; then
+ lsof -nP -iTCP:${port} -sTCP:LISTEN > /dev/null 2>&1 && return 0
fi
return 1
}
@@ -77,35 +77,35 @@ install_base() {
case "${release}" in
ubuntu | debian | armbian)
apt-get update && apt-get install -y -q cron curl tar tzdata socat ca-certificates openssl
- ;;
+ ;;
fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol)
dnf -y update && dnf install -y -q cronie curl tar tzdata socat ca-certificates openssl
- ;;
+ ;;
centos)
if [[ "${VERSION_ID}" =~ ^7 ]]; then
yum -y update && yum install -y cronie curl tar tzdata socat ca-certificates openssl
else
dnf -y update && dnf install -y -q cronie curl tar tzdata socat ca-certificates openssl
fi
- ;;
+ ;;
arch | manjaro | parch)
pacman -Syu && pacman -Syu --noconfirm cronie curl tar tzdata socat ca-certificates openssl
- ;;
+ ;;
opensuse-tumbleweed | opensuse-leap)
zypper refresh && zypper -q install -y cron curl tar timezone socat ca-certificates openssl
- ;;
+ ;;
alpine)
apk update && apk add dcron curl tar tzdata socat ca-certificates openssl
- ;;
+ ;;
*)
apt-get update && apt-get install -y -q cron curl tar tzdata socat ca-certificates openssl
- ;;
+ ;;
esac
}
gen_random_string() {
local length="$1"
- openssl rand -base64 $(( length * 2 )) \
+ openssl rand -base64 $((length * 2)) \
| tr -dc 'a-zA-Z0-9' \
| head -c "$length"
}
@@ -113,7 +113,7 @@ gen_random_string() {
install_acme() {
echo -e "${green}Installing acme.sh for SSL certificate management...${plain}"
cd ~ || return 1
- curl -s https://get.acme.sh | sh >/dev/null 2>&1
+ curl -s https://get.acme.sh | sh > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo -e "${red}Failed to install acme.sh${plain}"
return 1
@@ -128,60 +128,60 @@ setup_ssl_certificate() {
local server_ip="$2"
local existing_port="$3"
local existing_webBasePath="$4"
-
+
echo -e "${green}Setting up SSL certificate...${plain}"
-
+
# Check if acme.sh is installed
- if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
+ if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
install_acme
if [ $? -ne 0 ]; then
echo -e "${yellow}Failed to install acme.sh, skipping SSL setup${plain}"
return 1
fi
fi
-
+
# Create certificate directory
local certPath="/root/cert/${domain}"
mkdir -p "$certPath"
-
+
# Issue certificate
echo -e "${green}Issuing SSL certificate for ${domain}...${plain}"
echo -e "${yellow}Note: Port 80 must be open and accessible from the internet${plain}"
-
- ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force >/dev/null 2>&1
+
+ ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force > /dev/null 2>&1
~/.acme.sh/acme.sh --issue -d ${domain} --listen-v6 --standalone --httpport 80 --force
-
+
if [ $? -ne 0 ]; then
echo -e "${yellow}Failed to issue certificate for ${domain}${plain}"
echo -e "${yellow}Please ensure port 80 is open and try again later with: x-ui${plain}"
- rm -rf ~/.acme.sh/${domain} 2>/dev/null
- rm -rf "$certPath" 2>/dev/null
+ rm -rf ~/.acme.sh/${domain} 2> /dev/null
+ rm -rf "$certPath" 2> /dev/null
return 1
fi
-
+
# Install certificate
~/.acme.sh/acme.sh --installcert -d ${domain} \
--key-file /root/cert/${domain}/privkey.pem \
--fullchain-file /root/cert/${domain}/fullchain.pem \
- --reloadcmd "systemctl restart x-ui" >/dev/null 2>&1
-
+ --reloadcmd "systemctl restart x-ui" > /dev/null 2>&1
+
if [ $? -ne 0 ]; then
echo -e "${yellow}Failed to install certificate${plain}"
return 1
fi
-
+
# Enable auto-renew
- ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1
+ ~/.acme.sh/acme.sh --upgrade --auto-upgrade > /dev/null 2>&1
# Secure permissions: private key readable only by owner
- chmod 600 $certPath/privkey.pem 2>/dev/null
- chmod 644 $certPath/fullchain.pem 2>/dev/null
-
+ chmod 600 $certPath/privkey.pem 2> /dev/null
+ chmod 644 $certPath/fullchain.pem 2> /dev/null
+
# Set certificate for panel
local webCertFile="/root/cert/${domain}/fullchain.pem"
local webKeyFile="/root/cert/${domain}/privkey.pem"
-
+
if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then
- ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" >/dev/null 2>&1
+ ${xui_folder}/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" > /dev/null 2>&1
echo -e "${green}SSL certificate installed and configured successfully!${plain}"
return 0
else
@@ -194,14 +194,14 @@ setup_ssl_certificate() {
# Requires acme.sh and port 80 open for HTTP-01 challenge
setup_ip_certificate() {
local ipv4="$1"
- local ipv6="$2" # optional
+ local ipv6="$2" # optional
echo -e "${green}Setting up Let's Encrypt IP certificate (shortlived profile)...${plain}"
echo -e "${yellow}Note: IP certificates are valid for ~6 days and will auto-renew.${plain}"
echo -e "${yellow}Default listener is port 80. If you choose another port, ensure external port 80 forwards to it.${plain}"
# Check for acme.sh
- if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
+ if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
install_acme
if [ $? -ne 0 ]; then
echo -e "${red}Failed to install acme.sh${plain}"
@@ -273,8 +273,8 @@ setup_ip_certificate() {
# Issue certificate with shortlived profile
echo -e "${green}Issuing IP certificate for ${ipv4}...${plain}"
- ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force >/dev/null 2>&1
-
+ ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt --force > /dev/null 2>&1
+
~/.acme.sh/acme.sh --issue \
${domain_args} \
--standalone \
@@ -288,9 +288,9 @@ setup_ip_certificate() {
echo -e "${red}Failed to issue IP certificate${plain}"
echo -e "${yellow}Please ensure port ${WebPort} is reachable (or forwarded from external port 80)${plain}"
# Cleanup acme.sh data for both IPv4 and IPv6 if specified
- rm -rf ~/.acme.sh/${ipv4} 2>/dev/null
- [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2>/dev/null
- rm -rf ${certDir} 2>/dev/null
+ rm -rf ~/.acme.sh/${ipv4} 2> /dev/null
+ [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2> /dev/null
+ rm -rf ${certDir} 2> /dev/null
return 1
fi
@@ -308,25 +308,25 @@ setup_ip_certificate() {
if [[ ! -f "${certDir}/fullchain.pem" || ! -f "${certDir}/privkey.pem" ]]; then
echo -e "${red}Certificate files not found after installation${plain}"
# Cleanup acme.sh data for both IPv4 and IPv6 if specified
- rm -rf ~/.acme.sh/${ipv4} 2>/dev/null
- [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2>/dev/null
- rm -rf ${certDir} 2>/dev/null
+ rm -rf ~/.acme.sh/${ipv4} 2> /dev/null
+ [[ -n "$ipv6" ]] && rm -rf ~/.acme.sh/${ipv6} 2> /dev/null
+ rm -rf ${certDir} 2> /dev/null
return 1
fi
-
+
echo -e "${green}Certificate files installed successfully${plain}"
# Enable auto-upgrade for acme.sh (ensures cron job runs)
- ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1
+ ~/.acme.sh/acme.sh --upgrade --auto-upgrade > /dev/null 2>&1
# Secure permissions: private key readable only by owner
- chmod 600 ${certDir}/privkey.pem 2>/dev/null
- chmod 644 ${certDir}/fullchain.pem 2>/dev/null
+ chmod 600 ${certDir}/privkey.pem 2> /dev/null
+ chmod 644 ${certDir}/fullchain.pem 2> /dev/null
# Configure panel to use the certificate
echo -e "${green}Setting certificate paths for the panel...${plain}"
${xui_folder}/x-ui cert -webCert "${certDir}/fullchain.pem" -webCertKey "${certDir}/privkey.pem"
-
+
if [ $? -ne 0 ]; then
echo -e "${yellow}Warning: Could not set certificate paths automatically${plain}"
echo -e "${yellow}Certificate files are at:${plain}"
@@ -346,9 +346,9 @@ setup_ip_certificate() {
ssl_cert_issue() {
local existing_webBasePath=$(${xui_folder}/x-ui setting -show true | grep 'webBasePath:' | awk -F': ' '{print $2}' | tr -d '[:space:]' | sed 's#^/##')
local existing_port=$(${xui_folder}/x-ui setting -show true | grep 'port:' | awk -F': ' '{print $2}' | tr -d '[:space:]')
-
+
# check for acme.sh first
- if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
+ if ! command -v ~/.acme.sh/acme.sh &> /dev/null; then
echo "acme.sh could not be found. Installing now..."
cd ~ || return 1
curl -s https://get.acme.sh | sh
@@ -364,18 +364,18 @@ ssl_cert_issue() {
local domain=""
while true; do
read -rp "Please enter your domain name: " domain
- domain="${domain// /}" # Trim whitespace
-
+ domain="${domain// /}" # Trim whitespace
+
if [[ -z "$domain" ]]; then
echo -e "${red}Domain name cannot be empty. Please try again.${plain}"
continue
fi
-
+
if ! is_domain "$domain"; then
echo -e "${red}Invalid domain format: ${domain}. Please enter a valid domain name.${plain}"
continue
fi
-
+
break
done
echo -e "${green}Your domain is: ${domain}, checking it...${plain}"
@@ -383,9 +383,9 @@ ssl_cert_issue() {
# detect existing certificate and reuse it if present
local cert_exists=0
- if ~/.acme.sh/acme.sh --list 2>/dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
+ if ~/.acme.sh/acme.sh --list 2> /dev/null | awk '{print $1}' | grep -Fxq "${domain}"; then
cert_exists=1
- local certInfo=$(~/.acme.sh/acme.sh --list 2>/dev/null | grep -F "${domain}")
+ local certInfo=$(~/.acme.sh/acme.sh --list 2> /dev/null | grep -F "${domain}")
echo -e "${yellow}Existing certificate found for ${domain}, will reuse it.${plain}"
[[ -n "${certInfo}" ]] && echo "$certInfo"
else
@@ -412,7 +412,7 @@ ssl_cert_issue() {
# Stop panel temporarily
echo -e "${yellow}Stopping panel temporarily...${plain}"
- systemctl stop x-ui 2>/dev/null || rc-service x-ui stop 2>/dev/null
+ systemctl stop x-ui 2> /dev/null || rc-service x-ui stop 2> /dev/null
if [[ ${cert_exists} -eq 0 ]]; then
# issue the certificate
@@ -421,7 +421,7 @@ ssl_cert_issue() {
if [ $? -ne 0 ]; then
echo -e "${red}Issuing certificate failed, please check logs.${plain}"
rm -rf ~/.acme.sh/${domain}
- systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
+ systemctl start x-ui 2> /dev/null || rc-service x-ui start 2> /dev/null
return 1
else
echo -e "${green}Issuing certificate succeeded, installing certificates...${plain}"
@@ -441,18 +441,18 @@ ssl_cert_issue() {
echo -e "${green}\t0.${plain} Keep default reloadcmd"
read -rp "Choose an option: " choice
case "$choice" in
- 1)
- echo -e "${green}Reloadcmd is: systemctl reload nginx ; systemctl restart x-ui${plain}"
- reloadCmd="systemctl reload nginx ; systemctl restart x-ui"
- ;;
- 2)
- echo -e "${yellow}It's recommended to put x-ui restart at the end${plain}"
- read -rp "Please enter your custom reloadcmd: " reloadCmd
- echo -e "${green}Reloadcmd is: ${reloadCmd}${plain}"
- ;;
- *)
- echo -e "${green}Keeping default reloadcmd${plain}"
- ;;
+ 1)
+ echo -e "${green}Reloadcmd is: systemctl reload nginx ; systemctl restart x-ui${plain}"
+ reloadCmd="systemctl reload nginx ; systemctl restart x-ui"
+ ;;
+ 2)
+ echo -e "${yellow}It's recommended to put x-ui restart at the end${plain}"
+ read -rp "Please enter your custom reloadcmd: " reloadCmd
+ echo -e "${green}Reloadcmd is: ${reloadCmd}${plain}"
+ ;;
+ *)
+ echo -e "${green}Keeping default reloadcmd${plain}"
+ ;;
esac
fi
@@ -469,14 +469,14 @@ ssl_cert_issue() {
installWroteFiles=1
fi
- if [[ -f "/root/cert/${domain}/privkey.pem" && -f "/root/cert/${domain}/fullchain.pem" && ( ${installRc} -eq 0 || ${installWroteFiles} -eq 1 ) ]]; then
+ if [[ -f "/root/cert/${domain}/privkey.pem" && -f "/root/cert/${domain}/fullchain.pem" && (${installRc} -eq 0 || ${installWroteFiles} -eq 1) ]]; then
echo -e "${green}Installing certificate succeeded, enabling auto renew...${plain}"
else
echo -e "${red}Installing certificate failed, exiting.${plain}"
if [[ ${cert_exists} -eq 0 ]]; then
rm -rf ~/.acme.sh/${domain}
fi
- systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
+ systemctl start x-ui 2> /dev/null || rc-service x-ui start 2> /dev/null
return 1
fi
@@ -486,18 +486,18 @@ ssl_cert_issue() {
echo -e "${yellow}Auto renew setup had issues, certificate details:${plain}"
ls -lah /root/cert/${domain}/
# Secure permissions: private key readable only by owner
- chmod 600 $certPath/privkey.pem 2>/dev/null
- chmod 644 $certPath/fullchain.pem 2>/dev/null
+ chmod 600 $certPath/privkey.pem 2> /dev/null
+ chmod 644 $certPath/fullchain.pem 2> /dev/null
else
echo -e "${green}Auto renew succeeded, certificate details:${plain}"
ls -lah /root/cert/${domain}/
# Secure permissions: private key readable only by owner
- chmod 600 $certPath/privkey.pem 2>/dev/null
- chmod 644 $certPath/fullchain.pem 2>/dev/null
+ chmod 600 $certPath/privkey.pem 2> /dev/null
+ chmod 644 $certPath/fullchain.pem 2> /dev/null
fi
# start panel
- systemctl start x-ui 2>/dev/null || rc-service x-ui start 2>/dev/null
+ systemctl start x-ui 2> /dev/null || rc-service x-ui start 2> /dev/null
# Prompt user to set panel paths after successful certificate installation
read -rp "Would you like to set this certificate for the panel? (y/n): " setPanel
@@ -513,14 +513,14 @@ ssl_cert_issue() {
echo ""
echo -e "${green}Access URL: https://${domain}:${existing_port}/${existing_webBasePath}${plain}"
echo -e "${yellow}Panel will restart to apply SSL certificate...${plain}"
- systemctl restart x-ui 2>/dev/null || rc-service x-ui restart 2>/dev/null
+ systemctl restart x-ui 2> /dev/null || rc-service x-ui restart 2> /dev/null
else
echo -e "${red}Error: Certificate or private key file not found for domain: $domain.${plain}"
fi
else
echo -e "${yellow}Skipping panel path setting.${plain}"
fi
-
+
return 0
}
@@ -528,7 +528,7 @@ ssl_cert_issue() {
# Sets global `SSL_HOST` to the chosen domain/IP for Access URL usage
prompt_and_setup_ssl() {
local panel_port="$1"
- local web_base_path="$2" # expected without leading slash
+ local web_base_path="$2" # expected without leading slash
local server_ip="$3"
local ssl_choice=""
@@ -539,124 +539,124 @@ prompt_and_setup_ssl() {
echo -e "${green}3.${plain} Custom SSL Certificate (Path to existing files)"
echo -e "${blue}Note:${plain} Options 1 & 2 require port 80 open. Option 3 requires manual paths."
read -rp "Choose an option (default 2 for IP): " ssl_choice
- ssl_choice="${ssl_choice// /}" # Trim whitespace
-
+ ssl_choice="${ssl_choice// /}" # Trim whitespace
+
# Default to 2 (IP cert) if input is empty or invalid (not 1 or 3)
if [[ "$ssl_choice" != "1" && "$ssl_choice" != "3" ]]; then
ssl_choice="2"
fi
case "$ssl_choice" in
- 1)
- # User chose Let's Encrypt domain option
- echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
- if ssl_cert_issue; then
- local cert_domain="${SSL_ISSUED_DOMAIN}"
- if [[ -z "${cert_domain}" ]]; then
- cert_domain=$(~/.acme.sh/acme.sh --list 2>/dev/null | tail -1 | awk '{print $1}')
+ 1)
+ # User chose Let's Encrypt domain option
+ echo -e "${green}Using Let's Encrypt for domain certificate...${plain}"
+ if ssl_cert_issue; then
+ local cert_domain="${SSL_ISSUED_DOMAIN}"
+ if [[ -z "${cert_domain}" ]]; then
+ cert_domain=$(~/.acme.sh/acme.sh --list 2> /dev/null | tail -1 | awk '{print $1}')
+ fi
+
+ if [[ -n "${cert_domain}" ]]; then
+ SSL_HOST="${cert_domain}"
+ echo -e "${green}✓ SSL certificate configured successfully with domain: ${cert_domain}${plain}"
+ else
+ echo -e "${yellow}SSL setup may have completed, but domain extraction failed${plain}"
+ SSL_HOST="${server_ip}"
+ fi
+ else
+ echo -e "${red}SSL certificate setup failed for domain mode.${plain}"
+ SSL_HOST="${server_ip}"
fi
+ ;;
+ 2)
+ # User chose Let's Encrypt IP certificate option
+ echo -e "${green}Using Let's Encrypt for IP certificate (shortlived profile)...${plain}"
+
+ # Ask for optional IPv6