auto / Dockerfile.bak
erayoc's picture
Rename Dockerfile to Dockerfile.bak
4706911 verified
# OpenClaw on Hugging Face Spaces
FROM node:22-slim
# 1. 基础依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
git openssh-client build-essential python3 python3-pip \
g++ make ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
# 2. 安装 Hugging Face Hub
RUN pip3 install --no-cache-dir huggingface_hub --break-system-packages
# 3. Git 配置
RUN update-ca-certificates && \
git config --global http.sslVerify false && \
git config --global url."https://github.com/".insteadOf ssh://git@github.com/
# 4. 安装 OpenClaw
RUN npm install -g openclaw@latest --unsafe-perm
# 5. 环境变量预设 - 所有可配置的环境变量,使用 ${VAR:-default} 格式
ENV \
# 基础配置
PORT=${PORT:-7860} \
NODE_ENV=${NODE_ENV:-production} \
HOME=${HOME:-/root} \
\
# OpenClaw 核心配置
OPENCLAW_GATEWAY_MODE=${OPENCLAW_GATEWAY_MODE:-local} \
OPENCLAW_GATEWAY_TOKEN=${OPENCLAW_GATEWAY_TOKEN:-} \
\
# 模型配置
MODEL_PROVIDER=${MODEL_PROVIDER:-nvidia} \
MODEL_ID=${MODEL_ID:-moonshotai/kimi-k2.5} \
MODEL_CONTEXT_WINDOW=${MODEL_CONTEXT_WINDOW:-256000} \
MODEL_DISPLAY_NAME=${MODEL_DISPLAY_NAME:-"Kimi K2.5"} \
\
# API 配置
API_BASE_URL=${API_BASE_URL:-https://integrate.api.nvidia.com/v1} \
API_TYPE=${API_TYPE:-openai-completions} \
OPENAI_API_KEY=${OPENAI_API_KEY:-} \
\
# 网关配置
GATEWAY_AUTH_MODE=${GATEWAY_AUTH_MODE:-token} \
GATEWAY_BIND=${GATEWAY_BIND:-lan} \
GATEWAY_TRUSTED_PROXIES=${GATEWAY_TRUSTED_PROXIES:-0.0.0.0/0,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16} \
GATEWAY_ALLOWED_ORIGINS=${GATEWAY_ALLOWED_ORIGINS:-https://control.example.com} \
\
# 控制UI配置
CONTROLUI_ALLOW_INSECURE_AUTH=${CONTROLUI_ALLOW_INSECURE_AUTH:-true} \
CONTROLUI_DANGEROUS_HOST_HEADER=${CONTROLUI_DANGEROUS_HOST_HEADER:-true} \
CONTROLUI_DANGEROUS_DISABLE_DEVICE_AUTH=${CONTROLUI_DANGEROUS_DISABLE_DEVICE_AUTH:-true} \
\
# Telegram 配置
TELEGRAM_ENABLED=${TELEGRAM_ENABLED:-false} \
TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-} \
TELEGRAM_DM_POLICY=${TELEGRAM_DM_POLICY:-allowlist} \
TELEGRAM_ALLOW_FROM=${TELEGRAM_ALLOW_FROM:-} \
\
# 备份配置
BACKUP_ENABLED=${BACKUP_ENABLED:-true} \
BACKUP_INTERVAL=${BACKUP_INTERVAL:-21600} \
BACKUP_RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-5} \
HF_DATASET=${HF_DATASET:-} \
HF_TOKEN=${HF_TOKEN:-}
# 6. 同步脚本
RUN cat > /usr/local/bin/sync.py << 'SYNC_EOF'
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", "")
retention_days = int(os.getenv("BACKUP_RETENTION_DAYS", "5"))
def restore():
if not repo_id or not token:
print("No HF_DATASET or HF_TOKEN, skipping restore")
return False
try:
files = api.list_repo_files(repo_id=repo_id, repo_type="dataset", token=token)
now = datetime.now()
for i in range(retention_days):
day = (now - timedelta(days=i)).strftime("%Y-%m-%d")
name = f"backup_{day}.tar.gz"
if name in files:
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"Restored from {name}")
return True
print("No backup found")
except Exception as e:
print(f"Restore warning: {e}")
return False
def backup():
if not repo_id or not token:
return
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("/root/.openclaw/sessions"):
tar.add("/root/.openclaw/sessions", arcname="sessions")
if os.path.exists("/root/.openclaw/openclaw.json"):
tar.add("/root/.openclaw/openclaw.json", arcname="openclaw.json")
api.upload_file(path_or_fileobj=name, path_in_repo=name, repo_id=repo_id, repo_type="dataset", token=token)
print(f"Backup {name} done")
os.remove(name)
except Exception as e:
print(f"Backup warning: {e}")
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "backup":
backup()
else:
restore()
SYNC_EOF
RUN chmod +x /usr/local/bin/sync.py
# 7. 启动脚本
RUN cat > /usr/local/bin/start-openclaw << 'START_EOF'
#!/bin/bash
set -e
mkdir -p /root/.openclaw/sessions
# 尝试恢复数据(可选)
if [ -n "$HF_DATASET" ] && [ -n "$HF_TOKEN" ]; then
python3 /usr/local/bin/sync.py restore || true
fi
# 准备 API 配置
CLEAN_BASE="${API_BASE_URL}"
CLEAN_BASE=$(echo "$CLEAN_BASE" | sed 's|/chat/completions||g' | sed 's|/v1/|/v1|g' | sed 's|/v1$|/v1|')
# 生成令牌(如果没设置)
if [ -z "$OPENCLAW_GATEWAY_TOKEN" ]; then
OPENCLAW_GATEWAY_TOKEN=$(openssl rand -hex 16)
fi
# 转换可信代理列表为JSON数组
TRUSTED_PROXIES_JSON=$(echo "$GATEWAY_TRUSTED_PROXIES" | tr ',' '\n' | awk '{ printf "\"%s\",", $0 }' | sed 's/,$//' | sed 's/^/[/' | sed 's/$/]/')
# 转换允许的源列表为JSON数组
ALLOWED_ORIGINS_JSON=$(echo "$GATEWAY_ALLOWED_ORIGINS" | tr ',' '\n' | awk '{ printf "\"%s\",", $0 }' | sed 's/,$//' | sed 's/^/[/' | sed 's/$/]/')
# 转换Telegram允许列表为JSON数组
if [ -n "$TELEGRAM_ALLOW_FROM" ]; then
# 规范化ID,添加tg:前缀(如果没有)
TELEGRAM_ALLOW_JSON=$(echo "$TELEGRAM_ALLOW_FROM" | tr ',' '\n' | while read id; do
id=$(echo "$id" | xargs) # 去除空格
if [[ "$id" =~ ^[0-9]+$ ]]; then
echo "\"tg:$id\""
elif [[ "$id" =~ ^tg: ]]; then
echo "\"$id\""
elif [[ "$id" =~ ^@ ]]; then
# 注意:@username需要在运行时通过doctor --fix解析
echo "\"$id\""
else
echo "\"$id\""
fi
done | paste -sd ',' | sed 's/^/[/' | sed 's/$/]/')
else
TELEGRAM_ALLOW_JSON="[]"
fi
# 创建 OpenClaw 配置
cat > /root/.openclaw/openclaw.json <<OPENCLAW_CONFIG
{
"models": {
"providers": {
"${MODEL_PROVIDER}": {
"baseUrl": "${CLEAN_BASE}",
"apiKey": "${OPENAI_API_KEY}",
"api": "${API_TYPE}",
"models": [{
"id": "${MODEL_ID}",
"name": "${MODEL_DISPLAY_NAME}",
"contextWindow": ${MODEL_CONTEXT_WINDOW}
}]
}
}
},
"agents": {
"defaults": {
"model": {
"primary": "${MODEL_PROVIDER}/${MODEL_ID}"
},
"workspace": "~/.openclaw/workspace"
}
},
"gateway": {
"mode": "${OPENCLAW_GATEWAY_MODE}",
"bind": "${GATEWAY_BIND}",
"port": ${PORT},
"trustedProxies": ${TRUSTED_PROXIES_JSON},
"auth": {
"mode": "${GATEWAY_AUTH_MODE}",
"token": "${OPENCLAW_GATEWAY_TOKEN}"
},
"remote": {
"token": "${OPENCLAW_GATEWAY_TOKEN}"
},
"controlUi": {
"allowInsecureAuth": ${CONTROLUI_ALLOW_INSECURE_AUTH},
"dangerouslyAllowHostHeaderOriginFallback": ${CONTROLUI_DANGEROUS_HOST_HEADER},
"dangerouslyDisableDeviceAuth": ${CONTROLUI_DANGEROUS_DISABLE_DEVICE_AUTH},
"allowedOrigins": ${ALLOWED_ORIGINS_JSON}
}
},
"session": {
"store": "/root/.openclaw/sessions/sessions.json"
},
"channels": {
"telegram": {
"enabled": ${TELEGRAM_ENABLED},
"botToken": "${TELEGRAM_BOT_TOKEN}",
"dmPolicy": "${TELEGRAM_DM_POLICY}",
"allowFrom": ${TELEGRAM_ALLOW_JSON}
}
}
}
OPENCLAW_CONFIG
echo "========================================"
echo "OpenClaw Gateway Starting..."
echo "Model: ${MODEL_ID}"
echo "Provider: ${MODEL_PROVIDER}"
echo "Port: ${PORT}"
echo "Backup: ${BACKUP_ENABLED}"
echo "Allowed Origins: ${GATEWAY_ALLOWED_ORIGINS}"
echo "Telegram Enabled: ${TELEGRAM_ENABLED}"
if [ "${TELEGRAM_ENABLED}" = "true" ]; then
echo "Telegram DM Policy: ${TELEGRAM_DM_POLICY}"
echo "Telegram Allow From: ${TELEGRAM_ALLOW_FROM}"
fi
echo "========================================"
# 后台备份循环(如果启用)
if [ "${BACKUP_ENABLED}" = "true" ] && [ -n "$HF_DATASET" ] && [ -n "$HF_TOKEN" ]; then
(
while true; do
sleep ${BACKUP_INTERVAL}
python3 /usr/local/bin/sync.py backup || true
done
) &
fi
# 启动网关
openclaw doctor --fix || true
exec openclaw gateway run --port $PORT
START_EOF
RUN chmod +x /usr/local/bin/start-openclaw
EXPOSE 7860
CMD ["/usr/local/bin/start-openclaw"]