Files
vps/install/20-NewApi.sh
T
eddy 37ccdafc23 feat: 更新 NewApi 安装脚本以支持安全更新
- 增加检测已有安装的功能,避免覆盖数据库路径和配置
- 提供用户选择:仅更新或强制重装
- 强制重装时需确认,防止意外数据丢失
2026-07-02 03:41:34 +08:00

240 lines
7.7 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# chmod +x 20-NewApi.sh && ./20-NewApi.sh
# curl -sS -O https://gitea.tohub.top/Share/vps/raw/branch/main/install/20-NewApi.sh && chmod +x 20-NewApi.sh && ./20-NewApi.sh
set -euo pipefail
port80=8200
if [ "$(id -u)" -ne 0 ]; then
echo "请使用 root 用户运行本脚本。" >&2
exit 1
fi
for required_cmd in openssl curl grep sed apt; do
if ! command -v "$required_cmd" >/dev/null 2>&1; then
echo "未检测到 $required_cmd。本脚本依赖 Debian/Ubuntu 系统环境,请先安装后再运行。" >&2
exit 1
fi
done
# 选择安装目录
install_dir=/root/data/docker_data/NewApi
update_script="$install_dir/auto-update.sh"
# 交互:已有安装时默认只更新,避免覆盖数据库路径、账号数据和密钥
existing_install=0
if [ -f "$install_dir/docker-compose.yml" ]; then
existing_install=1
fi
echo "请选择操作:"
if [ "$existing_install" -eq 1 ]; then
echo " 1) 已安装,仅执行 Docker 更新(默认,安全,不覆盖配置/数据库)"
echo " 2) 强制重装 NewApi(危险,会重写 docker-compose.yml"
else
echo " 1) 安装 NewApi(默认)"
echo " 2) 不安装,立即执行 Docker 更新"
fi
read -r -p "请输入选项 [1/2](默认 1):" action_choice
action_choice="${action_choice:-1}"
if { [ "$existing_install" -eq 1 ] && [ "$action_choice" = "1" ]; } || { [ "$existing_install" -eq 0 ] && [ "$action_choice" = "2" ]; }; then
echo "已选择:立即执行 Docker 更新。"
if [ -x "$update_script" ]; then
"$update_script"
elif [ -f "$install_dir/docker-compose.yml" ]; then
cd "$install_dir" || { echo "无法进入安装目录 $install_dir" >&2; exit 1; }
if docker compose version >/dev/null 2>&1; then
compose_cmd=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
compose_cmd=(docker-compose)
else
echo "未检测到 docker compose 或 docker-compose,无法执行更新。" >&2
exit 1
fi
"${compose_cmd[@]}" pull
"${compose_cmd[@]}" up -d
docker image prune -f
else
echo "未检测到已安装的 NewApi(缺少 $install_dir/docker-compose.yml),请先安装。" >&2
exit 1
fi
echo "Docker 更新完成。"
exit 0
fi
if [ "$existing_install" -eq 1 ] && [ "$action_choice" = "2" ]; then
echo "检测到已有 NewApi 安装:$install_dir/docker-compose.yml"
echo "强制重装会覆盖 docker-compose.yml,可能导致服务连接到新的空数据库。"
read -r -p "如确需重装,请输入 REINSTALL 确认:" reinstall_confirm
if [ "$reinstall_confirm" != "REINSTALL" ]; then
echo "未确认强制重装,已退出。原有配置未修改。"
exit 0
fi
fi
# 生成 sed 安全的随机密钥(hex)
redis_password=$(openssl rand -hex 16)
session_secret=$(openssl rand -hex 24)
ipv4_address=$(curl -fsS --max-time 10 ipv4.ip.sb || true)
# 校验 IPv4
ipv4_octet='(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
if ! printf '%s' "$ipv4_address" | grep -qE "^$ipv4_octet(\.$ipv4_octet){3}$"; then
ipv4_address="服务器IP"
fi
# 1、更新包(更新失败不阻断后续安装)
export DEBIAN_FRONTEND=noninteractive
apt update -y || true
apt upgrade -y || true
# 2、创建安装目录
mkdir -p /root/data/docker_data/NewApi
cd /root/data/docker_data/NewApi || { echo "无法进入安装目录 /root/data/docker_data/NewApi" >&2; exit 1; }
# 3、填写 docker-compose 配置
# 先写入占位符,再替换为实际配置
cat <<'EOF' > docker-compose.yml
services:
new-api:
image: calciumion/new-api:latest
container_name: new-api
restart: always
command: --log-dir /app/logs
ports:
- "__PORT80__:3000"
volumes:
- ./data:/data
- ./logs:/app/logs
- ./sqlite:/app/sqlite # SQLite数据库存储目录
environment:
- SQL_DB_TYPE=sqlite
- SQL_DB_PATH=/app/sqlite/new-api.db # SQLite数据库文件路径
- REDIS_CONN_STRING=redis://:__REDIS_PASSWORD__@redis
- TZ=Asia/Shanghai
- SESSION_SECRET=__SESSION_SECRET__
depends_on:
- redis
healthcheck:
test:
[
"CMD-SHELL",
"(command -v wget >/dev/null 2>&1 && wget -q -O - http://localhost:3000/api/status || command -v curl >/dev/null 2>&1 && curl -fsS http://localhost:3000/api/status) | grep -q '\"success\"[[:space:]]*:[[:space:]]*true'"
]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:alpine # 使用Alpine版本的Redis,更轻量
container_name: new-api-redis
restart: always
command: redis-server --requirepass __REDIS_PASSWORD__
volumes:
- redis_data:/data # 持久化Redis数据
volumes:
redis_data:
EOF
# 替换占位符为实际值
sed -i \
-e "s|__PORT80__|$port80|g" \
-e "s|__REDIS_PASSWORD__|$redis_password|g" \
-e "s|__SESSION_SECRET__|$session_secret|g" \
docker-compose.yml
# 4、安装
if ! command -v docker >/dev/null 2>&1; then
echo "未检测到 docker,请先安装 Docker 后再运行本脚本。" >&2
exit 1
fi
if docker compose version >/dev/null 2>&1; then
compose_cmd=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
compose_cmd=(docker-compose)
else
echo "未检测到 docker compose 或 docker-compose,请先安装 Docker Compose。" >&2
exit 1
fi
"${compose_cmd[@]}" up -d
# 5、打开防火墙的端口
if command -v ufw >/dev/null 2>&1; then
ufw allow "$port80"
ufw status
else
echo "未检测到 ufw,跳过防火墙端口放行。"
fi
# 6、配置每日自动更新
cat <<'EOF' > "$update_script"
#!/bin/bash
set -euo pipefail
install_dir=/root/data/docker_data/NewApi
archive_dir=/root/data/docker_data/NewApi.archive
# 备份数据,先写入临时目录,成功后再替换旧备份
mkdir -p "$(dirname "$archive_dir")"
tmp_archive_dir="${archive_dir}.tmp"
rm -rf "$tmp_archive_dir"
mkdir -p "$tmp_archive_dir"
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete --exclude 'auto-update.log' --exclude 'logs/' "$install_dir"/ "$tmp_archive_dir"/
else
cp -a "$install_dir"/. "$tmp_archive_dir"/
rm -f "$tmp_archive_dir"/auto-update.log
rm -rf "$tmp_archive_dir"/logs
fi
rm -rf "$archive_dir"
mv "$tmp_archive_dir" "$archive_dir"
cd "$install_dir" # 进入 docker-compose 所在的文件夹
if docker compose version >/dev/null 2>&1; then
compose_cmd=(docker compose)
elif command -v docker-compose >/dev/null 2>&1; then
compose_cmd=(docker-compose)
else
echo "未检测到 docker compose 或 docker-compose,无法自动更新。" >&2
exit 1
fi
"${compose_cmd[@]}" pull
"${compose_cmd[@]}" up -d
# 清理旧镜像,释放磁盘空间
docker image prune -f
EOF
chmod +x "$update_script"
# 写入每日 04:00 自动更新任务
cron_line="0 4 * * * $update_script >> /root/data/docker_data/NewApi/auto-update.log 2>&1"
if command -v crontab >/dev/null 2>&1; then
# 使用脚本路径去重,避免重复写入 NewApi 自动更新任务
( crontab -l 2>/dev/null | grep -v -F -- "$update_script" || true ; echo "$cron_line" ) | crontab -
echo "已配置定时自动更新任务:每天 04:00 自动更新 NewApi。"
else
echo "未检测到 crontab,跳过定时更新任务配置。可手动执行 $update_script 更新。"
fi
# 打印访问链接
echo "------------------------"
echo "访问链接:"
echo "http://$ipv4_address:$port80"
echo "User: root"
echo "默认密码: 123456 —— 该端口已对公网开放,请【立即】登录并修改密码!"
echo "------------------------"
echo "已开启定时自动更新:每天 04:00 自动备份并拉取最新镜像。"
echo "手动更新可执行:$update_script"
echo "------------------------"