This commit is contained in:
Torotin 2025-06-22 13:57:10 +03:00 committed by GitHub
commit c84bcf4c7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 296 additions and 47 deletions

View file

@ -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"

View file

@ -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.6.8/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 ../../
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# ------------------------------------------------------------------------------
# DockerInit.sh <20> download and prepare Xray binaries and geolocation databases
# ------------------------------------------------------------------------------
# Xray version
readonly XRAY_VERSION="v25.6.8"
# 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 <<EOF
Usage: $0 <architecture>
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-}"

View file

@ -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" ]