diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 148367b1..502f87f3 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,32 +1,45 @@ -name: 批量保活进程 - -on: - schedule: - # 使用cron表达式定义任务运行的时间 - # github使用utc时间 - - cron: '3 2 * * *' #波兰凌晨3点3分 - workflow_dispatch: - -jobs: - deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: 安装依赖 - run: | - sudo apt-get install sshpass - sudo apt-get install jq - - - name: 登录各个serv00并执行保活脚本 - env: - HOSTS_JSON: ${{ secrets.HOSTS_JSON }} - TELEGRAM_TOKEN: ${{secrets.TELEGRAM_TOKEN}} - TELEGRAM_USERID: ${{secrets.TELEGRAM_USERID}} - WXSENDKEY: ${{secrets.WXSENDKEY}} - SENDTYPE: ${{secrets.SENDTYPE}} - run: | - chmod +x ./revive.sh - ./revive.sh +name: 批量保活进程 + +on: + schedule: + # 使用cron表达式定义任务运行的时间 + # github使用utc时间 + - cron: '3 22 * * *' #北京时间6点 + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: 安装依赖 + run: | + sudo apt-get install sshpass + sudo apt-get install jq + sudo apt-get install connect-proxy + sudo apt-get install -y netcat-openbsd + + - name: 登录各个serv00并执行保活脚本 + env: + HOSTS_JSON: ${{ secrets.HOSTS_JSON }} + TELEGRAM_TOKEN: ${{secrets.TELEGRAM_TOKEN}} + TELEGRAM_USERID: ${{secrets.TELEGRAM_USERID}} + WXSENDKEY: ${{secrets.WXSENDKEY}} + WXPUSH_URL: ${{secrets.WXPUSH_URL}} + WX_TOKEN: ${{secrets.WX_TOKEN}} + SENDTYPE: ${{secrets.SENDTYPE}} + BUTTON_URL: ${{secrets.BUTTON_URL}} + AUTOUPDATE: ${{vars.AUTOUPDATE}} + LOGININFO: ${{vars.LOGININFO}} + LOGINONCE: ${{vars.LOGINONCE}} + PROXY_HOST: ${{secrets.PROXY_HOST}} + PROXY_PORT: ${{secrets.PROXY_PORT}} + PROXY_USER: ${{secrets.PROXY_USER}} + PROXY_PASS: ${{secrets.PROXY_PASS}} + + run: | + chmod +x ./revive.sh + ./revive.sh diff --git a/.github/workflows/keep.yml b/.github/workflows/keep.yml new file mode 100644 index 00000000..e38ebaea --- /dev/null +++ b/.github/workflows/keep.yml @@ -0,0 +1,36 @@ +name: 批量访问保活进程 + +on: + schedule: + # 使用cron表达式定义任务运行的时间 + #github最小时间间隔为10分钟 + - cron: '*/10 * * * *' + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: 安装依赖 + run: | + sudo apt-get install jq + + - name: 访问各个serv00并执行保活脚本 + env: + HOSTS_JSON: ${{ secrets.HOSTS_JSON }} + TELEGRAM_TOKEN: ${{secrets.TELEGRAM_TOKEN}} + TELEGRAM_USERID: ${{secrets.TELEGRAM_USERID}} + WXPUSH_URL: ${{secrets.WXPUSH_URL}} + WX_TOKEN: ${{secrets.WX_TOKEN}} + SENDTYPE: ${{secrets.SENDTYPE}} + BUTTON_URL: ${{secrets.BUTTON_URL}} + AUTOUPDATE: ${{vars.AUTOUPDATE}} + LOGININFO: ${{vars.LOGININFO}} + TOKEN: ${{secrets.TOKEN}} + run: | + chmod +x ./revive_node.sh + ./revive_node.sh diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index ecdcaa87..17a833cc 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -1,40 +1,40 @@ -name: Sync Fork with Upstream - -on: - schedule: - - cron: '0 19 * * *' - workflow_dispatch: - -permissions: - contents: write - -jobs: - sync_latest_from_upstream: - name: Sync latest commits from upstream repo - runs-on: ubuntu-latest - if: ${{ github.event.repository.fork }} - - steps: - # Step 1: run a standard checkout action - - name: Checkout target repo - uses: actions/checkout@v3 - - # Step 2: run the sync action - - name: Sync upstream changes - id: sync - uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 - with: - upstream_sync_repo: frankiejun/serv00-play - upstream_sync_branch: main - target_sync_branch: main - target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set - exclude: | - .github/workflows/sync.yml - - - name: Check for errors - if: failure() - run: echo "Sync failed! Please check the logs for more details." - - - name: Sync success message - if: success() - run: echo "Sync completed successfully!" +name: Sync Fork with Upstream + +on: + schedule: + - cron: '0 19 * * *' + workflow_dispatch: + +permissions: + contents: write + +jobs: + sync_latest_from_upstream: + name: Sync latest commits from upstream repo + runs-on: ubuntu-latest + if: ${{ github.event.repository.fork }} + + steps: + # Step 1: run a standard checkout action + - name: Checkout target repo + uses: actions/checkout@v3 + + # Step 2: run the sync action + - name: Sync upstream changes + id: sync + uses: aormsby/Fork-Sync-With-Upstream-action@v3.4 + with: + upstream_sync_repo: frankiejun/serv00-play + upstream_sync_branch: main + target_sync_branch: main + target_repo_token: ${{ secrets.GITHUB_TOKEN }} # automatically generated, no need to set + exclude: | + .github/workflows/sync.yml + + - name: Check for errors + if: failure() + run: echo "Sync failed! Please check the logs for more details." + + - name: Sync success message + if: success() + run: echo "Sync completed successfully!" diff --git a/.gitignore b/.gitignore index 2f3cc09a..41d77cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,12 @@ -*.log -*.json -*.out -*.js -a.* -*.swp -vmess/node_modules -vmess/list -vmess/cloudflared -vless/node_modules -tools/ \ No newline at end of file +*.log +*.json +*.out +*test +a.* +*.swp +vmess/node_modules +vmess/list +vmess/cloudflared +vless/node_modules +tools/ +.vscode/ diff --git a/LICENSE b/LICENSE index ebc743d4..079cec5e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,13 @@ -Copyright [2024] [饭奇骏] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. +Copyright [2024] [饭奇骏] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md index 6871e676..189f1d60 100644 --- a/README.md +++ b/README.md @@ -1,95 +1,114 @@ -# serv00 上的一些应用,包括 argo+vmess/vmess+ws/hy2/socks5/mtproto/alist/哪吒探针/sun-panel/webssh 等, 自动化部署、批量保号、进程防杀、消息推送 - -💖 如果你在用这个项目,请给我打个 star,好让我知道有多少人从这个项目中受益。 - -## 前置工作 - -1. 你需要有一个 serv00 帐号 -2. 首次运行,无需使用面板,选 1 安装 serv00-play 后,选 13 按回车,它会自动重新登录,输入 ss 回车进入界面。(以后都是输入 ss 回车进入界面) - -## 安装说明 - -```s -bash <(curl -Ls https://raw.githubusercontent.com/frankiejun/serv00-play/main/start.sh) -``` - -## 变量说明 - -| 变量名 | 示例 | 备注 | -| --------------- | ------ | ---------------------------------------- | -| HOSTS_JSON | 见示例 | 可存放 n 个服务器信息 | -| TELEGRAM_TOKEN | 略 | telegram 机器人的 token | -| TELEGRAM_USERID | 略 | 待通知的 teltegram 用户 ID | -| WXSENDKEY | 略 | server 酱的 sendkey,用于接收微信消息 | -| SENDTYPE | 3 | 选择推送方式,1.Telegram, 2.微信, 3.都有 | - -各主机保活时可不必输入消息通知参数,由 github 同一配置参数。 - -如果主机上配置了消息推送参数,则优先级大于 github 上的配置。 - -## action 保活内容 - -1.定时自动登录各个主机,起到保号作用(因 serv00 需要每 3 个月登录一次) -2.执行兜底保活策略 -3.检查主机上保活用的 cronjob 是否被删,若被删重建保活 cronjob -4.自动更新 serv00-play 代码 -5.同步更新 telegram、微信等参数 -6.登录失败有 TG 消息通知,提醒可能封号(平时正常不会给你发消息,发消息之时便是你封号之日) - -## 消息推送 - -支持向 Telegram 和微信用户发送通知 - -关于如何配置 Telegram 以实现消息推送,可以看 [这个视频](https://www.youtube.com/watch?v=l8fPnMfq86c&t=3s) - -关于微信的配置,目前使用第三方平台提供的功能,可以到 [这里](https://sct.ftqq.com/r/13223) 注册并登录 server 酱,取得 sendKey - -## HOSTS_JSON 的配置实例 - -```js - { - "info": [ - { - "host": "s2.serv00.com", - "username": "kkk", - "port": 22, - "password": "fdsafjijgn" - }, - { - "host": "s2.serv00.com", - "username": "bbb", - "port": 22, - "password": "fafwwwwazcs" - } - ] -} -``` - -## 安装说明视频 - -安装使用说明可以看[这里](https://youtu.be/bpYV8r85F-8) -临时隧道已失效,请使用固定隧道名,[如何申请固定隧道名](https://youtu.be/KyMvtWknu-k) -argo+vmess 的搭建教学看[这里](https://youtu.be/nmb2F6uBKsg?si=v8twWIkIjsN8UYb-) - -由于本项目一直在迭代开发,界面会有些变化,想详细了解,可以看这一系列视频[serv00-play 系列](https://www.youtube.com/playlist?list=PLaMnUIjE3d5zArqlLzTU2oMZ0h-5VP6C0) - -## 赞助 - -
[点击展开] 请作者喝杯咖啡 ~🧧 -_捐赠将是对我最大的支持,它将激励我持续的创新和创作。_ - -![](https://look.pics.cloudns.ch/img/%E6%AC%A7%E6%98%93%E8%B5%9E%E5%8A%A9%E7%A0%81.png) - -- **USDT-TRC20:** `TUa2hLirmyq6tUPpfxHuMmWJExR91vHo5t` - -
- -## 项目鸣谢 - -[nekohasekai](https://github.com/SagerNet/sing-box)、[AlistGo](https://github.com/AlistGo/alist)、[9seconds](https://github.com/9seconds/mtg)、[eooce](https://github.com/eooce)、[nrootconauto](https://github.com/nrootconauto/MrChrootBSD)、[nezhahq](https://github.com/nezhahq/agent)、[huashengdun](https://github.com/huashengdun/webssh)、[hslr-s](https://github.com/hslr-s/sun-panel) -[yangtb2024](https://github.com/yangtb2024/OneTimeMessagePHP) - -## 免责声明 - -本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 代码、数据及图片均有所属版权, 如转载须注明来源。 -使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。 +# serv00/hostuno 上的一些应用,包括 argo+vmess/vmess+ws/hy2/socks5/mtproto/alist/哪吒探针|面板/sun-panel/webssh 等, 自动化部署、批量保号、进程防杀、消息推送 + +💖 如果你在用这个项目,请给我打个 star,好让我知道有多少人从这个项目中受益。 + +## 前置工作 + +1. 你需要有一个 serv00/hostuno 帐号 +2. 运行安装命令后重新登录,输入 ss 回车进入界面。(以后都是输入 ss 回车进入界面) + +## 安装说明 + +```s +bash <(curl -Ls https://raw.githubusercontent.com/frankiejun/serv00-play/main/start.sh) --install +``` + +## 变量说明 + +| 变量名 | 示例 | 是否必须 | 变量类型 | 备注 | +| --------------- | ----------- | -------- | ---------- | -------------------------------------------------------------------------------- | +| HOSTS_JSON | 见示例 | ✅ | secrets | 可存放 n 个服务器信息 (必选) | +| TELEGRAM_TOKEN | 略 | ❌ | secrets | telegram 机器人的 token (发送 TG 消息必选) | +| TELEGRAM_USERID | 略 | ❌ | secrets | 待通知的 teltegram 用户 ID (发送 TG 消息必选) | +| ~~WXSENDKEY~~ | ~~略~~ | ~~❌~~ | ~~secrets~~ | ~~server 酱的 sendkey,用于接收微信消息 (发送微信消息必选)~~ | +| WXPUSH_URL | 略 | ❌ | secrets | [wxpush](https://github.com/frankiejun/wxpush)项目的请求url | +| WX_TOKEN | 略 | ❌ | secrets | [wxpush](https://github.com/frankiejun/wxpush)项目的API_TOKEN | +| SENDTYPE | 1 | ❌ | secrets | 选择推送方式,1.Telegram, 2.微信, 3.都有 (发送消息必选) | +| BUTTON_URL | 略 | ❌ | secrets | 设置 TG 推送消息中的按钮链接 (发送 TG 消息可选),支持#HOST,#USER,#PASS 等变量。 | +| AUTOUPDATE | Y/N | ❌ | variable | 设置是否自动更新服务器上的代码,设置在 variable 变量中,值为 Y/N(默认: Y) | +| LOGININFO | Y/N | ❌ | variable | 在 variable 变量中设置(默认为 N),Y:发送登录汇总消息 N:只在登录失败时发送 | +| LOGINONCE | Y/N | ❌ | variable | 在 variable 变量中设置(默认为 N),Y:每天只登录一个账号 N:每天登录所有账号送 | +| TOKEN | 123456 | ❌ | secrets | 网页保活(keepalive)的密钥(必选) | +| PROXY_HOST | 127.0.0.1 | ❌ | secrets | 代理服务器地址 (可选) | +| PROXY_PORT | 1080 | ❌ | secrets | 代理服务器端口 (可选) | +| PROXY_USER | user | ❌ | secrets | 代理服务器用户名 (可选) | +| PROXY_PASS | password | ❌ | secrets | 代理服务器密码 (可选) | + +各主机保活时可不必输入消息通知参数,由 github 同一配置参数。 + +如果主机上配置了消息推送参数,则优先级大于 github 上的配置。 + +## action 保活内容 + +1.定时自动登录各个主机,起到保号作用(因 serv00 需要每 3 个月登录一次) +2.执行兜底保活策略 +3.检查主机上保活用的 cronjob 是否被删,若被删重建保活 cronjob +4.自动更新 serv00-play 代码 +5.同步更新 telegram、微信等参数 +6.默认情况下只有登录失败才有 TG 消息通知,提醒可能封号(平时正常不会给你发消息,发消息之时便是你封号之日) +也可以设定 LOGININFO=Y,每次保活都会做汇总通知(但相信我,你不会喜欢这个功能) +7.keepalive 保活虽然不做 ssh 登录,但一样有延续服务器有效期的效果(不再需要 3 月一登)。 + +## 消息推送 + +支持向 Telegram 和微信用户发送通知 + +关于如何配置 Telegram 以实现消息推送,可以看 [这个视频](https://www.youtube.com/watch?v=l8fPnMfq86c&t=3s) + +关于微信的配置,使用我的项目[wxpush](https://github.com/frankiejun/wxpush), 不会配可以看[这个视频](https://youtu.be/sE1Kcol_XRs?si=G-UbUGlMhyysv-US) + + +## HOSTS_JSON 的配置实例 + +```js + { + "info": [ + { + "host": "s2.serv00.com", + "username": "kkk", + "port": 22, + "password": "fdsafjijgn" + }, + { + "host": "s2.serv00.com", + "username": "bbb", + "port": 22, + "password": "fafwwwwazcs" + } + ] +} +``` + +## 安装说明视频 + +安装使用说明可以看[这里](https://youtu.be/ZCr7YiQX8Qs) +临时隧道已失效,请使用固定隧道名,[如何申请固定隧道名](https://youtu.be/KyMvtWknu-k) +argo+vmess 的搭建教学看[这里](https://youtu.be/nmb2F6uBKsg?si=v8twWIkIjsN8UYb-) + +由于本项目一直在迭代开发,界面会有些变化,想详细了解,可以看这一系列视频[serv00-play 系列](https://www.youtube.com/playlist?list=PLaMnUIjE3d5zArqlLzTU2oMZ0h-5VP6C0) + +## 赞助 + +
[点击展开] 请作者喝杯咖啡 ~🧧 +_捐赠将是对我最大的支持,它将激励我持续的创新和创作。捐赠>=5u, 可联系我加入饭友会会员群, 捐赠>=10u, 加入赞助人感谢名单_ + +![](https://look.pics.cloudns.ch/img/%E6%AC%A7%E6%98%93%E8%B5%9E%E5%8A%A9%E7%A0%81.png) + +- **USDT-TRC20:** `TUa2hLirmyq6tUPpfxHuMmWJExR91vHo5t` + +
+ +| 赞助人 | 赞助方式 | 备注 | +| ---------------------------------------------------------------------------------------------------------------------- | ------------------------ | ---- | +| [YXVM](https://support.nodeget.com/page/promotion?id=105) 和 [NodeSupport](https://github.com/NodeSeekDev/NodeSupport) | 赞助本项目提供永久服务器 | -- | + +## 项目鸣谢 + +[nekohasekai](https://github.com/SagerNet/sing-box)、[AlistGo](https://github.com/AlistGo/alist)、[9seconds](https://github.com/9seconds/mtg)、[eooce](https://github.com/eooce)、[nrootconauto](https://github.com/nrootconauto/MrChrootBSD)、[nezhahq](https://github.com/nezhahq/agent)、[huashengdun](https://github.com/huashengdun/webssh)、[hslr-s](https://github.com/hslr-s/sun-panel)、[yangtb2024](https://github.com/yangtb2024/OneTimeMessagePHP) + +测试人员: [ryty1](https://github.com/ryty1), [fgr178707](https://github.com/fgr178707) + +## 免责声明 + +本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 代码、数据及图片均有所属版权, 如转载须注明来源。 +使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。 diff --git a/domains-support/websites/christmas.html b/domains-support/websites/christmas.html new file mode 100644 index 00000000..7f473137 --- /dev/null +++ b/domains-support/websites/christmas.html @@ -0,0 +1,265 @@ + + + + + + 圣诞快乐 - 暖心贺卡 + + + + + + +
+ +
+ 🎵 +
+ +
+ 🛷🦌🎅 +
+ +
+

MERRY CHRISTMAS

+ +
+

愿你的圣诞充满温馨与喜悦

+

在这个繁星闪烁的夜晚,所有的愿望都能成真 ✨

+
+ +
+
🧦
+
🎁
+
🎄
+
🎁
+
🧦
+
+
+ + + + \ No newline at end of file diff --git a/domains-support/websites/deyiedu.html b/domains-support/websites/deyiedu.html new file mode 100644 index 00000000..f6db1c9e --- /dev/null +++ b/domains-support/websites/deyiedu.html @@ -0,0 +1,269 @@ + + + + + + 德一教育 - 后台管理系统 + + + +
+
+ +

德一教育后台管理系统

+

Deyi Education Management System

+
+ +
+
+
+ + +
+ +
+ + +
+ 用户名或密码错误,请重新输入 +
+
+ +
+ + +
+ + + + +
+ +
© 2023 德一教育集团 - 版本 v3.5.2
+
+
+ + + + diff --git a/domains-support/websites/game.html b/domains-support/websites/game.html new file mode 100644 index 00000000..a6285772 --- /dev/null +++ b/domains-support/websites/game.html @@ -0,0 +1,1012 @@ + + + + + + 游戏殿堂 - 游戏资讯与社区 + + + + +
+ +
+ + + + + +
+ + +
+
+
+
+

次世代游戏体验

+

探索最新发布的AAA大作,感受前所未有的视觉冲击和沉浸式游戏体验。从开放世界到竞技对战,总有一款适合你。

+ 立即体验 +
+
+ +
+
+

独立游戏精选

+

发现那些充满创意和艺术感的独立游戏作品。这些游戏或许没有庞大的预算,却有着独特的玩法和感人的故事。

+ 发现独立游戏 +
+
+ +
+
+

竞技游戏联赛

+

加入全球玩家的竞技场,体验紧张刺激的电竞赛事。从新手到职业选手,这里有你展示实力的舞台。

+ 加入比赛 +
+
+ +
+
+
+
+
+
+
+ + +
+
+

热门游戏推荐

+
+ + + + + +
+
+ +
+ +
+ 星穹史诗 +
+
+
+

星穹史诗

+
+ 2023年发布 + 1200万+ +
+
+
+ 9.2 +
+
+ +

在广阔的宇宙中展开史诗般的冒险,探索未知星球,与外星种族建立联系,揭开古老文明的神秘面纱。

+ +
+ 角色扮演 + 开放世界 + 科幻 +
+ +
+
¥ 298
+ 购买 +
+
+
+ + +
+ 暗影行动 +
+
+
+

暗影行动

+
+ 2022年发布 + 850万+ +
+
+
+ 8.7 +
+
+ +

第一人称战术射击游戏,带领精英小队执行高风险任务。体验真实的武器系统和团队协作玩法。

+ +
+ 第一人称射击 + 战术 + 多人合作 +
+ +
+
¥ 198
+ 购买 +
+
+
+ + +
+ 帝国纪元 +
+
+
+

帝国纪元

+
+ 2023年发布 + 560万+ +
+
+
+ 9.0 +
+
+ +

建立你的帝国,从石器时代发展到太空时代。管理资源,发展科技,征服敌对文明,成为历史上最伟大的统治者。

+ +
+ 策略 + 模拟 + 历史 +
+ +
+
¥ 248
+ 购买 +
+
+
+ + +
+ 心灵之旅 +
+
+
+

心灵之旅

+
+ 2021年发布 + 320万+ +
+
+
+ 9.5 +
+
+ +

一段关于生命、死亡和情感的动人旅程。通过精美的艺术风格和感人的故事,探索人类情感的深度。

+ +
+ 独立游戏 + 冒险 + 情感叙事 +
+ +
+
¥ 88
+ 购买 +
+
+
+ + +
+ 极限竞速 +
+
+
+

极限竞速

+
+ 2023年发布 + 750万+ +
+
+
+ 8.9 +
+
+ +

体验最真实的赛车模拟,驾驶数百款授权车辆在全球知名赛道上驰骋。从街头赛到专业赛道,满足所有赛车爱好者的需求。

+ +
+ 竞速 + 模拟 + 体育 +
+ +
+
¥ 228
+ 购买 +
+
+
+ + +
+ 魔法学院 +
+
+
+

魔法学院

+
+ 2022年发布 + 410万+ +
+
+
+ 8.5 +
+
+ +

在一所魔法学校中,学习各种魔法咒语,解开古老谜题,与同学建立友谊,共同对抗威胁魔法世界的黑暗力量。

+ +
+ 角色扮演 + 魔法 + 冒险 +
+ +
+
¥ 168
+ 购买 +
+
+
+
+
+ + +
+
+

最新游戏资讯

+
+ +
+ + + + 人力资源管理系统 - 登录 + + + + + + + + diff --git a/domains-support/websites/resume.html b/domains-support/websites/resume.html new file mode 100644 index 00000000..da5a497c --- /dev/null +++ b/domains-support/websites/resume.html @@ -0,0 +1,146 @@ + + + + + + Li Ming's Resume + + + + +
+
+

Li Ming's Resume

+

Tsinghua University, Department of Computer Science, 3 Years Since Graduation

+
+ +
+
Personal Information
+
+

Name: Li Ming

+

Date of Birth: May 1, 1995

+

Email: liming@gmail.com

+

Phone: +86 138 6666 8888

+

Address: Haidian District, Beijing, China

+
+
+ +
+
Education
+
+
+

Tsinghua University, Department of Computer Science - Bachelor's Degree

+

Graduation Date: June 2022

+

Major Courses: Data Structures and Algorithms, Computer Networks, Operating Systems, Artificial Intelligence, Machine Learning

+
+
+
+ +
+
Work Experience
+
+
+

Tencent - Software Engineer

+

Employment Period: July 2022 - December 2024

+

Job Description: Involved in the architecture design and development of Tencent Cloud Platform, optimized system performance, and maintained backend services for company products. Led a cross-team project that successfully improved data processing efficiency.

+
+
+

ByteDance - Backend Engineer

+

Employment Period: January 2024 - Present

+

Job Description: Responsible for backend service development and optimization for a short-video platform, wrote efficient API interfaces using Python and Go, and performed system tuning to ensure service stability under high concurrency environments.

+
+
+
+ +
+
Skills
+
+
    +
  • Proficient in Python, Java, Go, and other programming languages
  • +
  • Deep understanding of data structures and algorithms, capable of solving problems efficiently
  • +
  • Familiar with Linux operating system, capable of system performance optimization and troubleshooting
  • +
  • Experienced in developing and maintaining large-scale distributed systems
  • +
  • Familiar with common database technologies such as MySQL, Redis, and MongoDB
  • +
  • Strong teamwork and communication skills
  • +
+
+
+ +
+
Project Experience
+
+
+

Online Education Platform

+

Project Description: Designed and developed an online education platform that supports live video streaming, courseware sharing, and interaction. Responsible for backend development, optimized video streaming and real-time data interaction, enhancing user experience.

+
+
+

Social Media Analytics System

+

Project Description: Participated in the development of a social media data analytics system that can capture and analyze data from social platforms in real time, helping businesses monitor brand sentiment. Optimized data storage and retrieval performance.

+
+
+
+ +
+
Language Skills
+
+

Chinese: Native

+

English: Fluent (TOEFL 100)

+
+
+ +
+ + + + diff --git a/domains-support/websites/sakura.html b/domains-support/websites/sakura.html new file mode 100644 index 00000000..7658a8c8 --- /dev/null +++ b/domains-support/websites/sakura.html @@ -0,0 +1,225 @@ + + + + + + 欢迎来到xx的博客 + + + + + + + + + +
+

欢迎来到xx的博客

+ +
+

春日赏樱小记

+
2025年3月15日
+

+ 今日阳光明媚,我独自前往城郊的樱花园赏花。园中樱花已盛开七分,粉白相间,美不胜收。微风拂过,花瓣纷纷扬扬落下,宛如一场粉色的雪。 +

+

+ 游人如织,却不觉拥挤。或许是被这美景所感染,大家都轻声细语,生怕惊扰了这份宁静。我在一棵古老的樱花树下小憩,看着阳光透过花瓣在地上投下斑驳的影子,心中无比平静。 +

+

+ 樱花花期短暂,正因如此才更显珍贵。人生亦如是,美好的事物总是转瞬即逝,我们更应珍惜当下,把握每一个绽放的瞬间。 +

+
+ +
+

学习前端开发的感悟

+
2025年2月28日
+

+ 最近开始系统地学习前端开发,从HTML、CSS到JavaScript,一步步构建自己的知识体系。虽然有时会遇到困难,但解决问题的过程也充满了乐趣。 +

+

+ 今天完成了这个博客网站的基本框架,虽然还很简陋,但看到自己的想法通过代码变成现实,那种成就感是无可比拟的。特别是实现了樱花飘落的效果,让整个页面生动起来。 +

+

+ 学习编程就像是在学习一门新的语言,通过这种语言,我们可以与计算机交流,创造出无限可能。期待未来能做出更多有趣的项目! +

+
+
+ + +
© 2025 xx的博客 - 由serv00-play搭建
+ + + + + diff --git a/keepalive.sh b/keepalive.sh index a00b3d95..e13de23c 100644 --- a/keepalive.sh +++ b/keepalive.sh @@ -1,183 +1,273 @@ #!/bin/bash - installpath="$HOME" source ${installpath}/serv00-play/utils.sh +LOCKFILE="$installpath/serv00-play/.keepalive.lock" + +# 检查是否已经有一个实例在运行 +if [ -e "$LOCKFILE" ]; then + echo "另一个实例正在运行,退出..." + exit 1 +fi + +# 创建锁文件 +touch "$LOCKFILE" + +# 定义清理函数 +cleanup() { + rm -f "$LOCKFILE" + exit +} + +# 捕获脚本退出信号并调用清理函数 +trap cleanup INT TERM EXIT + autoUp=$1 sendtype=$2 TELEGRAM_TOKEN="$3" TELEGRAM_USERID="$4" WXSENDKEY="$5" +BUTTON_URL="$6" +PASS="$7" +WXPUSH_URL="$8" +WX_TOKEN="$9" +autoUpdateHyIP="${10}" +#echo "TELEGRAM_TOKEN=$TELEGRAM_TOKEN, TELEGRAM_USERID=$TELEGRAM_USERID,WXSENDKEY=$WXSENDKEY,BUTTON_URL=$BUTTON_URL,pass=$PASS" checkHy2Alive() { - if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then - return 0 - else - return 1 - fi + if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then + return 0 + else + return 1 + fi } - sendMsg() { - local msg=$1 - if [ -n "$msg" ]; then - cd $installpath/serv00-play - msg="Host:$host, user:$user, $msg" - if [ "$sendtype" == "1" ]; then - ./tgsend.sh "$msg" - elif [ "$sendtype" == "2" ]; then - ./wxsend.sh "$msg" - elif [ "$sendtype" == "3" ]; then - ./tgsend.sh "$msg" - ./wxsend.sh "$msg" - fi - fi + local msg=$1 + if [ -n "$msg" ]; then + cd $installpath/serv00-play + msg="Host:$host, user:$user, $msg" + if [ "$sendtype" == "1" ]; then + ./tgsend.sh "$msg" + elif [ "$sendtype" == "2" ]; then + ./wxsend.sh "$msg" + elif [ "$sendtype" == "3" ]; then + ./tgsend.sh "$msg" + ./wxsend.sh "$msg" + fi + fi +} + +cleanUselessProc() { + # 获取域名列表 + local l_domains=$(ps aux | awk '{ print $11 $14}' | grep node | awk -F: '{gsub(/^[ \t]+|[ \t]+$/, "", $2); print $2}') + + echo "开始检查无用进程..." + + # 直接使用devil列表进行查找 + for domain in $l_domains; do + echo "检查域名: $domain" + + # 在devil列表输出中查找包含该域名的行 + result=$(devil www list | grep -w "$domain") + + if [ -z "$result" ]; then + echo "发现无用进程,准备删除: $domain" + pgrep -f "$domain" | xargs kill + fi + done } checkResetCron() { - echo "run checkResetCron" - local msg="" - cd ${installpath}/serv00-play/ - crontab -l | grep keepalive - if ! crontab -l | grep keepalive; then - msg="crontab记录被删过,并且已重建。" - tm=$(jq -r ".chktime" config.json) - addCron "$tm" - sendMsg $msg - fi + echo "run checkResetCron" + local msg="" + cd ${installpath}/serv00-play/ + tm=$(jq -r ".chktime" config.json) + if [ "$tm" == "null" ]; then + return + fi + crontab -l | grep keepalive + if ! crontab -l | grep keepalive; then + msg="crontab记录被删过,并且已重建。" + addCron "$tm" + sendMsg $msg + fi } #构建消息配置文件 -makeMsgConfig(){ - echo "构造消息配置文件..." - cat > msg.json <msg.json </dev/null 2>&1 & + local workedir="${installpath}/serv00-play/nezha" + cd ${workedir} + local config="nezha.json" + if [[ ! -e "$config" ]]; then + red "未安装哪吒探针,请先进行安装!" + return 1 + fi + nezha_domain=$(jq -r ".nezha_domain" $config) + nezha_port=$(jq -r ".nezha_port" $config) + nezha_pwd=$(jq -r ".nezha_pwd" $config) + ver=$(jq -r ".version" $config) + tls=$(jq -r ".tls" $config) + + if checknezhaAgentAlive; then + stopNeZhaAgent + fi + + local args="--report-delay 4 --disable-auto-update --disable-force-update " + if [[ "$tls" == "y" ]]; then + args="${args} --tls " + fi + + if [[ "$ver" == "1" ]]; then + nohup ./nezha-agent ${args} -s "${nezha_domain}:${nezha_port}" -p "${nezha_pwd}" >/dev/null 2>&1 & + else + local yamlcfg="config.yaml" + local datatls="" + if [[ "$tls" == "y" ]]; then + datatls="tls: true" + else + datatls="tls: false" + fi + nohup ./nezha-agent -c $yamlcfg 2>&1 & + fi } startMtg() { - cd ${installpath}/serv00-play/dmtg + cd ${installpath}/serv00-play/dmtg - config="config.json" + config="config.json" - secret=$(jq -r ".secret" $config) - port=$(jq -r ".port" $config) - cmd="nohup ./mtg simple-run -n 1.1.1.1 -t 30s -a 1MB 0.0.0.0:$port $secret -c 8192 --prefer-ip=\"prefer-ipv6\" >/dev/null 2>&1 &" - eval "$cmd" - sleep 3 - if checkMtgAlive; then - echo "启动成功" - else - echo "启动失败,请检查进程" - fi + secret=$(jq -r ".secret" $config) + port=$(jq -r ".port" $config) + cmd="nohup ./mtg simple-run -n 1.1.1.1 -t 30s -a 1MB 0.0.0.0:$port $secret -c 8192 --prefer-ip=\"prefer-ipv6\" >/dev/null 2>&1 &" + eval "$cmd" + sleep 1 + if checkMtgAlive; then + echo "启动成功" + else + echo "启动失败,请检查进程" + fi } +startNeZhaDashboard() { + cd ${installpath}/serv00-play/nezha-board + if checkProcAlive nezha-dashboard; then + stopNeZhaDashboard + fi + nohup ./nezha-dashboard -c config.yaml >borad.log 2>&1 & + if checkProcAlive nezha-dashboard; then + green "面板已启动!" + else + red "面板启动失败,请查看日志borad.log" + fi + +} startAlist() { - alistpath="${installpath}/serv00-play/alist" - - if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then - echo "正在启动alist..." - cd $alistpath - domain=$(jq -r ".domain" config.json) - - if checkProcAlive "alist"; then - echo "alist已启动,请勿重复启动!" - else - nohup ./alist server >/dev/null 2>&1 & - sleep 3 - if ! checkProcAlive "alist"; then - red "启动失败,请检查!" - return 1 - else - echo "启动成功!" - fi - fi - else - red "请先行安装再启动!" - return - fi + alistpath="${installpath}/serv00-play/alist" + + if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then + echo "正在启动alist..." + cd $alistpath + domain=$(jq -r ".domain" config.json) + + if checkProcAlive "alist"; then + echo "alist已启动,请勿重复启动!" + else + nohup ./alist server >/dev/null 2>&1 & + sleep 2 + if ! checkProcAlive "alist"; then + red "启动失败,请检查!" + return 1 + else + echo "启动成功!" + fi + fi + else + red "请先行安装再启动!" + return + fi } -startSunPanel(){ - cd ${installpath}/serv00-play/sunpanel - cmd="nohup ./sun-panel >/dev/null 2>&1 &" - eval "$cmd" +startSunPanel() { + cd ${installpath}/serv00-play/sunpanel + cmd="nohup ./sun-panel >/dev/null 2>&1 &" + eval "$cmd" } -startWebSSH(){ - cd ${installpath}/serv00-play/webssh - ssh_port=$(jq -r ".port" config.json) - cmd="nohup ./wssh --port=$ssh_port --fbidhttp=False --xheaders=False --encoding='utf-8' --delay=10 >/dev/null 2>&1 &" - eval "$cmd" +startWebSSH() { + cd ${installpath}/serv00-play/webssh + ssh_port=$(jq -r ".port" config.json) + cmd="nohup ./wssh --port=$ssh_port --fbidhttp=False --wpintvl=30 --xheaders=False --encoding='utf-8' --delay=10 >/dev/null 2>&1 &" + eval "$cmd" } #main -if [ -n "$autoUp" ]; then - echo "run autoUpdate" - autoUpdate +host=$(hostname) +user=$(whoami) + +echo "正在调用keepalive.sh" +if [[ "$autoUp" == "autoupdate" ]]; then + echo "run autoUpdate" + autoUpdate fi +#echo "Host:$host, user:$user" cd ${installpath}/serv00-play/ + +if [[ -n "$autoUp" ]]; then + makeMsgConfig +fi if [ ! -f config.json ]; then - echo "未配置保活项目,请先行配置!" - exit 0 + echo "未配置保活项目,请先行配置!" + cleanup fi monitor=($(jq -r ".item[]" config.json)) @@ -185,141 +275,215 @@ monitor=($(jq -r ".item[]" config.json)) tg_token=$(jq -r ".telegram_token // empty" config.json) if [[ -z "$tg_token" ]]; then - echo "从msg.json获取 telegram_token" - TELEGRAM_TOKEN=$(jq -r '.telegram_token // empty' msg.json) + echo "从msg.json获取 telegram_token" + if [[ -e "msg.json" ]]; then + TELEGRAM_TOKEN=$(jq -r '.telegram_token // empty' msg.json) + fi else - TELEGRAM_TOKEN=$tg_token + TELEGRAM_TOKEN=$tg_token fi tg_userid=$(jq -r ".telegram_userid // empty" config.json) if [[ -z "$tg_userid" ]]; then - echo "从msg.json获取telegram_userid" - TELEGRAM_USERID=$(jq -r ".telegram_userid // empty" msg.json) + echo "从msg.json获取telegram_userid" + if [[ -e "msg.json" ]]; then + TELEGRAM_USERID=$(jq -r ".telegram_userid // empty" msg.json) + fi else - TELEGRAM_USERID=$tg_userid + TELEGRAM_USERID=$tg_userid fi wx_sendkey=$(jq -r ".wxsendkey // empty" config.json) if [[ -z "$wx_sendkey" ]]; then - echo "从msg.json获取wxsendkey" - WXSENDKEY=$(jq -r ".wxsendkey // empty" msg.json) + echo "从msg.json获取wxsendkey" + if [[ -e "msg.json" ]]; then + WXSENDKEY=$(jq -r ".wxsendkey // empty" msg.json) + fi +else + WXSENDKEY=$wx_sendkey +fi + +wx_push_url=$(jq -r ".wxpush_url // empty" config.json) +if [[ -z "$wx_push_url" ]]; then + echo "从msg.json获取wxpush_url" + if [[ -e "msg.json" ]]; then + WXPUSH_URL=$(jq -r ".wxpush_url // empty" msg.json) + fi +else + WXPUSH_URL=$wx_push_url +fi + +wx_token=$(jq -r ".wx_token // empty" config.json) +if [[ -z "$wx_token" ]]; then + echo "从msg.json获取wx_token" + if [[ -e "msg.json" ]]; then + WX_TOKEN=$(jq -r ".wx_token // empty" msg.json) + fi else - WXSENDKEY=$wx_sendkey + WX_TOKEN=$wx_token fi send_type=$(jq -r ".sendtype // empty" config.json) if [ -z "$send_type" ]; then - echo "从msg.json获取 sendtype" - sendtype=$(jq -r ".sendtype // empty" msg.json) + echo "从msg.json获取 sendtype" + if [[ -e "msg.json" ]]; then + sendtype=$(jq -r ".sendtype // empty" msg.json) + fi else - sendtype=$send_type + sendtype=$send_type fi -export TELEGRAM_TOKEN TELEGRAM_USERID WXSENDKEY sendtype +if [ -z "$BUTTON_URL" ]; then + echo "从msg.json获取 button_url" + if [[ -e "msg.json" ]]; then + BUTTON_URL=$(jq -r ".button_url // empty" msg.json) + fi +fi + +if [ -z "$PASS" ]; then + echo "从msg.json获取 password" + if [[ -e "msg.json" ]]; then + PASS=$(jq -r ".password // empty" msg.json) + fi +fi + +export TELEGRAM_TOKEN TELEGRAM_USERID WXSENDKEY sendtype BUTTON_URL PASS WXPUSH_URL WX_TOKEN #echo "最终TELEGRAM_TOKEN=$TELEGRAM_TOKEN,TELEGRAM_USERID=$TELEGRAM_USERID" -host=$(hostname) -user=$(whoami) for obj in "${monitor[@]}"; do - msg="" - # echo "obj= $obj" - if [ "$obj" == "sun-panel" ]; then - if ! checkProcAlive "sun-panel"; then - startSunPanel - sleep 3 - if ! checkProcAlive "sun-panel"; then - msg="sun-panel restarted failure." - else - msg="sun-panel restarted successfully." - fi - fi - elif [ "$obj" == "webssh" ]; then - if ! checkProcAlive "wssh"; then - startWebSSH - sleep 5 - if ! checkProcAlive "wssh"; then - msg="webssh restarted failure." - else - msg="webssh restarted successfully." - fi - fi - elif [ "$obj" == "vmess" ]; then - if ! checkvmessAlive; then - cd ${installpath}/serv00-play/singbox - chmod +x ./start.sh && ./start.sh 1 keep - sleep 5 - if ! checkvmessAlive; then - msg="vmess restarted failure." - else - msg="vmess restarted successfully." - fi - fi - #hy2和vmess+ws都只需要启动serv00sb,所以可以这么写 - elif [[ "$obj" == "hy2/vmess+ws" || "$obj" == "hy2" ]]; then - if ! checkHy2Alive; then - #echo "重启serv00sb中..." - cd ${installpath}/serv00-play/singbox - chmod +x ./start.sh && ./start.sh 2 keep - sleep 5 - if ! checkHy2Alive; then - msg="hy2 restarted failure." - else - msg="hy2 restarted successfully." - fi - fi - elif [ "$obj" == "nezha-agent" ]; then - if ! checknezhaAgentAlive; then - cd ${installpath}/serv00-play/nezha - startNeZhaAgent - sleep 5 - if ! checknezhaAgentAlive; then - msg="nezha-agent restarted failure." - else - msg="nezha-agent restarted successfully." - fi - fi - elif [ "$obj" == "mtg" ]; then - if ! checkMtgAlive; then - cd ${installpath}/serv00-play/dmtg - startMtg - sleep 5 - if ! checkMtgAlive; then - msg="mtproto restarted failure." - else - msg="mtproto restarted successfully." - fi - fi - elif [ "$obj" == "alist" ]; then - if ! checkProcAlive "alist"; then - startAlist - sleep 5 - if ! checkProcAlive "alist"; then - msg="alist restarted failure." - else - msg="alist restarted successfully." - fi - fi - elif [ "$obj" == "wssh" ]; then - if ! checkProcAlive wssh; then - startAlist - sleep 5 - if ! checkAlistAlive; then - msg="alist restarted failure." - else - msg="alist restarted successfully." - fi - fi - else - continue - fi - - sendMsg "$msg" + msg="" + # echo "obj= $obj" + if [ "$obj" == "sun-panel" ]; then + if ! checkProcAlive "sun-panel"; then + startSunPanel + sleep 2 + if ! checkProcAlive "sun-panel"; then + msg="sun-panel 重启失败." + else + msg="sun-panel 重启成功." + fi + fi + elif [ "$obj" == "webssh" ]; then + if ! checkProcAlive "wssh"; then + startWebSSH + sleep 2 + if ! checkProcAlive "wssh"; then + msg="webssh 重启失败." + else + msg="webssh 重启成功." + fi + fi + elif [ "$obj" == "vmess" ]; then + if ! checkvmessAlive; then + cd ${installpath}/serv00-play/singbox + chmod +x ./start.sh && ./start.sh 1 keep + sleep 1 + if ! checkvmessAlive; then + msg="vmess 重启失败." + else + msg="vmess 重启成功." + fi + fi + #hy2和vmess+ws都只需要启动serv00sb,所以可以这么写 + elif [[ "$obj" == "hy2/vmess+ws" || "$obj" == "hy2" ]]; then + if ! checkHy2Alive; then + #echo "重启serv00sb中..." + cd ${installpath}/serv00-play/singbox + chmod +x ./start.sh && ./start.sh 2 keep + sleep 1 + if ! checkHy2Alive; then + msg="hy2 重启失败." + else + msg="hy2 重启成功." + fi + fi + elif [ "$obj" == "nezha-agent" ]; then + if ! checknezhaAgentAlive; then + cd ${installpath}/serv00-play/nezha + startNeZhaAgent + sleep 1 + if ! checknezhaAgentAlive; then + msg="nezha-agent 重启失败." + else + msg="nezha-agent 重启成功." + fi + fi + elif [ "$obj" == "nezha-dashboard" ]; then + if ! checkProcAlive "nezha-dashboard"; then + cd ${installpath}/serv00-play/nezha-board + startNeZhaDashboard + sleep 1 + if ! checkProcAlive "nezha-dashboard"; then + msg="nezha-dashboard 重启失败." + else + msg="nezha-dashboard 重启成功." + fi + fi + elif [ "$obj" == "mtg" ]; then + if ! checkMtgAlive; then + cd ${installpath}/serv00-play/dmtg + startMtg + sleep 1 + if ! checkMtgAlive; then + msg="mtproto 重启失败." + else + msg="mtproto 重启成功." + fi + fi + elif [ "$obj" == "alist" ]; then + if ! checkProcAlive "alist"; then + startAlist + sleep 1 + if ! checkProcAlive "alist"; then + msg="alist 重启失败." + else + msg="alist 重启成功." + fi + fi + elif [ "$obj" == "wssh" ]; then + if ! checkProcAlive wssh; then + startAlist + sleep 1 + if ! checkAlistAlive; then + msg="wssh 重启失败." + else + msg="wssh 重启成功." + fi + fi + elif [ "$obj" == "redis-server" ]; then + if ! checkProcAlive redis-server; then + echo "正在启动redis-server..." + cd ${installpath}/serv00-play/redis + nohup ./redis-server ./redis.conf >/dev/null 2>&1 & + sleep 2 + if ! checkProcAlive redis-server; then + msg="redis-server 重启失败." + else + msg="redis-server 重启成功." + fi + fi + else + continue + fi + + sendMsg "$msg" done if [ ${#monitor[@]} -gt 0 ]; then - checkResetCron + checkResetCron +fi + +if [[ "$autoUpdateHyIP" == "Y" ]]; then + echo "正在自动更新HY2IP..." + cd ${installpath}/serv00-play/singbox + chmod +x ./autoUpdateHyIP.sh && ./autoUpdateHyIP.sh fi + +devil info account &>/dev/null +cleanUselessProc +# 清理锁文件 +cleanup diff --git a/keepalive/app.js b/keepalive/app.js new file mode 100644 index 00000000..170ef8ea --- /dev/null +++ b/keepalive/app.js @@ -0,0 +1,200 @@ +const express = require('express') +const fs = require('fs') +const path = require('path') +const { exec } = require('child_process') +const bodyParser = require('body-parser') +const { log } = require('console') +const app = express() + +app.use(bodyParser.json()) +app.use(bodyParser.urlencoded({ extended: true })) +app.use('/static', express.static(path.join(__dirname, 'static'))) +const user = require('child_process').execSync('whoami').toString().trim() +const serv00PlayDir = `/home/${user}/serv00-play` +const keepaliveScript = `${serv00PlayDir}/keepalive.sh` + +// 读取配置文件 +const configPath = path.join(__dirname, 'config.json') +let config = {} +if (fs.existsSync(configPath)) { + config = JSON.parse(fs.readFileSync(configPath, 'utf8')) +} + +// 实现 loadConfig 方法 +function loadConfig() { + if (fs.existsSync(configPath)) { + config = JSON.parse(fs.readFileSync(configPath, 'utf8')) + logError('配置文件重新加载成功') + } else { + logError('配置文件不存在') + } +} + +// 监听配置文件变化 +fs.watchFile(configPath, (curr, prev) => { + if (curr.mtime !== prev.mtime) { + logError('检测到配置文件变化, 重新加载配置') + loadConfig() + } +}) + +// 验证token +function validateToken(req, res, next) { + const token = cleanAndDecode(req.query.token) + if (!token || token !== config.token) { + logError(`Token验证失败: ${token}`) + return res.status(401).send('无授权不能访问!') + } + next() +} + +// 修改日志函数,确保同步写入 +function logError(message) { + if (config.showlog !== 'Y') { + return + } + try { + const timestamp = new Date().toISOString() + const logMessage = `[${timestamp}] ${message}\n` + const logFile = path.join(__dirname, 'logs', 'debug.log') + + // 确保日志目录存在 + if (!fs.existsSync(path.dirname(logFile))) { + fs.mkdirSync(path.dirname(logFile), { recursive: true }) + } + + // 同步写入日志 + fs.appendFileSync(logFile, logMessage) + console.log(logMessage) // 同时输出到控制台 + } catch (error) { + console.error('日志记录失败:', error) + } +} +// 添加请求日志中间件 +app.use((req, res, next) => { + logError(`${req.method} ${req.url}`) + next() +}) + +// 清理和解码函数 +function cleanAndDecode(str) { + if (!str || str === 'null') return 'null' + try { + return Buffer.from(str.trim(), 'base64') + .toString('utf8') + .replace(/[\s\uFEFF\xA0]/g, '') + } catch (e) { + logError(`Base64 decode error: ${e.message}`) + return 'null' + } +} + +// 定时调用脚本的方法 +function scheduleScript() { + const cmd = `cd ${serv00PlayDir} && bash ${keepaliveScript} ` + + const executeScript = () => { + const interval = (parseInt(config.interval, 10) || 5) * 60000 // 默认5分钟 + + logError(`定时执行脚本: ${cmd}, 间隔: ${interval}ms`) + exec(cmd, (error, stdout, stderr) => { + if (error) { + logError(`定时执行脚本错误: ${error.message}`) + logError(stderr) + } else { + logError('定时执行脚本成功') + logError(stdout) + } + }) + + // 设置定时器 + setTimeout(executeScript, interval) + } + + // 立即执行一次 + executeScript() +} + +// 启动定时任务 +scheduleScript() + +// 记录启动信息 +logError('服务启动') +// 获取 autoupdate 状态 +function getAutoupdateStatus(autoupdate) { + return autoupdate === 'Y' ? 'autoupdate' : 'noupdate' +} + +// 处理首页请求 +app.get('/', (req, res) => { + if (config.img) { + res.send(` + + + + + + 首页 + + + 首页 + + + `) + } else { + res.send('Welcome') + } +}) + +app.get('/keep', validateToken, async (req, res) => { + logError('开始处理参数') + // 处理参数 + logError('接收到的参数:') + logError(`autoupdate: ${req.query.autoupdate}`) + logError(`sendtype: ${req.query.sendtype}`) + logError(`telegramtoken: ${req.query.telegramtoken}`) + logError(`telegramuserid: ${req.query.telegramuserid}`) + logError(`wxsendkey: ${req.query.wxsendkey}`) + logError(`buttonurl: ${req.query.buttonurl}`) + logError(`pass: ${req.query.pass}`) + logError(`wxpushurl: ${req.query.wxpushurl}`) + logError(`wxtoken: ${req.query.wxtoken}`) + + const params = { + autoupdate: getAutoupdateStatus(req.query.autoupdate), + sendtype: req.query.sendtype ? req.query.sendtype.trim() : 'null', + telegramtoken: cleanAndDecode(req.query.telegramtoken), + telegramuserid: req.query.telegramuserid + ? req.query.telegramuserid.trim() + : 'null', + wxsendkey: cleanAndDecode(req.query.wxsendkey), + buttonurl: cleanAndDecode(req.query.buttonurl), + pass: cleanAndDecode(req.query.password), + wxpushurl: cleanAndDecode(req.query.wxpushurl), + wxtoken: cleanAndDecode(req.query.wxtoken), + } + + logError( + '处理参数: ' + + JSON.stringify({ + ...params, + pass: '***', + }) + ) + // 本地执行 + logError('本地执行keepalive') + const cmd = `cd ${serv00PlayDir} && nohup bash ${keepaliveScript} ${params.autoupdate} ${params.sendtype} ${params.telegramtoken} ${params.telegramuserid} ${params.wxsendkey} ${params.buttonurl} ${params.pass} ${params.wxpushurl} ${params.wxtoken} > /dev/null 2>&1 &` + logError('cmd:' + cmd) + exec(cmd, (error) => { + if (error) { + logError(`本地执行错误: ${error}`) + } else { + logError('本地执行成功') + } + }) + res.send('ok') +}) + +app.listen(3000, () => { + console.log('Server is running on port 3000') +}) diff --git a/keepalive/config.json b/keepalive/config.json new file mode 100644 index 00000000..3def90f0 --- /dev/null +++ b/keepalive/config.json @@ -0,0 +1,6 @@ +{ + "interval": "TM", + "token": "uuid", + "img": "nezha.jpg", + "showlog": "N" +} diff --git a/keepalive/nezha.jpg b/keepalive/nezha.jpg new file mode 100644 index 00000000..a05ba8ed Binary files /dev/null and b/keepalive/nezha.jpg differ diff --git a/mkprofile.pl b/mkprofile.pl index 61b82ead..881656f6 100644 --- a/mkprofile.pl +++ b/mkprofile.pl @@ -7,6 +7,8 @@ export TZ=Asia/Shanghai export EDITOR=vim export VISUAL=vim +export LANG=en_US.UTF-8 +export LC_ALL=en_US.UTF-8 alias l='ls -ltr' alias pp='ps aux' alias ss='cd ~/serv00-play && ./start.sh' diff --git a/revive.sh b/revive.sh old mode 100755 new mode 100644 index 8ea09781..47cd1b55 --- a/revive.sh +++ b/revive.sh @@ -1,34 +1,114 @@ #!/bin/bash -#HOSTS_JSON='{ -#"info": [ -#{ -# "host": "s2.serv00.com", -# "username": "xloong", -# "port": 22, -# "password": "abc123" -#} -#] -#}' -#echo "host info:$HOSTS_JSON" -# 使用 jq 提取 JSON 数组,并将其加载为 Bash 数组 -hosts_info=($(echo "${HOSTS_JSON}" | jq -c ".info[]")) - -for info in "${hosts_info[@]}"; do - user=$(echo $info | jq -r ".username") - host=$(echo $info | jq -r ".host") - port=$(echo $info | jq -r ".port") - pass=$(echo $info | jq -r ".password") - - script="/home/$user/serv00-play/keepalive.sh autoupdate ${SENDTYPE} ${TELEGRAM_TOKEN} ${TELEGRAM_USERID} ${WXSENDKEY}" - - output=$(sshpass -p "$pass" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$host" "bash -s" <<< "$script") - - echo "output:$output" - if echo "$output" | grep -q "更新完毕"; then - echo "登录成功" - else - echo "登录失败" - ./tgsend.sh "主机:$host,用户名:$user,登录失败请检查!" - fi -done +AUTOUPDATE=${AUTOUPDATE:-Y} +SENDTYPE=${SENDTYPE:-null} +TELEGRAM_TOKEN=${TELEGRAM_TOKEN:-null} +TELEGRAM_USERID=${TELEGRAM_USERID:-null} +WXSENDKEY=${WXSENDKEY:-null} +WXPUSH_URL=${WXPUSH_URL:-null} +WX_TOKEN=${WX_TOKEN:-null} +BUTTON_URL=${BUTTON_URL:-null} +LOGININFO=${LOGININFO:-N} +LOGINONCE=${LOGINONCE:-N} +export TELEGRAM_TOKEN TELEGRAM_USERID BUTTON_URL WXSENDKEY WXPUSH_URL WX_TOKEN + +PROXY_HOST=${PROXY_HOST:-null} +PROXY_PORT=${PROXY_PORT:-null} +PROXY_USER=${PROXY_USER:-null} +PROXY_PASS=${PROXY_PASS:-null} + +export SOCKS5_USER="$PROXY_USER" +export SOCKS5_PASSWD="$PROXY_PASS" + +sendMsg() { + local msg="$1" + chmod +x ./tgsend.sh ./wxsend.sh + if [ -n "$msg" ]; then + if [ "$SENDTYPE" == "1" ]; then + ./tgsend.sh "$msg" + elif [ "$SENDTYPE" == "2" ]; then + ./wxsend.sh "$msg" + elif [ "$SENDTYPE" == "3" ]; then + ./tgsend.sh "$msg" + ./wxsend.sh "$msg" + fi + fi +} + +# 登录服务器并执行保活脚本 +login_server() { + local user=$1 + local host=$2 + local port=$3 + local pass=$4 + local msg="" + + if [[ "$AUTOUPDATE" == "Y" ]]; then + script="bash /home/$user/serv00-play/keepalive.sh autoupdate ${SENDTYPE} \"${TELEGRAM_TOKEN}\" \"${TELEGRAM_USERID}\" \"${WXSENDKEY}\" \"${BUTTON_URL}\" \"${pass}\" \"${WXPUSH_URL}\" \"${WX_TOKEN}\"" + else + script="bash /home/$user/serv00-play/keepalive.sh noupdate ${SENDTYPE} \"${TELEGRAM_TOKEN}\" \"${TELEGRAM_USERID}\" \"${WXSENDKEY}\" \"${BUTTON_URL}\" \"${pass}\" \"${WXPUSH_URL}\" \"${WX_TOKEN}\"" + fi + #使用socks5代理进行登录 + if [[ "$PROXY_HOST" != "null" ]]; then + echo "测试基础连接..." >&2 + if timeout 5 nc -zv "$PROXY_HOST" "$PROXY_PORT" &>/dev/null; then + echo "✓ 可以连接到代理服务器" >&2 + else + echo "✗ 无法连接到代理服务器" >&2 + exit 1 + fi + output=$(sshpass -p "$pass" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=30 -o ProxyCommand="connect -S ${PROXY_HOST}:${PROXY_PORT} %h %p" -p "$port" "$user@$host" "bash -s" <<<"$script") + else + output=$(sshpass -p "$pass" ssh -o StrictHostKeyChecking=no -p "$port" "$user@$host" "bash -s" <<<"$script") + fi + + #echo "output:$output" >&2 + + if echo "$output" | grep -q "keepalive.sh"; then + echo "登录成功" >&2 + msg="🟢主机 ${host}, 用户 ${user}, 登录成功!\n" + else + echo "登录失败" >&2 + msg="🔴主机 ${host}, 用户 ${user}, 登录失败!\n" + export PASS=$pass + sendMsg "Host:$host, user:$user, 登录失败,请检查!" + fi + echo -n "$msg" +} + +summary="" +if [[ "$LOGINONCE" == "Y" ]]; then + echo "只登录一次模式" + # 计算今天是今年的第几天(1-366) + DAY_OF_YEAR=$(date +%j) + + # 获取服务器数量 + SERVER_COUNT=$(echo "$HOSTS_JSON" | jq '.info | length') + + # 计算今天应该登录哪个服务器(取模运算) + INDEX=$(((10#$DAY_OF_YEAR - 1) % SERVER_COUNT)) + + # 获取对应的服务器配置 + CONFIG=$(echo "$HOSTS_JSON" | jq ".info[$INDEX]") + + HOST=$(echo "$CONFIG" | jq -r '.host') + USERNAME=$(echo "$CONFIG" | jq -r '.username') + PORT=$(echo "$CONFIG" | jq -r '.port') + PASSWORD=$(echo "$CONFIG" | jq -r '.password') + + summary=$(login_server "$USERNAME" "$HOST" "$PORT" "$PASSWORD") +else + mapfile -t hosts_info < <(echo "${HOSTS_JSON}" | jq -c ".info[]") + for info in "${hosts_info[@]}"; do + user=$(echo "$info" | jq -r ".username") + host=$(echo "$info" | jq -r ".host") + port=$(echo "$info" | jq -r ".port") + pass=$(echo "$info" | jq -r ".password") + + summary=$summary$(login_server "$user" "$host" "$port" "$pass") + done +fi + +if [[ "$LOGININFO" == "Y" ]]; then + sendMsg "$summary" +fi diff --git a/revive_node.sh b/revive_node.sh new file mode 100644 index 00000000..3bfbfef7 --- /dev/null +++ b/revive_node.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +toBase64() { + echo -n "$1" | base64 +} + +AUTOUPDATE=${AUTOUPDATE:-Y} +SENDTYPE=${SENDTYPE:-null} +TELEGRAM_TOKEN=${TELEGRAM_TOKEN:-null} +TELEGRAM_USERID=${TELEGRAM_USERID:-null} +WXSENDKEY=${WXSENDKEY:-null} +WXPUSH_URL=${WXPUSH_URL:-null} +WX_TOKEN=${WX_TOKEN:-null} +BUTTON_URL=${BUTTON_URL:-null} +LOGININFO=${LOGININFO:-N} +TOKEN=${TOKEN:-""} + +TOKEN=$(toBase64 $TOKEN) +base64_TELEGRAM_TOKEN=$(toBase64 $TELEGRAM_TOKEN) +Base64BUTTON_URL=$(toBase64 $BUTTON_URL) +base64_WXPUSH_URL=$(toBase64 $WXPUSH_URL) +base64_WX_TOKEN=$(toBase64 $WX_TOKEN) + +export TELEGRAM_TOKEN TELEGRAM_USERID BUTTON_URL + +# 使用 jq 提取 JSON 数组,并将其加载为 Bash 数组 +hosts_info=($(echo "${HOSTS_JSON}" | jq -c ".info[]")) +summary="" +for info in "${hosts_info[@]}"; do + user=$(echo $info | jq -r ".username") + host=$(echo $info | jq -r ".host") + pass=$(echo $info | jq -r ".password") + + echo "host: $host" + bas64_pass=$(toBase64 $pass) + output=$(curl -s -o /dev/null -w "%{http_code}" "https://$user.serv00.net/keep?token=$TOKEN&autoupdate=$AUTOUPDATE&sendtype=$SENDTYPE&telegramtoken=$base64_TELEGRAM_TOKEN&telegramuserid=$TELEGRAM_USERID&wxsendkey=$WXSENDKEY&buttonurl=$Base64BUTTON_URL&password=$bas64_pass&wxpushurl=$base64_WXPUSH_URL&wxtoken=$base64_WX_TOKEN") + + if [ "$output" -eq 200 ]; then + echo "连接成功,账号正常" + msg="🟢主机 ${host}, 用户 ${user}, 连接成功,账号正常!\n" + elif [ "$output" -eq 403 ]; then + echo "账号被封" + msg="🔴主机 ${host}, 用户 ${user}, 账号被封!\n" + chmod +x ./tgsend.sh + export PASS=$pass + ./tgsend.sh "Host:$host, user:$user, 账号被封,请检查!" + elif [ "$output" -eq 404 ]; then + echo "keepalive服务不在线" + msg="🔴主机 ${host}, 用户 ${user}, keepalive服务不在线!\n" + chmod +x ./tgsend.sh + export PASS=$pass + ./tgsend.sh "Host:$host, user:$user, keepalive服务不在线,请检查!" + elif [ "$output" -eq 401 ]; then + echo "授权码错误" + msg="🔴主机 ${host}, 用户 ${user}, 授权码错误!\n" + chmod +x ./tgsend.sh + export PASS=$pass + ./tgsend.sh "Host:$host, user:$user, 授权码错误,请检查!" + else + echo "连接失败,可能网络问题!" + msg="🔴主机 ${host}, 用户 ${user}, 连接失败,可能网络问题!\n" + chmod +x ./tgsend.sh + export PASS=$pass + ./tgsend.sh "Host:$host, user:$user, 连接失败,可能网络问题,可直接访问主页查看: https://$user.serv00.net" + fi + summary=$summary$(echo -n $msg) +done + +if [[ "$LOGININFO" == "Y" ]]; then + chmod +x ./tgsend.sh + ./tgsend.sh "$summary" +fi diff --git a/singbox/autoUpdateHyIP.sh b/singbox/autoUpdateHyIP.sh new file mode 100644 index 00000000..d517a079 --- /dev/null +++ b/singbox/autoUpdateHyIP.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +installpath="$HOME" +USER="$(whoami)" +if [[ -e "$installpath/serv00-play" ]]; then + source ${installpath}/serv00-play/utils.sh +fi + +cd ${installpath}/serv00-play/singbox +if [[ ! -e "singbox.json" || ! -e "config.json" ]]; then + red "未安装节点,请先安装!" + exit +fi +config="singbox.json" +cur_hy2_ip=$(jq -r ".HY2IP" $config) +# 检查 cur_hy2_ip 是否为空 +if [[ -z "$cur_hy2_ip" ]]; then + red "当前 HY2IP 为空,未安装hy2节点!" + exit +fi + +show_ip_status + +if printf '%s\n' "${useIPs[@]}" | grep -q "$cur_hy2_ip"; then + echo "目前ip可用" + exit +fi + +if [[ ${#useIPs[@]} -eq 0 ]]; then + red "当前无可用IP!" + exit +fi + +hy2_ip=${useIPs[0]} + +if [[ -z "$hy2_ip" ]]; then + red "很遗憾,已无可用IP!" + exit +fi + +if ! upInsertFd singbox.json HY2IP "$hy2_ip"; then + red "更新singbox.json配置文件失败!" + exit +fi + +if ! upSingboxFd config.json "inbounds" "tag" "hysteria-in" "listen" "$hy2_ip"; then + red "更新config.json配置文件失败!" + exit +fi +green "HY2 更换IP成功,当前IP为 $hy2_ip" + +echo "正在重启sing-box..." +stop_sing_box +start_sing_box diff --git a/singbox/killsing-box.sh b/singbox/killsing-box.sh index 77cc29e6..d02b9af7 100644 --- a/singbox/killsing-box.sh +++ b/singbox/killsing-box.sh @@ -1,18 +1,17 @@ #!/bin/bash -r=$(ps aux | grep cloudflare | grep -v grep | awk '{print $2}') -if [ -z "$r" ]; then - echo "can't find cloudflare" >/dev/null -else - echo $r - kill -9 $r -fi +# 定义需要检查和终止的进程名 +processes=("cloudflare" "serv00sb") -r=$(ps aux | grep serv00sb | grep -v grep | awk '{print $2}') +for process in "${processes[@]}"; do + # 查找进程 ID + pids=$(pgrep "$process") -if [ -z "$r" ]; then - echo "can't find serv00sb" >/dev/null -else - echo $r - kill -9 $r -fi + if [ -n "$pids" ]; then + echo "Killing process: $process (PIDs: $pids)" + # 逐个杀死进程 + for pid in $pids; do + kill -9 "$pid" + done + fi +done diff --git a/singbox/start.sh b/singbox/start.sh index 81fba785..4464c0be 100644 --- a/singbox/start.sh +++ b/singbox/start.sh @@ -1,6 +1,10 @@ #!/bin/bash config="singbox.json" +installpath="$HOME" +if [[ -e "$installpath/serv00-play" ]]; then + source ${installpath}/serv00-play/utils.sh +fi VMPORT=$(jq -r ".VMPORT" $config) HY2PORT=$(jq -r ".HY2PORT" $config) @@ -10,12 +14,12 @@ WSPATH=$(jq -r ".WSPATH" $config) ARGO_AUTH=$(jq -r ".ARGO_AUTH" $config) ARGO_DOMAIN=$(jq -r ".ARGO_DOMAIN" $config) - +TUNNEL_NAME=$(jq -r ".TUNNEL_NAME" $config) GOOD_DOMAIN=$(jq -r ".GOOD_DOMAIN" $config) SOCKS5_PORT=$(jq -r ".SOCKS5_PORT" $config) SOCKS5_USER=$(jq -r ".SOCKS5_USER" $config) SOCKS5_PASS=$(jq -r ".SOCKS5_PASS" $config) - +user="$(whoami)" if [ -z $1 ]; then type=$(jq -r ".TYPE" $config) @@ -25,38 +29,37 @@ fi keep=$2 - - run() { if ps aux | grep cloudflared | grep -v "grep" >/dev/null; then return fi - if [[ -n "${ARGO_AUTH}" && -n "${ARGO_DOMAIN}" ]]; then - if [[ "$ARGO_AUTH" =~ TunnelSecret ]]; then - echo "$ARGO_AUTH" | sed 's@{@{"@g;s@[,:]@"\0"@g;s@}@"}@g' >tunnel.json - cat >tunnel.yml <>tunnel.yml </dev/null 2>&1 & - elif [[ "$ARGO_AUTH" =~ ^[A-Z0-9a-z=]{120,250}$ ]]; then - nohup ./cloudflared tunnel --edge-ip-version auto --protocol http2 run --token ${ARGO_AUTH} >/dev/null 2>&1 & - fi + if [[ "${ARGO_AUTH}" != "null" && "${ARGO_DOMAIN}" != "null" ]]; then + nohup ./cloudflared tunnel --edge-ip-version auto --protocol http2 run --token ${ARGO_AUTH} >/dev/null 2>&1 & + elif [[ "$ARGO_DOMAIN" != "null" && "$TUNNEL_NAME" != "null" ]]; then + nohup ./cloudflared tunnel run $TUNNEL_NAME >/dev/null 2>&1 & else - nohup ./cloudflared tunnel --edge-ip-version auto --protocol http2 --no-autoupdate --url http://localhost:${VMPORT} >/dev/null 2>&1 & - sleep 5 - ARGO_DOMAIN=$(wget -qO- $(sockstat -4 -l -P tcp | grep cloudflare | awk '{for(i=1;i<=NF;i++) if($i ~ /127\.0\.0\.1/) print $i}')/quicktunnel | jq -r '.hostname') - echo "ARGO_DOMAIN:$ARGO_DOMAIN" + echo "未有tunnel相关配置!" + return 1 + fi +} + +uploadList() { + local token="$1" + local content="$2" + local user="${user,,}" + local url="${linkBaseurl}/addlist?token=$token" + local encode_content=$(echo -n "$content" | base64 -w 0) + + #echo "encode_content:$encode_content" + curl -X POST "$url" \ + -H "Content-Type: application/json" \ + -d "{\"content\":\"$encode_content\", + \"user\":\"$user\"}" + + if [[ $? -eq 0 ]]; then + return 0 + else + return 1 fi } @@ -64,32 +67,47 @@ export_list() { user="$(whoami)" host="$(hostname | cut -d '.' -f 1)" if [[ "$HY2IP" != "::" ]]; then - myip=${HY2IP} + myip=${HY2IP} else - myip="$(curl -s ifconfig.me)" + myip="$(curl -s icanhazip.com)" + fi + if [[ "$GOOD_DOMAIN" == "null" ]]; then + GOOD_DOMAIN="www.visa.com.hk" fi vmessname="Argo-vmess-$host-$user" hy2name="Hy2-$host-$user" - VMESSWS="{\"v\":\"2\",\"ps\": \"Vmessws-${host}-${user}\", \"add\":\"www.visa.com.hk\", \"port\":\"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"${GOOD_DOMAIN}\", \"path\": \"/${WSPATH}?ed=2048\", \"tls\": \"tls\", \"sni\": \"${GOOD_DOMAIN}\", \"alpn\": \"\", \"fp\": \"\"}" - ARGOVMESS="{ \"v\": \"2\", \"ps\": \"$vmessname\", \"add\": \"www.visa.com.hk\", \"port\": \"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"${ARGO_DOMAIN}\", \"path\": \"/${WSPATH}?ed=2048\", \"tls\": \"tls\", \"sni\": \"${ARGO_DOMAIN}\", \"alpn\": \"\" }" + VMESSWS="{ \"v\":\"2\", \"ps\": \"Vmessws-${host}-${user}\", \"add\":\"$GOOD_DOMAIN\", \"port\":\"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"${GOOD_DOMAIN}\", \"path\": \"/${WSPATH}?ed=2048\", \"tls\": \"tls\", \"sni\": \"${GOOD_DOMAIN}\", \"alpn\": \"\", \"fp\": \"\"}" + ARGOVMESS="{ \"v\": \"2\", \"ps\": \"$vmessname\", \"add\": \"$GOOD_DOMAIN\", \"port\": \"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"${ARGO_DOMAIN}\", \"path\": \"/${WSPATH}?ed=2048\", \"tls\": \"tls\", \"sni\": \"${ARGO_DOMAIN}\", \"alpn\": \"\", \"fp\": \"\" }" hysteria2="hysteria2://$UUID@$myip:$HY2PORT/?sni=www.bing.com&alpn=h3&insecure=1#$hy2name" - socks5="https://t.me/socks?server=${host}.serv00.com&port=${SOCKS5_PORT}&user=${SOCKS5_USER}&pass=${SOCKS5_PASS}" - proxyip="proxyip://${SOCKS5_USER}:${SOCKS5_PASS}@${host}.serv00.com:${SOCKS5_PORT}" - + socks5="https://t.me/socks?server=${host}.$(getDoMain)&port=${SOCKS5_PORT}&user=${SOCKS5_USER}&pass=${SOCKS5_PASS}" + proxyip="proxyip://${SOCKS5_USER}:${SOCKS5_PASS}@${host}.$(getDoMain):${SOCKS5_PORT}" cat >list </dev/null; then - nohup ./serv00sb run -c ./config.json >/dev/null 2>&1 & + nohup ./serv00sb run -c ./config.json >/dev/null 2>&1 & fi elif [[ "$type" =~ ^(1|3|1.1|3.1|4.4|2.4)$ ]]; then - chmod +x ./serv00sb - if ! ps aux | grep serv00sb | grep -v "grep" >/dev/null; then - nohup ./serv00sb run -c ./config.json >/dev/null 2>&1 & - fi + chmod +x ./serv00sb + if ! ps aux | grep serv00sb | grep -v "grep" >/dev/null; then + nohup ./serv00sb run -c ./config.json >/dev/null 2>&1 & + fi fi if [ -z "$keep" ]; then diff --git a/ssl/cronSSL.sh b/ssl/cronSSL.sh index af4847cb..a1a62229 100644 --- a/ssl/cronSSL.sh +++ b/ssl/cronSSL.sh @@ -3,6 +3,7 @@ installpath="$HOME" domain=$1 host="$(hostname | cut -d '.' -f 1)" +user=$(whoami) sno=${host/s/web} webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') resp=$(devil ssl www add $webIp le le $domain) @@ -13,15 +14,26 @@ if [[ "$resp" =~ .*succesfully.*$ ]]; then crontab -l | grep -v "$domain" >tmpcron crontab tmpcron rm -rf tmpcron - config="../config.json" + if grep "telegram_token" ../config.json; then + config="../config.json" + else + config="../msg.json" + fi if [ -e "$config" ]; then TELEGRAM_TOKEN=$(jq -r ".telegram_token" "$config") TELEGRAM_USERID=$(jq -r ".telegram_userid" "$config") if [[ -n "$TELEGRAM_TOKEN" && -n "$TELEGRAM_USERID" ]]; then - msg="你的域名($domain)申请的SSL证书已下发,请查收!" + msg="Host:$host, user:$user, 你的域名($domain)申请的SSL证书已下发,请查收!" cd $installpath/serv00-play export TELEGRAM_TOKEN="$TELEGRAM_TOKEN" TELEGRAM_USERID="$TELEGRAM_USERID" ./tgsend.sh "$msg" fi fi +elif [[ "$resp" =~ .*already.*$ ]]; then + echo "域名($domain)的SSL证书已存在,无需重复申请!" + crontab -l | grep -v "$domain" >tmpcron + crontab tmpcron + rm -rf tmpcron +else + echo "申请SSL证书失败,请检查域名($domain)是否正确!" fi diff --git a/start.sh b/start.sh index 39fc0a1a..75740e29 100755 --- a/start.sh +++ b/start.sh @@ -9,257 +9,299 @@ CYAN='\033[0;96m' WHITE='\033[0;37m' RESET='\033[0m' yellow() { - echo -e "${YELLOW}$1${RESET}" + echo -e "${YELLOW}$1${RESET}" } green() { - echo -e "${GREEN}$1${RESET}" + echo -e "${GREEN}$1${RESET}" } red() { - echo -e "${RED}$1${RESET}" + echo -e "${RED}$1${RESET}" } installpath="$HOME" -if [[ -e "$installpath/serv00-play" ]]; then - source ${installpath}/serv00-play/utils.sh +USER="$(whoami)" +if [[ -e "$installpath/serv00-play" ]]; then + source ${installpath}/serv00-play/utils.sh fi PS3="请选择(输入0退出): " -install(){ - cd ${installpath} - if [ -d serv00-play ]; then - cd "serv00-play" - git stash - if git pull; then - echo "更新完毕" - #重新给各个脚本赋权限 - chmod +x ./start.sh - chmod +x ./keepalive.sh - chmod +x ${installpath}/serv00-play/singbox/start.sh - chmod +x ${installpath}/serv00-play/singbox/killsing-box.sh - chmod +x ${installpath}/serv00-play/ssl/cronSSL.sh - red "请重新启动脚本!" - exit 0 - fi - fi - - cd ${installpath} - echo "正在安装..." - if ! git clone https://github.com/frankiejun/serv00-play.git; then - echo -e "${RED}安装失败!${RESET}" - exit 1; - fi - echo -e "${YELLOW}安装成功${RESET}" -} - -showSingBoxInfo(){ - cd ${installpath}/serv00-play/singbox - - if [ ! -f singbox.json ]; then - red "配置文件不存在,请先行配置!" - return - fi - if [ ! -e list ]; then - red "请先运行sing-box" - fi - config="singbox.json" - type=$(jq -r ".TYPE" $config) - chmod +x ./start.sh && ./start.sh $type list - -} - - -chooseSingbox(){ - echo "保活sing-box中哪个项目: " - echo " 1.hy2/vmess+ws/socks5 " - echo " 2.argo+vmess " - echo " 3.all " - read -p "请选择:" input - - if [ "$input" = "1" ]; then - item+=("hy2/vmess+ws") - elif [ "$input" = "2" ]; then - item+=("vmess") - elif [ "$input" = "3" ]; then - item+=("hy2/vmess+ws") - item+=("vmess") - else - red "无效选择!" - return 1 - fi - -} - -setConfig(){ - cd ${installpath}/serv00-play/ - - if [ -f config.json ]; then - echo "目前已有配置:" - config_content=$(cat config.json) - echo $config_content - read -p "是否修改? [y/n] [y]:" input - input=${input:-y} - if [ "$input" != "y" ]; then - return - fi - fi - createConfigFile -} - -createConfigFile(){ - - echo "选择你要保活的项目(可多选,用空格分隔):" - echo "1. sun-panel " - echo "2. sing-box(包含hy2,vmess,socks5) " - echo "3. 哪吒探针 " - echo "4. mtproto代理" - echo "5. alist" - echo "6. webssh" - echo "88. 暂停所有保活功能" - echo "99. 复通所有保活功能(之前有配置的情况下)" - item=() - - read -p "请选择: " choices - choices=($choices) - - if [[ "${choices[@]}" =~ "88" && ${#choices[@]} -gt 1 ]]; then - red "选择出现了矛盾项,请重新选择!" - return 1 - fi - - #过滤重复 - choices=($(echo "${choices[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) - - # 根据选择来询问对应的配置 - for choice in "${choices[@]}"; do - case "$choice" in - 1) - item+=("sun-panel") - ;; - 2) - if ! chooseSingbox; then - return - fi - ;; - 3) - item+=("nezha-agent") - ;; - 4) - item+=("mtg") - ;; - 5) - item+=("alist") - ;; - 6) - item+=("webssh") - ;; - 88) - delCron - backupConfig "config.json" - green "设置完毕!" - return 0 - ;; - 99) - if [[ ! -e config.bak ]]; then - red "之前未有配置,未能复通!" - return 1 - fi - restoreConfig "config.bak" - tm=$(jq -r ".chktime" config.json) - addCron $tm - green "设置完毕!" - return 0 - ;; - *) - echo "无效选择" - return 1 - ;; - esac -done - - json_content="{\n" - json_content+=" \"item\": [\n" - - for item in "${item[@]}"; do - json_content+=" \"$item\"," - done - - # 删除最后一个逗号并换行 - json_content="${json_content%,}\n" - json_content+=" ],\n" - - if [ "$num" = "4" ]; then - json_content+=" \"chktime\": \"null\"" - json_content+="}\n" - printf "$json_content" > ./config.json - echo -e "${YELLOW} 设置完成! ${RESET} " - delCron - return - fi - - read -p "配置保活检查的时间间隔(单位分钟,默认5分钟):" tm - tm=${tm:-"5"} - - json_content+=" \"chktime\": \"$tm\"," - - read -p "是否需要配置消息推送? [y/n] [n]:" input - input=${input:-n} - - if [ "${input}" == "y" ]; then - json_content+="\n" - - echo "选择要推送的app:" - echo "1) Telegram " - echo "2) 微信 " - echo "3) 以上皆是" - - read -p "请选择:" sendtype - - if [ "$sendtype" == "1" ]; then - writeTG - elif [ "$sendtype" == "2" ]; then - writeWX - elif [ "$sendtype" == "3" ]; then - writeTG - writeWX - else - echo "无效选择" - return - fi - else - sendtype=${sendtype:-"null"} - fi - json_content+="\n \"sendtype\": $sendtype \n" - json_content+="}\n" - - # 使用 printf 生成文件 - printf "$json_content" > ./config.json - addCron $tm - chmod +x ${installpath}/serv00-play/keepalive.sh - echo -e "${YELLOW} 设置完成! ${RESET} " - -} - -backupConfig(){ - local filename=$1 - if [[ -e "$filename" ]]; then - if [[ "$filename" =~ ".json" ]]; then - local basename=${filename%.json} - mv $filename $basename.bak - fi - fi -} - -restoreConfig(){ - local filename=$1 - if [[ -e "$filename" ]]; then - if [[ "$filename" =~ ".bak" ]]; then - local basename=${filename%.bak} - mv $filename $basename.json - fi - fi +install() { + local input=$1 + cd ${installpath} + if [ -d "serv00-play" ]; then + cd "serv00-play" + git stash + if git pull origin main; then + git fetch --tags + echo "更新完毕" + #重新给各个脚本赋权限 + chmod +x ./start.sh + chmod +x ./keepalive.sh + chmod +x ./tgsend.sh + chmod +x ./wxsend.sh + chmod +x ${installpath}/serv00-play/singbox/start.sh + chmod +x ${installpath}/serv00-play/singbox/killsing-box.sh + chmod +x ${installpath}/serv00-play/singbox/autoUpdateHyIP.sh + chmod +x ${installpath}/serv00-play/ssl/cronSSL.sh + red "请重新启动脚本!" + exit 0 + fi + fi + + cd ${installpath} + echo "正在安装..." + if ! git clone https://github.com/frankiejun/serv00-play.git; then + echo -e "${RED}安装失败!${RESET}" + exit 1 + fi + devil binexec on + touch .profile + cat .profile | perl ./serv00-play/mkprofile.pl >tmp_profile + mv -f tmp_profile .profile + if [[ ! -e "${installpath}/serv00-play" ]]; then + red "安装不成功!" + return + fi + + cd ${installpath}/serv00-play + chmod +x ./start.sh + chmod +x ./keepalive.sh + chmod +x ./tgsend.sh + chmod +x ./wxsend.sh + chmod +x ${installpath}/serv00-play/singbox/start.sh + chmod +x ${installpath}/serv00-play/singbox/killsing-box.sh + chmod +x ${installpath}/serv00-play/singbox/autoUpdateHyIP.sh + chmod +x ${installpath}/serv00-play/ssl/cronSSL.sh + if [ -z "$input" ]; then + read -p "$(yellow 设置完毕,需要重新登录才能生效,是否重新登录?[y/n] [y]:)" input + input=${input:-y} + fi + echo -e "${YELLOW}安装成功${RESET}" + + if [ "$input" = "y" ]; then + kill -9 $PPID + fi + +} + +showSingBoxInfo() { + cd ${installpath}/serv00-play/singbox + + if [ ! -f singbox.json ]; then + red "配置文件不存在,请先行配置!" + return + fi + if [ ! -e list ]; then + red "请先运行sing-box" + fi + config="singbox.json" + type=$(jq -r ".TYPE" $config) + chmod +x ./start.sh && ./start.sh $type list + +} + +chooseSingbox() { + echo "保活sing-box中哪个项目(单选): " + echo " 1.hy2/vmess+ws/socks5 " + echo " 2.argo+vmess " + echo " 3.all " + read -p "请选择:" input + + if [ "$input" = "1" ]; then + item+=("hy2/vmess+ws") + elif [ "$input" = "2" ]; then + item+=("vmess") + elif [ "$input" = "3" ]; then + item+=("hy2/vmess+ws") + item+=("vmess") + else + red "无效选择!" + return 1 + fi + +} + +setConfig() { + cd ${installpath}/serv00-play/ + + if [ -f config.json ]; then + echo "目前已有配置:" + config_content=$(cat config.json) + echo $config_content + read -p "是否修改? [y/n] [y]:" input + input=${input:-y} + if [ "$input" != "y" ]; then + return + fi + fi + createConfigFile +} + +createConfigFile() { + echo "选择你要保活的项目(可多选,用空格分隔):" + echo "1. sun-panel " + echo "2. sing-box(包含hy2,vmess,socks5) " + echo "3. 哪吒探针 " + echo "4. mtproto代理" + echo "5. alist" + echo "6. webssh" + echo "7. 哪吒面板" + echo "8. redis" + echo "88. 暂停所有保活功能" + echo "99. 复通所有保活功能(之前有配置的情况下)" + echo "0. 返回主菜单" + item=() + + read -p "请选择: " choices + choices=($choices) + + if [[ "${choices[@]}" =~ "88" && ${#choices[@]} -gt 1 ]]; then + red "选择出现了矛盾项,请重新选择!" + return 1 + fi + + #过滤重复 + choices=($(echo "${choices[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) + + # 根据选择来询问对应的配置 + for choice in "${choices[@]}"; do + case "$choice" in + 0) + showMenu + break + ;; + 1) + item+=("sun-panel") + ;; + 2) + if ! chooseSingbox; then + return + fi + ;; + 3) + item+=("nezha-agent") + ;; + 4) + item+=("mtg") + ;; + 5) + item+=("alist") + ;; + 6) + item+=("webssh") + ;; + 7) + item+=("nezha-dashboard") + ;; + 8) + item+=("redis-server") + ;; + 88) + #delCron + backupConfig "config.json" + green "设置完毕!" + return 0 + ;; + 99) + if [[ ! -e config.bak ]]; then + red "之前未有配置,未能复通!" + return 1 + fi + restoreConfig "config.bak" + tm=$(jq -r ".chktime" config.json) + addCron $tm + green "设置完毕!" + return 0 + ;; + *) + echo "无效选择" + return 1 + ;; + esac + done + + json_content="{\n" + json_content+=" \"item\": [\n" + + for item in "${item[@]}"; do + json_content+=" \"$item\"," + done + + # 删除最后一个逗号并换行 + json_content="${json_content%,}\n" + json_content+=" ],\n" + + read -p "是否需要配置消息推送? [y/n] [n]:" input + input=${input:-n} + + if [ "${input}" == "y" ]; then + json_content+="\n" + + echo "选择要推送的app:" + echo "1) Telegram " + echo "2) 微信 " + echo "3) 以上皆是" + + read -p "请选择:" sendtype + + if [ "$sendtype" == "1" ]; then + writeTG + elif [ "$sendtype" == "2" ]; then + writeWX + elif [ "$sendtype" == "3" ]; then + writeTG + writeWX + else + echo "无效选择" + return + fi + else + sendtype=${sendtype:-"null"} + fi + + read -p "是否使用cron保活? [y/n] [n]:" setcron + setcron=${setcron:-n} + + if [[ "$setcron" == "y" ]]; then + read -p "配置保活检查的时间间隔(单位分钟[1~59],默认5分钟):" tm + tm=${tm:-"5"} + json_content+=" \"chktime\": \"$tm\"," + fi + json_content+="\n \"sendtype\": $sendtype \n" + json_content+="}\n" + + # 使用 printf 生成文件 + printf "$json_content" >./config.json + if [[ "$setcron" == "y" ]]; then + addCron $tm + fi + + chmod +x ${installpath}/serv00-play/keepalive.sh + echo -e "${YELLOW} 设置完成! ${RESET} " + +} + +backupConfig() { + local filename=$1 + if [[ -e "$filename" ]]; then + if [[ "$filename" =~ ".json" ]]; then + local basename=${filename%.json} + mv $filename $basename.bak + fi + fi +} + +restoreConfig() { + local filename=$1 + if [[ -e "$filename" ]]; then + if [[ "$filename" =~ ".bak" ]]; then + local basename=${filename%.bak} + mv $filename $basename.json + fi + fi } make_vmess_config() { - cat >tempvmess.json <tempvmess.json <temp_outbound_socks5.json < temphy2.json <temphy2.json < tmpsocks5.json <tmpsocks5.json <config.json <config.json < singbox.json <~/.cloudflared/config.yml <singbox.json < /dev/null 2>&1 - rsync -a $srcpath/ ~/ 2>/dev/null - yellow "快照恢复完成!" - return - elif [ "$input" = "2" ]; then - declare -A foundArr - read -p "输入你要恢复到文件或目录:" infile - - for folder in "${!snapshot_paths[@]}"; do - path="${snapshot_paths[$folder]}" - results=$(find "${path}" -name "$infile" 2>/dev/null) - # echo "111results:|$results|" - if [[ -n "$results" ]]; then - #echo "put |$results| to folder:$folder" - foundArr["$folder"]="$results" - fi - done - local i=1 - sortedFoundArr=($(echo "${!foundArr[@]}" | tr ' ' '\n' | sort -r)) - declare -A indexPathArr - for folder in "${sortedFoundArr[@]}"; do - echo "$i. $folder:" - results="${foundArr[${folder}]}" - IFS=$'\n' read -r -d '' -a paths <<< "$results" - local j=1 - for path in "${paths[@]}"; do - indexPathArr["$i"."$j"]="$path" - echo " $j. $path" - - j=$((j+1)) - done - i=$((i+1)) - done - - while [ true ]; do - read -p "输入要恢复的文件序号,格式:日期序号.文件序号, 多个以逗号分隔.(如输入 1.2,3.2)[按enter返回]:" input - regex='^([0-9]+\.[0-9]+)(,[0-9]+\.[0-9]+)*$' - - if [ -z "$input" ]; then - return - fi - - if [[ "$input" =~ $regex ]]; then - declare -a pairNos - declare -a fileNos - IFS=',' read -r -a pairNos <<< "$input" - - echo "请选择文件恢复的目标路径:" - echo "1.原路返回 " - echo "2.${installpath}/restore " - read -p "请选择:" targetDir - - if [[ "$targetDir" != "1" ]] && [[ "$targetDir" != "2" ]];then - red "无效输入!" - return - fi - - for pairNo in "${pairNos[@]}"; do - srcpath="${indexPathArr[$pairNo]}" - - if [ "$targetDir" = "1" ]; then - local user=$(whoami) - targetPath=${srcpath#*${user}} - if [ -d $srcpath ]; then - targetPath=${targetPath%/*} - fi - echo "cp -r $srcpath $HOME/$targetPath" - cp -r ${srcpath} $HOME/${targetPath} - - elif [ "$targetDir" = "2" ]; then - targetPath="${installpath}/restore" - if [ ! -e "$targetPath" ]; then - mkdir -p "$targetPath" - fi - cp -r $srcpath $targetPath/ - fi - done - green "完成文件恢复" - - else - red "输入格式不对,请重新输入!" - fi - done - fi - -} - -uninstall(){ - read -p "确定卸载吗? [y/n] [n]:" input - input=${input:-n} - - if [ "$input" == "y" ]; then - delCron - stopSingBox - cd $HOME - rm -rf serv00-play - echo "bye!" - fi -} - -InitServer(){ - read -p "$(red "将初始化帐号系统,要继续?[y/n] [n]:")" input - input=${input:-n} - read -p "是否保留用户配置?[y/n] [y]:" saveProfile - saveProfile=${saveProfile:-y} - - if [[ "$input" == "y" ]] || [[ "$input" == "Y" ]]; then - cleanCron - green "清理进程中..." - killUserProc - green "清理磁盘中..." - if [[ "$saveProfile" = "y" ]] || [[ "$saveProfile" = "Y" ]]; then - rm -rf ~/* 2>/dev/null - else - rm -rf ~/* ~/.* 2>/dev/null - fi - cleanPort - yellow "初始化完毕" - - exit 0 - fi -} - -manageNeZhaAgent(){ - if ! checkInstalled "serv00-play"; then - return 1 - fi - while true; do - yellow "-------------------------" - echo "探针管理:" - echo "1.安装探针" - echo "2.升级探针" - echo "3.启动/重启探针" - echo "4.停止探针" - echo "9.返回主菜单" - echo "0.退出脚本" - yellow "-------------------------" - - read -p "请选择:" choice - case $choice in - 1) - installNeZhaAgent - ;; - 2) - updateAgent - ;; - 3) - startAgent - exit 0; - ;; - 4) - stopNeZhaAgent - ;; - 9) - break - ;; - 0) exit 0 - ;; - *) - echo "无效选项,请重试" - ;; - esac - done - showMenu -} - -updateAgent(){ - red "暂不提供在线升级, 只适配哪吒面板v0版本系列。" - return 1 - exepath="${installpath}/serv00-play/nezha/nezha-agent" - if [ ! -e "$exepath" ]; then - red "未安装探针,请先安装!!!" - return - fi - - local workedir="${installpath}/serv00-play/nezha" - cd $workedir - - local_version="v"$(./nezha-agent -v) - latest_version=$(curl -sL https://github.com/nezhahq/agent/releases/latest | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) - - if [[ "$local_version" != "$latest_version" ]]; then - echo "发现新版本: $latest_version,当前版本: $local_version。正在更新..." - download_url="https://github.com/nezhahq/agent/releases/download/$latest_version/nezha-agent_freebsd_amd64.zip" - - local filezip="nezha-agent_latest.zip" - curl -sL -o "$filezip" "$download_url" - if [[ ! -e "$filezip" || -n $(file "$filezip" | grep "text") ]]; then - echo "下载探针文件失败!" - return - fi - local agent_runing=0 - if checknezhaAgentAlive; then - stopNeZhaAgent - agent_runing=1 - fi - unzip -o $filezip -d . - chmod +x ./nezha-agent - if [ $agent_runing -eq 1 ]; then - startAgent - fi - rm -rf $filezip - green "更新完成!新版本: $latest_version" - else - echo "已经是最新版本: $local_version" - fi - if [[ $agent_runing -eq 1 ]]; then - exit 0; - fi -} - -startAgent(){ - local workedir="${installpath}/serv00-play/nezha" - if [ ! -e "${workedir}" ]; then - red "未安装探针,请先安装!!!" - return - fi - cd $workedir - - local configfile="./nezha.json" - if [ ! -e "$configfile" ]; then - red "未安装探针,请先安装!!!" - return - fi - - nezha_domain=$(jq -r ".nezha_domain" $configfile) - nezha_port=$(jq -r ".nezha_port" $configfile) - nezha_pwd=$(jq -r ".nezha_pwd" $configfile) - tls=$(jq -r ".tls" $configfile) - - if checknezhaAgentAlive; then - stopNeZhaAgent - fi - - local args="--report-delay 4 --disable-auto-update --disable-force-update " - if [[ "$tls" == "y" ]]; then - args="${args} --tls " - fi - - #echo "./nezha-agent ${args} -s ${nezha_domain}:${nezha_port} -p ${nezha_pwd}" - nohup ./nezha-agent ${args} -s ${nezha_domain}:${nezha_port} -p ${nezha_pwd} >/dev/null 2>&1 & - - if checknezhaAgentAlive; then - green "启动成功!" - else - red "启动失败!" - fi - #即便使用nohup放后台,此处如果使用ctrl+c退出脚本,nezha-agent进程也会退出。非常奇葩,因此startAgent后只能exit退出脚本,避免用户使用ctrl+c退出。 - -} - -installNeZhaAgent(){ - local workedir="${installpath}/serv00-play/nezha" - if [ ! -e "${workedir}" ]; then - mkdir -p "${workedir}" - fi - cd ${workedir} - if [[ ! -e nezha-agent ]]; then - echo "正在下载哪吒探针..." - local url="https://github.com/nezhahq/agent/releases/download/v0.20.3/nezha-agent_freebsd_amd64.zip" - agentZip="nezha-agent.zip" - if ! wget -qO "$agentZip" "$url"; then - red "下载哪吒探针失败" - return 1 - fi - unzip $agentZip > /dev/null 2>&1 - chmod +x ./nezha-agent - green "下载完毕" - fi - - local config="nezha.json" - local input="y" - if [[ -e "$config" ]]; then - echo "哪吒探针配置如下:" - cat "$config" - read -p "是否修改? [y/n] [n]:" input - input=${input:-n} - fi - - if [[ "$input" == "y" ]]; then - read -p "请输入哪吒面板的域名或ip:" nezha_domain - read -p "请输入哪吒面板RPC端口(默认 5555):" nezha_port - nezha_port=${nezha_port:-5555} - read -p "请输入服务器密钥(从哪吒面板中获取):" nezha_pwd - read -p "是否启用针对 gRPC 端口的 SSL/TLS加密 (--tls),需要请按 [y],默认是不需要,不理解用户可回车跳过: " tls - tls=${tls:-"N"} - else - nezha_domain=$(jq -r ".nezha_domain" $config) - nezha_port=$(jq -r ".nezha_port" $config) - nezha_pwd=$(jq -r ".nezha_pwd" $config) - tls=$(jq -r ".tls" $config) - fi - - if [[ -z "$nezha_domain" || -z "$nezha_port" || -z "$nezha_pwd" ]]; then - red "以上参数都不能为空!" - return 1 - fi - - cat > $config </dev/null 2>&1 + rsync -a $srcpath/ ~/ 2>/dev/null + yellow "快照恢复完成!" + return + elif [ "$input" = "2" ]; then + declare -A foundArr + read -p "输入你要恢复到文件或目录:" infile + + for folder in "${!snapshot_paths[@]}"; do + path="${snapshot_paths[$folder]}" + results=$(find "${path}" -name "$infile" 2>/dev/null) + # echo "111results:|$results|" + if [[ -n "$results" ]]; then + #echo "put |$results| to folder:$folder" + foundArr["$folder"]="$results" + fi + done + local i=1 + sortedFoundArr=($(echo "${!foundArr[@]}" | tr ' ' '\n' | sort -r)) + declare -A indexPathArr + for folder in "${sortedFoundArr[@]}"; do + echo "$i. $folder:" + results="${foundArr[${folder}]}" + IFS=$'\n' read -r -d '' -a paths <<<"$results" + local j=1 + for path in "${paths[@]}"; do + indexPathArr["$i"."$j"]="$path" + echo " $j. $path" + + j=$((j + 1)) + done + i=$((i + 1)) + done + + while [ true ]; do + read -p "输入要恢复的文件序号,格式:日期序号.文件序号, 多个以逗号分隔.(如输入 1.2,3.2)[按enter返回]:" input + regex='^([0-9]+\.[0-9]+)(,[0-9]+\.[0-9]+)*$' + + if [ -z "$input" ]; then + return + fi + + if [[ "$input" =~ $regex ]]; then + declare -a pairNos + declare -a fileNos + IFS=',' read -r -a pairNos <<<"$input" + + echo "请选择文件恢复的目标路径:" + echo "1.原路返回 " + echo "2.${installpath}/restore " + read -p "请选择:" targetDir + + if [[ "$targetDir" != "1" ]] && [[ "$targetDir" != "2" ]]; then + red "无效输入!" + return + fi + + for pairNo in "${pairNos[@]}"; do + srcpath="${indexPathArr[$pairNo]}" + + if [ "$targetDir" = "1" ]; then + local user=$(whoami) + targetPath=${srcpath#*${user}} + if [ -d $srcpath ]; then + targetPath=${targetPath%/*} + fi + echo "cp -r $srcpath $HOME/$targetPath" + cp -r ${srcpath} $HOME/${targetPath} + + elif [ "$targetDir" = "2" ]; then + targetPath="${installpath}/restore" + if [ ! -e "$targetPath" ]; then + mkdir -p "$targetPath" + fi + cp -r $srcpath $targetPath/ + fi + done + green "完成文件恢复" + + else + red "输入格式不对,请重新输入!" + fi + done + fi + +} + +get_domain_webip() { + local domain=$1 + if [[ -z "$domain" ]]; then + echo "" + return + fi + devil ssl www list | awk -v d="$domain" 'tolower($1)==tolower(d) {print $2; exit}' +} + +delete_domain_service() { + local domain=$1 + if [[ -z "$domain" ]]; then + return + fi + domain="${domain,,}" + local webip=$(get_domain_webip "$domain") + if [[ -n "$webip" ]]; then + devil ssl www del $webip $domain >/dev/null 2>&1 + fi + devil www del $domain --remove >/dev/null 2>&1 + rm -rf "${installpath}/domains/$domain" + green "已删除域名服务: $domain" +} + +delete_domains_from_domainlist() { + local list_file=$1 + if [[ ! -f "$list_file" ]]; then + red "domainlist文件不存在!" + return 1 + fi + while read -r domain; do + domain=$(echo "$domain" | xargs) + if [[ -z "$domain" ]]; then + continue + fi + delete_domain_service "$domain" + done < <(awk 'NF && $1 != "Domain" {print $1}' "$list_file") +} + +delete_domains_from_phpconfig() { + local config_file=$1 + if [[ ! -f "$config_file" ]]; then + red "未找到phpconfig.json!" + return 1 + fi + local domains=$(jq -r '.domains[].domain' "$config_file" 2>/dev/null) + if [[ -z "$domains" ]]; then + red "phpconfig.json中未找到域名!" + return 1 + fi + while read -r domain; do + domain=$(echo "$domain" | xargs) + if [[ -z "$domain" ]]; then + continue + fi + delete_domain_service "$domain" + done <<<"$domains" +} + +backupAll() { + local delete_choice="" + read -p "是否删除所有域名关联服务? [y/n] [n]:" delete_choice + delete_choice=${delete_choice:-n} + local phpconfig_file="${installpath}/serv00-play/domains-support/phpconfig.json" + local tarfile="${installpath}/all.tar.gz" + local phpconfig_rel="serv00-play/domains-support/phpconfig.json" + if [[ ! -f "$phpconfig_file" ]]; then + red "未找到phpconfig.json!" + return 1 + fi + echo "正在备份中,请稍后(可能需要几分钟)..." + tar -czf "$tarfile" -C "$installpath" "$phpconfig_rel" + if [[ $? -ne 0 ]]; then + red "备份失败!" + return 1 + fi + green "备份完成: $tarfile" + if [[ "$delete_choice" == "y" ]]; then + delete_domains_from_phpconfig "$phpconfig_file" + fi +} + +restore_domains_from_config() { + local workdir="${installpath}/serv00-play/domains-support" + local config_file="${workdir}/phpconfig.json" + if [[ ! -f "$config_file" ]]; then + red "未找到phpconfig.json!" + return 1 + fi + cd $workdir + local domains=$(jq -r '.domains[].domain' "$config_file" 2>/dev/null) + if [[ -z "$domains" ]]; then + red "phpconfig.json中未找到域名!" + return 1 + fi + read -r -p "是否自动配置 Cloudflare 域名 DNS?(y/n) [默认: n]: " auto_cf_dns + auto_cf_dns=${auto_cf_dns:-n} + local cf_api_token="" + local cf_email="" + if [[ "$auto_cf_dns" == "y" || "$auto_cf_dns" == "Y" ]]; then + read -r -p "请输入 Cloudflare API Token: " cf_api_token + if [[ -z "$cf_api_token" ]]; then + red "API Token 不能为空!" + return 1 + fi + read -r -p "请输入 Cloudflare 账户邮箱: " cf_email + if [[ -z "$cf_email" ]]; then + red "账户邮箱不能为空!" + return 1 + fi + fi + local failed_domains=() + while read -r domain; do + domain=$(echo "$domain" | xargs) + if [[ -z "$domain" ]]; then + continue + fi + domain="${domain,,}" + domainPath="$installpath/domains/$domain/public_html" + webIp="" + echo "正在恢复域名: $domain" + if ! makeWWW "" "" "php" "y" "$domain"; then + red "绑定域名 $domain 失败!" + continue + fi + if [[ "$auto_cf_dns" == "y" || "$auto_cf_dns" == "Y" ]]; then + if [[ -n "$webIp" && -n "$cf_api_token" && -n "$cf_email" ]]; then + yellow "正在为 $domain 配置 Cloudflare DNS..." + local zone_id=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${domain}" \ + -H "X-Auth-Email: ${cf_email}" \ + -H "X-Auth-Key: ${cf_api_token}" \ + -H "Content-Type: application/json" | jq -r '.result[0].id') + + if [[ -z "$zone_id" || "$zone_id" == "null" ]]; then + red "无法获取域名 $domain 的 Zone ID,请检查域名是否已添加到您的 Cloudflare 账户。" + failed_domains+=("$domain") + continue + else + local existing_record_id=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records?type=A&name=${domain}" \ + -H "X-Auth-Email: ${cf_email}" \ + -H "X-Auth-Key: ${cf_api_token}" \ + -H "Content-Type: application/json" | jq -r --arg domain "$domain" '.result[] | select(.name == $domain) | .id') + + if [[ -n "$existing_record_id" && "$existing_record_id" != "null" ]]; then + yellow "✓ 域名 $domain 已存在 A 记录,正在更新 IP 地址为 $webIp..." + local update_record_response=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records/${existing_record_id}" \ + -H "X-Auth-Email: ${cf_email}" \ + -H "X-Auth-Key: ${cf_api_token}" \ + -H "Content-Type: application/json" \ + --data '{"type":"A","name":"'"$domain"'","content":"'"$webIp"'","ttl":1,"proxied":false}') + + if [[ $(echo "$update_record_response" | jq -r '.success') != "true" ]]; then + red "更新域名 $domain 的 A 记录失败: $(echo "$update_record_response" | jq -r '.errors[0].message')" + failed_domains+=("$domain") + continue + fi + else + yellow "正在为 $domain 创建新的 A 记录..." + local create_record_response=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${zone_id}/dns_records" \ + -H "X-Auth-Email: ${cf_email}" \ + -H "X-Auth-Key: ${cf_api_token}" \ + -H "Content-Type: application/json" \ + --data '{"type":"A","name":"'"$domain"'","content":"'"$webIp"'","ttl":1,"proxied":false}') + + if [[ $(echo "$create_record_response" | jq -r '.success') != "true" ]]; then + red "为 $domain 创建 A 记录失败: $(echo "$create_record_response" | jq -r '.errors[0].message')" + failed_domains+=("$domain") + continue + fi + fi + fi + else + red "缺少 WebIP 或 Cloudflare 凭证,无法自动配置 DNS。" + failed_domains+=("$domain") + continue + fi + fi + sleep 10 + if ! applyLE "$domain" "$webIp" "y"; then + red "申请证书失败: $domain" + fi + if [[ ! -d "$domainPath" ]]; then + red "目标目录不存在: $domainPath" + continue + fi + local style_choice=$((RANDOM % 6 + 1)) + case "$style_choice" in + 1) + cp websites/sakura.html "$domainPath/index.html" + sed -i.bak "s|xx|樱花|g" "$domainPath/index.html" + ;; + 2) + cp websites/hr.html "$domainPath/index.html" + ;; + 3) + cp websites/deyiedu.html "$domainPath/index.html" + ;; + 4) + cp websites/resume.html "$domainPath/index.html" + ;; + 5) + cp websites/game.html "$domainPath/index.html" + ;; + 6) + cp websites/christmas.html "$domainPath/index.html" + ;; + esac + green "域名 $domain 的网站恢复完成!" + done <<<"$domains" + if [[ ${#failed_domains[@]} -gt 0 ]]; then + red "以下域名 DNS 配置失败,请手动修改 DNS 后再进行批量导入域名:" + for d in "${failed_domains[@]}"; do + echo "$d" + done + fi +} + +restoreAll() { + local tarfile="${installpath}/all.tar.gz" + local phpconfig_file="${installpath}/serv00-play/domains-support/phpconfig.json" + if [[ ! -f "$tarfile" ]]; then + red "未发现备份文件: $tarfile" + return 1 + fi + tar -xzf "$tarfile" -C "$installpath" + if [[ $? -ne 0 ]]; then + red "恢复失败!" + return 1 + fi + if [[ ! -f "$phpconfig_file" ]]; then + red "未恢复到phpconfig.json!" + return 1 + fi + green "文件恢复完成!" + restore_domains_from_config +} + +backupRestoreServ() { + while true; do + yellow "---------------------" + echo "备份/恢复功能:" + echo "1. 备份" + echo "2. 恢复" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + backupAll + ;; + 2) + restoreAll + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +uninstall() { + local input=$1 + if [ -z "$input" ]; then + read -p "确定卸载吗? [y/n] [n]:" input + input=${input:-n} + fi + + if [ "$input" == "y" ]; then + delCron + stopSingBox + cd $HOME + rm -rf serv00-play + echo "bye!" + fi +} + +InitServer() { + read -p "$(red "将初始化帐号系统,要继续?[y/n] [n]:")" input + input=${input:-n} + if [[ "$input" != "y" ]]; then + return + fi + read -p "是否保留用户配置?[y/n] [y]:" saveProfile + saveProfile=${saveProfile:-y} + + if [[ "$input" == "y" ]] || [[ "$input" == "Y" ]]; then + cleanCron + green "清理进程中..." + killUserProc + green "清理磁盘中..." + if [[ "$saveProfile" == "y" ]] || [[ "$saveProfile" == "Y" ]]; then + find ~ -mindepth 1 -maxdepth 1 ! -name "domains" ! -name "backups" ! -name "repo" ! -name "mail" ! -name ".*" -exec rm -rf {} + >/dev/null 2>&1 + else + rm -rf ~/* ~/.* 2>/dev/null + clean_all_domains + clean_all_dns + create_default_domain + fi + cleanPort + yellow "初始化完毕" + + exit 0 + fi +} + +manageNeZhaAgent() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "-------------------------" + echo "探针管理:" + echo "服务状态: $(checkProcStatus nezha-agent)" + echo "1.安装探针(v0或v1)" + echo "2.升级探针(仅v1以上版本)" + echo "3.启动/重启探针" + echo "4.停止探针" + echo "5.卸载探针" + echo "9.返回主菜单" + echo "0.退出脚本" + yellow "-------------------------" + + read -p "请选择:" choice + case $choice in + 1) + installNeZhaAgent + ;; + 2) + updateAgent + ;; + 3) + startAgent + exit 0 + ;; + 4) + stopNeZhaAgent + ;; + 5) + uninstallAgent + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +installNeZhaAgent() { + local workedir="${installpath}/serv00-play/nezha" + if [ ! -e "${workedir}" ]; then + mkdir -p "${workedir}" + fi + + cd ${workedir} + if [ -e nezha-agent ]; then + red "探针已安装,重新安装请先卸载!" + return 1 + fi + echo "确认安装哪吒探针的版本:" + echo "1. v0.20.5" + echo "2. v1 -latest" + read -p "请选择:" ver + if [[ "$ver" != "1" && "$ver" != "2" ]]; then + echo "无效输入!" + return 1 + fi + + echo "正在下载哪吒探针..." + if [[ "$ver" == "1" ]]; then + # 安装v0版本 + local url="https://github.com/nezhahq/agent/releases/download/v0.20.5/nezha-agent_freebsd_amd64.zip" + agentZip="nezha-agent.zip" + if ! wget -qO "$agentZip" "$url"; then + red "下载哪吒探针失败" + return 1 + fi + unzip $agentZip >/dev/null 2>&1 + else + latest_version=$(curl -sL https://github.com/nezhahq/agent/releases/latest | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) + download_url="https://github.com/nezhahq/agent/releases/download/$latest_version/nezha-agent_freebsd_amd64.zip" + local filezip="nezha-agent_latest.zip" + curl -sL -o "$filezip" "$download_url" + if [[ ! -e "$filezip" || -n $(file "$filezip" | grep "text") ]]; then + echo "下载探针文件失败!" + return + fi + unzip -o $filezip -d . + fi + chmod +x ./nezha-agent + green "下载完毕" + + local config="nezha.json" + + read -p "请输入哪吒面板的域名或ip:" nezha_domain + read -p "请输入哪吒面板RPC端口(默认 5555):" nezha_port + nezha_port=${nezha_port:-5555} + read -p "请输入服务器密钥(从哪吒面板中获取):" nezha_pwd + read -p "是否启用针对 gRPC 端口的 SSL/TLS加密 (--tls),需要请按 [y],默认是不需要,不理解用户可回车跳过: " tls + tls=${tls:-"N"} + + if [[ -z "$nezha_domain" || -z "$nezha_port" || -z "$nezha_pwd" ]]; then + red "以上参数都不能为空!" + return 1 + fi + + cat >$config <$yamlcfg </dev/null 2>&1 & + else + nohup ./nezha-agent -c $yamlcfg >/dev/null 2>&1 & + fi + green "哪吒探针成功启动!" + +} + +updateAgent() { + exepath="${installpath}/serv00-play/nezha/nezha-agent" + if [ ! -e "$exepath" ]; then + red "未安装探针,请先安装!!!" + return + fi + + cd ${installpath}/serv00-play/nezha + + if ! check_update_from_net "nezha-agent"; then + return 1 + fi + + stopNeZhaAgent + download_from_net "nezha-agent" + if [[ -e "nezha-agent" ]]; then + chmod +x ./nezha-agent + else + red "下载失败!" + return + fi + startNeZhaAgent + green "更新完毕!" + + return + +} + +startAgent() { + local exepath="${installpath}/serv00-play/nezha/nezha-agent" + if [ ! -e "${exepath}" ]; then + red "未安装探针,请先安装!!!" + return + fi + cd "${installpath}/serv00-play/nezha" + + local configfile="./nezha.json" + if [ ! -e "$configfile" ]; then + red "未安装探针,请先安装!!!" + return + fi + + nezha_domain=$(jq -r ".nezha_domain" $configfile) + nezha_port=$(jq -r ".nezha_port" $configfile) + nezha_pwd=$(jq -r ".nezha_pwd" $configfile) + ver=$(jq -r ".version" $configfile) + tls=$(jq -r ".tls" $configfile) + + if checknezhaAgentAlive; then + stopNeZhaAgent + fi + + local args="--report-delay 4 --disable-auto-update --disable-force-update " + if [[ "$tls" == "y" ]]; then + args="${args} --tls " + fi + + if [[ "$ver" == "1" ]]; then + #echo "./nezha-agent ${args} -s ${nezha_domain}:${nezha_port} -p ${nezha_pwd}" + nohup ./nezha-agent ${args} -s ${nezha_domain}:${nezha_port} -p ${nezha_pwd} >/dev/null 2>&1 & + else + nohup ./nezha-agent -c config.yaml 2>&1 & + fi + + if checknezhaAgentAlive; then + green "启动成功!" + else + red "启动失败!" + fi + #即便使用nohup放后台,此处如果使用ctrl+c退出脚本,nezha-agent进程也会退出。非常奇葩,因此startAgent后只能exit退出脚本,避免用户使用ctrl+c退出。 + +} + +uninstallAgent() { + read -p "确定卸载哪吒探针? [y/n] [n]:" input + input=${input:-n} + + if [[ "$input" == "y" ]]; then + if checknezhaAgentAlive; then + stopNeZhaAgent + fi + local workedir="${installpath}/serv00-play/nezha" + rm -rf $workedir + green "卸载完毕!" + fi + +} +manageNeZhaBoard() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "---------------------" + echo "哪吒面板管理(仅支持v1):" + echo "服务状态: $(checkProcStatus nezha-dashboard)" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" + echo "4. 更新" + echo "8. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + installNeZhaDashboard + ;; + 2) + startNeZhaDashboard + ;; + 3) + stopNeZhaDashboard + ;; + 4) + updateNeZhaDashboard + ;; + 8) + uninstallNeZhaDashboard + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +installNeZhaDashboard() { + local workedir="${installpath}/serv00-play/nezha-board" + if [ ! -e "${workedir}" ]; then + mkdir -p "${workedir}" + fi + + cd ${workedir} + if [ -e "./nezha-dashboard" ]; then + red "面板已安装,重新安装请先卸载!" + return 1 + fi + if ! download_from_net "nezha-dashboard"; then + return 1 + fi + if [[ -e "dashboard" ]]; then + mv ./dashboard ./nezha-dashboard + chmod +x ./nezha-dashboard + else + red "下载失败!" + return 1 + fi + + #自动分配端口 + loadPort + randomPort tcp nezha-dashboard + if [[ -n "$port" ]]; then + nz_port="$port" + else + red "未输入端口号" + return 1 + fi + read -p "请输入站点标题: " nz_site_title + echo "请指定后台语言" + echo "1. 中文(简体)" + echo "2. 中文(繁体)" + echo "3. English" + while true; do + read -p "请输入选项 [1-3]" option + case "${option}" in + 1) + nz_lang=zh_CN + break + ;; + 2) + nz_lang=zh_TW + break + ;; + 3) + nz_lang=en_US + break + ;; + *) + echo "请输入正确的选项 [1-3]" + ;; + esac + done + echo "正在安装哪吒面板,请等待..." + domain="" + webIp="" + if ! makeWWW "" $nz_port; then + echo "绑定域名失败!" + return 1 + fi + if ! applyLE $domain $webIp; then + echo "申请证书失败!" + return 1 + fi + cd ${workedir} + nz_hostport="${domain}:${nz_port}" + #serv00不支持gprc转发,所以不需要tls + + cat >config.yaml </dev/null 2>&1 & - green "哪吒探针成功启动!" - -} - -uninstallAgent(){ - read -p "确定卸载哪吒探针? [y/n] [n]:" input - input=${input:-n} - - if [[ "$input" == "y" ]]; then - if checknezhaAgentAlive; then - stopNeZhaAgent - fi - local workedir="${installpath}/serv00-play/nezha" - rm -rf $workedir - green "卸载完毕!" - fi - -} - -setCnTimeZone(){ - read -p "确定设置中国上海时区? [y/n] [y]:" input - input=${input:-y} - - cd ${installpath} - if [ "$input" = "y" ]; then - devil binexec on - touch .profile - cat .profile | perl ./serv00-play/mkprofile.pl > tmp_profile - mv -f tmp_profile .profile - - read -p "$(yellow 设置完毕,需要重新登录才能生效,是否重新登录?[y/n] [y]:)" input - input=${input:-y} - - if [ "$input" = "y" ]; then - kill -9 $PPID - fi - fi - -} - -setColorWord(){ - cd ${installpath} - # 定义颜色编码 - bright_black="\033[1;90m" - bright_red="\033[1;91m" - bright_green="\033[1;92m" - bright_yellow="\033[1;93m" - bright_blue="\033[1;94m" - bright_magenta="\033[1;95m" - bright_cyan="\033[1;96m" - bright_white="\033[1;97m" - reset="\033[0m" - - # 显示颜色选项列表,并使用颜色着色 - echo -e "请选择一个颜色来输出你的签名:" - echo -e "1) ${bright_black}明亮黑色${reset}" - echo -e "2) ${bright_red}明亮红色${reset}" - echo -e "3) ${bright_green}明亮绿色${reset}" - echo -e "4) ${bright_yellow}明亮黄色${reset}" - echo -e "5) ${bright_blue}明亮蓝色${reset}" - echo -e "6) ${bright_magenta}明亮紫色${reset}" - echo -e "7) ${bright_cyan}明亮青色${reset}" - echo -e "8) ${bright_white}明亮白色${reset}" - - # 读取用户输入的选择 - read -p "请输入你的选择(1-8): " color_choice - - read -p "请输入你的大名(仅支持ascii字符):" name - - # 根据用户的选择设置颜色 - case $color_choice in - 1) color_code="90" ;; # 明亮黑色 - 2) color_code="91" ;; # 明亮红色 - 3) color_code="92" ;; # 明亮绿色 - 4) color_code="93" ;; # 明亮黄色 - 5) color_code="94" ;; # 明亮蓝色 - 6) color_code="95" ;; # 明亮紫色 - 7) color_code="96" ;; # 明亮青色 - 8) color_code="97" ;; # 明亮白色 - *) echo "无效选择,使用默认颜色 (明亮白色)"; color_code="97" ;; - esac - - if grep "chAngEYourName" .profile > /dev/null ; then - cat .profile | grep -v "chAngEYourName" > tmp_profile - echo "echo -e \"\033[1;${color_code}m\$(figlet \"${name}\")\033[0m\" #chAngEYourName" >> tmp_profile - mv -f tmp_profile .profile - else - echo "echo -e \"\033[1;${color_code}m\$(figlet \"${name}\")\033[0m\" #chAngEYourName" >> .profile - fi - - read -p "设置完毕! 重新登录看效果? [y/n] [y]:" input - input=${input:-y} - if [[ "$input" == "y" ]]; then - kill -9 $PPID - fi - -} - -showIP(){ - myip="$(curl -s ifconfig.me)" - green "本机IP: $myip" -} - -uninstallMtg(){ - read -p "确定卸载? [y/n] [n]:" input - input=${input:-n} - - if [[ "$input" == "n" ]]; then - return 1 - fi - - if [[ -e "mtg" ]]; then - if checkProcAlive mtg; then - stopMtg - fi - cd ${installpath}/serv00-play - rm -rf dmtg - green "卸载完毕!" - fi -} - -installMtg(){ - if [ ! -e "mtg" ]; then - # read -p "请输入使用密码:" password - if ! checkDownload "mtg"; then - return 1 - fi - fi - - chmod +x ./mtg - if [ -e "config.json" ]; then - echo "已存在配置如下:" - cat config.json - read -p "是否重新生成配置? [y/n] [n]:" input - input=${input:-n} - if [ "$input" == "n" ]; then - return 0 - fi - fi - - #自动生成密钥 - head=$(hostname | cut -d '.' -f 1) - no=${head#s} - host="panel${no}.serv00.com" - secret=$(./mtg generate-secret --hex $host ) - loadPort - randomPort tcp mtg - if [[ -n "$port" ]]; then - mtpport="$port" - fi - - cat > config.json <borad.log 2>&1 & + if checkProcAlive nezha-dashboard; then + green "面板已启动!" + else + red "面板启动失败,请查看日志borad.log" + fi + +} +stopNeZhaDashboard() { + if checkProcAlive nezha-dashboard; then + stopProc nezha-dashboard + else + red "面板未启动!" + fi +} +updateNeZhaDashboard() { + if [ ! -e "${installpath}/serv00-play/nezha-board/nezha-dashboard" ]; then + red "未安装面板,请先安装!!!" + return + fi + cd ${installpath}/serv00-play/nezha-board + + if ! check_update_from_net "nezha-dashboard"; then + return 1 + fi + + stopNeZhaDashboard + download_from_net "nezha-dashboard" + if [[ -e "dashboard" ]]; then + mv -f ./dashboard ./nezha-dashboard + chmod +x ./nezha-dashboard + fi + startNeZhaDashboard + green "更新完毕!" + + return +} + +uninstallNeZhaDashboard() { + local workedir="${installpath}/serv00-play/nezha-board" + if [ ! -e "${workedir}" ]; then + red "未安装面板!" + return + fi + uninstallProc $workedir "nezha-dashboard" +} + +setCnTimeZone() { + read -p "确定设置中国上海时区? [y/n] [y]:" input + input=${input:-y} + + cd ${installpath} + if [ "$input" = "y" ]; then + devil binexec on + touch .profile + cat .profile | perl ./serv00-play/mkprofile.pl >tmp_profile + mv -f tmp_profile .profile + + read -p "$(yellow 设置完毕,需要重新登录才能生效,是否重新登录?[y/n] [y]:)" input + input=${input:-y} + + if [ "$input" = "y" ]; then + kill -9 $PPID + fi + fi + +} + +setColorWord() { + cd ${installpath} + # 定义颜色编码 + bright_black="\033[1;90m" + bright_red="\033[1;91m" + bright_green="\033[1;92m" + bright_yellow="\033[1;93m" + bright_blue="\033[1;94m" + bright_magenta="\033[1;95m" + bright_cyan="\033[1;96m" + bright_white="\033[1;97m" + reset="\033[0m" + + # 显示颜色选项列表,并使用颜色着色 + echo -e "请选择一个颜色来输出你的签名:" + echo -e "1) ${bright_black}明亮黑色${reset}" + echo -e "2) ${bright_red}明亮红色${reset}" + echo -e "3) ${bright_green}明亮绿色${reset}" + echo -e "4) ${bright_yellow}明亮黄色${reset}" + echo -e "5) ${bright_blue}明亮蓝色${reset}" + echo -e "6) ${bright_magenta}明亮紫色${reset}" + echo -e "7) ${bright_cyan}明亮青色${reset}" + echo -e "8) ${bright_white}明亮白色${reset}" + + # 读取用户输入的选择 + read -p "请输入你的选择(1-8): " color_choice + + read -p "请输入你的大名(仅支持ascii字符):" name + + # 根据用户的选择设置颜色 + case $color_choice in + 1) color_code="90" ;; # 明亮黑色 + 2) color_code="91" ;; # 明亮红色 + 3) color_code="92" ;; # 明亮绿色 + 4) color_code="93" ;; # 明亮黄色 + 5) color_code="94" ;; # 明亮蓝色 + 6) color_code="95" ;; # 明亮紫色 + 7) color_code="96" ;; # 明亮青色 + 8) color_code="97" ;; # 明亮白色 + *) + echo "无效选择,使用默认颜色 (明亮白色)" + color_code="97" + ;; + esac + + if grep "chAngEYourName" .profile >/dev/null; then + cat .profile | grep -v "chAngEYourName" >tmp_profile + echo "echo -e \"\033[1;${color_code}m\$(figlet \"${name}\")\033[0m\" #chAngEYourName" >>tmp_profile + mv -f tmp_profile .profile + else + echo "echo -e \"\033[1;${color_code}m\$(figlet \"${name}\")\033[0m\" #chAngEYourName" >>.profile + fi + + read -p "设置完毕! 重新登录看效果? [y/n] [y]:" input + input=${input:-y} + if [[ "$input" == "y" ]]; then + kill -9 $PPID + fi + +} + +showIP() { + myip="$(curl -s icanhazip.com)" + green "本机IP: $myip" +} + +uninstallMtg() { + read -p "确定卸载? [y/n] [n]:" input + input=${input:-n} + + if [[ "$input" == "n" ]]; then + return 1 + fi + + if [[ -e "mtg" ]]; then + if checkProcAlive mtg; then + stopMtg + fi + cd ${installpath}/serv00-play + rm -rf dmtg + green "卸载完毕!" + fi +} + +installMtg() { + local workedir="${installpath}/serv00-play/dmtg" + if [ ! -e "${workedir}" ]; then + mkdir -p "${workedir}" + fi + cd ${workedir} + + if [ ! -e "mtg" ]; then + # read -p "请输入使用密码:" password + if ! checkDownload "mtg"; then + return 1 + fi + fi + + chmod +x ./mtg + if [ -e "config.json" ]; then + echo "已存在配置如下:" + cat config.json + read -p "是否重新生成配置? [y/n] [n]:" input + input=${input:-n} + if [ "$input" == "n" ]; then + return 0 + fi + fi + + #自动生成密钥 + head=$(hostname | cut -d '.' -f 1) + no=${head#s} + host="panel${no}.$(getDoMain)" + secret=$(./mtg generate-secret --hex $host) + loadPort + randomPort tcp mtg + if [[ -n "$port" ]]; then + mtpport="$port" + fi + + cat >config.json <&1 &" - eval "$cmd" - sleep 3 - if checkMtgAlive; then - mtproto="https://t.me/proxy?server=${host}.serv00.com&port=${port}&secret=${secret}" - echo "$mtproto" - green "启动成功" - else - echo "启动失败,请检查进程" - fi - -} - -stopMtg(){ - r=$(ps aux | grep mtg | grep -v "grep" | awk '{print $2}' ) - if [ -z "$r" ]; then - echo "没有运行!" - return - else - kill -9 $r - fi - echo "已停掉mtproto!" - -} - -mtprotoServ(){ - if ! checkInstalled "serv00-play"; then - return 1 - fi - cd ${installpath}/serv00-play - - if [ ! -e "dmtg" ]; then - mkdir -p dmtg - fi - cd dmtg - - while true; do - yellow "---------------------" - echo "服务状态: $(checkProcStatus mtg)" - echo "mtproto管理:" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" - echo "4. 卸载" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "---------------------" - read -p "请选择:" input - - case $input in - 1) installMtg - ;; - 2) startMtg - ;; - 3) stopMtg - ;; - 4) uninstallMtg - ;; - 9) break - ;; - 0) exit 0 - ;; - *) - echo "无效选项,请重试" - ;; - esac - done - showMenu - + yellow "安装完成!" +} + +startMtg() { + cd ${installpath}/serv00-play + + if [ ! -e "dmtg" ]; then + ehco "未安装mtproto,请先行安装配置!" + return 1 + fi + cd dmtg + config="config.json" + if [ ! -e $config ]; then + red "未安装mtproto,请先行安装配置!" + return 1 + fi + + if checkMtgAlive; then + echo "已在运行,请勿重复启动" + return 0 + fi + + read -p "是否需要日志?: [y/n] [n]:" input + input=${input:-n} + + if [ "$input" == "y" ]; then + green "日志文件名称为:mtg.log" + logfile="-d >mtg.log" + else + logfile=" >/dev/null " + fi + + host="$(hostname | cut -d '.' -f 1)" + + secret=$(jq -r ".secret" $config) + port=$(jq -r ".port" $config) + + cmd="nohup ./mtg simple-run -n 1.1.1.1 -t 30s -a 1MB 0.0.0.0:${port} ${secret} -c 8192 --prefer-ip=\"prefer-ipv6\" ${logfile} 2>&1 &" + eval "$cmd" + sleep 3 + if checkMtgAlive; then + mtproto="https://t.me/proxy?server=${host}.$(getDoMain)&port=${port}&secret=${secret}" + echo "$mtproto" + green "启动成功" + else + echo "启动失败,请检查进程" + fi + +} + +stopMtg() { + r=$(ps aux | grep mtg | grep -v "grep" | awk '{print $2}') + if [ -z "$r" ]; then + echo "没有运行!" + return + else + kill -9 $r + fi + echo "已停掉mtproto!" + +} + +mtprotoServ() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + cd ${installpath}/serv00-play + + if [ ! -e "dmtg" ]; then + mkdir -p dmtg + fi + cd dmtg + + while true; do + yellow "---------------------" + echo "服务状态: $(checkProcStatus mtg)" + echo "mtproto管理:" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" + echo "4. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + installMtg + ;; + 2) + startMtg + ;; + 3) + stopMtg + ;; + 4) + uninstallMtg + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu + } extract_user_and_password() { - output=$1 + output=$1 - username=$(echo "$output" | grep "username:" | sed 's/.*username: //') - password=$(echo "$output" | grep "password:" | sed 's/.*password: //') - echo "生成用户密码如下,请谨记! 只会出现一次:" - green "Username: $username" - green "Password: $password" + username=$(echo "$output" | grep "username:" | sed 's/.*username: //') + password=$(echo "$output" | grep "password:" | sed 's/.*password: //') + echo "生成用户密码如下,请谨记! 只会出现一次:" + green "Username: $username" + green "Password: $password" } update_http_port() { - cd data || return 1 - local port=$1 - local config_file="config.json" - - if [ -z "$port" ]; then - echo "Error: No port number provided." - return 1 - fi - # 使用 jq 来更新配置文件中的 http_port - jq --argjson new_port "$port" '.scheme.http_port = $new_port' "$config_file" > tmp.$$.json && mv tmp.$$.json "$config_file" - - echo "配置文件处理完毕." - -} - - -installAlist(){ - if ! checkInstalled "serv00-play"; then - return 1 - fi - cd ${installpath}/serv00-play/ || return 1 - alistpath="${installpath}/serv00-play/alist" - - if [[ ! -e "$alistpath" ]]; then - mkdir -p $alistpath - fi - if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then - echo "已安装,请勿重复安装。" - return - else - cd "alist" || return 1 - if [ ! -e "alist" ]; then - # read -p "请输入使用密码:" password - if ! checkDownload "alist"; then - return 1 - fi - fi - fi - - loadPort - randomPort tcp alist - if [[ -n "$port" ]]; then - alist_port="$port" - fi - echo "正在安装alist,请等待..." - domain="" - webIp="" - if ! makeWWW alist $alist_port ; then - echo "绑定域名失败!" - return 1 - fi - if ! applyLE $domain $webIp; then - echo "申请证书失败!" - return 1 - fi - cd $alistpath - rt=$(chmod +x ./alist && ./alist admin random 2>&1 ) - extract_user_and_password "$rt" - update_http_port "$alist_port" - - green "安装完毕" - -} - -startAlist(){ - alistpath="${installpath}/serv00-play/alist" - cd $alistpath - domain=$(jq -r ".domain" config.json) - - if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then - cd $alistpath - echo "正在启动alist..." - if checkProcAlive alist; then - echo "alist已启动,请勿重复启动!" - else - nohup ./alist server > /dev/null 2>&1 & - sleep 3 - if ! checkProcAlive alist; then - red "启动失败,请检查!" - return 1 - else - green "启动成功!" - green "alist管理地址: https://$domain" - fi - fi - else - red "请先行安装再启动!" - return - fi -} - -stopAlist(){ - if checkProcAlive "alist"; then - stopProc "alist" - sleep 3 - fi - + cd data || return 1 + local port=$1 + local config_file="config.json" + + if [ -z "$port" ]; then + echo "Error: No port number provided." + return 1 + fi + # 使用 jq 来更新配置文件中的 http_port + jq --argjson new_port "$port" '.scheme.http_port = $new_port' "$config_file" >tmp.$$.json && mv tmp.$$.json "$config_file" + + echo "配置文件处理完毕." + +} + +installAlist() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + cd ${installpath}/serv00-play/ || return 1 + alistpath="${installpath}/serv00-play/alist" + + if [[ ! -e "$alistpath" ]]; then + mkdir -p $alistpath + fi + if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then + echo "已安装,请勿重复安装。" + return + else + cd "alist" || return 1 + if [ ! -e "alist" ]; then + if ! download_from_net "alist"; then + return 1 + fi + fi + fi + + loadPort + randomPort tcp alist + if [[ -n "$port" ]]; then + alist_port="$port" + fi + echo "正在安装alist,请等待..." + domain="" + webIp="" + if ! makeWWW alist $alist_port; then + echo "绑定域名失败!" + return 1 + fi + if ! applyLE $domain $webIp; then + echo "申请证书失败!" + return 1 + fi + cd $alistpath + rt=$(chmod +x ./alist && ./alist admin random 2>&1) + extract_user_and_password "$rt" + update_http_port "$alist_port" + + green "安装完毕" + +} + +startAlist() { + alistpath="${installpath}/serv00-play/alist" + cd $alistpath + domain=$(jq -r ".domain" config.json) + + if [[ -d "$alistpath/data" && -e "$alistpath/alist" ]]; then + cd $alistpath + echo "正在启动alist..." + if checkProcAlive alist; then + echo "alist已启动,请勿重复启动!" + else + nohup ./alist server >/dev/null 2>&1 & + sleep 3 + if ! checkProcAlive alist; then + red "启动失败,请检查!" + return 1 + else + green "启动成功!" + green "alist管理地址: https://$domain" + fi + fi + else + red "请先行安装再启动!" + return + fi +} + +stopAlist() { + if checkProcAlive "alist"; then + stopProc "alist" + sleep 3 + fi + } # uninstallPHP(){ @@ -1447,302 +2219,375 @@ stopAlist(){ # yellow "已删除域名 $domain 的相关服务!" # } -uninstallProc(){ - local path=$1 - local procname=$2 - - if [ ! -e "$path" ]; then - red "未安装$procname!!!" - return 1 - fi - cd $path - read -p "确定卸载${procname}吗? [y/n] [n]:" input - input=${input:-n} - if [[ "$input" == "y" ]]; then - stopProc "$procname" - domain=$(jq -r ".domain" config.json) - webip=$(jq -r ".webip" config.json) - resp=$(devil ssl www del $webIp $domain) - resp=$(devil www del $domain --remove) - cd ${installpath}/serv00-play - rm -rf $path - green "卸载完毕!" - fi - -} - -uninstallAlist(){ - alistpath="${installpath}/serv00-play/alist" - uninstallProc "$alistpath" alist - -} - -resetAdminPass(){ - alistpath="${installpath}/serv00-play/alist" - cd $alistpath - - output=$(./alist admin random 2>&1) - extract_user_and_password "$output" -} - -alistServ(){ - if ! checkInstalled "serv00-play"; then - return 1 - fi - while true; do - yellow "----------------------" - echo "alist:" - echo "服务状态: $(checkProcStatus alist)" - echo "1. 安装部署alist " - echo "2. 启动alist" - echo "3. 停掉alist" - echo "4. 重置admin密码" - echo "8. 卸载alist" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "----------------------" - read -p "请选择:" input - - case $input in - 1) installAlist - ;; - 2) startAlist - ;; - 3) stopAlist - ;; - 4) resetAdminPass - ;; - 8) uninstallAlist - ;; - 9) break - ;; - 0) exit 0 - ;; - *) - echo "无效选项,请重试" - ;; - esac - done - showMenu +uninstallProc() { + local path=$1 + local procname=$2 + + if [ ! -e "$path" ]; then + red "未安装$procname!!!" + return 1 + fi + cd $path + read -p "确定卸载${procname}吗? [y/n] [n]:" input + input=${input:-n} + if [[ "$input" == "y" ]]; then + stopProc "$procname" + domain=$(jq -r ".domain" config.json) + webip=$(jq -r ".webip" config.json) + resp=$(devil ssl www del $webIp $domain) + resp=$(devil www del $domain --remove) + cd ${installpath}/serv00-play + rm -rf $path + green "卸载完毕!" + fi + } -declare -a indexPorts -loadIndexPorts(){ - output=$(devil port list) +uninstallAlist() { + alistpath="${installpath}/serv00-play/alist" + uninstallProc "$alistpath" alist - indexPorts=() - # 解析输出内容 - index=0 - while read -r port typ opis; do - # 跳过标题行 - if [[ "$port" =~ "Port" ]]; then - continue - fi - #echo "port:$port,typ:$typ, opis:$opis" - if [[ "$port" =~ "Brak" || "$port" =~ "No" ]]; then - echo "未分配端口" - return 0 - fi +} - if [[ -n "$port" ]]; then - opis=${opis:-""} - indexPorts[$index]="$port|$typ|$opis" - ((index++)) - fi - done <<< "$output" +resetAdminPass() { + alistpath="${installpath}/serv00-play/alist" + cd $alistpath + + output=$(./alist admin random 2>&1) + extract_user_and_password "$output" +} +updateAlist() { + cd ${installpath}/serv00-play/alist || (echo "未安装alist" && return) + + if ! check_update_from_net "alist"; then + return 1 + fi + + stopAlist + download_from_net "alist" + chmod +x ./alist + startAlist + echo "更新完毕!" +} + +alistServ() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "----------------------" + echo "alist:" + echo "服务状态: $(checkProcStatus alist)" + echo "1. 安装部署" + echo "2. 启动" + echo "3. 停掉" + echo "4. 重置admin密码" + echo "5. 更新" + echo "8. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "----------------------" + read -p "请选择:" input + + case $input in + 1) + installAlist + ;; + 2) + startAlist + ;; + 3) + stopAlist + ;; + 4) + resetAdminPass + ;; + 5) + updateAlist + ;; + 8) + uninstallAlist + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +declare -a indexPorts +loadIndexPorts() { + output=$(devil port list) + + indexPorts=() + # 解析输出内容 + index=0 + while read -r port typ opis; do + # 跳过标题行 + if [[ "$port" =~ "Port" ]]; then + continue + fi + #echo "port:$port,typ:$typ, opis:$opis" + if [[ "$port" =~ "Brak" || "$port" =~ "No" ]]; then + echo "未分配端口" + return 0 + fi + + if [[ -n "$port" ]]; then + opis=${opis:-""} + indexPorts[$index]="$port|$typ|$opis" + ((index++)) + fi + done <<<"$output" } printIndexPorts() { - local i=1 - echo " Port | Type | Description" - for entry in "${indexPorts[@]}"; do - # 使用 | 作为分隔符拆分 port、typ 和 opis - - IFS='|' read -r port typ opis <<< "$entry" - echo "${i}. $port | $typ | $opis" - ((i++)) - done -} - - -delPortMenu(){ - loadIndexPorts - - if [[ ${#indexPorts[@]} -gt 0 ]]; then - printIndexPorts - read -p "请选择要删除的端口记录编号(输入0删除所有端口记录, 回车返回):" number - number=${number:-99} - - if [[ $number -eq 99 ]]; then - return - elif [[ $number -gt 3 || $number -lt 0 ]]; then - echo "非法输入!" - return - elif [[ $number -eq 0 ]]; then - cleanPort - else - idx=$((number-1)) - IFS='|' read -r port typ opis <<< ${indexPorts[$idx]} - devil port del $typ $port > /dev/null 2>&1 - fi - echo "删除完毕!" - else - red "未有分配任何端口!" - fi - -} - -addPortMenu(){ - echo "选择端口类型:" - echo "1. tcp" - echo "2. udp" - read -p "请选择:" co - - if [[ "$co" != "1" && "$co" != "2" ]]; then - red "非法输入" - return - fi - local type="" - if [[ "$co" == "1" ]]; then - type="tcp" - else - type="udp" - fi - loadPort - read -p "请输入端口备注(如hy2,vmess,用于脚本自动获取端口):" opts - local port=$(getPort $type $opts ) - if [[ "$port" == "failed" ]]; then - red "分配端口失败,请重新操作!" - else - green "分配出来的端口是:$port" - fi -} - -portServ(){ - while true; do - yellow "----------------------" - echo "端口管理:" - echo "1. 删除某条端口记录" - echo "2. 增加一条端口记录" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "----------------------" - read -p "请选择:" input - case $input in - 1) delPortMenu - ;; - 2) addPortMenu - ;; - 9) - break - ;; - 0) - exit 0 - ;; - *) - echo "无效选项,请重试" - ;; - esac - done - showMenu -} - -cronLE(){ - read -p "请输入定时运行的时间间隔(小时[1-23]):" tm - tm=${tm:-""} - if [[ -z "$tm" ]]; then - red "时间不能为空" - return 1 - fi - if [[ $tm -lt 1 || $tm -gt 23 ]]; then - red "输入非法!" - return 1 - fi - crontab -l > le.cron - echo "0 */$tm * * * $workpath/cronSSL.sh $domain > /dev/null 2>&1 " >> le.cron - crontab le.cron > /dev/null 2>&1 - rm -rf le.cron - echo "设置完毕!" -} - -get_default_webip(){ - local host="$(hostname | cut -d '.' -f 1)" - local sno=${host/s/web} - local webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') - echo "$webIp" -} - -applyLE(){ - local domain=$1 - local webIp=$2 - workpath="${installpath}/serv00-play/ssl" - cd "$workpath" - - if [[ -z "$domain" ]]; then - read -p "请输入待申请证书的域名:" domain - domain=${domain:-""} - if [[ -z "$domain" ]]; then - red "域名不能为空" - return 1 - fi - fi - inCron="0" - if crontab -l | grep -F "$domain" > /dev/null 2>&1 ; then - inCron="1" - echo "该域名已配置定时申请证书,是否删除定时配置记录,改为手动申请?[y/n] [n]:" input - input=${input:-n} - - if [[ "$input" == "y" ]]; then - crontab -l | grep -v "$domain" | crontab - - fi - fi - if [[ -z "$webIp" ]]; then - read -p "是否指定webip? [y/n] [n]:" input - input=${input:-n} - if [[ "$input" == "y" ]]; then - read -p "请输入webip:" webIp - if [[ -z "webIp" ]]; then - red "webip 不能为空!!!" - return 1 - fi - else - host="$(hostname | cut -d '.' -f 1)" - sno=${host/s/web} - webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') - fi - fi - #echo "申请证书时,webip是: $webIp" - resp=$(devil ssl www add $webIp le le $domain) - if [[ ! "$resp" =~ .*succesfully.*$ ]]; then - red "申请ssl证书失败!$resp" - if [[ "$inCron" == "0" ]]; then - read -p "是否配置定时任务自动申请SSL证书? [y/n] [n]:" input - input=${input:-n} - if [[ "$input" == "y" ]]; then - cronLE - fi - fi - else - green "证书申请成功!" - fi -} - -selfSSL(){ - workpath="${installpath}/serv00-play/ssl" - cd "$workpath" - - read -p "请输入待申请证书的域名:" self_domain - self_domain=${self_domain:-""} - if [[ -z "$self_domain" ]]; then - red "域名不能为空" - return 1 - fi - - echo "正在生成证书..." - - cat > openssl.cnf </dev/null 2>&1 + fi + echo "删除完毕!" + else + red "未有分配任何端口!" + fi + +} + +addPortMenu() { + echo "选择端口类型:" + echo "1. tcp" + echo "2. udp" + read -p "请选择:" co + + if [[ "$co" != "1" && "$co" != "2" ]]; then + red "非法输入" + return + fi + local type="" + if [[ "$co" == "1" ]]; then + type="tcp" + else + type="udp" + fi + loadPort + read -p "请输入端口备注(如hy2,vmess,用于脚本自动获取端口):" opts + read -p "是否自动分配端口? [y/n] [y]:" input + input=${input:-y} + if [[ "$input" == "y" ]]; then + port=$(getPort $type $opts) + if [[ "$port" == "failed" ]]; then + red "分配端口失败,请重新操作!" + else + green "分配出来的端口是:$port" + fi + else + read -p "请输入端口号:" port + if [[ -z "$port" ]]; then + red "端口不能为空" + return 1 + fi + resp=$(devil port add $type $port $opts) + if [[ "$resp" =~ .*succesfully.*$ || "$resp" =~ .*Ok.*$ ]]; then + green "添加端口成功!" + else + red "添加端口失败!" + fi + fi + +} + +portServ() { + while true; do + yellow "----------------------" + echo "端口管理:" + echo "1. 删除某条端口记录" + echo "2. 增加一条端口记录" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "----------------------" + read -p "请选择:" input + case $input in + 1) + delPortMenu + ;; + 2) + addPortMenu + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +cronLE() { + local l_domain=$1 + local nointeraction=$2 + if [[ -n "$nointeraction" ]]; then + tm=1 + else + read -p "请输入定时运行的时间间隔(小时[1-23]):" tm + tm=${tm:-""} + if [[ -z "$tm" ]]; then + red "时间不能为空" + return 1 + fi + if [[ $tm -lt 1 || $tm -gt 23 ]]; then + red "输入非法!" + return 1 + fi + fi + crontab -l >le.cron + # 生成0-59的随机数 + local mm=$((RANDOM % 60)) + if [[ $tm -eq 1 ]]; then + #每小时执行一次 + echo "$mm * * * * bash $workpath/cronSSL.sh $l_domain > /dev/null 2>&1 " >>le.cron + else + #每tm小时执行一次 + echo "$mm */$tm * * * bash $workpath/cronSSL.sh $l_domain > /dev/null 2>&1 " >>le.cron + fi + crontab le.cron >/dev/null 2>&1 + rm -rf le.cron + echo "设置完毕!" +} + +get_default_webip() { + local host="$(hostname | cut -d '.' -f 1)" + local sno=${host/s/web} + local webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') + echo "$webIp" +} + +applyLE() { + local l_domain=$1 + local l_webip=$2 + local nointeraction=$3 + workpath="${installpath}/serv00-play/ssl" + cd "$workpath" + + #echo "domain=$l_domain, webip=$l_webip, nointeraction=$nointeraction" + if [[ -z "$l_domain" ]]; then + read -p "请输入待申请证书的域名:" l_domain + l_domain=${l_domain:-""} + if [[ -z "$l_domain" ]]; then + red "域名不能为空" + return 1 + fi + fi + local inCron="0" + if crontab -l | grep -F "$l_domain" >/dev/null 2>&1; then + inCron="1" + if [[ -z "$nointeraction" ]]; then + echo "该域名已配置定时申请证书,是否删除定时配置记录,改为手动申请?[y/n] [n]:" input + input=${input:-n} + + if [[ "$input" == "y" ]]; then + crontab -l | grep -v "$l_domain" | crontab - + fi + else + crontab -l | grep -v "$l_domain" | crontab - + fi + fi + if [[ -z "$l_webip" ]]; then + read -p "是否指定webip? [y/n] [n]:" input + input=${input:-n} + + if [[ "$input" == "y" ]]; then + read -p "请输入webIp:" l_webip + if [[ -z "$l_webip" ]]; then + red "webIp 不能为空!!!" + return 1 + fi + else + host="$(hostname | cut -d '.' -f 1)" + sno=${host/s/web} + l_webip=$(devil vhost list public | grep "$sno" | awk '{print $1}') + fi + fi + #echo "申请证书时,webip是: $l_webip" + resp=$(devil ssl www add $l_webip le le $l_domain) + if [[ ! "$resp" =~ .*succesfully.*$ ]]; then + red "申请ssl证书失败!$resp" + #echo "inCron: $inCron" + if [[ "$inCron" == "0" ]]; then + if [[ -z "$nointeraction" ]]; then + read -p "是否配置定时任务自动申请SSL证书? [y/n] [n]:" input + input=${input:-n} + else + input="y" + fi + if [[ "$input" == "y" ]]; then + if [[ -z "$nointeraction" ]]; then + cronLE $l_domain + else + cronLE $l_domain $nointeraction + fi + fi + fi + else + green "证书申请成功!" + fi + cd - +} + +selfSSL() { + workpath="${installpath}/serv00-play/ssl" + cd "$workpath" + + read -p "请输入待申请证书的域名:" self_domain + self_domain=${self_domain:-""} + if [[ -z "$self_domain" ]]; then + red "域名不能为空" + return 1 + fi + + echo "正在生成证书..." + + cat >openssl.cnf < /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo "生成证书失败!" - return 1 - fi - - echo "已生成证书:" - green "_private.key" - green "_cert.crt" - - echo "正在导入证书.." - host="$(hostname | cut -d '.' -f 1)" - sno=${host/s/web} - webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') - resp=$(devil ssl www add "$webIp" ./_cert.crt ./_private.key "$self_domain" ) - - if [[ ! "$resp" =~ .*succesfully.*$ ]]; then - echo "导入证书失败:$resp" - return 1 - fi - - echo "导入成功!" - -} - -domainSSLServ(){ - while true; do - yellow "---------------------" - echo "域名证书管理:" - echo "1. 抢域名证书" - echo "2. 配置自签证书" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "---------------------" - read -p "请选择:" input - - case $input in - 1) applyLE - ;; - 2) selfSSL - ;; - 9) break - ;; - 0) - exit 0 - ;; - *) - echo "无效选项,请重试" - ;; - esac - done - showMenu -} - -installRoot(){ - workpath="${installpath}/serv00-play/root" - if [[ ! -e $workpath ]]; then - mkdir -p "$workpath" - fi - - if [[ -e "$workpath/MrChrootBSD/mrchroot" ]]; then - echo "检测到已经安装mrchroot,请勿重复安装!" - return - fi - echo "正在安装..." - cd $workpath - git clone https://github.com/nrootconauto/MrChrootBSD.git - cd MrChrootBSD - wget https://download.freebsd.org/releases/amd64/14.1-RELEASE/base.txz - wget https://download.freebsd.org/releases/amd64/14.1-RELEASE/lib32.txz #Needed for gdb for some reason - mkdir chroot - cd chroot - tar xvf ../base.txz - tar xvf ../lib32.txz - cd .. - cmake . - make - cp /etc/resolv.conf chroot/etc - if screen -S rootsession -dm ./mrchroot chroot /bin/sh; then - echo "安装成功!" - else - echo "安装失败!" - fi - -} - -enterRoot(){ - workpath="${installpath}/serv00-play/root/MrChrootBSD" - if [[ ! -e "$workpath/mrchroot" ]]; then - red "未安装mrchroot,请先行安装!" - return - fi - - SESSION_NAME="rootsession" - if screen -list | grep -q "\.$SESSION_NAME"; then - echo "进入root..." - screen -r "$SESSION_NAME" - else - echo "未发现root进程,尝试创建井进入root..." - cd $workpath - if screen -S $SESSION_NAME -dm ./mrchroot chroot /bin/sh; then - echo "创建成功!" - screen -r "$SESSION_NAME" - else - echo "创建失败!" - fi - - fi -} - -uninstallRoot(){ - SESSION_NAME="rootsession" - - if [[ ! -e "${installpath}/serv00-play/root" ]]; then - echo "未安装root,无需卸载!" - return - fi - - read -p "确定卸载root吗?[y/n] [n]:" input - input=${input:-n} - - if [[ "$input" == "y" ]]; then - - if screen -list | grep -q "\.${SESSION_NAME}"; then - screen -S "$SESSION_NAME" -X quit - fi - - workpath="${installpath}/serv00-play/" - cd $workpath - rm -rf ./root - fi - - green "卸载完毕!" -} - -rootServ(){ - while true; do - yellow "---------------------" - echo "一键root:" - echo "1. 安装root" - echo "2. 进入root" - echo "3. 卸载root" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "---------------------" - read -p "请选择:" input - - case $input in - 1) installRoot - ;; - 2) enterRoot - ;; - 3) uninstallRoot - ;; - 9) break - ;; - 0) exit 0 - ;; - *) echo "无效选项,请重试" - ;; - esac - done - showMenu -} - -getUnblockIP(){ - local hostname=$(hostname) - local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') - local hosts=("cache${host_number}.serv00.com" "web${host_number}.serv00.com" "$hostname") - - yellow "----------------------------------------------" - green " 主机名称 | IP | 状态" - yellow "----------------------------------------------" - # 遍历主机名称数组 - for host in "${hosts[@]}"; do - # 获取 API 返回的数据 - local response=$(curl -s "https://ss.botai.us.kg/api/getip?host=$host") - - # 检查返回的结果是否包含 "not found" - if [[ "$response" =~ "not found" ]]; then - echo "未识别主机${host}, 请联系作者饭奇骏!" - return - fi - local ip=$(echo "$response" | awk -F "|" '{print $1 }') - local status=$(echo "$response" | awk -F "|" '{print $2 }') - printf "%-20s | %-15s | %-10s\n" "$host" "$ip" "$status" - done - -} - -checkProcStatus(){ - local procname=$1 - if checkProcAlive $procname ; then - green "运行" - else - red "未运行" - fi - -} - -sunPanelServ(){ - if ! checkInstalled "serv00-play"; then - return 1 - fi - while true; do - yellow "---------------------" - echo "sun-panel:" - echo "服务状态: $(checkProcStatus sun-panel)" - echo "1. 安装" - echo "2. 启动" - echo "3. 停止" - echo "4. 初始化密码" - echo "8. 卸载" - echo "9. 返回主菜单" - echo "0. 退出脚本" - yellow "---------------------" - read -p "请选择:" input - - case $input in - 1) installSunPanel - ;; - 2) startSunPanel - ;; - 3) stopSunPanel - ;; - 4) resetSunPanelPwd - ;; - 8) uninstallSunPanel - ;; - 9) break - ;; - 0) exit 0 - ;; - *) echo "无效选项,请重试" - ;; - esac - done - showMenu -} - -uninstallSunPanel(){ - local workdir="${installpath}/serv00-play/sunpanel" - uninstallProc "$workdir" "sun-panel" -} - -resetSunPanelPwd(){ - local exepath="${installpath}/serv00-play/sunpanel/sun-panel" - if [[ ! -e $exepath ]]; then - echo "未安装,请先安装!" - return - fi - read -p "确定初始化密码? [y/n][n]:" input - input=${input:-n} - - if [[ "$input" == "y" ]]; then - local workdir="${installpath}/serv00-play/sunpanel" - cd $workdir - ./sun-panel -password-reset - fi - -} - -stopSunPanel(){ - stopProc "sun-panel" - if checkProcAlive "sun-panel"; then - echo "未能停止,请手动杀进程!" - fi - -} - -installSunPanel(){ - local workdir="${installpath}/serv00-play/sunpanel" - local exepath="${installpath}/serv00-play/sunpanel/sun-panel" - if [[ -e $exepath ]]; then - echo "已安装,请勿重复安装!" - return - fi - mkdir -p $workdir - cd $workdir - - if ! checkDownload "sun-panel"; then - return 1 - fi - if ! checkDownload "panelweb" 1; then - return 1 - fi - - if [[ ! -e "sun-panel" ]]; then - echo "下载文件解压失败!" - return 1 - fi - #初始化密码,并且生成相关目录文件 - ./sun-panel -password-reset - - if [[ ! -e "conf/conf.ini" ]]; then - echo "无配置文件生成!" - return 1 - fi - - loadPort - port="" - randomPort "tcp" "sun-panel" - if [ -n "$port" ]; then - sunPanelPort=$port - else - echo "未输入端口!" - return 1 - fi - cd conf - sed -i.bak -E "s/^http_port=[0-9]+$/http_port=${sunPanelPort}/" conf.ini - cd .. - - domain="" - webIp="" - if ! makeWWW panel $sunPanelPort ; then - echo "绑定域名失败!" - return 1 - fi - # 自定义域名时申请证书的webip可以从2个ip中选择 - if [ $is_self_domain -eq 1 ]; then - if ! applyLE $domain $webIp; then - echo "申请证书失败!" - return 1 - fi - else # 没有自定义域名时,webip是内置固定的,就是web(x).serv00.com - if ! applyLE $domain ; then - echo "申请证书失败!" - return 1 - fi - fi - green "安装完毕!" - -} - -makeWWW(){ - local proc=$1 - local port=$2 - local www_type=${3:-"proxy"} - - echo "正在处理服务IP,请等待..." - is_self_domain=0 - webIp=$(get_webip) - default_webip=$(get_default_webip) - green "可用webip是: $webIp, 默认webip是: $default_webip" - read -p "是否使用自定义域名? [y/n] [n]:" input - input=${input:-n} - if [[ "$input" == "y" ]]; then - is_self_domain=1 - read -p "请输入域名(确保此前域名已指向webip):" domain - else - user="$(whoami)" - if isServ00 ; then - domain="${proc}.$user.serv00.net" - else - domain="$proc.$user.ct8.pl" - fi - fi - - if [[ -z "$domain" ]]; then - red "输入无效域名!" - return 1 - fi - - domain=${domain,,} - echo "正在绑定域名,请等待..." - if [[ "$www_type" == "proxy" ]]; then - resp=$(devil www add $domain proxy localhost $port) - else - resp=$(devil www add $domain php) - fi - #echo "resp:$resp" - if [[ ! "$resp" =~ .*succesfully.*$ && ! "$resp" =~ .*Ok.*$ ]]; then - if [[ ! "$resp" =~ "This domain already exists" ]]; then - red "申请域名$domain 失败!" - return 1 - fi - fi - - # 自定义域名的特殊处理 - if [[ $is_self_domain -eq 1 ]]; then - host="$(hostname | cut -d '.' -f 1)" - sno=${host/s/web} - default_webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') - rid=$(devil dns list "$domain" | grep "$default_webIp" | awk '{print $1}') - resp=$(echo "y" | devil dns del "$domain" $rid) - #echo "resp:$resp" - else - webIp=$(get_default_webip) - fi - # 保存信息 - if [[ "$www_type" == "proxy" ]]; then - cat > config.json </dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "生成证书失败!" + return 1 + fi + + echo "已生成证书:" + green "_private.key" + green "_cert.crt" + + echo "正在导入证书.." + host="$(hostname | cut -d '.' -f 1)" + sno=${host/s/web} + webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') + resp=$(devil ssl www add "$webIp" ./_cert.crt ./_private.key "$self_domain") + + if [[ ! "$resp" =~ .*succesfully.*$ ]]; then + echo "导入证书失败:$resp" + return 1 + fi + + echo "导入成功!" + cd - +} + +domainSSLServ() { + while true; do + yellow "---------------------" + echo "域名证书管理:" + echo "1. 抢域名证书" + echo "2. 配置自签证书" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + applyLE + ;; + 2) + selfSSL + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +installRoot() { + workpath="${installpath}/serv00-play/root" + if [[ ! -e $workpath ]]; then + mkdir -p "$workpath" + fi + + if [[ -e "$workpath/MrChrootBSD/mrchroot" ]]; then + echo "检测到已经安装mrchroot,请勿重复安装!" + return + fi + echo "正在安装..." + cd $workpath + git clone https://github.com/nrootconauto/MrChrootBSD.git + cd MrChrootBSD + wget https://download.freebsd.org/releases/amd64/14.1-RELEASE/base.txz + wget https://download.freebsd.org/releases/amd64/14.1-RELEASE/lib32.txz #Needed for gdb for some reason + mkdir chroot + cd chroot + tar xvf ../base.txz + tar xvf ../lib32.txz + cd .. + cmake . + make + cp /etc/resolv.conf chroot/etc + if screen -S rootsession -dm ./mrchroot chroot /bin/sh; then + echo "安装成功!" + else + echo "安装失败!" + fi + +} + +enterRoot() { + workpath="${installpath}/serv00-play/root/MrChrootBSD" + if [[ ! -e "$workpath/mrchroot" ]]; then + red "未安装mrchroot,请先行安装!" + return + fi + + SESSION_NAME="rootsession" + if screen -list | grep -q "\.$SESSION_NAME"; then + echo "进入root..." + screen -r "$SESSION_NAME" + else + echo "未发现root进程,尝试创建井进入root..." + cd $workpath + if screen -S $SESSION_NAME -dm ./mrchroot chroot /bin/sh; then + echo "创建成功!" + screen -r "$SESSION_NAME" + else + echo "创建失败!" + fi + + fi +} + +uninstallRoot() { + SESSION_NAME="rootsession" + + if [[ ! -e "${installpath}/serv00-play/root" ]]; then + echo "未安装root,无需卸载!" + return + fi + + read -p "确定卸载root吗?[y/n] [n]:" input + input=${input:-n} + + if [[ "$input" == "y" ]]; then + + if screen -list | grep -q "\.${SESSION_NAME}"; then + screen -S "$SESSION_NAME" -X quit + fi + + workpath="${installpath}/serv00-play/" + cd $workpath + rm -rf ./root + fi + + green "卸载完毕!" +} + +rootServ() { + while true; do + yellow "---------------------" + echo "一键root:" + echo "1. 安装root" + echo "2. 进入root" + echo "3. 卸载root" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + installRoot + ;; + 2) + enterRoot + ;; + 3) + uninstallRoot + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +showIPStatus() { + yellow "----------------------------------------------" + green " 主机名称 | IP | 状态" + yellow "----------------------------------------------" + + show_ip_status +} + +checkProcStatus() { + local procname=$1 + if checkProcAlive $procname; then + green "运行" + else + red "未运行" + fi + +} + +sunPanelServ() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "---------------------" + echo "sun-panel:" + echo "服务状态: $(checkProcStatus sun-panel)" + echo "1. 安装" + echo "2. 启动" + echo "3. 停止" + echo "4. 初始化密码" + echo "5. 导入serv00账号信息(频道会员尊享功能)" + echo "8. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + installSunPanel + ;; + 2) + startSunPanel + ;; + 3) + stopSunPanel + ;; + 4) + resetSunPanelPwd + ;; + 5) + import_accounts + ;; + 8) + uninstallSunPanel + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu +} + +import_accounts() { + local workdir="${installpath}/serv00-play/sunpanel" + if ! vip_statement; then + return 1 + fi + + cd $workdir + read -p "请输入会员密码:" passwd + if ! checkDownload "importd_panel_accounts.sh" 0 "$passwd" 1; then + return 1 + fi + + chmod +x ./importd_panel_accounts.sh + + ./importd_panel_accounts.sh && rm -rf ./importd_panel_accounts.sh + + if [[ $? -ne 0 ]]; then + echo "导入失败!" + else + echo "导入成功!" + fi + +} + +import_accounts() { + local workdir="${installpath}/serv00-play/sunpanel" + if ! vip_statement; then + return 1 + fi + + cd $workdir + read -s -p "请输入会员密码:" passwd + if ! checkDownload "importd_panel_accounts.sh" 0 "$passwd" 1; then + return 1 + fi + + chmod +x ./importd_panel_accounts.sh + + ./importd_panel_accounts.sh && rm -rf ./importd_panel_accounts.sh + + if [[ $? -ne 0 ]]; then + echo "导入失败!" + else + echo "导入成功!" + fi + +} + +uninstallSunPanel() { + local workdir="${installpath}/serv00-play/sunpanel" + uninstallProc "$workdir" "sun-panel" +} + +resetSunPanelPwd() { + local exepath="${installpath}/serv00-play/sunpanel/sun-panel" + if [[ ! -e $exepath ]]; then + echo "未安装,请先安装!" + return + fi + read -p "确定初始化密码? [y/n][n]:" input + input=${input:-n} + + if [[ "$input" == "y" ]]; then + local workdir="${installpath}/serv00-play/sunpanel" + cd $workdir + ./sun-panel -password-reset + fi + +} + +stopSunPanel() { + stopProc "sun-panel" + if checkProcAlive "sun-panel"; then + echo "未能停止,请手动杀进程!" + fi + +} + +installSunPanel() { + local workdir="${installpath}/serv00-play/sunpanel" + local exepath="${installpath}/serv00-play/sunpanel/sun-panel" + if [[ -e $exepath ]]; then + echo "已安装,请勿重复安装!" + return + fi + mkdir -p $workdir + cd $workdir + + if ! checkDownload "sun-panel"; then + return 1 + fi + if ! checkDownload "panelweb" 1; then + return 1 + fi + + if [[ ! -e "sun-panel" ]]; then + echo "下载文件解压失败!" + return 1 + fi + #初始化密码,并且生成相关目录文件 + ./sun-panel -password-reset + + if [[ ! -e "conf/conf.ini" ]]; then + echo "无配置文件生成!" + return 1 + fi + + loadPort + port="" + randomPort "tcp" "sun-panel" + if [ -n "$port" ]; then + sunPanelPort=$port + else + echo "未输入端口!" + return 1 + fi + cd conf + sed -i.bak -E "s/^http_port=[0-9]+$/http_port=${sunPanelPort}/" conf.ini + cd .. + + domain="" + webIp="" + if ! makeWWW panel $sunPanelPort; then + echo "绑定域名失败!" + return 1 + fi + # 自定义域名时申请证书的webip可以从2个ip中选择 + if [ $is_self_domain -eq 1 ]; then + if ! applyLE $domain $webIp; then + echo "申请证书失败!" + return 1 + fi + else # 没有自定义域名时,webip是内置固定的,就是web(x).serv00.com + if ! applyLE $domain; then + echo "申请证书失败!" + return 1 + fi + fi + green "安装完毕!" + +} + +makeWWW() { + local proc=$1 + local port=$2 + local www_type=${3:-"proxy"} + local input=${4:-""} + domain=${5:-"$domain"} + + echo "正在处理服务IP,请等待..." + is_self_domain=0 + webIp=$(get_webip) + default_webip=$(get_default_webip) + if [[ -z "$webIp" ]]; then + webIp=$default_webip + fi + green "可用webip是: $webIp, 默认webip是: $default_webip" + if [[ -z "$domain" ]]; then + if [[ -z "$input" ]]; then + read -p "是否使用自定义域名? [y/n] [n]:" input + input=${input:-n} + fi + if [[ "$input" == "y" ]]; then + is_self_domain=1 + read -p "请输入域名(确保此前域名已指向webip):" domain + else + if [[ -z ${proc:""} ]]; then + read -p "请输入默认域名的二级域名的前缀(如二级域名 sub.main.com, 则填sub):" proc + fi + domain=$(getUserDoMain "$proc") + fi + else + is_self_domain=1 + fi + + if [[ -z "$domain" ]]; then + red "输入无效域名!" + return 1 + fi + + domain=${domain,,} + echo "正在绑定域名,请等待..." + if [[ "$www_type" == "proxy" ]]; then + resp=$(devil www add $domain proxy localhost $port) + else + resp=$(devil www add $domain php) + fi + #echo "resp:$resp" + if [[ ! "$resp" =~ .*succesfully.*$ && ! "$resp" =~ .*Ok.*$ ]]; then + if [[ ! "$resp" =~ "This domain already exists" ]]; then + red "申请域名$domain 失败!" + return 1 + fi + fi + + # 自定义域名的特殊处理 + # if [[ $is_self_domain -eq 1 ]]; then + # host="$(hostname | cut -d '.' -f 1)" + # sno=${host/s/web} + # default_webIp=$(devil vhost list public | grep "$sno" | awk '{print $1}') + # rid=$(devil dns list "$domain" | grep "$default_webIp" | awk '{print $1}') + # resp=$(echo "y" | devil dns del "$domain" $rid) + # #echo "resp:$resp" + # else + # webIp=$(get_default_webip) + # fi + # 保存信息 + if [[ "$www_type" == "proxy" ]]; then + cat >config.json < $configfile <> "$profile" - source $profile - fi - domain="" - webIp="" - if ! makeWWW ssh $websshPort ; then - echo "绑定域名失败!" - return 1 - fi - if ! applyLE $domain $webIp; then - echo "申请证书失败!" - return 1 - fi - echo "安装完成!" - -} - -stopWebSSH(){ - stopProc "wssh" - sleep 2 - if ! checkProcAlive "wssh"; then - echo "wssh已停止!" - else - echo "未能停止,请手动杀进程!" - fi -} - -startWebSSH(){ - local workdir="${installpath}/serv00-play/webssh" - local configfile="$workdir/config.json" - if [ ! -e "$configfile" ]; then - echo "未安装,请先安装!" - return - fi - cd $workdir - read -p "是否需要日志($workdir/running.log)? [y/n] [n]:" input - input=${input:-n} - args="" - if [[ "$input" == "y" ]]; then - args=" > running.log 2>&1 " - else - args=" > /dev/null 2>&1 " - fi - port=$(jq -r ".port" $configfile) - if checkProcAlive "wssh"; then - stopProc "wssh" - fi - echo "正在启动中..." - cmd="nohup ./wssh --port=$port --fbidhttp=False --xheaders=False --encoding='utf-8' --delay=10 $args &" - eval "$cmd" - sleep 2 - if checkProcAlive wssh; then - green "启动成功!" - else - echo "启动失败!" - fi -} - -nonServ(){ - cat < $configfile <>"$profile" + source $profile + fi + domain="" + webIp="" + if ! makeWWW ssh $websshPort; then + echo "绑定域名失败!" + return 1 + fi + if ! applyLE $domain $webIp; then + echo "申请证书失败!" + return 1 + fi + echo "安装完成!" + +} + +stopWebSSH() { + stopProc "wssh" + sleep 2 + if ! checkProcAlive "wssh"; then + echo "wssh已停止!" + else + echo "未能停止,请手动杀进程!" + fi +} + +startWebSSH() { + local workdir="${installpath}/serv00-play/webssh" + local configfile="$workdir/config.json" + if [ ! -e "$configfile" ]; then + echo "未安装,请先安装!" + return + fi + cd $workdir + read -p "是否需要日志($workdir/running.log)? [y/n] [n]:" input + input=${input:-n} + args="" + if [[ "$input" == "y" ]]; then + args=" > running.log 2>&1 " + else + args=" > /dev/null 2>&1 " + fi + port=$(jq -r ".port" $configfile) + if checkProcAlive "wssh"; then + stopProc "wssh" + fi + echo "正在启动中..." + cmd="nohup ./wssh --port=$port --wpintvl=30 --fbidhttp=False --xheaders=False --encoding='utf-8' --delay=10 $args &" + eval "$cmd" + sleep 2 + if checkProcAlive wssh; then + green "启动成功!" + else + echo "启动失败!" + fi +} + +nonServ() { + cat <" - echo -e "${CYAN}${art_wrod}${RESET}" - echo -e "${GREEN} 饭奇骏频道:https://www.youtube.com/@frankiejun8965 ${RESET}" - echo -e "${GREEN} TG交流群:https://t.me/fanyousuiqun ${RESET}" - echo "<------------------------------------------------------------------>" - echo "请选择一个选项:" - - options=("安装/更新serv00-play项目" "sun-panel" "webssh" "阅后即焚" "待开发" "设置保活的项目" "配置sing-box" \ - "运行sing-box" "停止sing-box" "显示sing-box节点信息" "快照恢复" "系统初始化" "前置工作及设置中国时区" "管理哪吒探针" "卸载探针" "设置彩色开机字样" "显示本机IP" \ - "mtproto代理" "alist管理" "端口管理" "域名证书管理" "一键root" "自动检测主机IP状态" "一键更换hy2的IP" "卸载" ) - - select opt in "${options[@]}" - do - case $REPLY in - 1) - install - ;; - 2) - sunPanelServ - ;; - 3) - websshServ - ;; - 4) - burnAfterReadingServ - ;; - 5) - nonServ - ;; - 6) - setConfig - ;; - 7) - configSingBox - ;; - 8) - startSingBox - ;; - 9) - stopSingBox - ;; - 10) - showSingBoxInfo - ;; - 11) - ImageRecovery - ;; - 12) - InitServer - ;; - 13) - setCnTimeZone - ;; - 14) - manageNeZhaAgent - ;; - 15) - uninstallAgent - ;; - 16) - setColorWord - ;; - 17) - showIP - ;; - 18) - mtprotoServ - ;; - 19) - alistServ - ;; - 20) - portServ - ;; - 21) - domainSSLServ - ;; - 22) - rootServ - ;; - 23) - getUnblockIP - ;; - 24) - changeHy2IP - ;; - 25) - uninstall - ;; - 0) - echo "退出" - exit 0 - ;; - *) - echo "无效的选项 " - ;; - esac - - done - -} - - -showMenu \ No newline at end of file +checkInstalled() { + local model=$1 + if [[ "$model" == "serv00-play" ]]; then + if [[ ! -d "${installpath}/$model" ]]; then + red "请先安装$model !!!" + return 1 + else + return 0 + fi + else + if [[ ! -d "${installpath}/serv00-play/$model" ]]; then + red "请先安装$model !!!" + return 1 + else + return 0 + fi + fi + return 1 +} + +changeHy2IP() { + cd ${installpath}/serv00-play/singbox + if [[ ! -e "singbox.json" || ! -e "config.json" ]]; then + red "未安装节点,请先安装!" + return 1 + fi + showIPStatus + read -p "是否让程序为HY2选择可用的IP?[y/n] [y]:" input + input=${input:-y} + + if [[ "$input" == "n" ]]; then + read -p "是否手动选择IP?[y/n] [y]:" choose + choose=${choose:-y} + if [[ "$choose" == "y" ]]; then + read -p "请选择你要的IP的序号:" num + if [[ -z "$num" ]]; then + red "选择不能为空!" + return 1 + fi + if [[ $num -lt 1 || $num -gt ${#localIPs[@]} ]]; then + echo "错误:num 的值非法!请输入 1 到 ${#localIPs[@]} 之间的整数。" + return 1 + fi + hy2_ip=${localIPs[$((num - 1))]} + else + return 1 + fi + else + hy2_ip=$(get_ip) + fi + + if [[ -z "$hy2_ip" ]]; then + red "很遗憾,已无可用IP!" + return 1 + fi + if ! upInsertFd singbox.json HY2IP "$hy2_ip"; then + red "更新singbox.json配置文件失败!" + return 1 + fi + + if ! upSingboxFd config.json "inbounds" "tag" "hysteria-in" "listen" "$hy2_ip"; then + red "更新config.json配置文件失败!" + return 1 + fi + green "HY2 更换IP成功,当前IP为 $hy2_ip" + + echo "正在重启sing-box..." + stopSingBox + startSingBox + +} + +linkAliveServ() { + workdir="${installpath}/serv00-play/linkalive" + if ! checkInstalled "serv00-play"; then + return 1 + fi + if ! vip_statement "linkAliveStatment"; then + return 1 + fi + + if [[ ! -e $workdir ]]; then + mkdir -p $workdir + fi + cd $workdir + + read -s -p "请输入会员密码:" passwd + #判断密码是否为空 + if [[ -z "$passwd" ]]; then + red "密码不能为空!" + return 1 + fi + if ! checkDownload "linkAlive.sh" $ISFILE "$passwd" $ISVIP; then + return 1 + fi + + chmod +x ./linkAlive.sh + ./linkAlive.sh "$passwd" + + #showMenu +} + +DSServ() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "---------------------" + echo "Domains-Support:" + echo "服务状态: $(checkCronNameStatus domains-support)" + echo "1. 新增域名" + echo "2. 删除域名" + echo "3. 配置" + echo "4. 开启服务" + echo "5. 停止服务" + echo "6. 批量新增域名" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + + read -p "请选择:" input + + case $input in + 1) + addDomain + ;; + 2) + delDomain + ;; + 3) + configDs + ;; + 4) + startDs + ;; + 5) + stopDs + ;; + 6) + batchAddDomains + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu + +} +write_ds_config() { + local domain=$1 + local url=$2 + cat >config.json < /dev/null 2>&1 #domains-support" >>mycron + crontab mycron >/dev/null 2>&1 + rm mycron + +} + +stopDs() { + local workdir="${installpath}/serv00-play/domains-support" + cd $workdir + if [[ ! -e "config.json" ]]; then + red "未配置,请先配置!" + return 1 + fi + if checkCronName domains-support; then + echo "正在停止服务..." + crontab -l | grep -v "domains-support" >mycron + crontab mycron >/dev/null 2>&1 + rm mycron + green "服务已停止!" + else + red "服务未开启!" + fi +} + +addDomain() { + local workdir="${installpath}/serv00-play/domains-support" + if [[ ! -e $workdir ]]; then + mkdir -p $workdir + fi + cd $workdir + domain="" + webIp="" + if ! makeWWW "" "" "php" "y"; then + echo "绑定域名失败!" + return 1 + fi + #echo "after makeWWW, domain=$domain,webIp=$webIp" + if ! applyLE "$domain" "$webIp" "n"; then + echo "申请证书失败!" + return 1 + fi + cd $workdir + target="$installpath/domains/$domain/public_html" + if [[ ! -e "$target" ]]; then + red "目标目录不存在!" + fi + + while true; do + echo "建站样式选择:" + echo "1. 樱花博客" + echo "2. 人力资源管理系统" + echo "3. 德一教育系统后台" + echo "4. 李明的英文简历" + echo "5. 游戏殿堂" + echo "6. 圣诞节贺卡" + echo "99. 自定义网站" + + read -p "你的选择: " choice + + case $choice in + 1) + echo "你选择了樱花博客" + break + ;; + 2) + echo "你选择了人力资源管理系统" + break + ;; + 3) + echo "你选择了德一教育系统后台" + break + ;; + 4) + echo "你选择了李明的英文简历" + break + ;; + 5) + echo "你选择了游戏殿堂" + break + ;; + 6) + echo "你选择了圣诞节贺卡" + break + ;; + 99) + break + ;; + 0) + echo "返回上一级" + return + ;; + *) + echo "无效选择,请重新输入" + ;; + esac + done + + if [[ "$choice" == "1" ]]; then + cp websites/sakura.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + read -p "输入你的名字([xx的博客]里的xx):" name + name=${name:-"樱花"} + sed -i.bak "s|xx|$name|g" $target/index.html + fi + if [[ "$choice" == "2" ]]; then + cp websites/hr.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + if [[ "$choice" == "3" ]]; then + cp websites/deyiedu.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + if [[ "$choice" == "4" ]]; then + cp websites/resume.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + if [[ "$choice" == "5" ]]; then + cp websites/game.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + if [[ "$choice" == "6" ]]; then + cp websites/christmas.html $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + if [[ "$choice" == "99" ]]; then + read -p "输入网址html文件路径:" input + if [[ -z "$input" ]]; then + red "输入不能为空!" + return 1 + fi + if [[ ! -e "$input" ]]; then + red "文件不存在!" + return 1 + fi + cp "$input" $target/index.html + if [ $? -ne 0 ]; then + red "安装失败!" + return 1 + fi + fi + + add_domain $domain $webIp + if [[ -e "config.json" ]]; then + local api_token=$(jq -r ".API_TOKEN" config.json) + local url=$(jq -r ".URL" config.json) + if [[ -z "$api_token" || -z "$url" ]]; then + red "配置文件错误,请检查!" + return 1 + fi + read -p "是否录入域名信息到数据库? [y/n] [n]:" input + input=${input:-n} + if [[ "$input" == "y" ]]; then + read -p "请输入注册商名称:" registrar + registrar=${registrar:-"注册商"} + + read -p "请输入注册商链接(可选):" registrar_link + registrar_link=${registrar_link:-""} + + read -p "请输入注册日期(格式: YYYY-MM-DD):" registrar_date + registrar_date=${registrar_date:-$(date +%Y-%m-%d)} + + read -p "请输入到期日期(格式: YYYY-MM-DD):" expiry_date + expiry_date=${expiry_date:-$(date -v+1y +%Y-%m-%d)} + + local host=$(hostname) + local username=$(whoami) + + read -p "请输入备注(可选):" memo + memo=${memo:-"$host-$username"} + fi + curl -X POST "https://$url/api/addrec?token=$api_token" \ + -H "Content-Type: application/json" \ + -d '{ + "domain": "'"$domain"'", + "registrar": "'"$registrar"'", + "registrar_date": "'"$registrar_date"'", + "registrar_link": "'"$registrar_link"'", + "expiry_date": "'"$expiry_date"'", + "service_type": "伪装网站", + "status": "在线", + "tgsend": "1", + "memo": "'"$memo"'" + }' >/dev/null 2>&1 + if [ $? -ne 0 ]; then + red "域名信息录入失败!" + return 1 + fi + fi + green "域名的网站安装成功!" +} + +delDomain() { + local workdir="${installpath}/serv00-play/domains-support" + if [[ ! -e $workdir ]]; then + red "未安装,请先安装!" + return 1 + fi + cd $workdir + print_domains + read -p "请输入要删除的域名(-1删除所有,0返回上级菜单):" domain + if [[ -z "$domain" ]]; then + red "输入不能为空!" + return 1 + fi + if [[ "$domain" == "-1" ]]; then + read -p "是否删除所有域名? [y/n] [n]:" input + input=${input:-n} + if [[ "$input" != "y" ]]; then + return 1 + fi + delete_all_domains + rm -rf "${installpath}/serv00-play/domains-support" + green "删除成功!" + return 0 + fi + if [[ "$domain" == "0" ]]; then + return 0 + fi + delete_domain "$domain" + green "域名删除成功!" +} + +keepAliveServ() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "---------------------" + echo "keepAlive:" + echo "1. 安装" + echo "2. 更新(须先按1更新serv00-play)" + echo "3. 更新保活时间间隔" + echo "4. 修改token" + echo "8. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + + case $input in + 1) + installkeepAlive + ;; + 2) + updatekeepAlive + ;; + 3) + setKeepAliveInterval + ;; + 4) + changeKeepAliveToken + ;; + 8) + uninstallkeepAlive + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + + showMenu +} + +installkeepAlive() { + local domain=$(getUserDoMain) + domain="${domain,,}" + local domainPath="${installpath}/domains/$domain/public_nodejs" + local workdir="${installpath}/serv00-play/keepalive" + if [[ -e "$domainPath/config.json" ]]; then + red "已安装,请勿重复安装!" + return 1 + fi + cd $workdir + + read -p "需要使用默认域名[$domain]进行安装,若继续安装将会删除默认域名,确认是否继续? [y/n] [y]:" input + input=${input:-y} + if [[ "$input" != "y" ]]; then + echo "取消安装" + return 1 + fi + delDefaultDomain + echo "正在安装..." + if ! createDefaultDomain; then + return 1 + fi + mv "$domainPath/public" "$domainPath/static" + cp ./nezha.jpg $domainPath/static + cp ./config.json $domainPath + cp ./app.js $domainPath + + cd $domainPath + if ! npm22 install express body-parser child_process fs; then + red "安装依赖失败" + return 1 + fi + + read -p "是否需要自定义token? [y/n] [y]:" input + input=${input:-y} + if [[ "$input" == "y" ]]; then + uuid="" + read -p "请输入token:" uuid + if [[ -z "$uuid" ]]; then + red "token不能为空!" + return 1 + fi + else + uuid=$(uuidgen) + fi + green "你的token是:$uuid" + sed -i '' "s/uuid/$uuid/g" config.json + read -p "输入保活时间间隔(单位:分钟)[默认:2分钟]:" interval + interval=${interval:-2} + sed -i '' "s/TM/$interval/g" config.json + + green "安装成功" + +} + +uninstallkeepAlive() { + local input=$1 + local domain=$(getUserDoMain) + domain="${domain,,}" + local domainPath="${installpath}/domains/$domain/public_nodejs" + if [ -z "$input" ]; then + read -p "是否卸载? [y/n] [n]:" input + input=${input:-n} + if [[ "$input" != "y" ]]; then + return 1 + fi + fi + if ! delDefaultDomain; then + return 1 + fi + green "卸载成功" +} + +createDefaultDomain() { + local domain=$(getUserDoMain) + domain="${domain,,}" + rt=$(devil www add $domain nodejs /usr/local/bin/node22 production) + if [[ ! "$rt" =~ .*succesfully*$ ]]; then + red "创建默认域名失败" + return 1 + fi +} + +delDefaultDomain() { + local domain=$(getUserDoMain) + domain="${domain,,}" + rt=$(devil www del $domain --remove) + if [[ ! "$rt" =~ .*deleted*$ ]]; then + red "删除默认域名失败" + return 1 + fi +} + +updatekeepAlive() { + local domain=$(getUserDoMain) + domain="${domain,,}" + domainPath="${installpath}/domains/$domain/public_nodejs" + workDir="$installpath/serv00-play/keepalive" + if [[ ! -e "$domainPath/config.json" ]]; then + red "未安装,请先安装!" + return 1 + fi + if [[ ! -e "$workDir" ]]; then + mkdir -p $workDir + fi + cd $workDir + + cp ./app.js $domainPath + + cp $workDir/app.js $domainPath + devil www restart $domain + green "更新成功" +} + +changeKeepAliveToken() { + local domain=$(getUserDoMain) + domain="${domain,,}" + domainPath="${installpath}/domains/$domain/public_nodejs" + if [[ ! -e "$domainPath/config.json" ]]; then + red "未安装,请先安装!" + return 1 + fi + + cur_token=$(jq -r ".token" $domainPath/config.json) + echo "当前token为: $cur_token" + token="" + read -p "输入新的token:" token + if [[ -z "$token" ]]; then + red "token不能为空!" + return 1 + fi + upInsertFd $domainPath/config.json token $token + if [ $? -ne 0 ]; then + red "更新失败!" + return 1 + fi + green "更新成功" +} + +setKeepAliveInterval() { + local domain=$(getUserDoMain) + domain="${domain,,}" + domainPath="${installpath}/domains/$domain/public_nodejs" + if [[ ! -e "$domainPath/config.json" ]]; then + red "未安装,请先安装!" + return 1 + fi + + cur_interval=$(jq -r ".interval" $domainPath/config.json) + echo "当前保活时间间隔为: $cur_interval 分钟" + read -p "输入保活时间间隔(单位:分钟)[默认:2分钟]:" interval + interval=${interval:-2} + upInsertFd $domainPath/config.json interval $interval + if [ $? -ne 0 ]; then + red "更新失败!" + return 1 + fi + green "更新成功" +} +installRedis() { + local workdir="${installpath}/serv00-play/redis" + if [[ ! -d "$workdir" ]]; then + mkdir -p "$workdir" + fi + # 使用 || 来处理 cd 失败的情况,增加脚本健壮性 + cd "$workdir" || { + red "错误:无法进入工作目录 $workdir" + return 1 + } + + # 步骤 1: 检查 redis.conf,如果不存在则下载 + if [ ! -f "redis.conf" ]; then + yellow "redis.conf 文件不存在,正在从 Redis 官方 GitHub 仓库下载..." + # 使用 curl 下载文件,-fsSL 参数可以在失败时静默处理并支持重定向 + if ! curl -fsSL -o redis.conf https://raw.githubusercontent.com/redis/redis/7.4/redis.conf; then + red "下载 redis.conf 失败!请检查网络连接或稍后重试。" + return 1 + fi + green "redis.conf 下载成功!" + else + yellow "检测到已存在的 redis.conf,将在此基础上进行修改。" + fi + + # 步骤 2: 交互式获取配置信息 + green "----------------------------------------" + loadPort + randomPort tcp redis + if [[ -n "$port" ]]; then + redis_port="$port" + else + red "未输入端口号" + return 1 + fi + + read -r -p "密码 (Password) [留空则禁用密码]: " redis_password + + read -r -p "日志文件路径 (Log file path) [默认: \"\"]: " redis_logfile + + read -r -p "是否允许所有网络接口访问 (全网监听)?(y/n) [默认: n]: " listen_all + listen_all=${listen_all:-n} + green "----------------------------------------" + + # 步骤 3: 根据输入修改配置文件 + yellow "正在根据您的输入修改 redis.conf..." + + # 修改端口 + sed -i '' "s/^port .*/port ${redis_port}/" redis.conf + + # 修改密码 + if [[ -n "$redis_password" ]]; then + # 如果 requirepass 存在且未被注释,则直接替换 + if grep -q "^requirepass" redis.conf; then + sed -i '' "s/^requirepass .*/requirepass ${redis_password}/" redis.conf + # 如果 requirepass 存在但被注释,则取消注释并替换 + elif grep -q "^# requirepass" redis.conf; then + sed -i '' "s/^# requirepass .*/requirepass ${redis_password}/" redis.conf + # 如果不存在,则追加 + else + echo "requirepass ${redis_password}" >>redis.conf + fi + green "✓ 密码已设置" + else + # 如果用户输入为空,则注释掉密码设置 + sed -i '' 's/^requirepass .*/# requirepass foobared/' redis.conf + yellow "✓ 密码已禁用" + fi + + # 修改日志文件路径 + sed -i '' "s|^logfile.*|logfile \"${redis_logfile}\"|" redis.conf + green "✓ 日志文件路径已设置" + + # 修改网络监听 + if [[ "$listen_all" == "y" || "$listen_all" == "Y" ]]; then + # 注释掉所有 bind 开头的行,以允许所有 IP 访问 + sed -i '' 's/^bind /# bind /' redis.conf + green "✓ 已配置为全网监听" + else + # 确保只监听本地回环地址 + sed -i '' 's/^# bind 127.0.0.1 -::1/bind 127.0.0.1 -::1/' redis.conf + green "✓ 已配置为仅本地监听" + fi + + green "----------------------------------------" + green "redis.conf 配置修改完成!" +} + +startRedis() { + local workdir="${installpath}/serv00-play/redis" + if [[ ! -d "$workdir" ]]; then + red "未安装redis,请先安装!" + return 1 + fi + cd "$workdir" + if checkProcAlive "redis-server"; then + red "redis已启动,请勿重复启动!" + return 1 + fi + echo "正在启动redis..." + nohup redis-server ./redis.conf >/dev/null 2>&1 & + sleep 2 + if checkProcAlive "redis-server"; then + green "启动成功!" + else + echo "启动失败!" + fi +} +stopRedis() { + local workdir="${installpath}/serv00-play/redis" + if [[ ! -d "$workdir" ]]; then + red "未安装redis,请先安装!" + return 1 + fi + cd "$workdir" + if ! checkProcAlive "redis-server"; then + red "redis未启动!" + return 1 + fi + echo "正在停止redis..." + stopProc "redis-server" + sleep 2 + if ! checkProcAlive "redis-server"; then + green "停止成功!" + else + echo "未能停止,请手动杀进程!" + fi +} + +uninstallRedis() { + local input=$1 + local workdir="${installpath}/serv00-play/redis" + if [[ ! -d "$workdir" ]]; then + red "未安装redis,请先安装!" + return 1 + fi + if [ -z "$input" ]; then + read -p "是否卸载? [y/n] [n]:" input + input=${input:-n} + if [[ "$input" != "y" ]]; then + return 1 + fi + fi + stopRedis + rm -rf "$workdir" + green "卸载成功" +} + +redisManage() { + while true; do + yellow "---------------------" + echo "redis管理:" + echo "服务状态: $(checkProcStatus redis-server)" + echo "1. 安装/修改配置" + echo "2. 启动" + echo "3. 停止" + echo "8. 卸载" + echo "9. 返回主菜单" + echo "0. 退出脚本" + yellow "---------------------" + read -p "请选择:" input + case $input in + 1) + installRedis + ;; + 2) + startRedis + ;; + 3) + stopRedis + ;; + 8) + uninstallRedis + ;; + 9) + break + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu + +} + +devManage() { + if ! checkInstalled "serv00-play"; then + return 1 + fi + while true; do + yellow "---------------------" + echo "开发工具管理:" + echo "1. redis" + echo "0. 退出脚本" + yellow "---------------------" + + read -p "请选择:" input + + case $input in + 1) + redisManage + ;; + 0) + exit 0 + ;; + *) + echo "无效选项,请重试" + ;; + esac + done + showMenu + +} + +linkAliveStatment() { + cat </dev/null) + if [ $? -ne 0 ]; then + echo null + else + echo $ver + fi +} + +showMenu() { + art_wrod=$(figlet "serv00-play") + echo "<------------------------------------------------------------------>" + echo -e "${CYAN}${art_wrod}${RESET}" + echo -e "${GREEN} 饭奇骏频道:https://www.youtube.com/@frankiejun8965 ${RESET}" + echo -e "${GREEN} TG交流群:https://t.me/fanyousuiqun ${RESET}" + echo -e "${GREEN} 当前版本号:$(getCurrentVer) 最新版本号:$(getLatestVer) ${RESET}" + echo "<------------------------------------------------------------------>" + echo "请选择一个选项:" + + options=("安装/更新serv00-play项目" "sun-panel" "webssh" "阅后即焚" "linkalive" "设置保活的项目" "配置sing-box" + "运行sing-box" "停止sing-box" "显示sing-box节点信息" "快照恢复" "系统初始化" "前置工作及设置中国时区" "哪吒探针管理" "哪吒面板管理" "设置彩色开机字样" "显示本机IP" + "mtproto代理" "alist管理" "端口管理" "域名证书管理" "一键root" "自动检测主机IP状态" "一键更换hy2的IP" "KeepAlive" "Domains-Support" "微信消息推送界面管理" + "开发工具管理" "备份/恢复" "卸载") + + select opt in "${options[@]}"; do + case $REPLY in + 1) + install + ;; + 2) + sunPanelServ + ;; + 3) + websshServ + ;; + 4) + burnAfterReadingServ + ;; + 5) + linkAliveServ + ;; + 6) + setConfig + ;; + 7) + configSingBox + ;; + 8) + startSingBox + ;; + 9) + stopSingBox + ;; + 10) + showSingBoxInfo + ;; + 11) + ImageRecovery + ;; + 12) + InitServer + ;; + 13) + setCnTimeZone + ;; + 14) + manageNeZhaAgent + ;; + 15) + manageNeZhaBoard + ;; + 16) + setColorWord + ;; + 17) + showIP + ;; + 18) + mtprotoServ + ;; + 19) + alistServ + ;; + 20) + portServ + ;; + 21) + domainSSLServ + ;; + 22) + rootServ + ;; + 23) + showIPStatus + ;; + 24) + changeHy2IP + ;; + 25) + keepAliveServ + ;; + 26) + DSServ + ;; + 27) + manageWxPushSkin + ;; + 28) + devManage + ;; + 29) + backupRestoreServ + ;; + 30) + uninstall + ;; + 0) + echo "退出" + exit 0 + ;; + *) + echo "无效的选项 " + ;; + esac + + done + +} + +if [ "$1" == "--uninstall" ]; then + echo "执行卸载操作" + uninstall "y" + exit 0 +elif [ "$1" == "--install" ]; then + echo "执行更新操作" + install "y" + exit 0 +else + showMenu +fi diff --git a/tgsend.sh b/tgsend.sh index 4eaa6008..916c338d 100755 --- a/tgsend.sh +++ b/tgsend.sh @@ -1,21 +1,116 @@ #!/bin/bash message_text=$1 -#解析模式,可选HTML或Markdown -MODE='HTML' -#api接口 + +replaceValue() { + local url=$1 + local target=$2 + local value=$3 + local result + result=$(printf '%s' "$url" | sed "s|#${target}|${value//&/\\&}|g") + echo "$result" +} + +toBase64() { + echo -n "$1" | base64 +} + +urlencode() { + local input="$1" + local output="" + local length=${#input} + for ((i = 0; i < length; i++)); do + local char="${input:i:1}" + case "$char" in + [a-zA-Z0-9.~_-]) output+="$char" ;; + *) output+="$(printf '%%%02X' "'$char")" ;; + esac + done + echo "$output" +} + +toTGMsg() { + local msg=$1 + local title="*Serv00-play通知*" + local host_icon="🖥️" + local user_icon="👤" + local time_icon="⏰" + local notify_icon="📢" + + # 获取当前时间 + local current_time=$(date "+%Y-%m-%d %H:%M:%S") + + if [[ "$msg" != Host:* ]]; then + local formatted_msg="${title} \n\n" + formatted_msg+="${time_icon} *时间:* ${current_time} \n" + formatted_msg+="${notify_icon} *通知内容:* \n$msg \n\n" + echo -e "$formatted_msg" + return + fi + + local host=$(echo "$msg" | sed -n 's/.*Host:\([^,]*\).*/\1/p' | xargs) + local user=$(echo "$msg" | sed -n 's/.*user:\([^,]*\).*/\1/p' | xargs) + local notify_content=$(echo "$msg" | sed -E 's/.*user:[^,]*,//' | xargs) + + # 格式化消息内容,Markdown 换行使用两个空格 + 换行 + local formatted_msg="${title} \n\n" + formatted_msg+="${host_icon} *主机:* ${host} \n" + formatted_msg+="${user_icon} *用户:* ${user} \n" + formatted_msg+="${time_icon} *时间:* ${current_time} \n\n" + formatted_msg+="${notify_icon} *通知内容:* ${notify_content} \n\n" + + echo -e "$formatted_msg|${host}|${user}" # 使用 -e 选项以确保换行符生效 +} + telegramBotToken=${TELEGRAM_TOKEN} telegramBotUserId=${TELEGRAM_USERID} +result=$(toTGMsg "$message_text") +formatted_msg=$(echo "$result" | awk -F'|' '{print $1}') +host=$(echo "$result" | awk -F'|' '{print $2}') +user=$(echo "$result" | awk -F'|' '{print $3}') + +if [[ "$BUTTON_URL" == "null" ]]; then + button_url="https://www.youtube.com/@frankiejun8965" +else + button_url=${BUTTON_URL:-"https://www.youtube.com/@frankiejun8965"} +fi URL="https://api.telegram.org/bot${telegramBotToken}/sendMessage" + +if [[ -n "$host" ]]; then + button_url=$(replaceValue $button_url HOST $host) +fi +if [[ -n "$user" ]]; then + button_url=$(replaceValue $button_url USER $user) +fi +if [[ -n "$PASS" ]]; then + pass=$(toBase64 $PASS) + button_url=$(replaceValue $button_url PASS $pass) +fi +encoded_url=$(urlencode "$button_url") +#echo "encoded_url: $encoded_url" +reply_markup='{ + "inline_keyboard": [ + [ + {"text": "点击查看", "url": "'"${encoded_url}"'"} + ] + ] + }' +#echo "reply_markup: $reply_markup" +#echo "telegramBotToken:$telegramBotToken,telegramBotUserId:$telegramBotUserId" if [[ -z ${telegramBotToken} ]]; then echo "未配置TG推送" else - res=$(timeout 20s curl -s -X POST $URL -d chat_id=${telegramBotUserId} -d parse_mode=${MODE} -d text="${message_text}") + res=$(curl -s -X POST "https://api.telegram.org/bot${telegramBotToken}/sendMessage" \ + -d chat_id="${telegramBotUserId}" \ + -d parse_mode="Markdown" \ + -d text="$formatted_msg" \ + -d reply_markup="$reply_markup") if [ $? == 124 ]; then echo 'TG_api请求超时,请检查网络是否重启完成并是否能够访问TG' exit 1 fi + #echo "res:$res" resSuccess=$(echo "$res" | jq -r ".ok") if [[ $resSuccess = "true" ]]; then echo "TG推送成功" diff --git a/utils.sh b/utils.sh index b1f4ef4a..e97c5680 100644 --- a/utils.sh +++ b/utils.sh @@ -9,397 +9,438 @@ CYAN='\033[0;96m' WHITE='\033[0;37m' RESET='\033[0m' yellow() { - echo -e "${YELLOW}$1${RESET}" + echo -e "${YELLOW}$1${RESET}" } green() { - echo -e "${GREEN}$1${RESET}" + echo -e "${GREEN}$1${RESET}" } red() { - echo -e "${RED}$1${RESET}" + echo -e "${RED}$1${RESET}" } installpath="$HOME" +baseurl="https://ss.fkj.pp.ua" +linkBaseurl="https://la.fkj.pp.ua" checknezhaAgentAlive() { - if ps aux | grep nezha-agent | grep -v "grep" >/dev/null; then - return 0 - else - return 1 - fi + if ps aux | grep nezha-agent | grep -v "grep" >/dev/null; then + return 0 + else + return 1 + fi } checkvmessAlive() { - local c=0 - if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then - ((c++)) - fi + local c=0 + if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then + ((c++)) + fi - if ps aux | grep cloudflared | grep -v "grep" >/dev/null; then - ((c++)) - fi + if ps aux | grep cloudflared | grep -v "grep" >/dev/null; then + ((c++)) + fi - if [ $c -eq 2 ]; then - return 0 - fi + if [ $c -eq 2 ]; then + return 0 + fi - return 1 # 有一个或多个进程不在运行 + return 1 # 有一个或多个进程不在运行 } #返回0表示成功, 1表示失败 #在if条件中,0会执行,1不会执行 checkProcAlive() { - local procname=$1 - if ps aux | grep "$procname" | grep -v "grep" >/dev/null; then - return 0 - else - return 1 - fi + local procname=$1 + if ps aux | grep "$procname" | grep -v "grep" >/dev/null; then + return 0 + else + return 1 + fi } stopProc() { - local procname=$1 - r=$(ps aux | grep "$procname" | grep -v "grep" | awk '{print $2}') - if [ -z "$r" ]; then - return 0 - else - kill -9 $r - fi - echo "已停掉$procname!" + local procname=$1 + r=$(ps aux | grep "$procname" | grep -v "grep" | awk '{print $2}') + if [ -z "$r" ]; then + return 0 + else + kill -9 $r + fi + echo "已停掉$procname!" + return 0 } checkSingboxAlive() { - local c=0 - if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then - ((c++)) - fi + local c=0 + if ps aux | grep serv00sb | grep -v "grep" >/dev/null; then + ((c++)) + fi - if ps aux | grep cloudflare | grep -v "grep" >/dev/null; then - ((c++)) - fi + if ps aux | grep cloudflare | grep -v "grep" >/dev/null; then + ((c++)) + fi - if [ $c -eq 2 ]; then - return 0 - fi + if [ $c -eq 2 ]; then + return 0 + fi - return 1 # 有一个或多个进程不在运行 + return 1 # 有一个或多个进程不在运行 } checkMtgAlive() { - if ps aux | grep mtg | grep -v "grep" >/dev/null; then - return 0 - else - return 1 - fi + if ps aux | grep mtg | grep -v "grep" >/dev/null; then + return 0 + else + return 1 + fi } stopNeZhaAgent() { - r=$(ps aux | grep nezha-agent | grep -v "grep" | awk '{print $2}') - if [ -z "$r" ]; then - return 0 - else - kill -9 $r - fi - echo "已停掉nezha-agent!" + r=$(ps aux | grep nezha-agent | grep -v "grep" | awk '{print $2}') + if [ -z "$r" ]; then + return 0 + else + kill -9 $r + fi + echo "已停掉nezha-agent!" } writeWX() { - has_fd=$(echo "$config_content" | jq 'has("wxsendkey")') - if [ "$has_fd" == "true" ]; then - wx_sendkey=$(echo "$config_content" | jq -r ".wxsendkey") - read -p "已有 WXSENDKEY ($wx_sendkey), 是否修改? [y/n] [n]:" input - input=${input:-n} - if [ "$input" == "y" ]; then - read -p "请输入 WXSENDKEY:" wx_sendkey - fi - json_content+=" \"wxsendkey\": \"${wx_sendkey}\", \n" - else - read -p "请输入 WXSENDKEY:" wx_sendkey - json_content+=" \"wxsendkey\": \"${wx_sendkey}\", \n" - fi + has_fd=$(echo "$config_content" | jq 'has("wxsendkey")') + if [ "$has_fd" == "true" ]; then + wx_sendkey=$(echo "$config_content" | jq -r ".wxsendkey") + read -p "已有 WXSENDKEY ($wx_sendkey), 是否修改? [y/n] [n]:" input + input=${input:-n} + if [ "$input" == "y" ]; then + read -p "请输入 WXSENDKEY:" wx_sendkey + fi + json_content+=" \"wxsendkey\": \"${wx_sendkey}\", \n" + else + read -p "请输入 WXSENDKEY:" wx_sendkey + json_content+=" \"wxsendkey\": \"${wx_sendkey}\", \n" + fi } writeTG() { - has_fd=$(echo "$config_content" | jq 'has("telegram_token")') - if [ "$has_fd" == "true" ]; then - tg_token=$(echo "$config_content" | jq -r ".telegram_token") - read -p "已有 TELEGRAM_TOKEN ($tg_token), 是否修改? [y/n] [n]:" input - input=${input:-n} - if [ "$input" == "y" ]; then - read -p "请输入 TELEGRAM_TOKEN:" tg_token - fi - json_content+=" \"telegram_token\": \"${tg_token}\", \n" - else - read -p "请输入 TELEGRAM_TOKEN:" tg_token - json_content+=" \"telegram_token\": \"${tg_token}\", \n" - fi - - has_fd=$(echo "$config_content" | jq 'has("telegram_userid")') - if [ "$has_fd" == "true" ]; then - tg_userid=$(echo "$config_content" | jq -r ".telegram_userid") - read -p "已有 TELEGRAM_USERID ($tg_userid), 是否修改? [y/n] [n]:" input - input=${input:-n} - if [ "$input" == "y" ]; then - read -p "请输入 TELEGRAM_USERID:" tg_userid - fi - json_content+=" \"telegram_userid\": \"${tg_userid}\", \n" - else - read -p "请输入 TELEGRAM_USERID:" tg_userid - json_content+=" \"telegram_userid\": \"${tg_userid}\",\n" - fi + has_fd=$(echo "$config_content" | jq 'has("telegram_token")') + if [ "$has_fd" == "true" ]; then + tg_token=$(echo "$config_content" | jq -r ".telegram_token") + read -p "已有 TELEGRAM_TOKEN ($tg_token), 是否修改? [y/n] [n]:" input + input=${input:-n} + if [ "$input" == "y" ]; then + read -p "请输入 TELEGRAM_TOKEN:" tg_token + fi + json_content+=" \"telegram_token\": \"${tg_token}\", \n" + else + read -p "请输入 TELEGRAM_TOKEN:" tg_token + json_content+=" \"telegram_token\": \"${tg_token}\", \n" + fi + + has_fd=$(echo "$config_content" | jq 'has("telegram_userid")') + if [ "$has_fd" == "true" ]; then + tg_userid=$(echo "$config_content" | jq -r ".telegram_userid") + read -p "已有 TELEGRAM_USERID ($tg_userid), 是否修改? [y/n] [n]:" input + input=${input:-n} + if [ "$input" == "y" ]; then + read -p "请输入 TELEGRAM_USERID:" tg_userid + fi + json_content+=" \"telegram_userid\": \"${tg_userid}\", \n" + else + read -p "请输入 TELEGRAM_USERID:" tg_userid + json_content+=" \"telegram_userid\": \"${tg_userid}\",\n" + fi } cleanCron() { - echo "" >null - crontab null - rm null + echo "" >null + crontab null + rm null } delCron() { - crontab -l | grep -v "keepalive" >mycron - crontab mycron >/dev/null 2>&1 - rm mycron + crontab -l | grep -v "keepalive" >mycron + crontab mycron >/dev/null 2>&1 + rm mycron } addCron() { - local tm=$1 - crontab -l | grep -v "keepalive" >mycron - echo "*/$tm * * * * bash ${installpath}/serv00-play/keepalive.sh > /dev/null 2>&1 " >>mycron - crontab mycron >/dev/null 2>&1 - rm mycron + local tm=$1 + crontab -l | grep -v "keepalive" >mycron + echo "*/$tm * * * * bash ${installpath}/serv00-play/keepalive.sh > /dev/null 2>&1 " >>mycron + crontab mycron >/dev/null 2>&1 + rm mycron } get_webip() { - # 获取主机名称,例如:s2.serv00.com - local hostname=$(hostname) - - # 提取主机名称中的数字,例如:2 - local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') - - # 构造主机名称的数组 - local hosts=("web${host_number}.serv00.com" "cache${host_number}.serv00.com") - - # 初始化最终 IP 变量 - local final_ip="" - - # 遍历主机名称数组 - for host in "${hosts[@]}"; do - # 获取 API 返回的数据 - local response=$(curl -s "https://ss.botai.us.kg/api/getip?host=$host") - - # 检查返回的结果是否包含 "not found" - if [[ "$response" =~ "not found" ]]; then - continue - fi - - # 提取第一个字段作为 IP,并检查第二个字段是否为 "Accessible" - local ip=$(echo "$response" | awk -F "|" '{ if ($2 == "Accessible") print $1 }') - # webxx.serv00.com域名对应的ip作为兜底ip - if [[ "$host" == "web${host_number}.serv00.com" ]]; then - final_ip=$(echo "$response" | awk -F "|" '{print $1}') - fi - - # 如果找到了 "Accessible",返回 IP - if [[ -n "$ip" ]]; then - echo "$ip" - return - fi - done - - echo "$final_ip" + # 获取主机名称,例如:s2.serv00.com + local hostname=$(hostname) + + # 提取主机名称中的数字,例如:2 + local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') + + # 构造主机名称的数组 + local hosts=("web${host_number}.$(getDoMain)" "cache${host_number}.$(getDoMain)") + + # 初始化最终 IP 变量 + local final_ip="$(devil vhost list | grep web | awk '{print $1}')" + local hostmain=$(getDoMain) + hostmain="${hostmain%.com}" + # 遍历主机名称数组 + for host in "${hosts[@]}"; do + # 获取 API 返回的数据 + local response=$(curl -s "${baseurl}/api/getip?host=$host&type=$hostmain") + + # 检查返回的结果是否包含 "not found" + if [[ "$response" =~ "not found" ]]; then + continue + fi + + # 提取第一个字段作为 IP,并检查第二个字段是否为 "Accessible" + local ip=$(echo "$response" | awk -F "|" '{ if ($2 == "Accessible") print $1 }') + # webxx.serv00.com域名对应的ip作为兜底ip + if [[ "$host" == "web${host_number}.$(getDoMain)" ]]; then + final_ip=$(echo "$response" | awk -F "|" '{print $1}') + fi + + # 如果找到了 "Accessible",返回 IP + if [[ -n "$ip" ]]; then + echo "$ip" + return + fi + done + + echo "$final_ip" } get_ip() { - # 获取主机名称,例如:s2.serv00.com - local hostname=$(hostname) + # 获取主机名称,例如:s2.serv00.com + local hostname=$(hostname) - # 提取主机名称中的数字,例如:2 - local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') + # 提取主机名称中的数字,例如:2 + local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') - # 构造主机名称的数组 - local hosts=("cache${host_number}.serv00.com" "web${host_number}.serv00.com" "$hostname") + # 构造主机名称的数组 + local hosts=("cache${host_number}.$(getDoMain)" "web${host_number}.$(getDoMain)" "$hostname") - # 初始化最终 IP 变量 - local final_ip="" + # 初始化最终 IP 变量 + local final_ip="$(curl -s icanhazip.com)" - # 遍历主机名称数组 - for host in "${hosts[@]}"; do - # 获取 API 返回的数据 - local response=$(curl -s "https://ss.botai.us.kg/api/getip?host=$host") + local hostmain=$(getDoMain) + hostmain="${hostmain%.com}" + # 遍历主机名称数组 + for host in "${hosts[@]}"; do + # 获取 API 返回的数据 + local response=$(curl -s "${baseurl}/api/getip?host=$host&type=$hostmain") - # 检查返回的结果是否包含 "not found" - if [[ "$response" =~ "not found" ]]; then - continue - fi + # 检查返回的结果是否包含 "not found" + if [[ "$response" =~ "not found" ]]; then + continue + fi - # 提取第一个字段作为 IP,并检查第二个字段是否为 "Accessible" - local ip=$(echo "$response" | awk -F "|" '{ if ($2 == "Accessible") print $1 }') + # 提取第一个字段作为 IP,并检查第二个字段是否为 "Accessible" + local ip=$(echo "$response" | awk -F "|" '{ if ($2 == "Accessible") print $1 }') - # 如果找到了 "Accessible",返回 IP - if [[ -n "$ip" ]]; then - echo "$ip" - return - fi + # 如果找到了 "Accessible",返回 IP + if [[ -n "$ip" ]]; then + echo "$ip" + return + fi - final_ip=$ip - done + final_ip=$ip + done - echo "$final_ip" + echo "$final_ip" } isServ00() { - [[ $(hostname) == *"serv00"* ]] + [[ $(hostname) == *"serv00"* ]] +} + +getDoMain() { + if isServ00; then + echo -n "serv00.com" + else + echo -n "hostuno.com" + fi +} + +getUserDoMain() { + local proc=$1 + local baseDomain="" + user="$(whoami)" + if isServ00; then + baseDomain="$user.serv00.net" + else + baseDomain="$user.useruno.com" + fi + if [[ -n "$proc" ]]; then + echo -n "$proc.$baseDomain" + else + echo -n "$baseDomain" + fi } #获取端口 getPort() { - local type=$1 - local opts=$2 - - local key="$type|$opts" - #echo "key: $key" - #port list中查找,如果没有随机分配一个 - if [[ -n "${port_array["$key"]}" ]]; then - #echo "找到list中的port" - echo "${port_array["$key"]}" - else - # echo "devil port add $type random $opts" - rt=$(devil port add $type random $opts) - if [[ "$rt" =~ .*succesfully.*$ || "$rt" =~ .*Ok.*$ ]]; then - loadPort - if [[ -n "$port_array["$key"]" ]]; then - echo "${port_array["$key"]}" - else - echo "failed" - fi - else - echo "failed" - fi - fi + local type=$1 + local opts=$2 + + local key="$type|$opts" + #echo "key: $key" + #port list中查找,如果没有随机分配一个 + if [[ -n "${port_array["$key"]}" ]]; then + #echo "找到list中的port" + echo "${port_array["$key"]}" + else + # echo "devil port add $type random $opts" + rt=$(devil port add $type random $opts) + if [[ "$rt" =~ .*succesfully.*$ || "$rt" =~ .*Ok.*$ ]]; then + loadPort + if [[ -n "${port_array["$key"]}" ]]; then + echo "${port_array["$key"]}" + else + echo "failed" + fi + else + echo "failed" + fi + fi } randomPort() { - local type=$1 - local opts=$2 - port="" - #echo "type:$type, opts:$opts" - read -p "是否自动分配${opts}端口($type)?[y/n] [y]:" input - input=${input:-y} - if [[ "$input" == "y" ]]; then - port=$(getPort $type $opts) - if [[ "$port" == "failed" ]]; then - read -p "自动分配端口失败,请手动输入${opts}端口:" port - else - green "自动分配${opts}端口为:${port}" - fi - else - read -p "请输入${opts}端口($type):" port - fi + local type=$1 + local opts=$2 + port="" + #echo "type:$type, opts:$opts" + read -p "是否自动分配${opts}端口($type)?[y/n] [y]:" input + input=${input:-y} + if [[ "$input" == "y" ]]; then + port=$(getPort $type $opts) + if [[ "$port" == "failed" ]]; then + read -p "自动分配端口失败,请手动输入${opts}端口:" port + else + green "自动分配${opts}端口为:${port}" + fi + else + read -p "请输入${opts}端口($type):" port + fi } declare -A port_array #检查是否可以自动分配端口 loadPort() { - output=$(devil port list) - - port_array=() - # 解析输出内容 - index=0 - while read -r port typ opis; do - # 跳过标题行 - if [[ "$port" =~ "Port" ]]; then - continue - fi - #echo "port:$port,typ:$typ, opis:$opis" - if [[ "$port" =~ "Brak" || "$port" == "No" ]]; then - echo "未分配端口" - return 0 - fi - # 将 Typ 和 Opis 合并并存储到数组中 - if [[ -n "$typ" ]]; then - # 如果 Opis 为空则用空字符串代替 - opis=${opis:-""} - combined="${typ}|${opis}" - port_array["$combined"]="$port" - # echo "port_array 读入 key=$combined, value=$port" - ((index++)) - fi - done <<<"$output" - - return 0 + output=$(devil port list) + + port_array=() + # 解析输出内容 + index=0 + while read -r port typ opis; do + # 跳过标题行 + if [[ "$port" =~ "Port" ]]; then + continue + fi + #echo "port:$port,typ:$typ, opis:$opis" + if [[ "$port" =~ "Brak" || "$port" == "No" ]]; then + echo "未分配端口" + return 0 + fi + # 将 Typ 和 Opis 合并并存储到数组中 + if [[ -n "$typ" ]]; then + # 如果 Opis 为空则用空字符串代替 + opis=${opis:-""} + combined="${typ}|${opis}" + port_array["$combined"]="$port" + # echo "port_array 读入 key=$combined, value=$port" + ((index++)) + fi + done <<<"$output" + + return 0 } cleanPort() { - output=$(devil port list) - while read -r port typ opis; do - # 跳过标题行 - if [[ "$typ" == "Type" ]]; then - continue - fi - if [[ "$port" == "Brak" || "$port" == "No" ]]; then - return 0 - fi - if [[ -n "$typ" ]]; then - devil port del $typ $port >/dev/null 2>&1 - fi - done <<<"$output" - return 0 -} - + output=$(devil port list) + while read -r port typ opis; do + # 跳过标题行 + if [[ "$typ" == "Type" ]]; then + continue + fi + if [[ "$port" == "Brak" || "$port" == "No" ]]; then + return 0 + fi + if [[ -n "$typ" ]]; then + devil port del $typ $port >/dev/null 2>&1 + fi + done <<<"$output" + return 0 +} + +ISIDR=1 +ISFILE=0 +ISVIP=1 +NOTVIP=0 checkDownload() { - local file=$1 - local filegz="$file.gz" - local is_dir=${2:-0} - - if [[ $is_dir -eq 1 ]]; then - filegz="$file.tar.gz" - fi - - #检查并下载核心程序 - if [[ ! -e $file ]] || [[ $(file $file) == *"text"* ]]; then - echo "正在下载 $file..." - url="https://gfg.fkj.pp.ua/app/serv00/$filegz?pwd=fkjyyds666" - curl -L -sS --max-time 20 -o $filegz "$url" - - if file $filegz | grep -q "text"; then - echo "无法正确下载!!!" - rm -f $filegz - return 1 - fi - if [ -e $filegz ]; then - if [[ $is_dir -eq 1 ]]; then - tar -zxf $filegz - else - gzip -d $filegz - fi - else - echo "下载失败,可能是网络问题." - return 1 - fi - #下载失败 - if [[ $is_dir -eq 0 && ! -e $file ]]; then - echo "无法下载核心程序,可能网络问题,请检查!" - return 1 - fi - # 设置可执行权限 - if [[ $is_dir -eq 0 ]]; then - chmod +x "$file" - fi - echo "下载完毕!" - fi - return 0 + local file=$1 + local is_dir=${2:-0} + local passwd=${3:-"fkjyyds666"} + local vipflag=${4:-0} + local filegz="$file.gz" + + if [[ $is_dir -eq 1 ]]; then + filegz="$file.tar.gz" + fi + + #检查并下载核心程序 + if [[ ! -e $file ]] || [[ $(file $file) == *"text"* ]]; then + echo "正在下载 $file..." + if [[ $vipflag -eq 1 ]]; then + url="https://gfg.fkj.pp.ua/app/vip/$filegz?pwd=$passwd" + else + url="https://gfg.fkj.pp.ua/app/serv00/$filegz?pwd=$passwd" + fi + #echo "url:$url" + curl -L -sS --max-time 20 -o $filegz "$url" + + if file $filegz | grep -q "text"; then + echo "无法正确下载!!!" + rm -f $filegz + return 1 + fi + if [ -e $filegz ]; then + if [[ $is_dir -eq 1 ]]; then + tar -zxf $filegz + else + gzip -d $filegz + fi + else + echo "下载失败,可能是网络问题." + return 1 + fi + #下载失败 + if [[ $is_dir -eq 0 && ! -e $file ]]; then + echo "无法下载核心程序,可能网络问题,请检查!" + return 1 + fi + # 设置可执行权限 + if [[ $is_dir -eq 0 ]]; then + chmod +x "$file" + fi + echo "下载完毕!" + fi + return 0 } # 对json文件字段进行插入或修改 # usage: upInsertFd jsonfile fieldname value upInsertFd() { - local jsonfile=$1 - local field=$2 - local value=$3 + local jsonfile=$1 + local field=$2 + local value=$3 - jq --arg field "$field" --arg value "$value" ' + jq --arg field "$field" --arg value "$value" ' if has($field) then .[$field] = $value else @@ -407,137 +448,402 @@ upInsertFd() { end ' "$jsonfile" >tmp.json && mv tmp.json "$jsonfile" - return $? + return $? } # 针对singbox.json, 对指定字段进行修改 upSingboxFd() { - local jsonfile=$1 - local array_name=$2 - local selector_key=$3 - local selector_value=$4 - local field_path=$5 - local value=$6 - - jq --arg selector_key "$selector_key" \ - --arg selector_value "$selector_value" \ - --arg field_path "$field_path" \ - --arg value "$value" " + local jsonfile=$1 + local array_name=$2 + local selector_key=$3 + local selector_value=$4 + local field_path=$5 + local value=$6 + + jq --arg selector_key "$selector_key" \ + --arg selector_value "$selector_value" \ + --arg field_path "$field_path" \ + --arg value "$value" " (.$array_name[] | select(.$selector_key == \$selector_value) | .[\$field_path]) = \$value " "$jsonfile" >tmp.json && mv tmp.json "$jsonfile" - return $? + return $? } # php默认配置文件操作 PHPCONFIG_FILE="phpconfig.json" # 判断JSON文件是否存在,若不存在则创建并初始化 initialize_json() { - if [ ! -f "$PHPCONFIG_FILE" ]; then - echo '{"domains": []}' >"$PHPCONFIG_FILE" - fi + if [ ! -f "$PHPCONFIG_FILE" ]; then + echo '{"domains": []}' >"$PHPCONFIG_FILE" + fi } # 添加新域名 add_domain() { - local new_domain="$1" - local webip="$2" + local new_domain="$1" + local webip="$2" - # 初始化JSON文件(如果不存在的话) - initialize_json + # 初始化JSON文件(如果不存在的话) + initialize_json - # 读取当前的JSON配置文件并检查域名是否已存在 - if grep -q "\"$new_domain\"" "$PHPCONFIG_FILE"; then - echo "域名 '$new_domain' 已存在!" - return 1 - fi + # 读取当前的JSON配置文件并检查域名是否已存在 + if grep -q "\"$new_domain\"" "$PHPCONFIG_FILE"; then + echo "域名 '$new_domain' 已存在!" + return 1 + fi - # 使用jq来处理JSON,添加新的域名到domains数组 - #jq --arg domain "$new_domain" '.domains += [$domain]' "$PHPCONFIG_FILE" >temp.json && mv temp.json "$PHPCONFIG_FILE" - jq ".domains += [{\"domain\": \"$domain\", \"webip\": \"$webip\"}]" "$PHPCONFIG_FILE" >"$PHPCONFIG_FILE.tmp" && mv "$PHPCONFIG_FILE.tmp" "$PHPCONFIG_FILE" - #echo "域名 '$new_domain' 添加成功!" - return 0 + # 使用jq来处理JSON,添加新的域名到domains数组 + #jq --arg domain "$new_domain" '.domains += [$domain]' "$PHPCONFIG_FILE" >temp.json && mv temp.json "$PHPCONFIG_FILE" + jq ".domains += [{\"domain\": \"$domain\", \"webip\": \"$webip\"}]" "$PHPCONFIG_FILE" >"$PHPCONFIG_FILE.tmp" && mv "$PHPCONFIG_FILE.tmp" "$PHPCONFIG_FILE" + #echo "域名 '$new_domain' 添加成功!" + return 0 } # 删除域名 delete_domain() { - local domain_to_delete="$1" + local domain_to_delete="$1" - # 初始化JSON文件(如果不存在的话) - initialize_json + # 初始化JSON文件(如果不存在的话) + initialize_json - # 读取当前的JSON配置文件并检查域名是否存在 - if ! grep -q "\"$domain_to_delete\"" "$PHPCONFIG_FILE"; then - echo "域名 '$domain_to_delete' 不存在!" - return 1 - fi + # 读取当前的JSON配置文件并检查域名是否存在 + if ! grep -q "\"$domain_to_delete\"" "$PHPCONFIG_FILE"; then + echo "域名 '$domain_to_delete' 不存在!" + return 1 + fi - local webip=$(jq -r ".domains[] | select(.domain == \"$domain\") | .webip" "$PHPCONFIG_FILE") - # 使用jq来处理JSON,删除指定的域名 - jq "del(.domains[] | select(.domain == \"$domain\"))" "$PHPCONFIG_FILE" >"$PHPCONFIG_FILE.tmp" && mv "$PHPCONFIG_FILE.tmp" "$PHPCONFIG_FILE" - local domainPath="$installpath/domains/$domain" - echo "正在删除域名相关服务,请等待..." - rm -rf "$domainPath" - resp=$(devil ssl www del $webip $domain) - resp=$(devil www del $domain --remove) - echo "已卸载域名[$domain_to_delete]相关服务!" - return 0 + local webip=$(jq -r ".domains[] | select(.domain == \"$domain\") | .webip" "$PHPCONFIG_FILE") + # 使用jq来处理JSON,删除指定的域名 + jq "del(.domains[] | select(.domain == \"$domain\"))" "$PHPCONFIG_FILE" >"$PHPCONFIG_FILE.tmp" && mv "$PHPCONFIG_FILE.tmp" "$PHPCONFIG_FILE" + local domainPath="$installpath/domains/$domain" + echo "正在删除域名相关服务,请等待..." + rm -rf "$domainPath" + resp=$(devil ssl www del $webip $domain) + resp=$(devil www del $domain --remove) + echo "已卸载域名[$domain_to_delete]相关服务!" + return 0 } # 判断domains数组是否为空 check_domains_empty() { - initialize_json + initialize_json - local domains_count=$(jq '.domains | length' "$PHPCONFIG_FILE") + local domains_count=$(jq '.domains | length' "$PHPCONFIG_FILE") - if [ "$domains_count" -eq 0 ]; then - return 0 - else - return 1 - fi + if [ "$domains_count" -eq 0 ]; then + return 0 + else + return 1 + fi } print_domains() { - yellow "----------------------------" - green "域名\t\t|\t服务IP" - yellow "----------------------------" + yellow "----------------------------" + green "域名\t\t|\t服务IP" + yellow "----------------------------" - # 使用jq格式化输出 - jq -r '.domains[] | "\(.domain)\t|\(.webip)"' "$PHPCONFIG_FILE" + # 使用jq格式化输出 + jq -r '.domains[] | "\(.domain)\t|\(.webip)"' "$PHPCONFIG_FILE" } delete_all_domains() { - initialize_json - - jq -r '.domains[] | "\(.domain)\t\(.webip)"' "$PHPCONFIG_FILE" | while read -r domain webip; do - echo "域名: $domain, 服务IP: $webip" - delete_domain "$domain" - done + initialize_json + + jq -r '.domains[] | "\(.domain)\t\(.webip)"' "$PHPCONFIG_FILE" | while read -r domain webip; do + echo "域名: $domain, 服务IP: $webip" + delete_domain "$domain" + done +} + +get_one_domain() { + initialize_json + + local first_domain=$(jq -r '.domains[0].domain' "$PHPCONFIG_FILE") + echo "$first_domain" +} + +download_from_net() { + local app=$1 + + case $app in + "alist") + download_from_github_release "AlistGo" "alist" "alist-freebsd-amd64.tar.gz" + ;; + "nezha-agent") + download_from_github_release "nezhahq" "agent" "nezha-agent_freebsd_amd64.zip" + ;; + "nezha-dashboard") + download_from_github_release "frankiejun" "freebsd-nezha" "dashboard.gz" + ;; + esac +} + +check_update_from_net() { + local app=$1 + + case $app in + "alist") + local current_version=$(./alist version | grep "Version: v" | awk '{print $2}') + if ! check_from_github "AlistGo" "alist" "$current_version"; then + echo "未发现新版本!" + return 1 + fi + download_from_github_release "AlistGo" "alist" "alist-freebsd-amd64.tar.gz" + ;; + "nezha-agent") + local current_version="v"$(./nezha-agent -v | awk '{print $3}') + if ! check_from_github "nezhahq" "agent" "$current_version"; then + echo "未发现新版本!" + return 1 + fi + download_from_github_release "nezhahq" "agent" "nezha-agent_freebsd_amd64.zip" + ;; + "nezha-dashboard") + local current_version=$(./nezha-dashboard -v) + if ! check_from_github "frankiejun" "freebsd-nezha" "$current_version"; then + echo "未发现新版本!" + return 1 + fi + download_from_github_release "frankiejun" "freebsd-nezha" "dashboard.gz" + ;; + esac +} + +check_from_github() { + local user=$1 + local repository=$2 + local local_version="$3" + local url="https://github.com/${user}/${repository}" + local latestUrl="$url/releases/latest" + + latest_version=$(curl -sL $latestUrl | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) + #latest_version=$(curl -sL "https://api.github.com/repos/${user}/${repository}/releases/latest" | jq -r '.tag_name // empty') + if [[ "$local_version" != "$latest_version" ]]; then + echo "发现新版本: $latest_version,当前版本: $local_version, 正在更新..." + return 0 + fi + return 1 +} + +download_allcode_from_github_release() { + local user=$1 + local repository=$2 + + local url="https://github.com/${user}/${repository}" + local latestUrl="$url/releases/latest" + local latest_version=$(curl -sL $latestUrl | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) + local download_url="${url}/archive/refs/tags/${latest_version}.zip" + + curl -sL -o "${repository}-${latest_version}.zip" "$download_url" + if [[ ! -e "${repository}-${latest_version}.zip" || -n $(file "${repository}-${latest_version}.zip" | grep "text") ]]; then + echo "下载 ${repository}-${latest_version}.zip 文件失败!" + return 1 + fi + + # 原地解压缩 + # 创建临时目录tmp + mkdir -p tmp + local clean_version="${latest_version#v}" + local target_dir="${repository}-${clean_version}" + #echo "target_dir: $target_dir" + case "${repository}-${latest_version}.zip" in + *.zip) + unzip -o "${repository}-${latest_version}.zip" -d tmp + # 使用cp命令替代mv命令,避免"Directory not empty"错误 + cp -r "tmp/${target_dir}/"* tmp/ + rm -rf "tmp/${target_dir}" + ;; + *.tar.gz) + tar -xzf "${repository}-${latest_version}.tar.gz" --xform="s|^[^/]*|tmp|" + ;; + *) + echo "不支持的文件格式" + return 1 + ;; + esac + rm -rf "${repository}-${latest_version}.zip" } download_from_github_release() { - local user=$1 - local repository=$2 - local package=$3 - local zippackage="$package.zip" - - local url="https://github.com/${user}/${repository}" - local latestUrl="$url/releases/latest" - - local latest_version=$(curl -sL $latestUrl | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) - - local download_url="${url}/releases/download/$latest_version/$zippackage" - curl -sL -o "$zippackage" "$download_url" - if [[ ! -e "$zippackage" || -n $(file "$zippackage" | grep "text") ]]; then - echo "下载 $zippackage 文件失败!" - return 1 - fi - # 原地解压缩 - unzip -o "$zippackage" -d . - if [[ $? -ne 0 ]]; then - echo "解压 $zippackage 文件失败!" - return 1 - fi - rm -rf "$zippackage" - echo "下载并解压 $zippackage 成功!" - return 0 + local user=$1 + local repository=$2 + local zippackage="$3" + + local url="https://github.com/${user}/${repository}" + local latestUrl="$url/releases/latest" + + local latest_version=$(curl -sL $latestUrl | sed -n 's/.*tag\/\(v[0-9.]*\).*/\1/p' | head -1) + #latest_version=$(curl -sL "https://api.github.com/repos/${user}/${repository}/releases/latest" | jq -r '.tag_name // empty') + local download_url="${url}/releases/download/$latest_version/$zippackage" + curl -sL -o "$zippackage" "$download_url" + if [[ ! -e "$zippackage" || -n $(file "$zippackage" | grep "text") ]]; then + echo "下载 $zippackage 文件失败!" + return 1 + fi + # 原地解压缩 + case "$zippackage" in + *.zip) + unzip -o "$zippackage" -d . + ;; + *.tar.gz | *.tgz) + tar -xzf "$zippackage" + ;; + *.tar.bz2 | *.tbz2) + tar -xjf "$zippackage" + ;; + *.tar.xz | *.txz) + tar -xJf "$zippackage" + ;; + *.gz) + gzip -d "$zippackage" + ;; + *.tar) + tar -xf "$zippackage" + ;; + *) + echo "不支持的文件格式: $zippackage" + return 1 + ;; + esac + + if [[ $? -ne 0 ]]; then + echo "解压 $zippackage 文件失败!" + return 1 + fi + + rm -rf "$zippackage" + echo "下载并解压 $zippackage 成功!" + return 0 +} + +clean_all_domains() { + echo "正在清理域名..." + output=$(devil www list) + if echo "$output" | grep -q "No elements to display"; then + echo "没有发现在用域名." + return 0 + fi + domains=($(echo "$output" | awk 'NF && NR>2 {print $1}')) + + for domain in "${domains[@]}"; do + devil www del $domain --remove + done + echo "域名清理完毕!" +} + +create_default_domain() { + echo "正在创建默认域名..." + local domain=$(getUserDoMain) + domain="${domain,,}" + devil www add $domain php + echo "默认域名创建成功!" +} + +clean_all_dns() { + echo "正在清理DNS..." + output=$(devil dns list) + if echo "$output" | grep -q "No elements to display"; then + echo "没有发现在用DNS." + return 0 + fi + domains=($(echo "$output" | awk 'NF && NR>2 {print $1}')) + + for domain in "${domains[@]}"; do + devil dns del $domain + done + echo "DNS清理完毕!" +} + +show_ip_status() { + localIPs=() + useIPs=() + local hostname=$(hostname) + local host_number=$(echo "$hostname" | awk -F'[s.]' '{print $2}') + local hosts=("cache${host_number}.$(getDoMain)" "web${host_number}.$(getDoMain)" "$hostname") + local hostmain=$(getDoMain) + hostmain="${hostmain%.com}" + # 遍历主机名称数组 + local i=0 + for host in "${hosts[@]}"; do + ((i++)) + # 获取 API 返回的数据 + local response=$(curl -s "${baseurl}/api/getip?host=$host&type=$hostmain") + + # 检查返回的结果是否包含 "not found" + if [[ "$response" =~ "not found" ]]; then + echo "未识别主机${host}, 请联系作者饭奇骏!" + return + fi + local ip=$(echo "$response" | awk -F "|" '{print $1 }') + local status=$(echo "$response" | awk -F "|" '{print $2 }') + localIPs+=("$ip") + if [[ "$status" == "Accessible" ]]; then + useIPs+=("$ip") + fi + printf "%-2d %-20s | %-15s | %-10s\n" $i "$host" "$ip" "$status" + done +} + +stop_sing_box() { + cd ${installpath}/serv00-play/singbox + if [ -f killsing-box.sh ]; then + chmod 755 ./killsing-box.sh + ./killsing-box.sh + else + echo "请先安装serv00-play!!!" + return + fi + echo "已停掉sing-box!" +} + +start_sing_box() { + cd ${installpath}/serv00-play/singbox + + if [[ ! -e "singbox.json" ]]; then + red "请先进行配置!" + return 1 + fi + + if ! checkDownload "serv00sb"; then + return + fi + if ! checkDownload "cloudflared"; then + return + fi + + if checkSingboxAlive; then + red "sing-box 已在运行,请勿重复操作!" + return 1 + else #启动可能需要cloudflare,此处表示cloudflare和sb有一个不在线,所以干脆先杀掉再重启。 + chmod 755 ./killsing-box.sh + ./killsing-box.sh + fi + + if chmod +x start.sh && ! ./start.sh; then + red "sing-box启动失败!" + exit 1 + fi + sleep 2 + if checkProcAlive "serv00sb"; then + yellow "启动成功!" + else + red "启动失败!" + fi + +} + +checkCronNameStatus() { + if checkCronName $1; then + green "在线" + else + red "离线" + fi +} +checkCronName() { + local name=$1 + if crontab -l | grep -q "$name"; then + return 0 + else + return 1 + fi } diff --git a/wxsend.sh b/wxsend.sh old mode 100755 new mode 100644 index 40adade3..5211f57c --- a/wxsend.sh +++ b/wxsend.sh @@ -3,22 +3,48 @@ text=$1 sendKey=${WXSENDKEY} +wx_push_url=${WXPUSH_URL} +wx_token=${WX_TOKEN} title="msg_from_serv00-play" URL="https://sctapi.ftqq.com/$sendKey.send?" -if [[ -z ${sendKey} ]]; then - echo "未配置微信推送的sendKey,通过 https://sct.ftqq.com/r/13223 注册并登录server酱,取得sendKey" +if [[ -z "$1" ]]; then + echo "错误:未提供要发送的消息内容。" + echo "用法: $0 \"你的消息\"" + exit 1 +fi + +if [[ -z "${wx_push_url}" ]]; then + if [[ -z ${sendKey} ]]; then + echo "未配置微信推送的sendKey,通过 https://sct.ftqq.com/r/13223 注册并登录server酱,取得sendKey" + else + res=$(timeout 20s curl -s -X POST $URL -d title=${title} -d desp="${text}") + if [ $? == 124 ]; then + echo "发送消息超时" + exit 1 + fi + + err=$(echo "$res" | jq -r ".data.error") + if [ "$err" == "SUCCESS" ]; then + echo "微信推送成功" + else + echo "微信推送失败, error:$err" + fi + fi else - res=$(timeout 20s curl -s -X POST $URL -d title=${title} -d desp="${text}") - if [ $? == 124 ]; then - echo "发送消息超时" - exit 1 - fi + if [[ -z ${wx_token} ]]; then + echo "未配置wxpush微信推送的wx_token,请参考https://github.com/frankiejun/wxpush 获取wx_token" + else + res=$(timeout 20s curl -s -X POST "${wx_push_url}" -H "Authorization: $wx_token" -H "Content-Type: application/json" -d "{\"token\":\"${wx_token}\",\"title\":\"${title}\",\"content\":\"${text}\",\"contentType\":1,\"uids\":[],\"topicIds\":[]}") + if [ $? == 124 ]; then + echo "发送消息超时" + exit 1 + fi - err=$(echo "$res" | jq -r ".data.error") - if [ "$err" == "SUCCESS" ]; then - echo "微信推送成功" - else - echo "微信推送失败, error:$err" - fi + if echo "$res" | grep -q "Successfully"; then + echo "微信推送成功" + else + echo "微信推送失败, res:$res" + fi + fi fi