From 187084569fb3bf4e943f2d7256784bd65ef87b16 Mon Sep 17 00:00:00 2001 From: TorotinJenkins Date: Sat, 7 Jun 2025 12:08:08 +0300 Subject: [PATCH] Push the updated Docker configuration and scripts branch to the remote repository --- DockerEntrypoint.sh | 136 ++++++++++++++++++++++++++++-- DockerInit.sh | 195 +++++++++++++++++++++++++++++++++++--------- Dockerfile | 12 ++- 3 files changed, 296 insertions(+), 47 deletions(-) diff --git a/DockerEntrypoint.sh b/DockerEntrypoint.sh index 7511d2ea..90132510 100644 --- a/DockerEntrypoint.sh +++ b/DockerEntrypoint.sh @@ -1,7 +1,133 @@ -#!/bin/sh +#!/usr/bin/env bash +# Description: +# 1) Handle SIGTERM for graceful shutdown +# 2) Run all scripts from /mnt/sh/beforestart before starting the main application +# 3) Copy binaries from /mnt/bin to /app/bin +# 4) Launch x-ui in the background and capture its PID +# 5) After x-ui has started, run scripts from /mnt/sh/afterstart +# 6) Start fail2ban if enabled +# 7) Wait for x-ui to exit or receive a signal -# Start fail2ban -[ $XUI_ENABLE_FAIL2BAN == "true" ] && fail2ban-client -x start +set -euo pipefail -# Run x-ui -exec /app/x-ui +############################################################################### +# Logging function +############################################################################### +log() { + local level=$1 + shift + echo "$(date '+%Y-%m-%d %H:%M:%S') $level $*" +} + +############################################################################### +# Function: start_fail2ban_if_enabled +############################################################################### +start_fail2ban_if_enabled() { + if [ "${XUI_ENABLE_FAIL2BAN:-false}" != "true" ]; then + log INFO "Fail2Ban is disabled; skipping start." + return + fi + + log INFO "Attempting to start Fail2Ban..." + if fail2ban-client -x start; then + log INFO "Fail2Ban started successfully." + else + log ERROR "Fail2Ban failed to start." + exit 1 + fi +} + +############################################################################### +# 1) Handle SIGTERM for graceful shutdown +############################################################################### +# When a SIGTERM is received, properly stop the child process (x-ui) +term_handler() { + log INFO "Caught SIGTERM. Stopping x-ui..." + if [[ -n "${XUI_PID:-}" ]]; then + kill -TERM "$XUI_PID" 2>/dev/null || true + wait "$XUI_PID" + fi + log INFO "x-ui stopped." + exit 0 +} +trap 'term_handler' SIGTERM + +############################################################################### +# 2) Execute scripts from /mnt/sh/beforestart +############################################################################### +if [ -d "/mnt/sh/beforestart" ]; then + log INFO "Detected /mnt/sh/beforestart directory. Setting permissions..." + chmod -R 777 /mnt/sh/beforestart + + log INFO "Searching for scripts in /mnt/sh/beforestart..." + find /mnt/sh/beforestart -type f -name "*.sh" -print0 | sort -z | while IFS= read -r -d '' script; do + log INFO "Executing script: $script" + sh "$script" + if [ $? -ne 0 ]; then + log ERROR "Script failed: $script. Aborting startup." + exit 1 + fi + done + + log INFO "All scripts in /mnt/sh/beforestart executed successfully." +fi + +############################################################################### +# 3) Copy binaries from /mnt/bin to /app/bin +############################################################################### +if [ -d "/mnt/bin" ]; then + log INFO "Detected /mnt/bin directory. Copying contents to /app/bin..." + if ! cp -r /mnt/bin/* /app/bin/; then + log ERROR "Failed to copy from /mnt/bin to /app/bin. Aborting startup." + exit 1 + fi + log INFO "Binaries copied to /app/bin successfully." +fi + +############################################################################### +# 4) Launch the main application x-ui in the background +############################################################################### +log INFO "Launching x-ui in background..." +/app/x-ui & +XUI_PID=$! +log INFO "x-ui PID is $XUI_PID." + +# Sleep briefly to ensure the process has started before running afterstart scripts +sleep 10 + +############################################################################### +# 5) Execute scripts from /mnt/sh/afterstart after x-ui has started +############################################################################### +if [ -d "/mnt/sh/afterstart" ]; then + log INFO "Detected /mnt/sh/afterstart directory. Setting permissions..." + chmod -R 777 /mnt/sh/afterstart + + log INFO "Searching for scripts in /mnt/sh/afterstart..." + find /mnt/sh/afterstart -type f -name "*.sh" -print0 | sort -z | while IFS= read -r -d '' script; do + log INFO "Executing script: $script" + sh "$script" + if [ $? -ne 0 ]; then + log ERROR "Script failed: $script. Aborting startup." + # Stop x-ui if an afterstart script fails + kill -TERM "$XUI_PID" 2>/dev/null || true + wait "$XUI_PID" + exit 1 + fi + done + + log INFO "All scripts in /mnt/sh/afterstart executed successfully." +fi + +############################################################################### +# 6) Start Fail2Ban if enabled +############################################################################### +start_fail2ban_if_enabled + +############################################################################### +# 7) Wait for x-ui to exit (or receive a signal) +############################################################################### +log INFO "Waiting for x-ui (PID $XUI_PID) to exit..." +wait "$XUI_PID" +EXIT_CODE=$? +log INFO "x-ui exited with code $EXIT_CODE." +exit "$EXIT_CODE" diff --git a/DockerInit.sh b/DockerInit.sh index c55cea94..2cc36fcd 100755 --- a/DockerInit.sh +++ b/DockerInit.sh @@ -1,40 +1,155 @@ -#!/bin/sh -case $1 in - amd64) - ARCH="64" - FNAME="amd64" - ;; - i386) - ARCH="32" - FNAME="i386" - ;; - armv8 | arm64 | aarch64) - ARCH="arm64-v8a" - FNAME="arm64" - ;; - armv7 | arm | arm32) - ARCH="arm32-v7a" - FNAME="arm32" - ;; - armv6) - ARCH="arm32-v6" - FNAME="armv6" - ;; - *) - ARCH="64" - FNAME="amd64" - ;; -esac -mkdir -p build/bin -cd build/bin -wget -q "https://github.com/XTLS/Xray-core/releases/download/v25.5.16/Xray-linux-${ARCH}.zip" -unzip "Xray-linux-${ARCH}.zip" -rm -f "Xray-linux-${ARCH}.zip" geoip.dat geosite.dat -mv xray "xray-linux-${FNAME}" -wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat -wget -q https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat -wget -q -O geoip_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat -wget -q -O geosite_IR.dat https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat -wget -q -O geoip_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat -wget -q -O geosite_RU.dat https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat -cd ../../ \ No newline at end of file +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' + +# ------------------------------------------------------------------------------ +# DockerInit.sh — download and prepare Xray binaries and geolocation databases +# ------------------------------------------------------------------------------ + +# Xray version +readonly XRAY_VERSION="v25.5.16" + +# URL template for downloading Xray +readonly XRAY_URL_TEMPLATE="https://github.com/XTLS/Xray-core/releases/download/${XRAY_VERSION}/Xray-linux-%s.zip" + +# Directories +readonly BUILD_DIR="build/bin" +readonly ROOT_DIR="$(pwd)" + +# Check for required utilities +check_dependencies() { + local deps=(wget unzip) + for cmd in "${deps[@]}"; do + if ! command -v "$cmd" &> /dev/null; then + echo "Error: Required utility '$cmd' is not installed. Please install it and try again." >&2 + exit 1 + fi + done +} + +# Print usage help +usage() { + cat < + +Supported architectures: + amd64 ? 64-bit x86 + i386 ? 32-bit x86 + armv8 ? ARM64-v8a (also accepts arm64, aarch64) + armv7 ? ARM32-v7a (also accepts arm, arm32) + armv6 ? ARM32-v6 + +If no argument is provided or the argument is not recognized, 'amd64' will be used by default. + +Example: + $0 armv7 +EOF + exit 1 +} + +# Determine ARCH and FNAME based on input argument +detect_arch() { + local input="$1" + + case "$input" in + amd64) + ARCH="64" + FNAME="amd64" + ;; + i386) + ARCH="32" + FNAME="i386" + ;; + armv8 | arm64 | aarch64) + ARCH="arm64-v8a" + FNAME="arm64" + ;; + armv7 | arm | arm32) + ARCH="arm32-v7a" + FNAME="arm32" + ;; + armv6) + ARCH="arm32-v6" + FNAME="armv6" + ;; + "") + # If argument is empty, default to amd64 + ARCH="64" + FNAME="amd64" + ;; + *) + echo "Warning: Architecture '$input' not recognized. Defaulting to 'amd64'." >&2 + ARCH="64" + FNAME="amd64" + ;; + esac +} + +# Generic function to download a file by URL (with error handling) +download_file() { + local url="$1" + local output="$2" + + echo "Downloading: $url" + if ! wget -q -O "$output" "$url"; then + echo "Error: Failed to download '$url'" >&2 + exit 1 + fi +} + +# Main function: create directory, download and unpack Xray, then geolocation databases +main() { + # Check dependencies + check_dependencies + + # Get architecture from argument + local ARCH_ARG="${1-}" + detect_arch "$ARCH_ARG" + + # Construct URL for Xray download + local xray_url + printf -v xray_url "$XRAY_URL_TEMPLATE" "$ARCH" + + # Create build directory + echo "Creating directory: $BUILD_DIR" + mkdir -p "$BUILD_DIR" + cd "$BUILD_DIR" || exit 1 + + # Download and unpack Xray + local xray_zip="Xray-linux-${ARCH}.zip" + download_file "$xray_url" "$xray_zip" + echo "Unpacking $xray_zip" + unzip -q "$xray_zip" + rm -f "$xray_zip" geoip.dat geosite.dat + + # Rename binary according to target architecture + mv xray "xray-linux-${FNAME}" + chmod +x "xray-linux-${FNAME}" + + # Return to project root + cd "$ROOT_DIR" || exit 1 + + # Download standard GeoIP and GeoSite databases + echo "Downloading default GeoIP and GeoSite databases" + download_file "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat" "geoip.dat" + download_file "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat" "geosite.dat" + + # Download alternative GeoIP/GeoSite for Iran (IR) and Russia (RU) + echo "Downloading alternative GeoIP/GeoSite for Iran" + download_file "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat" "geoip_IR.dat" + download_file "https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat" "geosite_IR.dat" + + echo "Downloading alternative GeoIP/GeoSite for Russia" + download_file "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat" "geoip_RU.dat" + download_file "https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat" "geosite_RU.dat" + + echo "Done." +} + +# If -h or --help is passed, show usage +if [[ "${1-}" == "-h" || "${1-}" == "--help" ]]; then + usage +fi + +# Run main with the provided argument (if any) +main "${1-}" diff --git a/Dockerfile b/Dockerfile index 4a15f98d..650b5c15 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,11 +31,11 @@ RUN apk add --no-cache --update \ fail2ban \ bash -COPY --from=builder /app/build/ /app/ +# Copy only required build artifacts from builder stage +COPY --from=builder /app/build /app/ COPY --from=builder /app/DockerEntrypoint.sh /app/ COPY --from=builder /app/x-ui.sh /usr/bin/x-ui - # Configure fail2ban RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \ && cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local \ @@ -43,12 +43,20 @@ RUN rm -f /etc/fail2ban/jail.d/alpine-ssh.conf \ && sed -i "s/^\[sshd\]$/&\nenabled = false/" /etc/fail2ban/jail.local \ && sed -i "s/#allowipv6 = auto/allowipv6 = auto/g" /etc/fail2ban/fail2ban.conf +# Make scripts executable RUN chmod +x \ /app/DockerEntrypoint.sh \ /app/x-ui \ /usr/bin/x-ui +# Enable fail2ban via environment variable (can be overridden) ENV XUI_ENABLE_FAIL2BAN="true" + +# Define volume for persistent configuration VOLUME [ "/etc/x-ui" ] + +# Default command when container starts CMD [ "./x-ui" ] + +# Custom entrypoint to initialize runtime environment ENTRYPOINT [ "/app/DockerEntrypoint.sh" ]