Spaces:
Paused
Paused
File size: 7,694 Bytes
d222094 dede32b d222094 1d690e1 d222094 dede32b d222094 dede32b d222094 eab57ec d222094 dede32b d222094 7be6895 3742c4c 5d94446 cbed6a4 d222094 dede32b 86df536 a8c6b93 dede32b fb35c42 dede32b d222094 dede32b 86df536 dede32b 5d94446 86df536 dede32b 86df536 dede32b 4552bf2 dede32b a8c6b93 4552bf2 86df536 a8c6b93 86df536 dede32b b4ee1ca dede32b 665d4fc d222094 67a17ca b4ee1ca 192ce4c b4ee1ca dede32b b4ee1ca d222094 0bd0b14 86df536 b4ee1ca 5e82850 99f40b4 5e82850 99f40b4 b4ee1ca 99f40b4 5e82850 dede32b b4ee1ca dede32b d222094 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | # 核心镜像:使用 node-slim 保持轻量
FROM node:22-slim
# 1. 整合系统依赖安装
RUN apt-get update && apt-get install -y --no-install-recommends \
git python3 python3-pip ca-certificates procps tzdata \
&& rm -rf /var/lib/apt/lists/*
# 2. 安装 Python 同步依赖 (保持 --break-system-packages 以适配新版镜像)
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
# 3. 安装核心程序:合并清理指令
ARG OPENCLAW_VERSION=2026.2.26
RUN npm install -g openclaw@${OPENCLAW_VERSION} --registry=https://registry.npmjs.org/ \
--unsafe-perm=true --foreground-scripts && npm cache clean --force
# 4. 环境变量预设
ENV TZ=Asia/Shanghai \
PORT=7860 \
HOME=/root \
OPENCLAW_TRUST_LOCAL_WS=1 \
OPENCLAW_SECURITY_STRICT=false \
NODE_TLS_REJECT_UNAUTHORIZED=0 \
OPENCLAW_TRUST_PROXY=true \
NODE_ENV=production
# 5. 同步引擎 (修复了 Python 嵌套转义导致的 SyntaxError)
RUN echo 'import os, sys, tarfile, time\n\
from huggingface_hub import HfApi, hf_hub_download\n\
from datetime import datetime, timedelta\n\
api = HfApi()\n\
repo_id = os.getenv("HF_DATASET")\n\
token = os.getenv("HF_TOKEN")\n\
base_dir = "/root"\n\
\n\
def restore():\n\
if not repo_id or not token: return\n\
try:\n\
files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)\n\
now = datetime.now()\n\
for i in range(5):\n\
day = (now - timedelta(days=i)).strftime("%Y-%m-%d")\n\
name = "backup_" + day + ".tar.gz"\n\
if name in files:\n\
path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)\n\
with tarfile.open(path, "r:gz") as tar: tar.extractall(path=base_dir)\n\
print("--- [Sync] ✅ 恢复成功: " + day + " ---")\n\
return True\n\
except Exception as e: print("--- [Sync] ❌ 恢复失败: " + str(e))\n\
\n\
def backup():\n\
if not repo_id or not token: return\n\
try:\n\
target_dir = "/root/.openclaw"\n\
if not os.path.exists(target_dir): return\n\
day_str = datetime.now().strftime("%Y-%m-%d")\n\
name = "backup_" + day_str + ".tar.gz"\n\
with tarfile.open(name, "w:gz") as tar: tar.add(target_dir, arcname=".openclaw")\n\
api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)\n\
if os.path.exists(name): os.remove(name)\n\
print("--- [Sync] ✨ 备份完成: " + name + " ---")\n\
except Exception as e: print("--- [Sync] ❌ 备份失败: " + str(e))\n\
\n\
if __name__ == "__main__":\n\
if len(sys.argv) > 1 and sys.argv[1] == "backup": backup()\n\
else: restore()' > /usr/local/bin/sync.py
# 6. 最终启动脚本 (优化配置合并策略:严格深度合并 + 数组按ID智能合并)
RUN echo "#!/bin/bash\n\
mkdir -p /root/.openclaw\n\
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime\n\
\n\
echo \"--- [System] 📦 1. 尝试从云端恢复配置... ---\"\n\
python3 /usr/local/bin/sync.py restore || true\n\
find /root/.openclaw -name \"*.lock\" -delete\n\
chmod 700 /root/.openclaw\n\
\n\
echo \"--- [System] 📝 2. 开始合并默认配置与已恢复的配置... ---\"\n\
export CLEAN_BASE=\$(echo \"\$OPENAI_API_BASE\" | sed \"s|/chat/completions||g\" | sed \"s|/v1/|/v1|g\")\n\
\n\
# 使用 Python 深度合并 JSON (包含数组按ID合并逻辑)\n\
python3 -c \"\n\
import json, os\n\
\n\
def deep_update(d, u):\n\
for k, v in u.items():\n\
if isinstance(v, dict) and k in d and isinstance(d[k], dict):\n\
deep_update(d[k], v)\n\
elif isinstance(v, list) and k in d and isinstance(d[k], list):\n\
# 处理数组合并逻辑\n\
d_dict = {}\n\
non_id_d = []\n\
# 解析原配置(恢复的)数组\n\
for item in d[k]:\n\
if isinstance(item, dict) and 'id' in item:\n\
d_dict[item['id']] = item\n\
else:\n\
non_id_d.append(item)\n\
\n\
non_id_u = []\n\
# 解析新配置(环境变量)数组并进行合并\n\
for item in v:\n\
if isinstance(item, dict) and 'id' in item:\n\
if item['id'] in d_dict:\n\
# id相同,对内部字段继续深度合并(以新配置为准覆盖)\n\
d_dict[item['id']] = deep_update(d_dict[item['id']], item)\n\
else:\n\
d_dict[item['id']] = item\n\
else:\n\
# 对于普通元素(如字符串IP),去重合并\n\
if item not in non_id_d:\n\
non_id_u.append(item)\n\
\n\
# 组合合并后的数组\n\
d[k] = list(d_dict.values()) + non_id_d + non_id_u\n\
else:\n\
d[k] = v\n\
return d\n\
\n\
config_path = '/root/.openclaw/openclaw.json'\n\
current_config = {}\n\
\n\
if os.path.exists(config_path):\n\
try:\n\
with open(config_path, 'r', encoding='utf-8') as f:\n\
current_config = json.load(f)\n\
except Exception:\n\
pass\n\
\n\
clean_base = os.environ.get('CLEAN_BASE', '')\n\
api_key = os.environ.get('OPENAI_API_KEY', '')\n\
model = os.environ.get('MODEL', '')\n\
gateway_pw = os.environ.get('OPENCLAW_GATEWAY_PASSWORD', '')\n\
\n\
default_config = {\n\
'models': {\n\
'providers': {\n\
'siliconflow': {\n\
'baseUrl': clean_base,\n\
'apiKey': api_key,\n\
'api': 'openai-completions',\n\
'authHeader': True,\n\
'models': [{'id': model, 'name': 'DeepSeek', 'contextWindow': 128000}]\n\
}\n\
}\n\
},\n\
'agents': {\n\
'defaults': {\n\
'model': {'primary': 'siliconflow/' + model}\n\
}\n\
},\n\
'gateway': {\n\
'mode': 'local', 'port': 7860, 'bind': 'custom', 'customBindHost': '0.0.0.0',\n\
'trustedProxies': ['10.0.0.0/8'],\n\
'auth': {'mode': 'token', 'token': gateway_pw},\n\
'controlUi': {\n\
'enabled': True,\n\
'allowInsecureAuth': True,\n\
'dangerouslyDisableDeviceAuth': True,\n\
'dangerouslyAllowHostHeaderOriginFallback': True\n\
},\n\
'tools': {'deny': ['gateway']}\n\
}\n\
}\n\
\n\
merged_config = deep_update(current_config, default_config)\n\
\n\
with open(config_path, 'w', encoding='utf-8') as f:\n\
json.dump(merged_config, f, indent=2, ensure_ascii=False)\n\
\"\n\
echo \"--- [System] ✅ 配置合并完成。 ---\"\n\
\n\
# 启动后台备份任务\n\
(while true; do sleep 1800; python3 /usr/local/bin/sync.py backup; done) &\n\
\n\
export NODE_ENV=production\n\
export OPENCLAW_TRUST_PROXY=true\n\
\n\
echo \"--- [System] 🚀 3. 正在启动 OpenClaw Gateway... ---\"\n\
set +e\n\
trap 'kill -TERM \$PID 2>/dev/null' TERM INT\n\
\n\
while true; do\n\
find /root/.openclaw -name \"*.lock\" -delete\n\
\n\
openclaw gateway run --port 7860 &\n\
PID=\$!\n\
wait \$PID\n\
\n\
echo \"--- [System] ⚠️ OpenClaw 主进程退出,正在清理环境准备重启... ---\"\n\
openclaw gateway stop || true\n\
pkill -f openclaw || true\n\
pkill -f node || true\n\
\n\
python3 /usr/local/bin/sync.py backup || true\n\
sleep 3\n\
done\n\
" > /usr/local/bin/start-openclaw && chmod +x /usr/local/bin/start-openclaw
EXPOSE 7860
CMD ["/usr/local/bin/start-openclaw"] |