diff options
| author | Sanaei <ho3ein.sanaei@gmail.com> | 2025-12-28 02:03:33 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-28 02:03:33 +0300 |
| commit | 69ccdba734226ad6c1b8853d545bf8c8b462bdd6 (patch) | |
| tree | 80bb9a21c36df928226d643bc8bd23b9de94fccc /x-ui.sh | |
| parent | 4c797dc154b2b50f7d2d2bdfd28b7c5e30a78cb4 (diff) | |
Self-signed SSL (#3611)
Diffstat (limited to 'x-ui.sh')
| -rw-r--r-- | x-ui.sh | 253 |
1 files changed, 236 insertions, 17 deletions
@@ -213,6 +213,57 @@ gen_random_string() { echo "$random_string" } +# Generate and configure a self-signed SSL certificate +setup_self_signed_certificate() { + local name="$1" # domain or IP to place in SAN + local certDir="/root/cert/selfsigned" + + LOGI "Generating a self-signed certificate (not publicly trusted)..." + + mkdir -p "$certDir" + + local sanExt="" + if [[ "$name" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ || "$name" =~ : ]]; then + sanExt="IP:${name}" + else + sanExt="DNS:${name}" + fi + + openssl req -x509 -nodes -newkey rsa:2048 -days 365 \ + -keyout "${certDir}/privkey.pem" \ + -out "${certDir}/fullchain.pem" \ + -subj "/CN=${name}" \ + -addext "subjectAltName=${sanExt}" >/dev/null 2>&1 + + if [[ $? -ne 0 ]]; then + local tmpCfg="${certDir}/openssl.cnf" + cat > "$tmpCfg" <<EOF +[req] +distinguished_name=req_distinguished_name +req_extensions=v3_req +[req_distinguished_name] +[v3_req] +subjectAltName=${sanExt} +EOF + openssl req -x509 -nodes -newkey rsa:2048 -days 365 \ + -keyout "${certDir}/privkey.pem" \ + -out "${certDir}/fullchain.pem" \ + -subj "/CN=${name}" \ + -config "$tmpCfg" -extensions v3_req >/dev/null 2>&1 + rm -f "$tmpCfg" + fi + + if [[ ! -f "${certDir}/fullchain.pem" || ! -f "${certDir}/privkey.pem" ]]; then + LOGE "Failed to generate self-signed certificate" + return 1 + fi + + chmod 755 ${certDir}/* >/dev/null 2>&1 + /usr/local/x-ui/x-ui cert -webCert "${certDir}/fullchain.pem" -webCertKey "${certDir}/privkey.pem" >/dev/null 2>&1 + LOGI "Self-signed certificate configured. Browsers will show a warning." + return 0 +} + reset_webbasepath() { echo -e "${yellow}Resetting Web Base Path${plain}" @@ -256,7 +307,7 @@ check_config() { local existing_webBasePath=$(echo "$info" | grep -Eo 'webBasePath: .+' | awk '{print $2}') local existing_port=$(echo "$info" | grep -Eo 'port: .+' | awk '{print $2}') - local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep -Eo 'cert: .+' | awk '{print $2}') + local existing_cert=$(/usr/local/x-ui/x-ui setting -getCert true | grep 'cert:' | awk -F': ' '{print $2}' | tr -d '[:space:]') local server_ip=$(curl -s --max-time 3 https://api.ipify.org) if [ -z "$server_ip" ]; then server_ip=$(curl -s --max-time 3 https://4.ident.me) @@ -271,7 +322,22 @@ check_config() { echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" fi else - echo -e "${green}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${red}⚠ WARNING: No SSL certificate configured!${plain}" + read -rp "Generate a self-signed SSL certificate now? [y/N]: " gen_self + if [[ "$gen_self" == "y" || "$gen_self" == "Y" ]]; then + stop >/dev/null 2>&1 + setup_self_signed_certificate "${server_ip}" + if [[ $? -eq 0 ]]; then + restart >/dev/null 2>&1 + echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + else + LOGE "Self-signed SSL setup failed." + echo -e "${yellow}You can try again via option 18 (SSL Certificate Management).${plain}" + fi + else + echo -e "${yellow}Access URL: http://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + echo -e "${yellow}For security, please configure SSL certificate using option 18 (SSL Certificate Management)${plain}" + fi fi } @@ -958,6 +1024,7 @@ ssl_cert_issue_main() { 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}\t6.${plain} Auto SSL for Server IP" echo -e "${green}\t0.${plain} Back to Main Menu" read -rp "Choose an option: " choice @@ -1051,6 +1118,16 @@ ssl_cert_issue_main() { fi ssl_cert_issue_main ;; + 6) + echo -e "${yellow}Automatic SSL Certificate for Server IP${plain}" + echo -e "This will automatically obtain and configure an SSL certificate for your server's IP address." + echo -e "${yellow}Note: Let's Encrypt supports IP certificates. Make sure port 80 is open.${plain}" + confirm "Do you want to proceed?" "y" + if [[ $? == 0 ]]; then + ssl_cert_issue_for_ip + fi + ssl_cert_issue_main + ;; *) echo -e "${red}Invalid option. Please select a valid number.${plain}\n" @@ -1059,6 +1136,134 @@ ssl_cert_issue_main() { esac } +ssl_cert_issue_for_ip() { + LOGI "Starting automatic SSL certificate generation for server IP..." + + local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') + local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') + + # Get server IP + local server_ip=$(curl -s --max-time 3 https://api.ipify.org) + if [ -z "$server_ip" ]; then + server_ip=$(curl -s --max-time 3 https://4.ident.me) + fi + + if [ -z "$server_ip" ]; then + LOGE "Failed to get server IP address" + return 1 + fi + + LOGI "Server IP detected: ${server_ip}" + + # check for acme.sh first + if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then + LOGI "acme.sh not found, installing..." + install_acme + if [ $? -ne 0 ]; then + LOGE "Failed to install acme.sh" + return 1 + fi + fi + + # install socat + case "${release}" in + ubuntu | debian | armbian) + apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 + ;; + fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol) + dnf -y update >/dev/null 2>&1 && dnf -y install socat >/dev/null 2>&1 + ;; + centos) + if [[ "${VERSION_ID}" =~ ^7 ]]; then + yum -y update >/dev/null 2>&1 && yum -y install socat >/dev/null 2>&1 + else + dnf -y update >/dev/null 2>&1 && dnf -y install socat >/dev/null 2>&1 + fi + ;; + arch | manjaro | parch) + pacman -Sy --noconfirm socat >/dev/null 2>&1 + ;; + opensuse-tumbleweed | opensuse-leap) + zypper refresh >/dev/null 2>&1 && zypper -q install -y socat >/dev/null 2>&1 + ;; + alpine) + apk add socat curl openssl >/dev/null 2>&1 + ;; + *) + LOGW "Unsupported OS for automatic socat installation" + ;; + esac + + # check if certificate already exists for this IP + local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}') + if [ "${currentCert}" == "${server_ip}" ]; then + LOGI "Certificate already exists for IP: ${server_ip}" + certPath="/root/cert/${server_ip}" + else + # create directory for certificate + certPath="/root/cert/${server_ip}" + if [ ! -d "$certPath" ]; then + mkdir -p "$certPath" + else + rm -rf "$certPath" + mkdir -p "$certPath" + fi + + # Use port 80 for certificate issuance + local WebPort=80 + LOGI "Using port ${WebPort} to issue certificate for IP: ${server_ip}" + LOGI "Make sure port ${WebPort} is open and not in use..." + + # issue the certificate for IP + ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt + ~/.acme.sh/acme.sh --issue -d ${server_ip} --listen-v6 --standalone --httpport ${WebPort} --force + if [ $? -ne 0 ]; then + LOGE "Failed to issue certificate for IP: ${server_ip}" + LOGE "Make sure port ${WebPort} is open and the server is accessible from the internet" + rm -rf ~/.acme.sh/${server_ip} + return 1 + else + LOGI "Certificate issued successfully for IP: ${server_ip}" + fi + + # install the certificate + ~/.acme.sh/acme.sh --installcert -d ${server_ip} \ + --key-file /root/cert/${server_ip}/privkey.pem \ + --fullchain-file /root/cert/${server_ip}/fullchain.pem \ + --reloadcmd "x-ui restart" + + if [ $? -ne 0 ]; then + LOGE "Failed to install certificate" + rm -rf ~/.acme.sh/${server_ip} + return 1 + else + LOGI "Certificate installed successfully" + fi + + # enable auto-renew + ~/.acme.sh/acme.sh --upgrade --auto-upgrade >/dev/null 2>&1 + chmod 755 $certPath/* + fi + + # Set certificate paths for the panel + local webCertFile="/root/cert/${server_ip}/fullchain.pem" + local webKeyFile="/root/cert/${server_ip}/privkey.pem" + + if [[ -f "$webCertFile" && -f "$webKeyFile" ]]; then + /usr/local/x-ui/x-ui cert -webCert "$webCertFile" -webCertKey "$webKeyFile" + LOGI "Certificate configured for panel" + LOGI " - Certificate File: $webCertFile" + LOGI " - Private Key File: $webKeyFile" + echo -e "${green}Access URL: https://${server_ip}:${existing_port}${existing_webBasePath}${plain}" + LOGI "Panel will restart to apply SSL certificate..." + restart + return 0 + else + LOGE "Certificate files not found after installation" + return 1 + fi +} + ssl_cert_issue() { local existing_webBasePath=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'webBasePath: .+' | awk '{print $2}') local existing_port=$(/usr/local/x-ui/x-ui setting -show true | grep -Eo 'port: .+' | awk '{print $2}') @@ -1072,33 +1277,32 @@ ssl_cert_issue() { fi fi - # install socat second + # install socat case "${release}" in ubuntu | debian | armbian) - apt-get update && apt-get install socat -y + apt-get update >/dev/null 2>&1 && apt-get install socat -y >/dev/null 2>&1 ;; fedora | amzn | virtuozzo | rhel | almalinux | rocky | ol) - dnf -y update && dnf -y install socat + dnf -y update >/dev/null 2>&1 && dnf -y install socat >/dev/null 2>&1 ;; centos) - if [[ "${VERSION_ID}" =~ ^7 ]]; then - yum -y update && yum -y install socat - else - dnf -y update && dnf -y install socat - fi + if [[ "${VERSION_ID}" =~ ^7 ]]; then + yum -y update >/dev/null 2>&1 && yum -y install socat >/dev/null 2>&1 + else + dnf -y update >/dev/null 2>&1 && dnf -y install socat >/dev/null 2>&1 + fi ;; arch | manjaro | parch) - pacman -Sy --noconfirm socat + pacman -Sy --noconfirm socat >/dev/null 2>&1 ;; - opensuse-tumbleweed | opensuse-leap) - zypper refresh && zypper -q install -y socat + opensuse-tumbleweed | opensuse-leap) + zypper refresh >/dev/null 2>&1 && zypper -q install -y socat >/dev/null 2>&1 ;; alpine) - apk add socat curl openssl + apk add socat curl openssl >/dev/null 2>&1 ;; *) - echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" - exit 1 + LOGW "Unsupported OS for automatic socat installation" ;; esac if [ $? -ne 0 ]; then @@ -1110,7 +1314,22 @@ ssl_cert_issue() { # get the domain here, and we need to verify it local domain="" - read -rp "Please enter your domain name: " domain + while true; do + read -rp "Please enter your domain name: " domain + domain="${domain// /}" # Trim whitespace + + if [[ -z "$domain" ]]; then + LOGE "Domain name cannot be empty. Please try again." + continue + fi + + if ! is_domain "$domain"; then + LOGE "Invalid domain format: ${domain}. Please enter a valid domain name." + continue + fi + + break + done LOGD "Your domain is: ${domain}, checking it..." # check if there already exists a certificate |
