From f901cd42a5330dae12fe996da3e98c1bf2ccb630 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Tue, 2 Jun 2026 21:26:47 +0200 Subject: [PATCH] fix(docker): make x-ui CLI menu work inside containers check_status() only recognized a systemd service or Alpine's /etc/init.d/x-ui, neither of which exists in a container where the panel runs as the foreground main process (PID 1 via "exec /app/x-ui"). Every CLI command therefore failed with "Please install the panel first", and restart/restart-xray relied on rc-service/systemctl that aren't present. Detect the container (/.dockerenv or XUI_IN_DOCKER) and, when inside one: - resolve the panel binary under /app instead of /usr/local/x-ui - derive status from the running process instead of a service file - restart via SIGHUP and restart-xray via SIGUSR1 to the panel process - show Docker-appropriate guidance for start/stop/enable/disable The Dockerfile sets XUI_IN_DOCKER/XUI_MAIN_FOLDER so detection is explicit even though /.dockerenv alone suffices. Closes #4817 --- Dockerfile | 4 +- x-ui.sh | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3383bc6c..e75eb90b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -63,9 +63,9 @@ RUN chmod +x \ /app/x-ui \ /usr/bin/x-ui +ENV XUI_IN_DOCKER="true" +ENV XUI_MAIN_FOLDER="/app" ENV XUI_ENABLE_FAIL2BAN="true" -# Database backend: set XUI_DB_TYPE=postgres and XUI_DB_DSN=postgres://... to use PostgreSQL. -# Default (unset) is SQLite stored under /etc/x-ui. ENV XUI_DB_TYPE="" ENV XUI_DB_DSN="" EXPOSE 2053 diff --git a/x-ui.sh b/x-ui.sh index 1954820c..9265e3af 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -69,8 +69,17 @@ echo "The OS release is: $release" os_version="" os_version=$(grep "^VERSION_ID" /etc/os-release | cut -d '=' -f2 | tr -d '"' | tr -d '.') +running_in_docker="false" +if [[ -f /.dockerenv ]] || [[ "${XUI_IN_DOCKER}" == "true" ]]; then + running_in_docker="true" +fi + # Declare Variables -xui_folder="${XUI_MAIN_FOLDER:=/usr/local/x-ui}" +if [[ "${running_in_docker}" == "true" ]]; then + xui_folder="${XUI_MAIN_FOLDER:=/app}" +else + xui_folder="${XUI_MAIN_FOLDER:=/usr/local/x-ui}" +fi xui_service="${XUI_SERVICE:=/etc/systemd/system}" log_folder="${XUI_LOG_FOLDER:=/var/log/x-ui}" mkdir -p "${log_folder}" @@ -400,6 +409,15 @@ start() { echo "" LOGI "Panel is running, No need to start again, If you need to restart, please select restart" else + if [[ "${running_in_docker}" == "true" ]]; then + LOGE "Panel process is not running inside this container." + LOGI "In Docker the panel is the container's main process. Restart the container to bring it back up:" + LOGI " docker restart " + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-service x-ui start else @@ -425,6 +443,15 @@ stop() { echo "" LOGI "Panel stopped, No need to stop again!" else + if [[ "${running_in_docker}" == "true" ]]; then + LOGI "In Docker the panel runs as the container's main process." + LOGI "To stop it, stop the container from the host:" + LOGI " docker stop " + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-service x-ui stop else @@ -445,6 +472,26 @@ stop() { } restart() { + if [[ "${running_in_docker}" == "true" ]]; then + if signal_xui HUP; then + sleep 1 + signal_xui USR1 + LOGI "Restart signal sent to the panel and xray-core." + else + LOGE "Could not find the running panel process to signal." + fi + sleep 2 + check_status + if [[ $? == 0 ]]; then + LOGI "x-ui and xray Restarted successfully" + else + LOGE "Panel restart failed, Please check the log information later" + fi + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-service x-ui restart else @@ -463,6 +510,19 @@ restart() { } restart_xray() { + if [[ "${running_in_docker}" == "true" ]]; then + if signal_xui USR1; then + LOGI "xray-core Restart signal sent successfully, Please check the log information to confirm whether xray restarted successfully" + else + LOGE "Could not find the running panel process to signal." + fi + sleep 2 + show_xray_status + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-service x-ui reload else @@ -477,6 +537,13 @@ restart_xray() { } status() { + if [[ "${running_in_docker}" == "true" ]]; then + show_status + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-service x-ui status else @@ -488,6 +555,14 @@ status() { } enable() { + if [[ "${running_in_docker}" == "true" ]]; then + LOGI "Autostart is controlled by the Docker restart policy (e.g. 'restart: unless-stopped' in docker-compose.yml)." + LOGI "There is no service to enable inside the container." + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-update add x-ui default else @@ -505,6 +580,14 @@ enable() { } disable() { + if [[ "${running_in_docker}" == "true" ]]; then + LOGI "Autostart is controlled by the Docker restart policy (e.g. 'restart: unless-stopped' in docker-compose.yml)." + LOGI "Set 'restart: no' for the container on the host to disable autostart." + if [[ $# == 0 ]]; then + before_show_menu + fi + return 0 + fi if [[ $release == "alpine" ]]; then rc-update del x-ui else @@ -673,8 +756,31 @@ update_shell() { fi } +xui_pid() { + ps -ef 2> /dev/null | grep -F "${xui_folder}/x-ui" | grep -v grep | awk 'NR==1 {print $1}' +} + +signal_xui() { + local sig="$1" pid + pid="$(xui_pid)" + if [[ -z "${pid}" ]]; then + return 1 + fi + kill -"${sig}" "${pid}" 2> /dev/null +} + # 0: running, 1: not running, 2: not installed check_status() { + if [[ "${running_in_docker}" == "true" ]]; then + if [[ ! -x "${xui_folder}/x-ui" ]]; then + return 2 + fi + if [[ -n "$(xui_pid)" ]]; then + return 0 + else + return 1 + fi + fi if [[ $release == "alpine" ]]; then if [[ ! -f /etc/init.d/x-ui ]]; then return 2 @@ -761,6 +867,10 @@ show_status() { } show_enable_status() { + if [[ "${running_in_docker}" == "true" ]]; then + echo -e "Start automatically: ${green}Managed by Docker${plain}" + return + fi check_enabled if [[ $? == 0 ]]; then echo -e "Start automatically: ${green}Yes${plain}"