使用 1Panel 内置 API 配合计划任务,实现面板自动更新,支持开启 MFA 认证及安全入口。

风险警告:不论是手动还是自动更新,都存在更新失败或出现问题的风险,请确保自身有解决问题的能力。

一、注意事项

  1. 在 “面板设置” - “面板”,设置 “服务器地址”(必做,多数情况设置为公网 IP 地址)

  2. 在 “面板设置” - “面板”,将 “默认网卡” 设置为 “所有”(可选,排错的时候或许可以解决问题)

  3. 在 “面板设置” - “安全”,将 “监听地址” 设置为 “0.0.0.0”(可选,排错的时候或许可以解决问题)

  4. 若已开启 MFA 认证,但没有保存密钥,请关闭 “两步验证” 后重新生成,密钥显示位置,如下图所示

二、安装 OATH Tool 软件包(启用 MFA 时必做)

如果面板启用 MFA 认证,则需要在系统安装 oathtool 软件包,并且在脚本设置 MFA 密钥

# Debian
sudo apt -y install oathtool
# CentOS (具体使用 dnf 还是 yum 根据自己使用的发行版决定)
sudo dnf -y install oathtool
sudo yum -y install oathtool

三、创建计划任务

  • 任务类型:Shell脚本

  • 任务名称:根据自己喜好,自行决定。

  • 执行周期:根据需求和自己解决问题的能力,自行决定,喜欢折腾也不必太频繁,每周或每月一次就够了

  • 脚本内容:复制下方的脚本(记得填写面板密码和 MFA 密钥,如果遇到问题,根据实际情况自行调整代码)

  • 保留份数:保留日志的数量,通常留 1 个月就够了,自行决定

四、自动更新脚本

一般来讲只需要设置PASSWORDMFA_SECRET 就可以用了,但毕竟每个人的环境各不相同,本人仅测试了开启 MFA 和安全入口、且服务器地址和监听地址均为公网 IP 的情况,如果遇到问题,请自行调整代码~

#!/bin/bash

PASSWORD="XXXXXXXXXXXXXXXXXXXXXXXXXX"  # 1Panel 面板密码
MFA_SECRET="XXXXXXXXXXXXXXXXXXXXXXXXXX"  # MFA 密钥
DEBUG=false  # 显示调试信息

# 输出调试信息
debug() {
    if [ "$(echo "$DEBUG" | tr '[:upper:]' '[:lower:]')" = "true" ]; then
        echo -e "$1"
    fi
}

# 检查 OATH Tool 安装情况
if [ -n "$MFA_SECRET" ] && ! command -v oathtool &> /dev/null; then
    echo "[错误] 请在系统中安装 oathtool 后重试"
    exit 1
fi

if [ -z "$PASSWORD" ]; then
    echo "[错误] 请在脚本的 PASSWORD 变量中正确填写 1Panel 面板的登录密码"
    exit 1
fi

# 获取 1Panel 面板地址及用户名
USER_INFO=$(1pctl user-info)
debug "[调试] 执行 1pctl user-info 输出的信息:\n$USER_INFO"

if echo "$USER_INFO" | grep -q "Panel address:"; then
    BASE_URL=$(echo "$USER_INFO" | grep "Panel address:" | awk '{print $3}')
    USERNAME=$(echo "$USER_INFO" | grep "Panel user:" | awk '{print $3}')
else
    BASE_URL=$(echo "$USER_INFO" | grep "面板地址:" | awk '{print $2}')
    USERNAME=$(echo "$USER_INFO" | grep "面板用户:" | awk '{print $2}')
fi

debug "[调试] 经过处理的信息:"
echo "[信息] 面板地址: $BASE_URL"
echo "[信息] 面板用户: $USERNAME"

ENTRANCECODE=""

# 处理安全入口
if echo "$BASE_URL" | grep -q "^[^/]*//[^/]*/"; then
    ENTRANCECODE=$(echo "$BASE_URL" | sed -E 's#^[^/]*//[^/]*/([^/]+).*#\1#')
    BASE_URL=$(echo "$BASE_URL" | sed -E 's#^(([^/]*/+){3})[^/]+.*#\1#' | sed 's:/$::')
fi

echo "[信息] 基本地址: $BASE_URL"
echo "[信息] 安全入口: $ENTRANCECODE"

ENTRANCECODE=$(echo -n "$ENTRANCECODE" | base64)
debug "[调试] 安全入口(Base64): $ENTRANCECODE"

if [ -z "$BASE_URL" ] || [ -z "$USERNAME" ]; then
    echo "[错误] 无法获取面板地址或用户名,请检查 1pctl 命令是否可用"
    exit 1
fi

COOKIE_FILE=$(mktemp)
debug "[调试] 临时文件(Cookie): $COOKIE_FILE"

