diff --git a/README.md b/README.md index 54d0552..04689cc 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Documentation: [English version](https://github.com/fscarmen2/Argo-Nezha-Service - [客户端接入](README.md#客户端接入) - [SSH 接入](README.md#ssh-接入) - [手动备份数据](README.md#手动备份数据) +- [手动更新备份和还原脚本](README.md#手动更新备份和还原脚本) - [自动还原备份](README.md#自动还原备份) - [手动还原备份](README.md#手动还原备份) - [完美搬家](README.md#完美搬家) @@ -92,16 +93,17 @@ Argo 隧道认证方式有 json 和 token,使用两个方式其中之一。推 用到的变量 | 变量名 | 是否必须 | 备注 | | ------------ | ------ | ---- | - | GH_USER | 是 | github 的用户名,用于面板管理授权 | - | GH_CLIENTID | 是 | 在 github 上申请 | - | GH_CLIENTSECRET| 是 | 在 github 上申请 | - | GH_BACKUP_USER | 否 | 在 github 上备份哪吒服务端数据库的 github 用户名,不填则与面板管理授权的账户 GH_USER 一致 | - | GH_REPO | 否 | 在 github 上备份哪吒服务端数据库文件的 github 库 | - | GH_EMAIL | 否 | github 的邮箱,用于备份的 git 推送到远程库 | - | GH_PAT | 否 | github 的 PAT | - | NGINX | 否 | 默认使用 gRPCwebProxy 应用来反代,这时可以不填写该变量;如需 nginx 反代,请设置该值为 1 | - | ARGO_AUTH | 是 | Json: 从 https://fscarmen.cloudflare.now.cc 获取的 Argo Json
Token: 从 Cloudflare 官网获取 | - | ARGO_DOMAIN | 是 | Argo 域名 | + | GH_USER | 是 | github 的用户名,用于面板管理授权 | + | GH_CLIENTID | 是 | 在 github 上申请 | + | GH_CLIENTSECRET | 是 | 在 github 上申请 | + | GH_BACKUP_USER | 否 | 在 github 上备份哪吒服务端数据库的 github 用户名,不填则与面板管理授权的账户 GH_USER 一致 | + | GH_REPO | 否 | 在 github 上备份哪吒服务端数据库文件的 github 库 | + | GH_EMAIL | 否 | github 的邮箱,用于备份的 git 推送到远程库 | + | GH_PAT | 否 | github 的 PAT | + | REVERSE_PROXY_MODE | 否 | 默认使用 nginx 应用来反代,这时可以不填写该变量;如需 gRPCwebProxy 反代,请设置该值为 `grpcwebproxy` | + | ARGO_AUTH | 是 | Json: 从 https://fscarmen.cloudflare.now.cc 获取的 Argo Json
Token: 从 Cloudflare 官网获取 | + | ARGO_DOMAIN | 是 | Argo 域名 | + | NO_AUTO_RENEW | 否 | 默认不需要该变量,即每天定时同步在线最新的备份和还原脚本。如不需要该功能,设置此变量,并赋值为 `1` | Koyeb @@ -135,7 +137,8 @@ docker run -dit \ -e ARGO_AUTH='<填获取的 Argo json 或者 token>' \ -e ARGO_DOMAIN=<填自定义的> \ -e GH_BACKUP_USER=<选填,选填,选填! 如与 GH_USER 一致,可以不要该环境变量> \ - -e NGINX=<选填,选填,选填! 如想用 nginx 替代 gRPCwebProxy 反代的话,把该值设置为1> \ + -e REVERSE_PROXY_MODE=<选填,选填,选填! 如想用 gRPCwebProxy 替代 nginx 反代的话,请设置该变量并赋值为 `grpcwebproxy`> \ + -e NO_AUTO_RENEW=<选填,选填,选填! 如果不需要自动在线同步最新的 backup.sh 和 restore.sh,请设置该变量并赋值为 `1`> fscarmen/argo-nezha ``` @@ -158,7 +161,8 @@ services: - ARGO_AUTH='<填获取的 Argo json 或者 token>' - ARGO_DOMAIN=<填自定义的> - GH_BACKUP_USER=<选填,选填,选填! 如与 GH_USER 一致,可以不要该环境变量> - - NGINX=<选填,选填,选填! 如想用 nginx 替代 gRPCwebProxy 反代的话,把该值设置为1> + - REVERSE_PROXY_MODE=<选填,选填,选填! 如想用 gRPCwebProxy 替代 nginx 反代的话,请设置该变量并赋值为 `grpcwebproxy`> + - NO_AUTO_RENEW=<选填,选填,选填! 如果不需要自动在线同步最新的 backup.sh 和 restore.sh,请设置该变量并赋值为 `1`> ``` @@ -197,6 +201,10 @@ curl -L https://raw.githubusercontent.com/naiba/nezha/master/script/install.sh - 方法二: ssh 进去后,容器版本运行 `/dashboard/backup.sh`; 非容器版本运行 `/opt/nezha/dashboard/backup.sh` +## 手动更新备份和还原脚本 +ssh 进去后,容器版本运行 `/dashboard/renew.sh`; 非容器版本运行 `/opt/nezha/dashboard/renew.sh` + + ## 自动还原备份 * 把需要还原的文件名改到 github 备份库里的 `README.md`,定时服务会每分钟检测更新,并把上次同步的文件名记录在本地 `/dbfile` 处以与在线的文件内容作比对 @@ -229,6 +237,7 @@ tar czvf dashboard.tar.gz /dashboard |-- argo.yml # Argo 隧道 yml 文件,用于在一同隧道下,根据不同域名来分流 web, gRPC 和 ssh 协议的作用 |-- backup.sh # 备份数据脚本 |-- restore.sh # 还原备份脚本 +|-- renew.sh # 在线更新备份和还原文件的脚本 |-- dbfile # 记录最新的还原或备份文件名 |-- resource # 面板主题、语言和旗帜等资料的文件夹 |-- data diff --git a/README_EN.md b/README_EN.md index bcc40af..9e73e3d 100644 --- a/README_EN.md +++ b/README_EN.md @@ -17,6 +17,7 @@ Documentation: English version | [中文版](https://github.com/fscarmen2/Argo-N - [Client Access](README_EN.md#client-access) - [SSH Access](README_EN.md#ssh-access) - [Manual Backup data](README_EN.md#manual-backup-data) +- [Manual Rerew backup and restore scrpits](README_EN.md#manual-renew-backup-and-restore-scrpits) - [Auto Restore Backup](README_EN.md#automatically-restore-backups) - [Manual Restore Backup](README_EN.md#manually-restore-the-backup) - [Migrating data](README_EN.md#migrating-data) @@ -92,16 +93,17 @@ Image `fscarmen/argo-nezha:latest`, supports amd64 and arm64 architectures. Variables used | Variable Name | Required | Remarks | | ------------ | ------ | ---- | - | GH_USER | Yes | github username for panel admin authorization | - | GH_CLIENTID | yes | apply on github | - | GH_CLIENTSECRET | yes | apply on github | - | GH_BACKUP_USER | No | The github username for backing up Nezha's server-side database on github, if not filled in, it is the same as the account GH_USER for panel management authorization | - | GH_REPO | No | The github repository for backing up Nezha's server-side database files on github | - | GH_EMAIL | No | github's mailbox for git push backups to remote repositories | - | GH_PAT | No | github's PAT | - | NGINX | No | If you want to use nginx instead of gRPCwebProxy for reverse proxying, set this value to 1 | - | ARGO_AUTH | Yes | Argo Json from https://fscarmen.cloudflare.now.cc
Argo token from Cloudflare official website | - | ARGO_DOMAIN | Yes | Argo domain | + | GH_USER | Yes | github username for panel admin authorization | + | GH_CLIENTID | yes | apply on github | + | GH_CLIENTSECRET | yes | apply on github | + | GH_BACKUP_USER | No | The github username for backing up Nezha's server-side database on github, if not filled in, it is the same as the account GH_USER for panel management authorization | + | GH_REPO | No | The github repository for backing up Nezha's server-side database files on github | + | GH_EMAIL | No | github's mailbox for git push backups to remote repositories | + | GH_PAT | No | github's PAT | + | REVERSE_PROXY_MODE | No | If you want to use gRPCwebProxy instead of nginx for reverse proxying, set this value to `grpcwebproxy` | + | ARGO_AUTH | Yes | Argo Json from https://fscarmen.cloudflare.now.cc
Argo token from Cloudflare official website | + | ARGO_DOMAIN | Yes | Argo domain | + | NO_AUTO_RENEW | No | The latest backup and restore scripts are synchronized online regularly every day. If you don't need this feature, set this variable and assign it a value of `1` | Koyeb @@ -135,7 +137,8 @@ docker run -dit \ -e ARGO_AUTH='' \ -e ARGO_DOMAIN= \ -e GH_BACKUP_USER= \ - -e NGINX= \ + -e REVERSE_PROXY_MODE= \ + -e NO_AUTO_RENEW= fscarmen/argo-nezha ``` @@ -158,7 +161,8 @@ services. - ARGO_AUTH='' - ARGO_DOMAIN= - GH_BACKUP_USER= - - NGINX= + - REVERSE_PROXY_MODE= + - NO_AUTO_RENEW= ``` @@ -197,6 +201,11 @@ Method 1: Change the contents of the `README.md` file in the Github backup repos Method 2: After ssh, run `/dashboard/backup.sh` for container version; `/opt/nezha/dashboard/backup.sh` for VPS host version. +## Manual Rerew backup and restore scrpits + +After ssh, run `/dashboard/renew.sh` for container version; `/opt/nezha/dashboard/renew.sh` for VPS host version. + + ## Automatically restore backups * Change the name of the file to be restored to `README.md` in the github backup repository, the timer service will check for updates every minute and record the last synchronized filename in the local `/dbfile` to compare with the online file content. @@ -230,6 +239,7 @@ tar czvf dashboard.tar.gz /dashboard |-- argo.yml # Argo tunnel yml file, used for streaming web, gRPC and ssh protocols under a single tunnel with different domains. |-- backup.sh # Backup data scripts |-- restore.sh # Restore backup scripts +|-- renew.sh # Scripts to update backup and restore files online |-- dbfile # Record the name of the latest restore or backup file |-- resource # Folders of information on panel themes, languages, flags, etc. |-- data diff --git a/dashboard.sh b/dashboard.sh index ba06865..49802ee 100644 --- a/dashboard.sh +++ b/dashboard.sh @@ -7,7 +7,7 @@ TEMP_DIR='/tmp/nezha' START_PORT='5000' NEED_PORTS=3 # web , gRPC , gRPC proxy -trap "rm -rf $TEMP_DIR; echo -e '\n' ;exit 1" INT QUIT TERM EXIT +trap "rm -rf $TEMP_DIR; echo -e '\n' ;exit" INT QUIT TERM EXIT mkdir -p $TEMP_DIR @@ -87,10 +87,12 @@ E[36]="Downloading the \${FAILED[*]} failed. Installation aborted. Feedback: [ht C[36]="下载 \${FAILED[*]} 失败,安装中止,问题反馈:[https://github.com/fscarmen2/Argo-Nezha-Service-Container/issues]" E[37]="Install Nezha's official VPS or docker version (https://github.com/naiba/nezha)" C[37]="安装哪吒官方 VPS 或 Docker 版本 (https://github.com/naiba/nezha)" -E[38]="Please choose gRPC proxy mode:\n 1. gRPCwebProxy (default) \n 2. Nginx" -C[38]="请选择 gRPC 代理模式:\n 1. gRPCwebProxy (默认) \n 2. Nginx" +E[38]="Please choose gRPC proxy mode:\n 1. Nginx (default) \n 2. gRPCwebProxy" +C[38]="请选择 gRPC 代理模式:\n 1. Nginx (默认) \n 2. gRPCwebProxy" E[39]="To uninstall Nginx press [y], it is not uninstalled by default:" C[39]="如要卸载 Nginx 请按 [y],默认不卸载:" +E[40]="Default: enable automatic online synchronization of the latest backup.sh and restore.sh scripts. If you do not want this feature, enter [n]:" +C[40]="默认开启自动在线同步最新 backup.sh 和 restore.sh 脚本的功能,如不需要该功能,请输入 [n]:" # 自定义字体彩色,read 函数 warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 @@ -260,12 +262,12 @@ certificate() { } dashboard_variables() { - [ -z "$GH_USER"] && reading " (1/10) $(text 9) " GH_USER - [ -z "$GH_CLIENTID"] && reading "\n (2/10) $(text 10) " GH_CLIENTID - [ -z "$GH_CLIENTSECRET"] && reading "\n (3/10) $(text 11) " GH_CLIENTSECRET + [ -z "$GH_USER"] && reading " (1/11) $(text 9) " GH_USER + [ -z "$GH_CLIENTID"] && reading "\n (2/11) $(text 10) " GH_CLIENTID + [ -z "$GH_CLIENTSECRET"] && reading "\n (3/11) $(text 11) " GH_CLIENTSECRET local a=5 until [[ "$ARGO_AUTH" =~ TunnelSecret || "$ARGO_AUTH" =~ ^[A-Z0-9a-z=]{120,250}$ || "$ARGO_AUTH" =~ .*cloudflared.*service[[:space:]]+install[[:space:]]+[A-Z0-9a-z=]{1,100} ]]; do - [ "$a" = 0 ] && error "\n $(text 3) \n" || reading "\n (4/10) $(text 12) " ARGO_AUTH + [ "$a" = 0 ] && error "\n $(text 3) \n" || reading "\n (4/11) $(text 12) " ARGO_AUTH if [[ "$ARGO_AUTH" =~ TunnelSecret ]]; then ARGO_JSON=${ARGO_AUTH//[ ]/} elif [[ "$ARGO_AUTH" =~ ^[A-Z0-9a-z=]{120,250}$ ]]; then @@ -279,22 +281,26 @@ dashboard_variables() { done # 处理可能输入的错误,去掉开头和结尾的空格,去掉最后的 : - [ -z "$ARGO_DOMAIN"] && reading "\n (5/10) $(text 13) " ARGO_DOMAIN + [ -z "$ARGO_DOMAIN"] && reading "\n (5/11) $(text 13) " ARGO_DOMAIN ARGO_DOMAIN=$(sed 's/[ ]*//g; s/:[ ]*//' <<< "$ARGO_DOMAIN") { certificate; }& - # 用户选择使用 grpcwebproxy 还是 Nginx 作 gRPC 反代,默认为 grpcwebproxy - [ -z "$NGINX" ] && info "\n (6/10) $(text 38) \n" && reading " $(text 24) " NGINX + # 用户选择使用 Nginx 还是 grpcwebproxy 作 gRPC 反代,默认为 Nginx + [ -z "$REVERSE_PROXY_MODE" ] && info "\n (6/11) $(text 38) \n" && reading " $(text 24) " REVERSE_PROXY_CHOOSE + [ "$REVERSE_PROXY_CHOOSE" = 2 ] && REVERSE_PROXY_MODE=grpcwebproxy || REVERSE_PROXY_MODE=nginx [[ -z "$GH_USER" || -z "$GH_CLIENTID" || -z "$GH_CLIENTSECRET" || -z "$ARGO_AUTH" || -z "$ARGO_DOMAIN" ]] && error "\n $(text 18) " - [ -z "$GH_REPO"] && reading "\n (7/10) $(text 14) " GH_REPO + [ -z "$GH_REPO"] && reading "\n (7/11) $(text 14) " GH_REPO if [ -n "$GH_REPO" ]; then - reading "\n (8/10) $(text 15) " GH_BACKUP_USER + reading "\n (8/11) $(text 15) " GH_BACKUP_USER GH_BACKUP_USER=${GH_BACKUP_USER:-$GH_USER} - [ -z "$GH_EMAIL"] && reading "\n (9/10) $(text 16) " GH_EMAIL - [ -z "$GH_PAT"] && reading "\n (10/10) $(text 17) " GH_PAT + [ -z "$GH_EMAIL"] && reading "\n (9/11) $(text 16) " GH_EMAIL + [ -z "$GH_PAT"] && reading "\n (10/11) $(text 17) " GH_PAT fi + + [ -z "$AUTO_RENEW_OR_NOT"] && reading "\n (11/11) $(text 40) " AUTO_RENEW_OR_NOT + grep -qiw 'n' <<< "$AUTO_RENEW_OR_NOT" && IS_AUTO_RENEW=# } # 安装面板 @@ -306,11 +312,7 @@ install() { hint "\n $(text 25) " # 根据 grpcwebproxy 或 nginx 作处理 - if [ "$NGINX" != '2' ]; then - wget -c ${GH_PROXY}https://github.com/fscarmen2/Argo-Nezha-Service-Container/releases/download/grpcwebproxy/grpcwebproxy_linux_$ARCH.tar.gz -qO- | tar xz -C $TEMP_DIR >/dev/null 2>&1 - chmod +x $WORK_DIR/grpcwebproxy - GRPC_PROXY_RUN="nohup ${WORK_DIR}/grpcwebproxy --run_http_server=false --server_tls_cert_file=${WORK_DIR}/nezha.pem --server_tls_key_file=${WORK_DIR}/nezha.key --server_http_tls_port=$GRPC_PROXY_PORT --backend_addr=localhost:${GRPC_PORT} --backend_tls_noverify --server_http_max_read_timeout=300s --server_http_max_write_timeout=300s >/dev/null 2>&1 &" - else + if [ "$REVERSE_PROXY_MODE" = 'nginx' ]; then [ ! $(type -p nginx) ] && ${PACKAGE_INSTALL[int]} nginx GRPC_PROXY_RUN="nginx -c $WORK_DIR/nginx.conf" cat > $TEMP_DIR/nginx.conf << EOF @@ -344,6 +346,10 @@ http { } } EOF + elif [ "$REVERSE_PROXY_MODE" = 'grpcwebproxy' ]; then + wget -c ${GH_PROXY}https://github.com/fscarmen2/Argo-Nezha-Service-Container/releases/download/grpcwebproxy/grpcwebproxy_linux_$ARCH.tar.gz -qO- | tar xz -C $TEMP_DIR >/dev/null 2>&1 + chmod +x $TEMP_DIR/grpcwebproxy + GRPC_PROXY_RUN="nohup ${WORK_DIR}/grpcwebproxy --run_http_server=false --server_tls_cert_file=${WORK_DIR}/nezha.pem --server_tls_key_file=${WORK_DIR}/nezha.key --server_http_tls_port=$GRPC_PROXY_PORT --backend_addr=localhost:${GRPC_PORT} --backend_tls_noverify --server_http_max_read_timeout=300s --server_http_max_write_timeout=300s >/dev/null 2>&1 &" fi wait @@ -352,13 +358,13 @@ EOF for f in ${TEMP_DIR}/{cloudflared,app,nezha.key,nezha.csr,nezha.pem}; do [ ! -s "$f" ] && FAILED+=("${f//${TEMP_DIR}\//}") done - [ "$NGINX" != '2' ] && [ ! -s $TEMP_DIR/grpcwebproxy ] && FAILED+=("grpcwebproxy") + [ "$REVERSE_PROXY_MODE" = 'grpcwebproxy' ] && [ ! -s $TEMP_DIR/grpcwebproxy ] && FAILED+=("grpcwebproxy") [ "${#FAILED[@]}" -gt 0 ] && error "\n $(text 36) " # 从临时文件夹复制已下载的所有到工作文件夹 [ ! -d ${WORK_DIR}/data ] && mkdir -p ${WORK_DIR}/data cp -r $TEMP_DIR/{app,cloudflared,nezha.*} $WORK_DIR - [ "$NGINX" != '2' ] && cp -f $TEMP_DIR/grpcwebproxy $WORK_DIR || cp -f $TEMP_DIR/nginx.conf $WORK_DIR + [ "$REVERSE_PROXY_MODE" = 'nginx' ] && cp -f $TEMP_DIR/nginx.conf $WORK_DIR || cp -f $TEMP_DIR/grpcwebproxy $WORK_DIR rm -rf $TEMP_DIR # 根据参数生成哪吒服务端配置文件 @@ -430,7 +436,7 @@ EOF cat > ${WORK_DIR}/run.sh << EOF #!/usr/bin/env bash SYSTEM=$SYSTEM -NGINX=$NGINX +REVERSE_PROXY_MODE=$REVERSE_PROXY_MODE if [ "\$1" = 'start' ]; then cd ${WORK_DIR} @@ -442,10 +448,10 @@ if [ "\$1" = 'start' ]; then $ARGO_RUN elif [ "\$1" = 'stop' ]; then - if [ "\$NGINX" = '2' ]; then - [ "\$SYSTEM" = 'Alpine' ] && ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|app)/{print \$1}' | xargs kill -9 || ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|app)/{print \$2}' | xargs kill -9 - else + if [ "\$REVERSE_PROXY_MODE" = 'nginx' ]; then [ "\$SYSTEM" = 'Alpine' ] && ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|grpcwebproxy|app)/{print \$1}' | xargs kill -9 || ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|grpcwebproxy|app)/{print \$2}' | xargs kill -9 + elif [ "\$REVERSE_PROXY_MODE" = 'grpcwebproxy' ]; then + [ "\$SYSTEM" = 'Alpine' ] && ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|app)/{print \$1}' | xargs kill -9 || ps -ef | awk '/\/opt\/nezha\/dashboard\/(cloudflared|app)/{print \$2}' | xargs kill -9 fi fi EOF @@ -469,7 +475,7 @@ RestartSec=5s WantedBy=multi-user.target EOF - # 生成定时备份数据库脚本,定时任务,删除 5 天前的备份 + # 生成 backup.sh 文件的步骤1 - 设置环境变量 cat > ${WORK_DIR}/backup.sh << EOF #!/usr/bin/env bash @@ -483,307 +489,64 @@ GH_REPO=$GH_REPO SYSTEM=$SYSTEM ARCH=$ARCH WORK_DIR=$WORK_DIR +DAYS=5 +IS_DOCKER=0 -warning() { echo -e "\033[31m\033[01m\$*\033[0m"; } # 红色 -error() { echo -e "\033[31m\033[01m\$*\033[0m" && exit 1; } # 红色 -info() { echo -e "\033[32m\033[01m\$*\033[0m"; } # 绿色 -hint() { echo -e "\033[33m\033[01m\$*\033[0m"; } # 黄色 - -cmd_systemctl() { - local ENABLE_DISABLE=\$1 - if [ "\$ENABLE_DISABLE" = 'enable' ]; then - if [ "\$SYSTEM" = 'Alpine' ]; then - local TRY=5 - until [ \$(systemctl is-active nezha-dashboard) = 'active' ]; do - systemctl stop nezha-dashboard; sleep 1 - systemctl start nezha-dashboard - ((TRY--)) - [ "\$TRY" = 0 ] && break - done - cat > /etc/local.d/nezha-dashboard.start << ABC -#!/usr/bin/env bash - -systemctl start nezha-dashboard -ABC - chmod +x /etc/local.d/nezha-dashboard.start - rc-update add local >/dev/null 2>&1 - else - systemctl enable --now nezha-dashboard - fi - - elif [ "\$ENABLE_DISABLE" = 'disable' ]; then - if [ "\$SYSTEM" = 'Alpine' ]; then - systemctl stop nezha-dashboard - rm -f /etc/local.d/nezha-dashboard.start - else - systemctl disable --now nezha-dashboard - fi - fi -} - -# 手自动标志 -[ "\$1" = 'a' ] && WAY=Scheduled || WAY=Manualed -[ "\$1" = 'f' ] && WAY=Manualed && FORCE_UPDATE=true - -# 检查更新面板主程序 app 及 cloudflared -cd \$WORK_DIR -DASHBOARD_NOW=\$(./app -v) -DASHBOARD_LATEST=\$(wget -qO- "https://api.github.com/repos/naiba/nezha/releases/latest" | awk -F '"' '/"tag_name"/{print \$4}') -[[ "\$DASHBOARD_LATEST" =~ ^v([0-9]{1,3}\.){2}[0-9]{1,3}\$ && "\$DASHBOARD_NOW" != "\$DASHBOARD_LATEST" ]] && DASHBOARD_UPDATE=true - -CLOUDFLARED_NOW=\$(./cloudflared -v | awk '{for (i=0; i README.md - find ./ -name '*.gz' | sort | head -n -5 | xargs rm -f - git config --global user.name \$GH_BACKUP_USER - git config --global user.email \$GH_EMAIL - git checkout --orphan tmp_work - git add . - git commit -m "\$WAY at \$TIME ." - git push -f -u origin HEAD:main --quiet - IS_BACKUP="\$?" - cd .. - rm -rf \$GH_REPO - [ "\$IS_BACKUP" = 0 ] && echo "dashboard-\$TIME.tar.gz" > \$WORK_DIR/dbfile && info "\n Succeed to upload the backup files dashboard-\$TIME.tar.gz to Github.\n" || hint "\n Failed to upload the backup files dashboard-\$TIME.tar.gz to Github.\n" - hint "\n Start Nezha-dashboard \n" - fi - fi - - # 重启面板 - cmd_systemctl enable >/dev/null 2>&1; sleep 2 -fi - -[ "\$(systemctl is-active nezha-dashboard)" = 'active' ] && info "\n Done! \n" || error "\n Fail! \n" +######## EOF + # 生成 backup.sh 文件的步骤2 - 在线获取 template/bakcup.sh 模板生成完整 backup.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/backup.sh | sed '1,/^########/d' >> ${WORK_DIR}/backup.sh + if [[ -n "$GH_BACKUP_USER" && -n "$GH_REPO" && -n "$GH_PAT" ]]; then # 生成还原数据脚本 touch ${WORK_DIR}/dbfile + # 生成 restore.sh 文件的步骤1 - 设置环境变量 cat > ${WORK_DIR}/restore.sh << EOF #!/usr/bin/env bash # restore.sh 传参 a 自动还原 README.md 记录的文件,当本地与远程记录文件一样时不还原; 传参 f 不管本地记录文件,强制还原成备份库里 README.md 记录的文件; 传参 dashboard-***.tar.gz 还原成备份库里的该文件;不带参数则要求选择备份库里的文件名 +GH_PROXY=$GH_PROXY GH_PAT=$GH_PAT GH_BACKUP_USER=$GH_BACKUP_USER GH_REPO=$GH_REPO SYSTEM=$SYSTEM WORK_DIR=$WORK_DIR TEMP_DIR=/tmp/restore_temp -BACKUP_FLAG=/tmp/backuping - -trap "rm -rf \$TEMP_DIR; echo -e '\n' ;exit 1" INT QUIT TERM EXIT - -mkdir -p \$TEMP_DIR - -warning() { echo -e "\033[31m\033[01m\$*\033[0m"; } # 红色 -error() { echo -e "\033[31m\033[01m\$*\033[0m" && exit 1; } # 红色 -info() { echo -e "\033[32m\033[01m\$*\033[0m"; } # 绿色 -hint() { echo -e "\033[33m\033[01m\$*\033[0m"; } # 黄色 - -cmd_systemctl() { - local ENABLE_DISABLE=\$1 - if [ "\$ENABLE_DISABLE" = 'enable' ]; then - if [ "\$SYSTEM" = 'Alpine' ]; then - local TRY=5 - until [ \$(systemctl is-active nezha-dashboard) = 'active' ]; do - systemctl stop nezha-dashboard; sleep 1 - systemctl start nezha-dashboard - ((TRY--)) - [ "\$TRY" = 0 ] && break - done - cat > /etc/local.d/nezha-dashboard.start << ABC -#!/usr/bin/env bash - -systemctl start nezha-dashboard -ABC - chmod +x /etc/local.d/nezha-dashboard.start - rc-update add local >/dev/null 2>&1 - else - systemctl enable --now nezha-dashboard - fi - - elif [ "\$ENABLE_DISABLE" = 'disable' ]; then - if [ "\$SYSTEM" = 'Alpine' ]; then - systemctl stop nezha-dashboard - rm -f /etc/local.d/nezha-dashboard.start - else - systemctl disable --now nezha-dashboard - fi - fi -} - -ONLINE="\$(wget -qO- --header="Authorization: token \$GH_PAT" "https://raw.githubusercontent.com/\$GH_BACKUP_USER/\$GH_REPO/main/README.md" | sed "/^$/d" | head -n 1)" - -# 若用户在 Github 的 README.md 里改了内容包含关键词 backup,则触发实时备份;为解决 Github cdn 导致获取文件内容来回跳的问题,设置自锁并检测到备份文件后延时3分钟断开(3次 运行 restore.sh 的时间) -if grep -qi 'backup' <<< "\$ONLINE"; then - [ ! -e \${BACKUP_FLAG}* ] && { touch \${BACKUP_FLAG}; \$WORK_DIR/backup.sh; exit 0; } -elif [ -e \${BACKUP_FLAG} ]; then - mv -f \${BACKUP_FLAG} \${BACKUP_FLAG}1 -elif [ -e \${BACKUP_FLAG}1 ]; then - mv -f \${BACKUP_FLAG}1 \${BACKUP_FLAG}2 -elif [ -e \${BACKUP_FLAG}2 ]; then - mv -f \${BACKUP_FLAG}2 \${BACKUP_FLAG}3 -elif [ -e \${BACKUP_FLAG}3 ]; then - rm -f \${BACKUP_FLAG}3 -fi - -# 读取面板现配置信息 -CONFIG_HTTPPORT=\$(grep -i '^HTTPPort:' \$WORK_DIR/data/config.yaml) -CONFIG_LANGUAGE=\$(grep -i '^Language:' \$WORK_DIR/data/config.yaml) -CONFIG_GRPCPORT=\$(grep -i '^GRPCPort:' \$WORK_DIR/data/config.yaml) -CONFIG_GRPCHOST=\$(grep -i '^GRPCHost:' \$WORK_DIR/data/config.yaml) -CONFIG_PROXYGRPCPORT=\$(grep -i '^ProxyGRPCPort:' \$WORK_DIR/data/config.yaml) -CONFIG_TYPE=\$(sed -n '/Type:/ s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_ADMIN=\$(sed -n '/Admin:/ s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_CLIENTID=\$(sed -n '/ClientID:/ s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_CLIENTSECRET=\$(sed -n '/ClientSecret:/ s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) - -# 如 dbfile 不为空,即不是首次安装,记录当前面板的主题等信息 -[ -s \$WORK_DIR/dbfile ] && CONFIG_BRAND=\$(sed -n '/brand:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) && -CONFIG_COOKIENAME=\$(sed -n '/cookiename:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) && -CONFIG_THEME=\$(sed -n '/theme:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) - -if [ "\$1" = a ]; then - [ "\$ONLINE" = "\$(cat \$WORK_DIR/dbfile)" ] && exit - [[ "\$ONLINE" =~ tar\.gz$ && "\$ONLINE" != "\$(cat \$WORK_DIR/dbfile)" ]] && FILE="\$ONLINE" || exit -elif [ "\$1" = f ]; then - [[ "\$ONLINE" =~ tar\.gz$ ]] && FILE="\$ONLINE" || exit -elif [[ "\$1" =~ tar\.gz$ ]]; then - [[ "\$FILE" =~ http.*/.*tar.gz ]] && FILE=\$(awk -F '/' '{print \$NF}' <<< \$FILE) || FILE="\$1" -elif [ -z "\$1" ]; then - BACKUP_FILE_LIST=(\$(wget -qO- --header="Authorization: token \$GH_PAT" https://api.github.com/repos/\$GH_BACKUP_USER/\$GH_REPO/contents/ | awk -F '"' '/"path".*tar.gz/{print \$4}' | sort -r)) - until [[ "\$CHOOSE" =~ ^[1-\${#BACKUP_FILE_LIST[@]}]$ ]]; do - for i in \${!BACKUP_FILE_LIST[@]}; do echo " \$[i+1]. \${BACKUP_FILE_LIST[i]} "; done - echo "" - [ -z "\$FILE" ] && read -rp " Please choose the backup file [1-\${#BACKUP_FILE_LIST[@]}]: " CHOOSE - [[ ! "\$CHOOSE" =~ ^[1-\${#BACKUP_FILE_LIST[@]}]$ ]] && echo -e "\n Error input!" && sleep 1 - ((j++)) && [ \$j -ge 5 ] && error "\n The choose has failed more than 5 times and the script exits. \n" - done - FILE=\${BACKUP_FILE_LIST[\$((CHOOSE-1))]} -fi +NO_ACTION_FLAG=/tmp/flag +IS_DOCKER=0 -DOWNLOAD_URL=https://raw.githubusercontent.com/\$GH_BACKUP_USER/\$GH_REPO/main/\$FILE -wget --header="Authorization: token \$GH_PAT" --header='Accept: application/vnd.github.v3.raw' -O \$TEMP_DIR/backup.tar.gz "\$DOWNLOAD_URL" - -if [ -e \$TEMP_DIR/backup.tar.gz ]; then - hint "\n Stop Nezha-dashboard \n" && cmd_systemctl disable - - # 容器版的备份旧方案是 /dashboard 文件夹,新方案是备份工作目录 < WORK_DIR > 下的文件,此判断用于根据压缩包里的目录架构判断到哪个目录下解压,以兼容新旧备份方案 - FILE_LIST=\$(tar tzf \$TEMP_DIR/backup.tar.gz) - FILE_PATH=\$(sed -n 's#\(.*/\)data/sqlite\.db.*#\1#gp' <<< "\$FILE_LIST") - - # 判断备份文件里是否有用户自定义主题,如有则一并解压 - CUSTOM_PATH=(\$(sed -n "/custom/s#\$FILE_PATH\(.*custom\)/.*#\1#gp" <<< "\$FILE_LIST" | sort -u)) - [ \${#CUSTOM_PATH[@]} -gt 0 ] && CUSTOM_FULL_PATH=(\$(for k in \${CUSTOM_PATH[@]}; do echo \${FILE_PATH}\${k}; done)) - echo "↓↓↓↓↓↓↓↓↓↓ Restore-file list ↓↓↓↓↓↓↓↓↓↓" - tar xzvf \$TEMP_DIR/backup.tar.gz -C \$TEMP_DIR \${CUSTOM_FULL_PATH[@]} \${FILE_PATH}data - echo -e "↑↑↑↑↑↑↑↑↑↑ Restore-file list ↑↑↑↑↑↑↑↑↑↑\n\n" - - # 处理 v0.15.17 之后自定义主题静态链接的路径问题,删除备份文件中 resource 下的非 custom 文件夹及文件 - [ -d \$TEMP_DIR/resource/static/theme-custom ] && mv -f \$TEMP_DIR/resource/static/theme-custom \$TEMP_DIR/resource/static/custom - [ -s \$TEMP_DIR/resource/template/theme-custom/header.html ] && sed -i 's#/static/theme-custom/#/static-custom/#g' \$TEMP_DIR/resource/template/theme-custom/header.html - if [ -d \$TEMP_DIR/resource ]; then - find \$TEMP_DIR/resource ! -path "\$TEMP_DIR/resource/*/*custom*" -type f -delete - find \$TEMP_DIR/resource ! -path "\$TEMP_DIR/resource/*/*custom*" -type d -empty -delete +######## +EOF + # 生成 restore.sh 文件的步骤2 - 在线获取 template/restore.sh 模板生成完整 restore.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/restore.sh | sed '1,/^########/d' >> ${WORK_DIR}/restore.sh fi - # 还原面板配置的最新信息 - sed -i "s@HTTPPort:.*@\$CONFIG_HTTPPORT@; s@Language:.*@\$CONFIG_LANGUAGE@; s@^GRPCPort:.*@\$CONFIG_GRPCPORT@; s@gGRPCHost:.*@I\$CONFIG_GRPCHOST@; s@ProxyGRPCPort:.*@\$CONFIG_PROXYGRPCPORT@; s@Type:.*@\$CONFIG_TYPE@; s@Admin:.*@\$CONFIG_ADMIN@; s@ClientID:.*@\$CONFIG_CLIENTID@; s@ClientSecret:.*@\$CONFIG_CLIENTSECRET@I" \${TEMP_DIR}/\${FILE_PATH}data/config.yaml - - # 逻辑是安装首次使用备份文件里的主题信息,之后使用本地最新的主题信息 - [[ -n "\$CONFIG_BRAND && -n "\$CONFIG_COOKIENAME && -n "\$CONFIG_THEME" ]] && - sed -i "s@brand:.*@\$CONFIG_BRAND@; s@cookiename:.*@\$CONFIG_COOKIENAME@; s@theme:.*@\$CONFIG_THEME@" \${TEMP_DIR}/\${FILE_PATH}data/config.yaml - - # 复制临时文件到正式的工作文件夹 - cp -f \${TEMP_DIR}/\${FILE_PATH}data/* \${WORK_DIR}/data/ - [ -d \${TEMP_DIR}/\${FILE_PATH}resource ] && cp -rf \${TEMP_DIR}/\${FILE_PATH}resource \${WORK_DIR} - rm -rf \${TEMP_DIR} + # 生成 renew.sh 文件的步骤1 - 设置环境变量 + cat > ${WORK_DIR}/renew.sh << EOF +#!/usr/bin/env bash - # 在本地记录还原文件名 - echo "\$ONLINE" > \$WORK_DIR/dbfile - rm -f \$TEMP_DIR/backup.tar.gz - hint "\n Start Nezha-dashboard \n" && cmd_systemctl enable >/dev/null 2>&1; sleep 5 -fi +GH_PROXY=$GH_PROXY +WORK_DIR=$WORK_DIR +TEMP_DIR=/tmp/renew -[ "\$(systemctl is-active nezha-dashboard)" = 'active' ] && info "\n Done! \n" || error "\n Fail! \n" +######## EOF - # 生成定时任务,每天北京时间 4:00:00 备份一次,并重启 cron 服务; 每分钟自动检测在线备份文件里的内容 - if [ "$SYSTEM" = 'Alpine' ]; then - grep -q "${WORK_DIR}/backup.sh" /var/spool/cron/crontabs/root || echo "0 4 * * * bash ${WORK_DIR}/backup.sh a" >> /var/spool/cron/crontabs/root - grep -q "${WORK_DIR}/restore.sh" /var/spool/cron/crontabs/root || echo "* * * * * bash ${WORK_DIR}/restore.sh a" >> /var/spool/cron/crontabs/root - else - grep -q "${WORK_DIR}/backup.sh" /etc/crontab || echo "0 4 * * * root bash ${WORK_DIR}/backup.sh a" >> /etc/crontab - grep -q "${WORK_DIR}/restore.sh" /etc/crontab || echo "* * * * * root bash ${WORK_DIR}/restore.sh a" >> /etc/crontab - service cron restart >/dev/null 2>&1 - fi + # 生成 renew.sh 文件的步骤2 - 在线获取 template/renew.sh 模板生成完整 renew.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/renew.sh | sed '1,/^########/d' >> ${WORK_DIR}/renew.sh + + # 生成定时任务: 1.每天北京时间 3:30:00 更新备份和还原文件,2.每天北京时间 4:00:00 备份一次,并重启 cron 服务; 3.每分钟自动检测在线备份文件里的内容 + if [ "$SYSTEM" = 'Alpine' ]; then + [ -s $WORK_DIR/renew.sh ] && ! grep -q "${WORK_DIR}/renew.sh" /var/spool/cron/crontabs/root && echo "${IS_AUTO_RENEW}30 3 * * * bash ${WORK_DIR}/renew.sh a" >> /var/spool/cron/crontabs/root + [ -s $WORK_DIR/backup.sh ] && ! grep -q "${WORK_DIR}/backup.sh" /var/spool/cron/crontabs/root && echo "0 4 * * * bash ${WORK_DIR}/backup.sh a" >> /var/spool/cron/crontabs/root + [ -s $WORK_DIR/restore.sh ] && ! grep -q "${WORK_DIR}/restore.sh" /var/spool/cron/crontabs/root && echo "* * * * * bash ${WORK_DIR}/restore.sh a" >> /var/spool/cron/crontabs/root + else + [ -s $WORK_DIR/renew.sh ] && ! grep -q "${WORK_DIR}/renew.sh" /etc/crontab && echo "${IS_AUTO_RENEW}30 3 * * * root bash ${WORK_DIR}/renew.sh" >> /etc/crontab + [ -s $WORK_DIR/backup.sh ] && ! grep -q "${WORK_DIR}/backup.sh" /etc/crontab && echo "0 4 * * * root bash ${WORK_DIR}/backup.sh a" >> /etc/crontab + [ -s $WORK_DIR/restore.sh ] && ! grep -q "${WORK_DIR}/restore.sh" /etc/crontab && echo "* * * * * root bash ${WORK_DIR}/restore.sh a" >> /etc/crontab + service cron restart >/dev/null 2>&1 fi # 赋执行权给 sh 文件 @@ -808,7 +571,7 @@ EOF # 卸载 uninstall() { cmd_systemctl disable - grep -q 'NGINX=2' ${WORK_DIR}/dashboard/run.sh && [ $(ps -ef | grep 'nginx' | wc -l) -le 1 ] && reading " $(text 39) " REMOVE_NGINX + grep -q 'REVERSE_PROXY_MODE=nginx' ${WORK_DIR}/run.sh && [ $(ps -ef | grep 'nginx' | wc -l) -le 1 ] && reading " $(text 39) " REMOVE_NGINX [[ "$REMOVE_NGINX" = [Yy] ]] && ${PACKAGE_UNINSTALL[int]} nginx rm -rf /etc/systemd/system/nezha-dashboard.service ${WORK_DIR} if [ "$SYSTEM" = 'Alpine' ]; then diff --git a/init.sh b/init.sh index 3fd0f1c..d745073 100644 --- a/init.sh +++ b/init.sh @@ -3,6 +3,9 @@ # 首次运行时执行以下流程,再次运行时存在 /etc/supervisor/conf.d/damon.conf 文件,直接到最后一步 if [ ! -s /etc/supervisor/conf.d/damon.conf ]; then + # 设置 Github CDN + GH_PROXY=https://mirror.ghproxy.com/ + # 如不分离备份的 github 账户,默认与哪吒登陆的 github 账户一致 GH_BACKUP_USER=${GH_BACKUP_USER:-$GH_USER} WORK_DIR=/dashboard @@ -32,9 +35,9 @@ if [ ! -s /etc/supervisor/conf.d/damon.conf ]; then * ) error " $(text 2) " esac - # 用户选择使用 grpcwebproxy 还是 Nginx 作 gRPC 反代,默认为 grpcwebproxy;NGINX 的值非空即用 nginx - if [ -z "$NGINX" ]; then - wget -c https://github.com/fscarmen2/Argo-Nezha-Service-Container/releases/download/grpcwebproxy/grpcwebproxy_linux_$ARCH.tar.gz -qO- | tar xz -C $WORK_DIR + # 用户选择使用 Nginx 还是 grpcwebproxy 作 gRPC 反代,默认为 nginx;如需使用 grpcwebproxy,把 REVERSE_PROXY_MODE 的值设为 grpcwebproxy + if [ "$REVERSE_PROXY_MODE" = 'grpcwebproxy' ]; then + wget -c ${GH_PROXY}https://github.com/fscarmen2/Argo-Nezha-Service-Container/releases/download/grpcwebproxy/grpcwebproxy_linux_$ARCH.tar.gz -qO- | tar xz -C $WORK_DIR chmod +x $WORK_DIR/grpcwebproxy GRPC_PROXY_RUN="$WORK_DIR/grpcwebproxy --server_tls_cert_file=$WORK_DIR/nezha.pem --server_tls_key_file=$WORK_DIR/nezha.key --server_http_tls_port=443 --backend_addr=localhost:5555 --backend_tls_noverify --server_http_max_read_timeout=300s --server_http_max_write_timeout=300s" else @@ -74,11 +77,11 @@ EOF # 下载需要的应用 DASHBOARD_LATEST=$(wget -qO- "https://api.github.com/repos/naiba/nezha/releases/latest" | awk -F '"' '/"tag_name"/{print $4}') - wget -O /tmp/dashboard.zip https://github.com/naiba/nezha/releases/download/$DASHBOARD_LATEST/dashboard-linux-$ARCH.zip + wget -O /tmp/dashboard.zip ${GH_PROXY}https://github.com/naiba/nezha/releases/download/$DASHBOARD_LATEST/dashboard-linux-$ARCH.zip unzip /tmp/dashboard.zip -d /tmp mv -f /tmp/dist/dashboard-linux-$ARCH $WORK_DIR/app - wget -qO $WORK_DIR/cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-$ARCH - wget -O $WORK_DIR/nezha-agent.zip https://github.com/nezhahq/agent/releases/latest/download/nezha-agent_linux_$ARCH.zip + wget -qO $WORK_DIR/cloudflared ${GH_PROXY}https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-$ARCH + wget -O $WORK_DIR/nezha-agent.zip ${GH_PROXY}https://github.com/nezhahq/agent/releases/latest/download/nezha-agent_linux_$ARCH.zip unzip $WORK_DIR/nezha-agent.zip -d $WORK_DIR/ rm -rf $WORK_DIR/nezha-agent.zip /tmp/dist /tmp/dashboard.zip @@ -95,7 +98,7 @@ TLS: true Oauth2: Type: "github" #Oauth2 登录接入类型,github/gitlab/jihulab/gitee/gitea ## Argo-容器版本只支持 github Admin: "$GH_USER" #管理员列表,半角逗号隔开 - ClientID: "$GH_CLIENTID" # 在 https://github.com/settings/developers 创建,无需审核 Callback 填 http(s)://域名或IP/oauth2/callback + ClientID: "$GH_CLIENTID" # 在 ${GH_PROXY}https://github.com/settings/developers 创建,无需审核 Callback 填 http(s)://域名或IP/oauth2/callback ClientSecret: "$GH_CLIENTSECRET" Endpoint: "" # 如gitea自建需要设置 ## Argo-容器版本只支持 github site: @@ -146,237 +149,70 @@ EOF openssl req -new -subj "/CN=$ARGO_DOMAIN" -key $WORK_DIR/nezha.key -out $WORK_DIR/nezha.csr openssl x509 -req -days 36500 -in $WORK_DIR/nezha.csr -signkey $WORK_DIR/nezha.key -out $WORK_DIR/nezha.pem - # 生成定时备份数据库脚本,定时任务,删除 5 天前的备份 - cat > $WORK_DIR/backup.sh << EOF + # 生成 backup.sh 文件的步骤1 - 设置环境变量 + cat > $WORK_DIR/backup.sh << EOF #!/usr/bin/env bash +# backup.sh 传参 a 自动还原; 传参 m 手动还原; 传参 f 强制更新面板 app 文件及 cloudflared 文件,并备份数据至成备份库 + +GH_PROXY=$GH_PROXY GH_PAT=$GH_PAT GH_BACKUP_USER=$GH_BACKUP_USER GH_EMAIL=$GH_EMAIL GH_REPO=$GH_REPO ARCH=$ARCH WORK_DIR=$WORK_DIR +DAYS=5 +IS_DOCKER=1 -warning() { echo -e "\033[31m\033[01m\$*\033[0m"; } # 红色 -error() { echo -e "\033[31m\033[01m\$*\033[0m" && exit 1; } # 红色 -info() { echo -e "\033[32m\033[01m\$*\033[0m"; } # 绿色 -hint() { echo -e "\033[33m\033[01m\$*\033[0m"; } # 黄色 - -# 手自动标志 -[ "\$1" = 'a' ] && WAY=Scheduled || WAY=Manualed -[ "\$1" = 'f' ] && WAY=Manualed && FORCE_UPDATE=true - -# 检查更新面板主程序 app 及 cloudflared -cd \$WORK_DIR -DASHBOARD_NOW=\$(./app -v) -DASHBOARD_LATEST=\$(wget -qO- "https://api.github.com/repos/naiba/nezha/releases/latest" | awk -F '"' '/"tag_name"/{print \$4}') -[[ "\$DASHBOARD_LATEST" =~ ^v([0-9]{1,3}\.){2}[0-9]{1,3}\$ && "\$DASHBOARD_NOW" != "\$DASHBOARD_LATEST" ]] && DASHBOARD_UPDATE=true - -CLOUDFLARED_NOW=\$(./cloudflared -v | awk '{for (i=0; i README.md - find ./ -name '*.gz' | sort | head -n -5 | xargs rm -f - git config --global user.name \$GH_BACKUP_USER - git config --global user.email \$GH_EMAIL - git checkout --orphan tmp_work - git add . - git commit -m "\$WAY at \$TIME ." - git push -f -u origin HEAD:main --quiet - IS_BACKUP="\$?" - cd .. - rm -rf \$GH_REPO - [ "\$IS_BACKUP" = 0 ] && echo "dashboard-\$TIME.tar.gz" > \$WORK_DIR/dbfile && info "\n Succeed to upload the backup files dashboard-\$TIME.tar.gz to Github.\n" || hint "\n Failed to upload the backup files dashboard-\$TIME.tar.gz to Github.\n" - hint "\n Start Nezha-dashboard \n" - fi - fi - hint "\n\$(supervisorctl start agent nezha grpcproxy)\n"; sleep 2 -fi - -[ \$(supervisorctl status all | grep -c "RUNNING") = \$(grep -c '\[program:.*\]' /etc/supervisor/conf.d/damon.conf) ] && info "\n Done! \n" || error "\n Fail! \n" +######## EOF + # 生成 backup.sh 文件的步骤2 - 在线获取 template/bakcup.sh 模板生成完整 backup.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/backup.sh | sed '1,/^########/d' >> $WORK_DIR/backup.sh + if [[ -n "$GH_BACKUP_USER" && -n "$GH_EMAIL" && -n "$GH_REPO" && -n "$GH_PAT" ]]; then - # 生成还原数据脚本 + # 生成 restore.sh 文件的步骤1 - 设置环境变量 cat > $WORK_DIR/restore.sh << EOF #!/usr/bin/env bash # restore.sh 传参 a 自动还原 README.md 记录的文件,当本地与远程记录文件一样时不还原; 传参 f 不管本地记录文件,强制还原成备份库里 README.md 记录的文件; 传参 dashboard-***.tar.gz 还原成备份库里的该文件;不带参数则要求选择备份库里的文件名 +GH_PROXY=$GH_PROXY GH_PAT=$GH_PAT GH_BACKUP_USER=$GH_BACKUP_USER GH_REPO=$GH_REPO WORK_DIR=$WORK_DIR TEMP_DIR=/tmp/restore_temp -BACKUP_FLAG=/tmp/backuping - -trap "rm -rf \$TEMP_DIR; echo -e '\n' ;exit 1" INT QUIT TERM EXIT - -mkdir -p \$TEMP_DIR - -warning() { echo -e "\033[31m\033[01m\$*\033[0m"; } # 红色 -error() { echo -e "\033[31m\033[01m\$*\033[0m" && exit 1; } # 红色 -info() { echo -e "\033[32m\033[01m\$*\033[0m"; } # 绿色 -hint() { echo -e "\033[33m\033[01m\$*\033[0m"; } # 黄色 - -ONLINE="\$(wget -qO- --header="Authorization: token \$GH_PAT" "https://raw.githubusercontent.com/\$GH_BACKUP_USER/\$GH_REPO/main/README.md" | sed "/^$/d" | head -n 1)" - -# 若用户在 Github 的 README.md 里改了内容包含关键词 backup,则触发实时备份;为解决 Github cdn 导致获取文件内容来回跳的问题,设置自锁并检测到备份文件后延时3分钟断开(3次 运行 restore.sh 的时间) -if grep -qi 'backup' <<< "\$ONLINE"; then - [ ! -e \${BACKUP_FLAG}* ] && { touch \${BACKUP_FLAG}; \$WORK_DIR/backup.sh; exit 0; } -elif [ -e \${BACKUP_FLAG} ]; then - mv -f \${BACKUP_FLAG} \${BACKUP_FLAG}1 -elif [ -e \${BACKUP_FLAG}1 ]; then - mv -f \${BACKUP_FLAG}1 \${BACKUP_FLAG}2 -elif [ -e \${BACKUP_FLAG}2 ]; then - mv -f \${BACKUP_FLAG}2 \${BACKUP_FLAG}3 -elif [ -e \${BACKUP_FLAG}3 ]; then - rm -f \${BACKUP_FLAG}3 -fi +NO_ACTION_FLAG=/tmp/flag +IS_DOCKER=1 -# 读取面板现配置信息 -CONFIG_HTTPPORT=\$(grep -i '^HTTPPort:' \$WORK_DIR/data/config.yaml) -CONFIG_LANGUAGE=\$(grep -i '^Language:' \$WORK_DIR/data/config.yaml) -CONFIG_GRPCPORT=\$(grep -i '^GRPCPort:' \$WORK_DIR/data/config.yaml) -CONFIG_GRPCHOST=\$(grep -i '^GRPCHost:' \$WORK_DIR/data/config.yaml) -CONFIG_PROXYGRPCPORT=\$(grep -i '^ProxyGRPCPort:' \$WORK_DIR/data/config.yaml) -CONFIG_TYPE=\$(sed -n '/Type:/I s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_ADMIN=\$(sed -n '/Admin:/I s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_CLIENTID=\$(sed -n '/ClientID:/I s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) -CONFIG_CLIENTSECRET=\$(sed -n '/ClientSecret:/I s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) - -# 如 dbfile 不为空,即不是首次安装,记录当前面板的主题等信息 -[ -s \$WORK_DIR/dbfile ] && CONFIG_BRAND=\$(sed -n '/brand:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) && -CONFIG_COOKIENAME=\$(sed -n '/cookiename:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) && -CONFIG_THEME=\$(sed -n '/theme:/s/^[ ]\+//gp' \$WORK_DIR/data/config.yaml) - -if [ "\$1" = a ]; then - [ "\$ONLINE" = "\$(cat \$WORK_DIR/dbfile)" ] && exit - [[ "\$ONLINE" =~ tar\.gz$ && "\$ONLINE" != "\$(cat \$WORK_DIR/dbfile)" ]] && FILE="\$ONLINE" || exit -elif [ "\$1" = f ]; then - [[ "\$ONLINE" =~ tar\.gz$ ]] && FILE="\$ONLINE" || exit -elif [[ "\$1" =~ tar\.gz$ ]]; then - [[ "\$FILE" =~ http.*/.*tar.gz ]] && FILE=\$(awk -F '/' '{print \$NF}' <<< \$FILE) || FILE="\$1" -elif [ -z "\$1" ]; then - BACKUP_FILE_LIST=(\$(wget -qO- --header="Authorization: token \$GH_PAT" https://api.github.com/repos/\$GH_BACKUP_USER/\$GH_REPO/contents/ | awk -F '"' '/"path".*tar.gz/{print \$4}' | sort -r)) - until [[ "\$CHOOSE" =~ ^[1-\${#BACKUP_FILE_LIST[@]}]$ ]]; do - for i in \${!BACKUP_FILE_LIST[@]}; do echo " \$[i+1]. \${BACKUP_FILE_LIST[i]} "; done - echo "" - [ -z "\$FILE" ] && read -rp " Please choose the backup file [1-\${#BACKUP_FILE_LIST[@]}]: " CHOOSE - [[ ! "\$CHOOSE" =~ ^[1-\${#BACKUP_FILE_LIST[@]}]$ ]] && echo -e "\n Error input!" && sleep 1 - ((j++)) && [ \$j -ge 5 ] && error "\n The choose has failed more than 5 times and the script exits. \n" - done - FILE=\${BACKUP_FILE_LIST[\$((CHOOSE-1))]} -fi +######## +EOF -DOWNLOAD_URL=https://raw.githubusercontent.com/\$GH_BACKUP_USER/\$GH_REPO/main/\$FILE -wget --header="Authorization: token \$GH_PAT" --header='Accept: application/vnd.github.v3.raw' -O \$TEMP_DIR/backup.tar.gz "\$DOWNLOAD_URL" - -if [ -e \$TEMP_DIR/backup.tar.gz ]; then - hint "\n\$(supervisorctl stop agent nezha grpcproxy)\n" - - # 容器版的备份旧方案是 /dashboard 文件夹,新方案是备份工作目录 < WORK_DIR > 下的文件,此判断用于根据压缩包里的目录架构判断到哪个目录下解压,以兼容新旧备份方案 - FILE_LIST=\$(tar tzf \$TEMP_DIR/backup.tar.gz) - FILE_PATH=\$(sed -n 's#\(.*/\)data/sqlite\.db.*#\1#gp' <<< "\$FILE_LIST") - - # 判断备份文件里是否有用户自定义主题,如有则一并解压到临时文件夹 - CUSTOM_PATH=(\$(sed -n "/custom/s#\$FILE_PATH\(.*custom\)/.*#\1#gp" <<< "\$FILE_LIST" | sort -u)) - [ \${#CUSTOM_PATH[@]} -gt 0 ] && CUSTOM_FULL_PATH=(\$(for k in \${CUSTOM_PATH[@]}; do echo \${FILE_PATH}\${k}; done)) - echo "↓↓↓↓↓↓↓↓↓↓ Restore-file list ↓↓↓↓↓↓↓↓↓↓" - tar xzvf \$TEMP_DIR/backup.tar.gz -C \$TEMP_DIR \${CUSTOM_FULL_PATH[@]} \${FILE_PATH}data - echo -e "↑↑↑↑↑↑↑↑↑↑ Restore-file list ↑↑↑↑↑↑↑↑↑↑\n\n" - - # 处理 v0.15.17 之后自定义主题静态链接的路径问题,删除备份文件中 resource 下的非 custom 文件夹及文件 - [ -d \$TEMP_DIR/resource/static/theme-custom ] && mv -f \$TEMP_DIR/resource/static/theme-custom \$TEMP_DIR/resource/static/custom - [ -s \$TEMP_DIR/resource/template/theme-custom/header.html ] && sed -i 's#/static/theme-custom/#/static-custom/#g' \$TEMP_DIR/resource/template/theme-custom/header.html - if [ -d \$TEMP_DIR/resource ]; then - find \$TEMP_DIR/resource ! -path "\$TEMP_DIR/resource/*/*custom*" -type f -delete - find \$TEMP_DIR/resource ! -path "\$TEMP_DIR/resource/*/*custom*" -type d -empty -delete + # 生成 restore.sh 文件的步骤2 - 在线获取 template/restore.sh 模板生成完整 restore.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/restore.sh | sed '1,/^########/d' >> $WORK_DIR/restore.sh fi - # 还原面板配置的最新信息 - sed -i "s@HTTPPort:.*@\$CONFIG_HTTPPORT@I; s@Language:.*@\$CONFIG_LANGUAGE@I; s@^GRPCPort:.*@\$CONFIG_GRPCPORT@I; s@gGRPCHost:.*@I\$CONFIG_GRPCHOST@I; s@ProxyGRPCPort:.*@\$CONFIG_PROXYGRPCPORT@I; s@Type:.*@\$CONFIG_TYPE@I; s@Admin:.*@\$CONFIG_ADMIN@I; s@ClientID:.*@\$CONFIG_CLIENTID@I; s@ClientSecret:.*@\$CONFIG_CLIENTSECRET@I" \${TEMP_DIR}/\${FILE_PATH}data/config.yaml - - # 逻辑是安装首次使用备份文件里的主题信息,之后使用本地最新的主题信息 - [[ -n "\$CONFIG_BRAND && -n "\$CONFIG_COOKIENAME && -n "\$CONFIG_THEME" ]] && - sed -i "s@brand:.*@\$CONFIG_BRAND@; s@cookiename:.*@\$CONFIG_COOKIENAME@; s@theme:.*@\$CONFIG_THEME@" \${TEMP_DIR}/\${FILE_PATH}data/config.yaml - - # 复制临时文件到正式的工作文件夹 - cp -f \${TEMP_DIR}/\${FILE_PATH}data/* \${WORK_DIR}/data/ - [ -d \${TEMP_DIR}/\${FILE_PATH}resource ] && cp -rf \${TEMP_DIR}/\${FILE_PATH}resource \${WORK_DIR} - rm -rf \${TEMP_DIR} + # 生成 renew.sh 文件的步骤1 - 设置环境变量 + cat > $WORK_DIR/renew.sh << EOF +#!/usr/bin/env bash - # 在本地记录还原文件名 - echo "\$ONLINE" > \$WORK_DIR/dbfile - rm -f \$TEMP_DIR/backup.tar.gz - hint "\n\$(supervisorctl start agent nezha grpcproxy)\n"; sleep 2 -fi +GH_PROXY=$GH_PROXY +WORK_DIR=/dashboard +TEMP_DIR=/tmp/renew -[ \$(supervisorctl status all | grep -c "RUNNING") = \$(grep -c '\[program:.*\]' /etc/supervisor/conf.d/damon.conf) ] && info "\n Done! \n" || error "\n Fail! \n" +######## EOF - # 生成定时任务,每天北京时间 4:00:00 备份一次,并重启 cron 服务; 每分钟自动检测在线备份文件里的内容 - grep -q "$WORK_DIR/backup.sh" /etc/crontab || echo "0 4 * * * root bash $WORK_DIR/backup.sh a" >> /etc/crontab - grep -q "$WORK_DIR/restore.sh" /etc/crontab || echo "* * * * * root bash $WORK_DIR/restore.sh a" >> /etc/crontab - service cron restart - fi + # 生成 renew.sh 文件的步骤2 - 在线获取 template/renew.sh 模板生成完整 renew.sh 文件 + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/renew.sh | sed '1,/^########/d' >> $WORK_DIR/renew.sh + + # 生成定时任务: 1.每天北京时间 3:30:00 更新备份和还原文件,2.每天北京时间 4:00:00 备份一次,并重启 cron 服务; 3.每分钟自动检测在线备份文件里的内容 + [ -z "$NO_AUTO_RENEW" ] && [ -s $WORK_DIR/renew.sh ] && ! grep -q "$WORK_DIR/renew.sh" /etc/crontab && echo "30 3 * * * root bash $WORK_DIR/renew.sh" >> /etc/crontab + [ -s $WORK_DIR/backup.sh ] && ! grep -q "$WORK_DIR/backup.sh" /etc/crontab && echo "0 4 * * * root bash $WORK_DIR/backup.sh a" >> /etc/crontab + [ -s $WORK_DIR/restore.sh ] && ! grep -q "$WORK_DIR/restore.sh" /etc/crontab && echo "* * * * * root bash $WORK_DIR/restore.sh a" >> /etc/crontab + service cron restart # 生成 supervisor 进程守护配置文件 cat > /etc/supervisor/conf.d/damon.conf << EOF diff --git a/template/backup.sh b/template/backup.sh new file mode 100644 index 0000000..2b8af19 --- /dev/null +++ b/template/backup.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash + +# backup.sh 传参 a 自动还原; 传参 m 手动还原; 传参 f 强制更新面板 app 文件及 cloudflared 文件,并备份数据至成备份库 + +GH_PROXY=https://mirror.ghproxy.com/ +GH_PAT= +GH_BACKUP_USER= +GH_EMAIL= +GH_REPO= +SYSTEM= +ARCH= +WORK_DIR= +DAYS=5 +IS_DOCKER= + +######## + +warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 +error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色 +info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色 +hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色 + +cmd_systemctl() { + local ENABLE_DISABLE=$1 + if [ "$ENABLE_DISABLE" = 'enable' ]; then + if [ "$SYSTEM" = 'Alpine' ]; then + local TRY=5 + until [ $(systemctl is-active nezha-dashboard) = 'active' ]; do + systemctl stop nezha-dashboard; sleep 1 + systemctl start nezha-dashboard + ((TRY--)) + [ "$TRY" = 0 ] && break + done + cat > /etc/local.d/nezha-dashboard.start << ABC +#!/usr/bin/env bash + +systemctl start nezha-dashboard +ABC + chmod +x /etc/local.d/nezha-dashboard.start + rc-update add local >/dev/null 2>&1 + else + systemctl enable --now nezha-dashboard + fi + + elif [ "$ENABLE_DISABLE" = 'disable' ]; then + if [ "$SYSTEM" = 'Alpine' ]; then + systemctl stop nezha-dashboard + rm -f /etc/local.d/nezha-dashboard.start + else + systemctl disable --now nezha-dashboard + fi + fi +} + +# 手自动标志 +[ "$1" = 'a' ] && WAY=Scheduled || WAY=Manualed +[ "$1" = 'f' ] && WAY=Manualed && FORCE_UPDATE=true + +# 检查更新面板主程序 app 及 cloudflared +cd $WORK_DIR +DASHBOARD_NOW=$(./app -v) +DASHBOARD_LATEST=$(wget -qO- "https://api.github.com/repos/naiba/nezha/releases/latest" | awk -F '"' '/"tag_name"/{print $4}') +[[ "$DASHBOARD_LATEST" =~ ^v([0-9]{1,3}\.){2}[0-9]{1,3}$ && "$DASHBOARD_NOW" != "$DASHBOARD_LATEST" ]] && DASHBOARD_UPDATE=true + +CLOUDFLARED_NOW=$(./cloudflared -v | awk '{for (i=0; i README.md + find ./ -name '*.gz' | sort | head -n -$DAYS | xargs rm -f + git config --global user.name $GH_BACKUP_USER + git config --global user.email $GH_EMAIL + git checkout --orphan tmp_work + git add . + git commit -m "$WAY at $TIME ." + git push -f -u origin HEAD:main --quiet + IS_BACKUP="$?" + cd .. + rm -rf $GH_REPO + [ "$IS_BACKUP" = 0 ] && echo "dashboard-$TIME.tar.gz" > $WORK_DIR/dbfile && info "\n Succeed to upload the backup files dashboard-$TIME.tar.gz to Github.\n" || hint "\n Failed to upload the backup files dashboard-$TIME.tar.gz to Github.\n" + hint "\n Start Nezha-dashboard \n" + fi + fi + + # 重启面板 + if [ "$IS_DOCKER" = 1 ]; then + hint "\n$(supervisorctl start agent nezha grpcproxy)\n" + else + cmd_systemctl enable >/dev/null 2>&1 + fi + sleep 2 +fi + +if [ "$IS_DOCKER" = 1 ]; then + [ $(supervisorctl status all | grep -c "RUNNING") = $(grep -c '\[program:.*\]' /etc/supervisor/conf.d/damon.conf) ] && info "\n Done! \n" || error "\n Failed! \n" +else + [ "$(systemctl is-active nezha-dashboard)" = 'active' ] && info "\n Done! \n" || error "\n Failed! \n" +fi diff --git a/template/renew.sh b/template/renew.sh new file mode 100644 index 0000000..8024d7f --- /dev/null +++ b/template/renew.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# renew.sh 用于在线同步最新的 backup.sh 和 restore.sh 脚本 + +GH_PROXY=https://mirror.ghproxy.com/ +WORK_DIR= +TEMP_DIR= + +######## + +# 自定义字体彩色,read 函数 +warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 +error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色 +info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色 +hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色 + +trap "rm -rf $TEMP_DIR; echo -e '\n' ;exit" INT QUIT TERM EXIT + +mkdir -p $TEMP_DIR + +# 在线更新 renew.sh,backup.sh 和 restore.sh 文件 +for i in {renew,backup,restore}; do + if [ -s $WORK_DIR/$i.sh ]; then + sed -n '1,/^########/p' $WORK_DIR/$i.sh > $TEMP_DIR/$i.sh + wget -qO- ${GH_PROXY}https://raw.githubusercontent.com/fscarmen2/Argo-Nezha-Service-Container/main/template/$i.sh | sed '1,/^########/d' >> $TEMP_DIR/$i.sh + [ $(wc -l $TEMP_DIR/$i.sh | awk '{print $1}') -gt 20 ] && mv -f $TEMP_DIR/$i.sh $WORK_DIR/ && info "\n Update $i.sh Successful. \n" || warning "\n Update $i.sh failed.\n" + fi +done \ No newline at end of file diff --git a/template/restore.sh b/template/restore.sh new file mode 100644 index 0000000..6dea404 --- /dev/null +++ b/template/restore.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +# restore.sh 传参 a 自动还原 README.md 记录的文件,当本地与远程记录文件一样时不还原; 传参 f 不管本地记录文件,强制还原成备份库里 README.md 记录的文件; 传参 dashboard-***.tar.gz 还原成备份库里的该文件;不带参数则要求选择备份库里的文件名 + +GH_PROXY=https://mirror.ghproxy.com/ +GH_PAT= +GH_BACKUP_USER= +GH_REPO= +SYSTEM= +WORK_DIR= +TEMP_DIR=/tmp/restore_temp +NO_ACTION_FLAG=/tmp/flag +IS_DOCKER= + +######## + +trap "rm -rf $TEMP_DIR; echo -e '\n' ;exit" INT QUIT TERM EXIT + +mkdir -p $TEMP_DIR + +warning() { echo -e "\033[31m\033[01m$*\033[0m"; } # 红色 +error() { echo -e "\033[31m\033[01m$*\033[0m" && exit 1; } # 红色 +info() { echo -e "\033[32m\033[01m$*\033[0m"; } # 绿色 +hint() { echo -e "\033[33m\033[01m$*\033[0m"; } # 黄色 + +cmd_systemctl() { + local ENABLE_DISABLE=$1 + if [ "$ENABLE_DISABLE" = 'enable' ]; then + if [ "$SYSTEM" = 'Alpine' ]; then + local TRY=5 + until [ $(systemctl is-active nezha-dashboard) = 'active' ]; do + systemctl stop nezha-dashboard; sleep 1 + systemctl start nezha-dashboard + ((TRY--)) + [ "$TRY" = 0 ] && break + done + cat > /etc/local.d/nezha-dashboard.start << ABC +#!/usr/bin/env bash + +systemctl start nezha-dashboard +ABC + chmod +x /etc/local.d/nezha-dashboard.start + rc-update add local >/dev/null 2>&1 + else + systemctl enable --now nezha-dashboard + fi + + elif [ "$ENABLE_DISABLE" = 'disable' ]; then + if [ "$SYSTEM" = 'Alpine' ]; then + systemctl stop nezha-dashboard + rm -f /etc/local.d/nezha-dashboard.start + else + systemctl disable --now nezha-dashboard + fi + fi +} + +ONLINE="$(wget -qO- --header="Authorization: token $GH_PAT" "${GH_PROXY}https://raw.githubusercontent.com/$GH_BACKUP_USER/$GH_REPO/main/README.md" | sed "/^$/d" | head -n 1)" + +# 若用户在 Github 的 README.md 里改了内容包含关键词 backup,则触发实时备份;为解决 Github cdn 导致获取文件内容来回跳的问题,设置自锁并检测到备份文件后延时3分钟断开(3次 运行 restore.sh 的时间) +if grep -qi 'backup' <<< "$ONLINE"; then + [ ! -e ${NO_ACTION_FLAG}* ] && { touch ${NO_ACTION_FLAG}; $WORK_DIR/backup.sh; exit 0; } +elif [ -e ${NO_ACTION_FLAG} ]; then + mv -f ${NO_ACTION_FLAG} ${NO_ACTION_FLAG}1 +elif [ -e ${NO_ACTION_FLAG}1 ]; then + mv -f ${NO_ACTION_FLAG}1 ${NO_ACTION_FLAG}2 +elif [ -e ${NO_ACTION_FLAG}2 ]; then + mv -f ${NO_ACTION_FLAG}2 ${NO_ACTION_FLAG}3 +elif [ -e ${NO_ACTION_FLAG}3 ]; then + rm -f ${NO_ACTION_FLAG}3 +fi + +# 读取面板现配置信息 +CONFIG_HTTPPORT=$(grep -i '^HTTPPort:' $WORK_DIR/data/config.yaml) +CONFIG_LANGUAGE=$(grep -i '^Language:' $WORK_DIR/data/config.yaml) +CONFIG_GRPCPORT=$(grep -i '^GRPCPort:' $WORK_DIR/data/config.yaml) +CONFIG_GRPCHOST=$(grep -i '^GRPCHost:' $WORK_DIR/data/config.yaml) +CONFIG_PROXYGRPCPORT=$(grep -i '^ProxyGRPCPort:' $WORK_DIR/data/config.yaml) +CONFIG_TYPE=$(sed -n '/Type:/ s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) +CONFIG_ADMIN=$(sed -n '/Admin:/ s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) +CONFIG_CLIENTID=$(sed -n '/ClientID:/ s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) +CONFIG_CLIENTSECRET=$(sed -n '/ClientSecret:/ s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) + +# 如 dbfile 不为空,即不是首次安装,记录当前面板的主题等信息 +[ -s $WORK_DIR/dbfile ] && CONFIG_BRAND=$(sed -n '/brand:/s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) && +CONFIG_COOKIENAME=$(sed -n '/cookiename:/s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) && +CONFIG_THEME=$(sed -n '/theme:/s/^[ ]\+//gp' $WORK_DIR/data/config.yaml) + +if [ "$1" = a ]; then + [ "$ONLINE" = "$(cat $WORK_DIR/dbfile)" ] && exit + [[ "$ONLINE" =~ tar\.gz$ && "$ONLINE" != "$(cat $WORK_DIR/dbfile)" ]] && FILE="$ONLINE" || exit +elif [ "$1" = f ]; then + [[ "$ONLINE" =~ tar\.gz$ ]] && FILE="$ONLINE" || exit +elif [[ "$1" =~ tar\.gz$ ]]; then + [[ "$FILE" =~ http.*/.*tar.gz ]] && FILE=$(awk -F '/' '{print $NF}' <<< $FILE) || FILE="$1" +elif [ -z "$1" ]; then + BACKUP_FILE_LIST=($(wget -qO- --header="Authorization: token $GH_PAT" https://api.github.com/repos/$GH_BACKUP_USER/$GH_REPO/contents/ | awk -F '"' '/"path".*tar.gz/{print $4}' | sort -r)) + until [[ "$CHOOSE" =~ ^[1-${#BACKUP_FILE_LIST[@]}]$ ]]; do + for i in ${!BACKUP_FILE_LIST[@]}; do echo " $[i+1]. ${BACKUP_FILE_LIST[i]} "; done + echo "" + [ -z "$FILE" ] && read -rp " Please choose the backup file [1-${#BACKUP_FILE_LIST[@]}]: " CHOOSE + [[ ! "$CHOOSE" =~ ^[1-${#BACKUP_FILE_LIST[@]}]$ ]] && echo -e "\n Error input!" && sleep 1 + ((j++)) && [ $j -ge 5 ] && error "\n The choose has failed more than 5 times and the script exits. \n" + done + FILE=${BACKUP_FILE_LIST[$((CHOOSE-1))]} +fi + +DOWNLOAD_URL=${GH_PROXY}https://raw.githubusercontent.com/$GH_BACKUP_USER/$GH_REPO/main/$FILE +wget --header="Authorization: token $GH_PAT" --header='Accept: application/vnd.github.v3.raw' -O $TEMP_DIR/backup.tar.gz "$DOWNLOAD_URL" + +if [ -e $TEMP_DIR/backup.tar.gz ]; then + if [ "$IS_DOCKER" = 1 ]; then + hint "\n$(supervisorctl stop agent nezha grpcproxy)\n" + else + hint "\n Stop Nezha-dashboard \n" && cmd_systemctl disable + fi + + # 容器版的备份旧方案是 /dashboard 文件夹,新方案是备份工作目录 < WORK_DIR > 下的文件,此判断用于根据压缩包里的目录架构判断到哪个目录下解压,以兼容新旧备份方案 + FILE_LIST=$(tar tzf $TEMP_DIR/backup.tar.gz) + FILE_PATH=$(sed -n 's#\(.*/\)data/sqlite\.db.*#\1#gp' <<< "$FILE_LIST") + + # 判断备份文件里是否有用户自定义主题,如有则一并解压到临时文件夹 + CUSTOM_PATH=($(sed -n "/custom/s#$FILE_PATH\(.*custom\)/.*#\1#gp" <<< "$FILE_LIST" | sort -u)) + [ ${#CUSTOM_PATH[@]} -gt 0 ] && CUSTOM_FULL_PATH=($(for k in ${CUSTOM_PATH[@]}; do echo ${FILE_PATH}${k}; done)) + echo "↓↓↓↓↓↓↓↓↓↓ Restore-file list ↓↓↓↓↓↓↓↓↓↓" + tar xzvf $TEMP_DIR/backup.tar.gz -C $TEMP_DIR ${CUSTOM_FULL_PATH[@]} ${FILE_PATH}data + echo -e "↑↑↑↑↑↑↑↑↑↑ Restore-file list ↑↑↑↑↑↑↑↑↑↑\n\n" + + # 处理 v0.15.17 之后自定义主题静态链接的路径问题,删除备份文件中 resource 下的非 custom 文件夹及文件 + [ -d $TEMP_DIR/resource/static/theme-custom ] && mv -f $TEMP_DIR/resource/static/theme-custom $TEMP_DIR/resource/static/custom + [ -s $TEMP_DIR/resource/template/theme-custom/header.html ] && sed -i 's#/static/theme-custom/#/static-custom/#g' $TEMP_DIR/resource/template/theme-custom/header.html + if [ -d $TEMP_DIR/resource ]; then + find $TEMP_DIR/resource ! -path "$TEMP_DIR/resource/*/*custom*" -type f -delete + find $TEMP_DIR/resource ! -path "$TEMP_DIR/resource/*/*custom*" -type d -empty -delete + fi + + # 还原面板配置的最新信息 + sed -i "s@HTTPPort:.*@$CONFIG_HTTPPORT@; s@Language:.*@$CONFIG_LANGUAGE@; s@^GRPCPort:.*@$CONFIG_GRPCPORT@; s@gGRPCHost:.*@I$CONFIG_GRPCHOST@; s@ProxyGRPCPort:.*@$CONFIG_PROXYGRPCPORT@; s@Type:.*@$CONFIG_TYPE@; s@Admin:.*@$CONFIG_ADMIN@; s@ClientID:.*@$CONFIG_CLIENTID@; s@ClientSecret:.*@$CONFIG_CLIENTSECRET@I" ${TEMP_DIR}/${FILE_PATH}data/config.yaml + + # 逻辑是安装首次使用备份文件里的主题信息,之后使用本地最新的主题信息 + [[ -n "$CONFIG_BRAND && -n "$CONFIG_COOKIENAME && -n "$CONFIG_THEME" ]] && + sed -i "s@brand:.*@$CONFIG_BRAND@; s@cookiename:.*@$CONFIG_COOKIENAME@; s@theme:.*@$CONFIG_THEME@" ${TEMP_DIR}/${FILE_PATH}data/config.yaml + + # 复制临时文件到正式的工作文件夹 + cp -f ${TEMP_DIR}/${FILE_PATH}data/* ${WORK_DIR}/data/ + [ -d ${TEMP_DIR}/${FILE_PATH}resource ] && cp -rf ${TEMP_DIR}/${FILE_PATH}resource ${WORK_DIR} + rm -rf ${TEMP_DIR} + + # 在本地记录还原文件名 + echo "$ONLINE" > $WORK_DIR/dbfile + rm -f $TEMP_DIR/backup.tar.gz + if [ "$IS_DOCKER" = 1 ]; then + hint "\n$(supervisorctl start agent nezha grpcproxy)\n" + else + hint "\n Start Nezha-dashboard \n" && cmd_systemctl enable >/dev/null 2>&1 + fi + sleep 3 +fi + +if [ "$IS_DOCKER" = 1 ]; then + [ $(supervisorctl status all | grep -c "RUNNING") = $(grep -c '\[program:.*\]' /etc/supervisor/conf.d/damon.conf) ] && info "\n Done! \n" || error "\n Failed! \n" +else + [ "$(systemctl is-active nezha-dashboard)" = 'active' ] && info "\n Done! \n" || error "\n Failed! \n" +fi