🚀 运行: ...
IP: ...
ISP: 检测中...

OpenWrt / ImmortalWrt 专属:Passwall 自动更新管理脚本部署指南

在日常维护 OpenWrt 或 ImmortalWrt 路由器时,手动检查并更新 Passwall 插件是一件繁琐的工作。此外,由于系统自带的 wget 在处理 GitHub 重定向链接时存在缺陷,经常会导致下载的安装包文件名变成乱码,从而引起安装失败。

为了解决这些痛点,本文提供了一款专为 OpenWrt/ImmortalWrt 环境打造的 Passwall 自动更新与管理脚本。该脚本带有可视化交互菜单,支持全自动版本匹配、一键配置定时更新、运行状态监控以及脚本自卸载功能。

✨ 核心特性

  • 🤖 智能环境自适应: 自动检测系统主版本(支持 22.0323.05-24.10 及最新的 25.12+ 分支),自动匹配 .ipk (opkg) 或 .apk (apk) 包管理器。
  • 🔗 原生文件名解析: 完美解决 GitHub Release 链接重定向导致的下载乱码问题,确保安装包名称原汁原味。
  • 🎛️ 交互式管理面板: 告别繁杂的命令行,提供清晰的数字菜单供日常维护使用。
  • ⏱️ 零感定时更新: 一键将更新任务写入系统 Cron 计划,每天凌晨自动静默比对 GitHub 最新版本并完成升级。
  • 🧹 纯净无残留: 脚本内置自卸载选项,一键清理定时任务、运行日志及脚本文件本身,绝不制造系统垃圾。

🚀 部署步骤

第一步:创建并写入脚本

通过 SSH 登录到你的路由器终端,直接复制并执行以下整段命令。这会自动在 /root 目录下创建脚本文件并赋予运行权限:

Bash

cat << 'EOF' > /root/pw_autoupdate.sh
#!/bin/sh

# ================= 基础变量 =================
SCRIPT_PATH="/root/pw_autoupdate.sh"
LOG_FILE="/tmp/passwall_update.log"
CRON_CMD="30 4 * * * $SCRIPT_PATH auto >> $LOG_FILE 2>&1"

# ================= 核心更新逻辑 =================
do_update() {
    echo "--------------------------------------"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始执行自动检测更新..."
    
    . /etc/openwrt_release 2>/dev/null
    SYS_VER="${DISTRIB_RELEASE:-}"

    if command -v apk >/dev/null 2>&1 && [ ! -x "/bin/opkg" ]; then
        PKG_TYPE="apk"
        MATCH_PREFIX="25.12+"
    elif echo "$SYS_VER" | grep -qE '^2[5-9]\.|SNAPSHOT'; then
        PKG_TYPE="apk"
        MATCH_PREFIX="25.12+"
    elif echo "$SYS_VER" | grep -qE '^22\.03|^21\.|^19\.|^18\.'; then
        PKG_TYPE="ipk"
        MATCH_PREFIX="22.03"
    else
        PKG_TYPE="ipk"
        MATCH_PREFIX="23.05-24.10"
    fi

    LOCAL_VER=""
    if [ "$PKG_TYPE" = "apk" ]; then
        LOCAL_VER=$(apk list -I "luci-app-passwall" 2>/dev/null | awk -F'-' '{print $(NF-1)}')
    else
        LOCAL_VER=$(opkg list-installed luci-app-passwall 2>/dev/null | awk '{print $3}')
    fi

    API_URL="https://api.github.com/repos/Openwrt-Passwall/openwrt-passwall/releases/latest"
    RELEASE_DATA=$(curl -s "$API_URL" || wget -qO- "$API_URL")

    if [ -z "$RELEASE_DATA" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] [-] 无法连接 GitHub API,终止本次更新。"
        return 1
    fi

    REMOTE_VER=$(echo "$RELEASE_DATA" | grep '"tag_name":' | head -n 1 | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')

    if [ -n "$LOCAL_VER" ] && echo "$LOCAL_VER" | grep -q "${REMOTE_VER%%-*}"; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] [✓] 当前版本 ($LOCAL_VER) 已是最新 ($REMOTE_VER),跳过更新。"
        return 0
    fi

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [*] 发现新版本 $REMOTE_VER,开始下载..."

    URL_APP=$(echo "$RELEASE_DATA" | grep -o "https://[^\"]*${MATCH_PREFIX}[^\"]*luci-app-passwall[^\"]*\.${PKG_TYPE}" | head -n 1)
    URL_I18N=$(echo "$RELEASE_DATA" | grep -o "https://[^\"]*${MATCH_PREFIX}[^\"]*luci-i18n-passwall-zh-cn[^\"]*\.${PKG_TYPE}" | head -n 1)

    if [ -z "$URL_APP" ] || [ -z "$URL_I18N" ]; then
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] [-] 未找到匹配 ${MATCH_PREFIX} 的 .${PKG_TYPE} 更新包。"
        return 1
    fi

    TMP_DIR="/tmp/pw_tmp_dir"
    mkdir -p "$TMP_DIR" && cd "$TMP_DIR" || return 1

    FILE_APP=$(basename "$URL_APP")
    FILE_I18N=$(basename "$URL_I18N")

    wget -q -O "$FILE_APP" "$URL_APP"
    wget -q -O "$FILE_I18N" "$URL_I18N"

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [*] 下载完成,开始静默安装..."
    if [ "$PKG_TYPE" = "apk" ]; then
        apk add --allow-untrusted *."$PKG_TYPE" >/dev/null 2>&1
    else
        opkg update >/dev/null 2>&1
        opkg install *."$PKG_TYPE" --force-depends >/dev/null 2>&1
    fi

    rm -rf "$TMP_DIR"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [✓] 新版本更新流程执行完毕!"
}

# ================= 静默运行模式 (供计划任务调用) =================
if [ "$1" = "auto" ]; then
    do_update
    exit 0
fi

# ================= 交互菜单模式 =================
pause() {
    echo ""
    printf "按【回车键】返回主菜单..."
    read -r DUMMY
}

install_cron() {
    clear
    echo "======================================"
    echo "       安装定时自动更新任务"
    echo "======================================"
    if grep -q "$SCRIPT_PATH auto" /etc/crontabs/root 2>/dev/null; then
        echo "[!] 定时任务已存在,无需重复安装。"
    else
        echo "$CRON_CMD" >> /etc/crontabs/root
        /etc/init.d/cron restart
        echo "[✓] 已成功添加定时任务:每天凌晨 4:30 自动检查并更新。"
    fi
    pause
}

uninstall_script() {
    clear
    echo "======================================"
    echo "      卸载本管理脚本及定时任务"
    echo "======================================"
    echo "⚠️  警告:此操作将彻底删除【自动更新脚本】及相关定时任务。"
    echo "(不用担心,您已安装的 Passwall 插件主体不会受到任何影响)"
    printf "确认要删除本脚本吗?(y/n): "
    read -r confirm
    if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
        if [ -f "/etc/crontabs/root" ]; then
            sed -i "|$SCRIPT_PATH auto|d" /etc/crontabs/root
            /etc/init.d/cron restart
        fi
        rm -f "$LOG_FILE"
        echo "[✓] 定时任务和历史日志已清理干净。"
        echo "[✓] 脚本本体即将自我删除。退出面板。"
        rm -f "$SCRIPT_PATH"
        exit 0
    else
        echo "[-] 已取消卸载。"
        pause
    fi
}

check_status() {
    clear
    echo "======================================"
    echo "         自动更新任务运行状态"
    echo "======================================"
    echo "1. 【后台定时任务】:"
    if grep -q "$SCRIPT_PATH auto" /etc/crontabs/root 2>/dev/null; then
        echo "   🟢 运行中 (设定为每天凌晨 4:30 自动执行)"
    else
        echo "   🔴 未启用 (如需启用,请在主菜单选择 1 进行安装)"
    fi
    
    echo ""
    echo "2. 【当前插件版本】:"
    if command -v apk >/dev/null 2>&1 && [ ! -x "/bin/opkg" ]; then
        apk list -I "luci-app-passwall" 2>/dev/null || echo "   未检测到安装包"
    else
        opkg list-installed luci-app-passwall 2>/dev/null || echo "   未检测到安装包"
    fi
    pause
}

view_logs() {
    clear
    echo "======================================"
    echo "         自动更新执行日志"
    echo "======================================"
    if [ -f "$LOG_FILE" ]; then
        tail -n 30 "$LOG_FILE"
    else
        echo "[-] 暂无日志记录 (计划任务尚未触发或已被清理)。"
    fi
    pause
}

manual_run() {
    clear
    echo "======================================"
    echo "        立即手动执行一次检查更新"
    echo "======================================"
    do_update
    pause
}

while true; do
    clear
    echo "======================================"
    echo "    Passwall 自动更新管理工具 v3.0"
    echo "======================================"
    echo "  1. ⏱️ 开启自动更新 (每天凌晨 4:30)"
    echo "  2. 🗑️ 卸载本脚本 (彻底清理定时任务)"
    echo "  3. 🩺 查看任务运行状态"
    echo "  4. 📋 查看自动执行日志"
    echo "  5. 🚀 立即检查并更新 (测试用)"
    echo "  0. 退出管理面板"
    echo "======================================"
    printf "请输入对应数字 [0-5]: "
    read choice
    case "$choice" in
        1) install_cron ;;
        2) uninstall_script ;;
        3) check_status ;;
        4) view_logs ;;
        5) manual_run ;;
        0) clear; exit 0 ;;
        *) echo "[-] 输入无效。"; sleep 1 ;;
    esac
done
EOF

chmod +x /root/pw_autoupdate.sh

第二步:唤出交互面板

代码写入完成后,随时可以通过以下命令启动可视化管理面板:

Bash

/root/pw_autoupdate.sh

🛠️ 面板功能说明

  • 选项 1(开启自动更新): 选择后,脚本会自动将执行命令写入系统的 Cron 计划。每天凌晨 4:30,系统会在后台静默完成版本比对和安装,全程无需人工干预。
  • 选项 3 & 4(状态与日志查看): 方便排查网络环境是否正常,你可以查阅最近一次后台自动更新的详细执行日志。
  • 选项 5(立即检查并更新): 若不想等待凌晨的计划任务,也可以随时通过此选项立刻拉取最新版本。
  • 选项 2(卸载本脚本): 若不再需要自动更新功能,此选项会自动清除 Cron 任务、清空执行日志,并销毁脚本文件自身,实现无痕卸载(不会影响已安装的 Passwall 插件主体)。

💡 提示: 确保路由器的网络环境可以正常访问 GitHub API,否则脚本在获取最新版本信息时可能会提示连接失败。