# 设置 MFA 密钥时生成 TOTP 验证码
if [ -n "$MFA_SECRET" ]; then
    MFA_CODE=$(oathtool --totp -b "$MFA_SECRET")
    echo "[信息] 使用的 MFA 验证码(TOTP):$MFA_CODE"
    # 使用 MFA 登录
    LOGIN_RESPONSE=$(curl -k -s --location --request POST "$BASE_URL/api/v1/auth/mfalogin" \
    --header "entrancecode: $ENTRANCECODE" \
    --data-raw '{
        "name": "'"$USERNAME"'",
        "password": "'"$PASSWORD"'",
        "secret": "",
        "code": "'"$MFA_CODE"'",
        "authMethod": "session"
    }' --cookie-jar $COOKIE_FILE)
else
    # 常规登录方式
    LOGIN_RESPONSE=$(curl -k -s --location --request POST "$BASE_URL/api/v1/auth/login" \
    --header "entrancecode: $ENTRANCECODE" \
    --data-raw '{
        "authMethod": "session",
        "captcha": "",
        "captchaID": "",
        "ignoreCaptcha": true,
        "language": "zh",
        "name": "'"$USERNAME"'",
        "password": "'"$PASSWORD"'"
    }' --cookie-jar $COOKIE_FILE)
fi

debug "[调试] 完整登录响应: $LOGIN_RESPONSE"

CODE=$(echo "$LOGIN_RESPONSE" | grep -o '"code":[0-9]*' | awk -F':' '{print $2}')
echo "[信息] 登录响应代码: $CODE"

if [ "$CODE" != "200" ]; then
    echo "[错误] 登录失败,请检查 MFA 密钥和验证码或面板密码是否正确"
    rm $COOKIE_FILE -f
    exit 1
fi

# 检查面板更新
UPGRADE_RESPONSE=$(curl -k -s --request GET "$BASE_URL/api/v1/settings/upgrade" --cookie $COOKIE_FILE \
--header "entrancecode: $ENTRANCECODE")
debug "[调试] 完整版本检查响应: $UPGRADE_RESPONSE"

CODE=$(echo "$UPGRADE_RESPONSE" | grep -o '"code":[0-9]*' | awk -F':' '{print $2}')
TEST_VERSION=$(echo "$UPGRADE_RESPONSE" | grep -o '"testVersion":"[^"]*' | sed 's/"testVersion":"//')
NEW_VERSION=$(echo "$UPGRADE_RESPONSE" | grep -o '"newVersion":"[^"]*' | sed 's/"newVersion":"//')
LATEST_VERSION=$(echo "$UPGRADE_RESPONSE" | grep -o '"latestVersion":"[^"]*' | sed 's/"latestVersion":"//')

echo "[信息] 版本检查响应代码: $CODE"

if [ "$CODE" == "200" ]; then
    if [ -n "$TEST_VERSION" ]; then
        VERSION_TO_UPDATE="$TEST_VERSION"
        echo "[信息] 测试版本: $TEST_VERSION"
    elif [ -n "$LATEST_VERSION" ]; then
        VERSION_TO_UPDATE="$LATEST_VERSION"
        echo "[信息] 最新版本: $LATEST_VERSION"
    elif [ -n "$NEW_VERSION" ]; then
        VERSION_TO_UPDATE="$NEW_VERSION"
        echo "[信息] 更新版本: $NEW_VERSION"
    else
        echo "[信息] 当前已是最新版本"
        rm $COOKIE_FILE -f
        exit 0
    fi

    echo "[信息] 检测到新版本($VERSION_TO_UPDATE),即将进行升级..."
    UPDATE_RESPONSE=$(curl -k -s --location --request POST "$BASE_URL/api/v1/settings/upgrade" \
    --header "entrancecode: $ENTRANCECODE" \
    --data-raw '{
        "version": "'"$VERSION_TO_UPDATE"'"
    }' --cookie $COOKIE_FILE)
    UPDATE_CODE=$(echo "$UPDATE_RESPONSE" | grep -o '"code":[0-9]*' | awk -F':' '{print $2}')
    echo "[信息] 版本检查响应: $UPDATE_RESPONSE"
    echo "[信息] 版本检查响应代码: $UPDATE_CODE"
    if [ "$UPDATE_CODE" == "200" ]; then
        echo "[信息] 面板更新完毕"
    else
        echo "[错误] 面板更新失败"
    fi
else
    echo "[错误] 检查更新失败"
fi

rm -f $COOKIE_FILE

此脚本参考 https://bbs.fit2cloud.com/t/topic/9241 根据本人需求进行了一些调整,在此感谢原作者的分享,各位可以根据自身需求参考本帖和原版来调整出适合自己的版本。

调整内容:

  • 支持 1pctl 命令英文输出(由于我的环境 1pctl 输出是英文的,直接使用原贴的代码,首先遇到了无法获取面板地址和用户名的问题,所以增加了一些判断)

  • 移除了将面板地址转换为环回地址的步骤(可能是由于我在面板设置中,指定了默认网卡或监听地址,所以127.0.0.1无法访问面板)

  • 添加 调试信息 选项(显示详细输出,方便定位错误)

  • 调整 输出消息 格式(有一点点强迫症,看起来稍微整齐一些)