FROM node:22-slim # Install system dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ git openssh-client build-essential python3 python3-pip \ g++ make ca-certificates curl chromium tzdata \ libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 \ libgbm1 libasound2 libpangocairo-1.0-0 libpango-1.0-0 \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && rm -rf /var/lib/apt/lists/* # Install Python packages RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages # Git and CA config RUN update-ca-certificates && \ git config --global http.sslVerify false && \ git config --global url."https://github.com/".insteadOf ssh://git@github.com/ ENV HOME=/root ENV PORT=7860 \ OPENCLAW_GATEWAY_MODE=local \ OPENCLAW_BROWSER_PATH=/usr/bin/chromium # Install OpenClaw RUN npm install -g openclaw@latest zod --unsafe-perm # Generate sync.py using a Heredoc to avoid syntax/escaping issues RUN cat <<'EOF' > /usr/local/bin/sync.py import os, sys, tarfile 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") def restore(): try: print(f"--- [SYNC] Start recovery process, target repository: {repo_id} ---") if repo_id and token: files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token) now = datetime.now() found = False 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"--- [SYNC] Backup file found: {name}, Downloading... ---") path = hf_hub_download(repo_id=repo_id, filename=name, repo_type="dataset", token=token) with tarfile.open(path, "r:gz") as tar: tar.extractall(path="/root/.openclaw/") print(f"--- [SYNC] Recovery successful! ---") found = True break if not found: print("--- [SYNC] No backup packages found for the last 5 days---") else: print("--- [SYNC] Skip recovery: HF_DATASET or HF_TOKEN not configured ---") # Clean up .lock files count = 0 for root, dirs, fs in os.walk("/root/.openclaw/"): for f in fs: if f.endswith(".lock"): try: os.remove(os.path.join(root, f)) count += 1 except: pass if count > 0: print(f"--- [SYNC] {count} residual lock files cleaned up---") return True except Exception as e: print(f"--- [SYNC] Recovery Exception: {e} ---") def backup(): try: day = datetime.now().strftime("%Y-%m-%d") name = f"backup_{day}.tar.gz" print(f"--- [SYNC] Performing a full backup: {name} ---") def lock_filter(tarinfo): if tarinfo.name.endswith(".lock"): return None return tarinfo with tarfile.open(name, "w:gz") as tar: for target in ["sessions", "workspace", "agents", "memory", "plugins", "openclaw.json"]: full_path = f"/root/.openclaw/{target}" if os.path.exists(full_path): tar.add(full_path, arcname=target, filter=lock_filter) if repo_id and token: api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token) print("--- [SYNC] Backup upload successful! ---") except Exception as e: print(f"--- [SYNC] Backup failed: {e} ---") if __name__ == "__main__": if len(sys.argv) > 1 and sys.argv[1] == "backup": backup() else: restore() EOF # Create startup script RUN cat <<'EOF' > /usr/local/bin/start-openclaw #!/bin/bash set -e mkdir -p /root/.openclaw/{sessions,workspace,plugins,agents/main/sessions,credentials} ln -s /root/.openclaw/workspace /root/.openclaw/memory || true chmod 700 /root/.openclaw || true python3 /usr/local/bin/sync.py restore || true export OPENCLAW_GATEWAY_TOKEN="${OPENCLAW_GATEWAY_PASSWORD}" CLEAN_BASE=$(echo "${OPENAI_API_BASE}" | sed "s|/chat/completions||g" | sed "s|/v1/|/v1|g" | sed "s|/v1$|/v1|g") cat > /root/.openclaw/openclaw.json <