🔄 卡若AI 同步 2026-02-22 05:46 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个

This commit is contained in:
2026-02-22 05:46:08 +08:00
parent bcfab416dd
commit f63045803a
9 changed files with 447 additions and 4 deletions

View File

@@ -0,0 +1,70 @@
# Node 项目未启动 · MODULE_NOT_FOUND 修复指南
> 针对 kr宝塔 43.139.27.93 多个 Node 项目「未启动」及「启动失败 MODULE_NOT_FOUND」的处理。
---
## 一、批量启动(先执行)
**宝塔面板 → 终端** 执行 `references/宝塔面板终端_Node批量启动指南.md` 中的脚本,先尝试批量启动所有未运行项目。
---
## 二、MODULE_NOT_FOUND 原因
错误示例:
```
Error: Cannot find module '/www/wwwroot/自营/玩值/玩值大屏'
Error: Cannot find module '/www/wwwroot/自营/wzdj'
```
**原因**:启动命令配置错误,把**目录路径**当成了入口文件。Node 无法把目录当模块执行。
---
## 三、按项目修复(宝塔 Node 项目 → 编辑)
| 项目 | 根目录 | 建议启动命令 | 说明 |
|------|--------|--------------|------|
| **玩值大屏** | /www/wwwroot/自营/玩值/玩值大屏 | `cd /www/wwwroot/自营/玩值/玩值大屏 && node server.js``npm run start` | 先确认目录内有 server.js / package.json 的 scripts.start |
| **wzdj** | /www/wwwroot/自营/wzdj | `cd /www/wwwroot/自营/wzdj && node server.js``npm run start` | 同上 |
| **tongzhi** | /www/wwwroot/自营/玩值/tongzhi | `cd /www/wwwroot/自营/玩值/tongzhi && node server.js``npm run start` | 同上 |
| **is_phone** | /www/wwwroot/自营/kr/kr-phone | `cd /www/wwwroot/自营/kr/kr-phone && node server.js``npm run start` | 同上 |
| **ai_hair** | /www/wwwroot/客户/ai_hair | 同上 | 同上 |
| **AITOUFA** | /www/wwwroot/扩展/小工具/AITOUFA | `cd /www/wwwroot/扩展/小工具/AITOUFA && npm run start` | 参考 Skill §4.6 |
| **zhiji** | /www/wwwroot/... | 同上 | 按实际结构 |
| **ymao** | /www/wwwroot/扩展/ymao | 同上 | 同上 |
| **zhaoping** | /www/wwwroot/客户/zhaoping | 同上 | 同上 |
---
## 四、启动命令规则
1. **Next.js**`cd 项目根目录 && npm run start``pnpm start`;若用 standalone`node .next/standalone/server.js`
2. **Express / 普通 Node**`cd 项目根目录 && node server.js``node index.js`
3. **禁止**`node /www/wwwroot/xxx/项目名`(目录不能当入口)
---
## 五、修复步骤(每个失败项目)
1. 宝塔 → **网站****Node 项目** → 找到该项目 → **设置****编辑**
2. 找到「启动文件」或「启动命令」配置
3. 改为:`cd /项目根目录 && node server.js``npm run start`(按项目类型选)
4. **Node 版本**:与 package.json 的 engines 一致(多数 v18.20.0wzdj/zhiji 用 v20.18.0
5. 保存后点击 **重启**
---
## 六、先确认项目结构
在宝塔终端执行,确认各项目有入口文件:
```bash
for d in /www/wwwroot/自营/玩值/玩值大屏 /www/wwwroot/自营/wzdj /www/wwwroot/自营/玩值/tongzhi /www/wwwroot/自营/kr/kr-phone; do
echo "=== $d ==="
ls -la "$d/" 2>/dev/null | grep -E "server\.js|index\.js|package\.json|\.next" || echo " (无常见入口)"
done
```
根据输出选择 `node server.js``node index.js``npm run start`

View File

@@ -1,6 +1,7 @@
# kr宝塔 SSH 登录方式与故障排查
# 宝塔 SSH 登录方式与故障排查
> 当一种方式失败时,依次尝试其他方式。终极备选:**宝塔面板 → 终端**(无需 SSH
> **存客宝 SSH 修复**:在存客宝宝塔终端执行 `scripts/存客宝_SSH修复_宝塔终端执行.sh` 内容。
---
@@ -132,3 +133,14 @@ fail2ban-client set ssh-iptables unbanip 你的公网IP
```
**一键脚本**`scripts/宝塔_IP封禁解封与优化命令.sh`,在服务器上执行 `bash 脚本路径 你的公网IP`
---
## 七、存客宝 SSH 修复Permission denied 时)
存客宝若密码/密钥均 Permission denied需在**存客宝宝塔面板 → 终端**执行修复:
1. 打开 https://42.194.245.239:9988 → 登录 ckb/zhiqun1984 → 左侧「终端」
2. 复制 `scripts/存客宝_SSH修复_宝塔终端执行.sh` 的**全部内容**,粘贴到终端执行
脚本会:添加本机公钥、允许密码登录、`PermitRootLogin yes`、重置 root 密码为 Zhiqun1984、解封 IP 140.245.37.56、重载 sshd。执行完成后本机即可 SSH。

View File

@@ -10,8 +10,8 @@
|------|-----|
| IP | 42.194.245.239 |
| SSH 端口 | 22022 |
| SSH 账号 | ckb |
| SSH 密码 | zhiqun1984 |
| SSH 账号 | root面板账号 ckb 仅用于 Web |
| SSH 密码 | Zhiqun1984(大写 Z与 kr宝塔一致 |
| 宝塔面板 | https://42.194.245.239:9988 |
| 面板账号 | ckb |
| 面板密码 | zhiqun1984 |
@@ -19,6 +19,12 @@
---
## SSH 修复Permission denied 时)
在宝塔面板 → 终端执行 `scripts/存客宝_SSH修复_宝塔终端执行.sh` 全部内容,修复后 root/Zhiqun1984 可登录。
---
## 快速操作
- **Node 项目**:若有 Node 项目,可参考 `references/宝塔Node项目管理_SKILL.md` 编写存客宝版批量修复脚本PANEL、API_KEY 改为存客宝)

View File

@@ -124,5 +124,5 @@ python3 /tmp/kr_node_batch_fix.py
## 注意事项
- **AITOUFA** 若仍报 `MODULE_NOT_FOUND`,需在宝塔 **Node 项目 → 编辑 AITOUFA**修正启动命令(例如改为 `npm start` 或正确入口文件)
- **MODULE_NOT_FOUND**玩值大屏、wzdj、tongzhi 等若报此错,需在 **Node 项目 → 编辑**启动命令改为 `cd /项目根目录 && node server.js``npm run start`,勿用目录路径当入口。详见 `references/Node项目未启动_MODULE_NOT_FOUND修复指南.md`
- 若某项目因端口占用失败,脚本会自动尝试清理端口后重试;若仍失败,需在面板中手动检查该项目配置。

View File

@@ -0,0 +1,41 @@
#!/bin/bash
# 存客宝 42.194.245.239 SSH 修复 · 在宝塔面板【终端】复制整段粘贴执行
# 修复后root 密码 Zhiqun1984支持密钥与密码登录
PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBY/abEb3JpB/CP3jFqN9KqXspSGgAzHzYlsQzXLmPOt karuo@example.com"
MY_IP="140.245.37.56"
echo "========== 存客宝 SSH 修复 =========="
# 1. 添加公钥
mkdir -p /root/.ssh
chmod 700 /root/.ssh
grep -qF "$PUBKEY" /root/.ssh/authorized_keys 2>/dev/null || echo "$PUBKEY" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
echo "[1/5] 公钥已写入"
# 2. 允许密码登录
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%s)
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config
grep -q "^PasswordAuthentication" /etc/ssh/sshd_config || echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
grep -q "^PermitRootLogin" /etc/ssh/sshd_config || echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
echo "[2/5] sshd 已允许密码与 root 登录"
# 3. 重置 root 密码
echo "root:Zhiqun1984" | chpasswd
echo "[3/5] root 密码已设为 Zhiqun1984"
# 4. 解封 IP
for j in sshd ssh-iptables; do
fail2ban-client set "$j" unbanip "$MY_IP" 2>/dev/null && echo "$j 已解封 $MY_IP"
done
echo "[4/5] IP 解封已执行"
# 5. 重载 sshd
systemctl reload sshd 2>/dev/null || systemctl reload ssh 2>/dev/null || service sshd reload 2>/dev/null
echo "[5/5] sshd 已重载"
echo ""
echo "========== 完成 =========="
echo "本机测试: sshpass -p 'Zhiqun1984' ssh -p 22022 -o PubkeyAuthentication=no root@42.194.245.239 'whoami'"
echo "或密钥: ssh -p 22022 -i Steam/id_ed25519 root@42.194.245.239"

View File

@@ -0,0 +1,147 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
腾讯云 TAT 在 kr宝塔 CVM 上执行 Node 批量修复(无需 SSH
凭证00_账号与API索引.md 或环境变量
依赖pip install tencentcloud-sdk-python-common tencentcloud-sdk-python-tat
"""
import base64
import os
import re
import sys
import time
KR_INSTANCE_ID = "ins-aw0tnqjo"
REGION = "ap-guangzhou"
def _find_karuo_ai_root():
d = os.path.dirname(os.path.abspath(__file__))
for _ in range(6):
if os.path.basename(d) == "卡若AI" or (os.path.isdir(os.path.join(d, "运营中枢")) and os.path.isdir(os.path.join(d, "01_卡资"))):
return d
d = os.path.dirname(d)
return None
def _read_creds():
root = _find_karuo_ai_root()
if not root:
return None, None
path = os.path.join(root, "运营中枢", "工作台", "00_账号与API索引.md")
if not os.path.isfile(path):
return None, None
with open(path, "r", encoding="utf-8") as f:
text = f.read()
secret_id = secret_key = None
in_tencent = False
for line in text.splitlines():
if "### 腾讯云" in line:
in_tencent = True
continue
if in_tencent and line.strip().startswith("###"):
break
if not in_tencent:
continue
m = re.search(r"\|\s*[^|]*(?:SecretId|密钥)[^|]*\|\s*`([^`]+)`", line, re.I)
if m:
val = m.group(1).strip()
if val.startswith("AKID"):
secret_id = val
m = re.search(r"\|\s*SecretKey\s*\|\s*`([^`]+)`", line, re.I)
if m:
secret_key = m.group(1).strip()
return secret_id or None, secret_key or None
# 在服务器上执行的 Node 批量修复脚本(内联)
NODE_FIX_SCRIPT = r'''
import hashlib, json, os, re, subprocess, time, urllib.request, urllib.parse, ssl
ssl._create_default_https_context = ssl._create_unverified_context
PANEL, API_KEY = "https://127.0.0.1:9988", "qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT"
def sign():
n = int(time.time())
s = str(n) + hashlib.md5(API_KEY.encode()).hexdigest()
return {"request_time": n, "request_token": hashlib.md5(s.encode()).hexdigest()}
def post(p, d=None):
pl = sign()
if d: pl.update(d)
r = urllib.request.Request(PANEL + p, data=urllib.parse.urlencode(pl).encode())
with urllib.request.urlopen(r, timeout=25) as resp:
return json.loads(resp.read().decode())
def pids(port):
try:
o = subprocess.check_output("ss -tlnp | grep ':%s ' || true" % port, shell=True, universal_newlines=True)
return sorted({int(x) for x in re.findall(r"pid=(\d+)", o)})
except: return []
def ports(it):
cfg = it.get("project_config") or {}
ps = []
if cfg.get("port"): ps.append(int(cfg["port"]))
for m in re.findall(r"-p\s*(\d+)", str(cfg.get("project_script",""))): ps.append(int(m))
return sorted(set(ps))
items = post("/project/nodejs/get_project_list").get("data") or post("/project/nodejs/get_project_list").get("list") or []
for it in items:
name = it.get("name")
if not name or it.get("run") is True: continue
for port in ports(it):
for pid in pids(port): subprocess.call("kill -9 %s" % pid, shell=True)
pf = "/www/server/nodejs/vhost/pids/%s.pid" % name
if os.path.exists(pf): open(pf,"w").write("0")
post("/project/nodejs/stop_project", {"project_name": name})
r = post("/project/nodejs/start_project", {"project_name": name})
ok = r.get("status") is True or "成功" in str(r.get("msg",""))
print("%s: %s" % (name, "OK" if ok else "FAIL"))
time.sleep(1)
time.sleep(4)
items2 = post("/project/nodejs/get_project_list").get("data") or []
run_c = sum(1 for x in items2 if x.get("run"))
print("RUN:%d STOP:%d" % (run_c, len(items2)-run_c))
'''
def main():
secret_id = os.environ.get("TENCENTCLOUD_SECRET_ID")
secret_key = os.environ.get("TENCENTCLOUD_SECRET_KEY")
if not secret_id or not secret_key:
sid, skey = _read_creds()
secret_id = secret_id or sid
secret_key = secret_key or skey
if not secret_id or not secret_key:
print("❌ 未配置腾讯云 SecretId/SecretKey")
return 1
try:
from tencentcloud.common import credential
from tencentcloud.tat.v20201028 import tat_client, models
except ImportError:
print("请安装: pip install tencentcloud-sdk-python-common tencentcloud-sdk-python-tat")
return 1
cred = credential.Credential(secret_id, secret_key)
client = tat_client.TatClient(cred, REGION)
req = models.RunCommandRequest()
req.Content = base64.b64encode(NODE_FIX_SCRIPT.encode()).decode()
req.InstanceIds = [KR_INSTANCE_ID]
req.CommandType = "SHELL"
req.Timeout = 120
req.CommandName = "NodeBatchFix"
resp = client.RunCommand(req)
inv_id = resp.InvocationId
print("✅ TAT 执行已下发 InvocationId:", inv_id)
print(" 等待 30s 后查询结果...")
time.sleep(30)
# 查询执行结果Filter 方式)
try:
req2 = models.DescribeInvocationTasksRequest()
f = models.Filter()
f.Name = "invocation-id"
f.Values = [inv_id]
req2.Filters = [f]
resp2 = client.DescribeInvocationTasks(req2)
for t in (resp2.InvocationTaskSet or []):
print(" 任务:", getattr(t, "InvocationTaskId", t), "状态:", getattr(t, "TaskStatus", "N/A"))
if hasattr(t, "Output") and t.Output:
print(" 输出:", (t.Output or "")[:800])
except Exception as e:
print(" 查询结果异常:", e)
print("=" * 50)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,165 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
腾讯云 TAT在 kr宝塔 CVM 上解封 fail2ban SSH + 批量启动 Node免 SSH
凭证00_账号与API索引.md 或环境变量 TENCENTCLOUD_SECRET_ID / TENCENTCLOUD_SECRET_KEY
依赖pip install tencentcloud-sdk-python-common tencentcloud-sdk-python-tat
用法python3 腾讯云_TAT_解封SSH并批量启动Node.py [本机IP]
不传 IP 时默认 211.156.92.72
"""
import base64
import os
import re
import sys
import time
KR_INSTANCE_ID = "ins-aw0tnqjo"
REGION = "ap-guangzhou"
def _find_karuo_ai_root():
d = os.path.dirname(os.path.abspath(__file__))
for _ in range(6):
if os.path.basename(d) == "卡若AI" or (os.path.isdir(os.path.join(d, "运营中枢")) and os.path.isdir(os.path.join(d, "01_卡资"))):
return d
d = os.path.dirname(d)
return None
def _read_creds():
root = _find_karuo_ai_root()
if not root:
return None, None
path = os.path.join(root, "运营中枢", "工作台", "00_账号与API索引.md")
if not os.path.isfile(path):
return None, None
with open(path, "r", encoding="utf-8") as f:
text = f.read()
secret_id = secret_key = None
in_tencent = False
for line in text.splitlines():
if "### 腾讯云" in line:
in_tencent = True
continue
if in_tencent and line.strip().startswith("###"):
break
if not in_tencent:
continue
m = re.search(r"\|\s*[^|]*(?:SecretId|密钥)[^|]*\|\s*`([^`]+)`", line, re.I)
if m:
val = m.group(1).strip()
if val.startswith("AKID"):
secret_id = val
m = re.search(r"\|\s*SecretKey\s*\|\s*`([^`]+)`", line, re.I)
if m:
secret_key = m.group(1).strip()
return secret_id or None, secret_key or None
# Node 批量修复 Python 脚本(与 腾讯云_TAT_Node批量修复.py 一致)
NODE_FIX_B64 = base64.b64encode(r'''
import hashlib, json, os, re, subprocess, time, urllib.request, urllib.parse, ssl
ssl._create_default_https_context = ssl._create_unverified_context
PANEL, API_KEY = "https://127.0.0.1:9988", "qcWubCdlfFjS2b2DMT1lzPFaDfmv1cBT"
def sign():
n = int(time.time())
s = str(n) + hashlib.md5(API_KEY.encode()).hexdigest()
return {"request_time": n, "request_token": hashlib.md5(s.encode()).hexdigest()}
def post(p, d=None):
pl = sign()
if d: pl.update(d)
r = urllib.request.Request(PANEL + p, data=urllib.parse.urlencode(pl).encode())
with urllib.request.urlopen(r, timeout=25) as resp:
return json.loads(resp.read().decode())
def pids(port):
try:
o = subprocess.check_output("ss -tlnp | grep ':%s ' || true" % port, shell=True, universal_newlines=True)
return sorted({int(x) for x in re.findall(r"pid=(\d+)", o)})
except: return []
def ports(it):
cfg = it.get("project_config") or {}
ps = []
if cfg.get("port"): ps.append(int(cfg["port"]))
for m in re.findall(r"-p\s*(\d+)", str(cfg.get("project_script",""))): ps.append(int(m))
return sorted(set(ps))
items = post("/project/nodejs/get_project_list").get("data") or post("/project/nodejs/get_project_list").get("list") or []
for it in items:
name = it.get("name")
if not name or it.get("run") is True: continue
for port in ports(it):
for pid in pids(port): subprocess.call("kill -9 %s" % pid, shell=True)
pf = "/www/server/nodejs/vhost/pids/%s.pid" % name
if os.path.exists(pf): open(pf,"w").write("0")
post("/project/nodejs/stop_project", {"project_name": name})
r = post("/project/nodejs/start_project", {"project_name": name})
ok = r.get("status") is True or "成功" in str(r.get("msg",""))
print(name, "OK" if ok else "FAIL")
time.sleep(1)
time.sleep(4)
items2 = post("/project/nodejs/get_project_list").get("data") or []
run_c = sum(1 for x in items2 if x.get("run"))
print("RUN:", run_c, "STOP:", len(items2)-run_c)
'''.encode()).decode()
def build_shell(unban_ip: str) -> str:
return f'''#!/bin/bash
set -e
echo "=== 1. 解封 fail2ban SSH (unbanip {unban_ip}) ==="
fail2ban-client set sshd unbanip {unban_ip} 2>/dev/null || echo " (fail2ban 未启用或已解封)"
echo "=== 2. Node 批量启动 ==="
echo "{NODE_FIX_B64}" | base64 -d | python3 -
echo "=== 完成 ==="
'''
def main():
unban_ip = (sys.argv[1:] or ["211.156.92.72"])[0]
secret_id = os.environ.get("TENCENTCLOUD_SECRET_ID")
secret_key = os.environ.get("TENCENTCLOUD_SECRET_KEY")
if not secret_id or not secret_key:
sid, skey = _read_creds()
secret_id = secret_id or sid
secret_key = secret_key or skey
if not secret_id or not secret_key:
print("❌ 未配置腾讯云 SecretId/SecretKey环境变量或 00_账号与API索引.md")
return 1
try:
from tencentcloud.common import credential
from tencentcloud.tat.v20201028 import tat_client, models
except ImportError:
print("请安装: pip install tencentcloud-sdk-python-common tencentcloud-sdk-python-tat")
return 1
shell = build_shell(unban_ip)
cred = credential.Credential(secret_id, secret_key)
client = tat_client.TatClient(cred, REGION)
req = models.RunCommandRequest()
req.Content = base64.b64encode(shell.encode()).decode()
req.InstanceIds = [KR_INSTANCE_ID]
req.CommandType = "SHELL"
req.Timeout = 180
req.CommandName = "UnbanSSH_NodeBatchFix"
resp = client.RunCommand(req)
inv_id = resp.InvocationId
print("✅ 腾讯云 TAT 执行已下发")
print(" InvocationId:", inv_id)
print(" 解封 IP:", unban_ip)
print(" 等待 60s 后查询结果...")
time.sleep(60)
try:
req2 = models.DescribeInvocationTasksRequest()
f = models.Filter()
f.Name = "invocation-id"
f.Values = [inv_id]
req2.Filters = [f]
resp2 = client.DescribeInvocationTasks(req2)
for t in (resp2.InvocationTaskSet or []):
print(" 任务状态:", getattr(t, "TaskStatus", "N/A"))
if hasattr(t, "Output") and t.Output:
print(" 输出:\n", t.Output or "")
except Exception as e:
print(" 查询异常:", e)
print("=" * 50)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -49,3 +49,4 @@
| 2026-02-21 21:06:44 | 🔄 卡若AI 同步 2026-02-21 21:06 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 |
| 2026-02-22 05:04:01 | 🔄 卡若AI 同步 2026-02-22 05:03 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 |
| 2026-02-22 05:11:04 | 🔄 卡若AI 同步 2026-02-22 05:11 | 更新:金仓、水溪整理归档、运营中枢工作台 | 排除 >20MB: 5 个 |
| 2026-02-22 05:25:32 | 🔄 卡若AI 同步 2026-02-22 05:25 | 更新:金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 5 个 |

View File

@@ -52,3 +52,4 @@
| 2026-02-21 21:06:44 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-21 21:06 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-02-22 05:04:01 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 05:03 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-02-22 05:11:04 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 05:11 | 更新:金仓、水溪整理归档、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |
| 2026-02-22 05:25:32 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-22 05:25 | 更新:金仓、卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 5 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |