Created
December 7, 2025 11:30
-
-
Save Cloud0310/4e1ee15ff24539db0102473cefa291d3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| # --- Configuration --- | |
| GITHUB_REPO="MetaCubex/mihomo" | |
| CONFIG_REMOTE_URL="" | |
| CONFIG_LOCAL_FILE="/etc/mihomo/config.yaml" | |
| MIHOMO_API_URL="http://localhost:9090" | |
| MIHOMO_API_TOKEN="" | |
| # --- Dependency Check --- | |
| if [[ $EUID -ne 0 ]]; then | |
| echo "Error: This script must be run as root." | |
| exit 1 | |
| fi | |
| for cmd in jq curl awk; do | |
| if ! command -v $cmd &> /dev/null; then | |
| echo "Error: '$cmd' is not installed. Please install it to proceed." >&2 | |
| exit 1 | |
| fi | |
| done | |
| # --- PART 1: Binary Update Logic --- | |
| update_binary() { | |
| echo "--- [Binary Update] Checking for latest release ---" | |
| # 1. Get Local Version | |
| # Output format: Mihomo Meta v1.19.17 linux amd64 ... | |
| # We extract the 3rd field: v1.19.17 | |
| if command -v mihomo &> /dev/null; then | |
| LOCAL_VER=$(mihomo -v | grep "Mihomo Meta" | awk '{print $3}') | |
| echo "Current Local Version: $LOCAL_VER" | |
| else | |
| LOCAL_VER="none" | |
| echo "Current Local Version: None (Not installed)" | |
| fi | |
| # 2. Determine Architecture | |
| ARCH_NAME=$(uname --machine) | |
| FILE_PREFIX="" | |
| if [ "$ARCH_NAME" == "x86_64" ]; then | |
| FILE_PREFIX="mihomo-linux-amd64-v3" | |
| elif [ "$ARCH_NAME" == "aarch64" ]; then | |
| FILE_PREFIX="mihomo-linux-arm64" | |
| else | |
| echo "Error: Unsupported architecture: $ARCH_NAME" | |
| exit 1 | |
| fi | |
| # 3. Determine OS Family & Extension | |
| if [ -f /etc/os-release ]; then | |
| . /etc/os-release | |
| else | |
| echo "Error: /etc/os-release not found." | |
| exit 1 | |
| fi | |
| FILE_SUFFIX="" | |
| DISTRO_TYPE="" | |
| if [[ "$ID" == "arch" || "$ID_LIKE" == *"arch"* ]]; then | |
| FILE_SUFFIX="pkg.tar.zst" | |
| DISTRO_TYPE="arch" | |
| elif [[ "$ID" == "debian" || "$ID_LIKE" == *"debian"* ]]; then | |
| FILE_SUFFIX=".deb" | |
| DISTRO_TYPE="debian" | |
| else | |
| echo "Error: Could not determine strictly Arch or Debian lineage." | |
| exit 1 | |
| fi | |
| # 4. Fetch GitHub API | |
| echo "Querying GitHub API..." | |
| API_URL="https://api.github.com/repos/$GITHUB_REPO/releases/latest" | |
| RESPONSE=$(curl -s -L \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| "$API_URL") | |
| # 5. Parse Remote Version and Download URL | |
| # We extract both the tag_name (version) and the specific asset URL | |
| PARSED_DATA=$(echo "$RESPONSE" | jq -r --arg prefix "$FILE_PREFIX" --arg suffix "$FILE_SUFFIX" \ | |
| '{ | |
| tag: .tag_name, | |
| url: (.assets | map(select(.name | startswith($prefix) and endswith($suffix))) | .[0].browser_download_url) | |
| }') | |
| REMOTE_VER=$(echo "$PARSED_DATA" | jq -r '.tag') | |
| DOWNLOAD_URL=$(echo "$PARSED_DATA" | jq -r '.url') | |
| if [ "$REMOTE_VER" == "null" ] || [ -z "$REMOTE_VER" ]; then | |
| echo "Error: Could not determine remote version." | |
| exit 1 | |
| fi | |
| echo "Latest Remote Version: $REMOTE_VER" | |
| # 6. Compare and Update | |
| if [ "$LOCAL_VER" == "$REMOTE_VER" ]; then | |
| echo "✅ System is already running the latest version. Skipping binary update." | |
| return 0 | |
| fi | |
| if [ "$DOWNLOAD_URL" == "null" ] || [ -z "$DOWNLOAD_URL" ]; then | |
| echo "Error: No matching asset found for architecture/OS." | |
| exit 1 | |
| fi | |
| echo "⚡ Update available ($LOCAL_VER -> $REMOTE_VER). Downloading..." | |
| # 7. Install logic | |
| if [ "$DISTRO_TYPE" == "arch" ]; then | |
| echo "Detected Arch Linux. Installing via pacman..." | |
| TEMP_PKG=$(mktemp --suffix=.pkg.tar.zst) | |
| curl -L -o "$TEMP_PKG" "$DOWNLOAD_URL" | |
| pacman -U --noconfirm "$TEMP_PKG" | |
| rm -f "$TEMP_PKG" | |
| elif [ "$DISTRO_TYPE" == "debian" ]; then | |
| echo "Detected Debian/Ubuntu. Downloading and installing via dpkg..." | |
| TEMP_DEB=$(mktemp --suffix=.deb) | |
| curl -L -o "$TEMP_DEB" "$DOWNLOAD_URL" | |
| dpkg -i "$TEMP_DEB" | |
| rm -f "$TEMP_DEB" | |
| fi | |
| echo "Binary update complete." | |
| # Force a service restart later because binary changed | |
| BINARY_UPDATED=1 | |
| } | |
| # --- PART 2: Configuration Update Logic --- | |
| trigger_internal_upgrades() { | |
| echo "Triggering Mihomo UI and Geo data upgrades..." | |
| # We check if service is up before curling | |
| if systemctl is-active --quiet mihomo.service; then | |
| curl -sfL -X POST -H "Authorization: Bearer $MIHOMO_API_TOKEN" "${MIHOMO_API_URL}/upgrade/ui" || echo "Warning: Failed to upgrade UI" | |
| curl -sfL -X POST -H "Authorization: Bearer $MIHOMO_API_TOKEN" "${MIHOMO_API_URL}/upgrade/geo" || echo "Warning: Failed to upgrade GeoIP" | |
| echo "Internal upgrades triggered." | |
| else | |
| echo "Service is not running, skipping API triggers." | |
| fi | |
| } | |
| update_config() { | |
| echo "--- [Config Update] Checking remote config ---" | |
| mkdir -p "$(dirname "$CONFIG_LOCAL_FILE")" | |
| SHOULD_RESTART=0 | |
| # If binary was just updated, we MUST restart regardless of config change | |
| if [ "$BINARY_UPDATED" == "1" ]; then | |
| SHOULD_RESTART=1 | |
| fi | |
| # Case 1: Initial Download | |
| if [ ! -f "$CONFIG_LOCAL_FILE" ]; then | |
| echo "Local file not found. Performing initial download..." | |
| curl --noproxy "*" -fLo "$CONFIG_LOCAL_FILE" "$CONFIG_REMOTE_URL" | |
| SHOULD_RESTART=1 | |
| else | |
| # Case 2: Conditional Update | |
| LAST_MOD_HEADER=$(date -Rur "$CONFIG_LOCAL_FILE" | sed 's/+0000/GMT/') | |
| TEMP_FILE=$(mktemp) | |
| trap 'rm -f "$TEMP_FILE"' RETURN | |
| HTTP_STATUS=$(curl --noproxy "*" -sL -w '%{http_code}' -o "$TEMP_FILE" -H "If-Modified-Since: $LAST_MOD_HEADER" "$CONFIG_REMOTE_URL") | |
| if [ "$HTTP_STATUS" == "200" ]; then | |
| echo "Remote config is newer. Updating..." | |
| if [ -s "$TEMP_FILE" ]; then | |
| mv "$CONFIG_LOCAL_FILE" "${CONFIG_LOCAL_FILE}.bak" | |
| mv "$TEMP_FILE" "$CONFIG_LOCAL_FILE" | |
| SHOULD_RESTART=1 | |
| else | |
| echo "Error: Downloaded empty file." | |
| fi | |
| elif [ "$HTTP_STATUS" == "304" ]; then | |
| echo "Config is up to date." | |
| else | |
| echo "Error fetching config. HTTP Status: $HTTP_STATUS" | |
| fi | |
| fi | |
| # Restart Service if needed | |
| if [ "$SHOULD_RESTART" -eq 1 ]; then | |
| echo "Restarting mihomo service..." | |
| systemctl restart mihomo.service | |
| sleep 5 | |
| trigger_internal_upgrades | |
| else | |
| echo "No changes required." | |
| fi | |
| } | |
| # --- Main Execution --- | |
| BINARY_UPDATED=0 | |
| # 1. Update Binary | |
| update_binary | |
| # 2. Update Config | |
| update_config | |
| echo "All tasks finished." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment