File size: 5,870 Bytes
3f49de3 0ace41e 3f49de3 0ace41e 3f49de3 0ace41e 416d80d 0ace41e 416d80d 0ace41e f5d3971 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 a937c7e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e b204b33 0ace41e e52cf6c 0ace41e b204b33 0ace41e d1b9593 0ace41e cf1882c 0ace41e 13681ab 0ace41e e6a5980 f444687 e52cf6c 0ace41e 8c43c56 0ace41e b204b33 0ace41e 8c43c56 0ace41e 3f49de3 | 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 | FROM node:22-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
git openssh-client build-essential python3 python3-pip g++ make ca-certificates sqlite3 \
&& rm -rf /var/lib/apt/lists/*
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
RUN update-ca-certificates && \
git config --global http.sslVerify false && \
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
RUN npm install -g openclaw@2026.6.9 --unsafe-perm
ENV PORT=7860 OPENCLAW_GATEWAY_MODE=local HOME=/root
# ==================== 同步引擎 - 最终修复版 ====================
RUN cat > /usr/local/bin/sync.py << 'EOF'
import os, sys, tarfile, shutil
from huggingface_hub import HfApi, hf_hub_download
from datetime import datetime, timedelta
api = HfApi()
repo_id = os.getenv("HF_DATASET")
token = os.getenv("HF_TOKEN")
BASE = "/root/.openclaw"
def restore():
print("🔍 [Restore] Searching latest backup...")
try:
files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)
now = datetime.now()
for i in range(5):
day = (now - timedelta(days=i)).strftime("%Y-%m-%d")
name = f"backup_{day}.tar.gz"
if name in files:
print(f"📦 Downloading {name}...")
path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token)
print("📂 Tar contents preview:")
with tarfile.open(path, "r:gz") as tar:
for member in tar.getmembers()[:20]: # 只打印前20个
print(" ", member.name)
for member in tar.getmembers():
# 关键修复:统一放到 .openclaw 下
if member.name.startswith('agents/') or member.name.startswith('skills/') or \
member.name.startswith('workspace/') or member.name.startswith('cron/') or \
member.name.startswith('state/'):
member.name = os.path.join('.openclaw', member.name)
elif member.name == 'openclaw.json' or member.name == 'backup_state.sqlite':
member.name = os.path.join('.openclaw', member.name)
tar.extract(member, "/root")
print("✅ Extraction completed")
# 处理 DB
if os.path.exists(f"{BASE}/backup_state.sqlite"):
os.makedirs(f"{BASE}/state", exist_ok=True)
shutil.move(f"{BASE}/backup_state.sqlite", f"{BASE}/state/openclaw.sqlite")
print("✅ SQLite (cron) restored")
return True
print("⚠️ No backup found")
except Exception as e:
print(f"❌ Restore error: {e}")
def backup():
print("📦 [Backup] Creating...")
try:
day = datetime.now().strftime("%Y-%m-%d")
name = f"backup_{day}.tar.gz"
with tarfile.open(name, "w:gz") as tar:
if os.path.exists(BASE):
tar.add(BASE, arcname=".openclaw")
api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)
print(f"✅ Backup uploaded: {name}")
except Exception as e:
print(f"❌ Backup error: {e}")
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "backup":
backup()
else:
restore()
EOF
# 模板
RUN mkdir -p /root/.openclaw
RUN cat > /root/.openclaw/openclaw.json.template << 'EOT'
{"models":{"providers":{"thirdparty":{"baseUrl":"PLACEHOLDER_BASE_URL","apiKey":"PLACEHOLDER_API_KEY","api":"openai-completions","headers":{"User-Agent":"Mozilla/5.0"},"models":[{"id":"PLACEHOLDER_MODEL_ID","name":"GLM-4.7-Flash","contextWindow":131072}]}}},"agents":{"defaults":{"model":{"primary":"thirdparty/PLACEHOLDER_MODEL_ID"}}},"gateway":{"mode":"local","bind":"lan","port":7860,"trustedProxies":["0.0.0.0/0","10.0.0.0/8","10.16.0.0/12","172.16.0.0/12","192.168.0.0/16"],"auth":{"mode":"token","token":"PLACEHOLDER_GATEWAY_PASSWORD"},"controlUi":{"enabled":true,"allowInsecureAuth":true,"dangerouslyAllowHostHeaderOriginFallback":true,"dangerouslyDisableDeviceAuth":true}}}
EOT
# 启动脚本
RUN cat > /usr/local/bin/start-openclaw << 'EOF'
#!/bin/bash
set -e
mkdir -p /root/.openclaw/{sessions,state}
echo "🚀 Starting OpenClaw..."
python3 /usr/local/bin/sync.py restore
sleep 8
if [ ! -d "/root/.openclaw/agents" ]; then
echo "🔄 Retrying restore..."
python3 /usr/local/bin/sync.py restore
sleep 6
fi
echo "=== Final Status ==="
echo "Agents dir: $([ -d "/root/.openclaw/agents" ] && echo Yes || echo No)"
echo "Sessions: $(ls /root/.openclaw/agents/main/sessions 2>/dev/null | wc -l || echo 0)"
echo "Skills: $(ls /root/.openclaw/skills 2>/dev/null | wc -l || echo 0)"
[ -f "/root/.openclaw/state/openclaw.sqlite" ] && echo "Cron jobs: $(sqlite3 /root/.openclaw/state/openclaw.sqlite "SELECT COUNT(*) FROM cron_jobs WHERE enabled=1;" 2>/dev/null || echo 0)"
#python3 /usr/local/bin/sync.py backup
CLEAN_BASE=$(echo "$OPENAI_API_BASE" | sed 's|/chat/completions||g' | sed 's|/v1/|/v1|g' | sed 's|/v1$|/v1|g')
sed -e "s|PLACEHOLDER_BASE_URL|$CLEAN_BASE|g" \
-e "s|PLACEHOLDER_API_KEY|$OPENAI_API_KEY|g" \
-e "s|PLACEHOLDER_MODEL_ID|$MODEL|g" \
-e "s|PLACEHOLDER_GATEWAY_PASSWORD|$OPENCLAW_GATEWAY_PASSWORD|g" \
/root/.openclaw/openclaw.json.template > /root/.openclaw/openclaw.json
echo "✅ OpenClaw started"
(while true; do sleep 12000; python3 /usr/local/bin/sync.py backup; done) &
openclaw doctor --fix
exec openclaw gateway run --port $PORT
EOF
RUN chmod +x /usr/local/bin/start-openclaw
EXPOSE 7860
CMD ["/usr/local/bin/start-openclaw"] |