Openclaw / start.sh
Elysiadev11's picture
Update start.sh
edfe3a2 verified
#!/usr/bin/env bash
set -euo pipefail
export PROXY_PORT="${PROXY_PORT:-7860}"
export OPENCLAW_PORT="${OPENCLAW_PORT:-8080}"
export CODE_PORT="${CODE_PORT:-8888}"
export PORT="${OPENCLAW_PORT}"
export HOST="0.0.0.0"
export OPENCLAW_HOST="0.0.0.0"
export OPENCLAW_PORT
export OPENCLAW_GATEWAY_PASSWORD="${OPENCLAW_GATEWAY_PASSWORD:-773322}"
export SYNC_INTERVAL="${SYNC_INTERVAL:-300}"
export PLAYWRIGHT_BROWSERS_PATH="${PLAYWRIGHT_BROWSERS_PATH:-/ms-playwright}"
export TELEGRAM_API_ROOT="${TELEGRAM_API_ROOT:-https://tg-relay.markdevil11.workers.dev}"
export OPENCLAW_TELEGRAM_API_ROOT="${OPENCLAW_TELEGRAM_API_ROOT:-${TELEGRAM_API_ROOT}}"
export SPACE_URL="${SPACE_URL:-https://elysiadev11-openclaw.hf.space}"
export TELEGRAM_BOT_TOKEN="${TELEGRAM_BOT_TOKEN:-}"
export TELEGRAM_ALLOW_ID="${TELEGRAM_ALLOW_ID:-0}"
configure_dns() {
if [ -w /etc/resolv.conf ]; then
cat > /etc/resolv.conf <<'EOF'
nameserver 1.1.1.1
nameserver 1.0.0.1
nameserver 8.8.8.8
nameserver 8.8.4.4
options timeout:2 attempts:3 rotate
EOF
echo "DNS configured with Cloudflare and Google resolvers."
else
echo "WARN: /etc/resolv.conf is not writable; keeping existing DNS."
fi
}
mkdir -p /root/workspace
configure_dns
/app/sync-root-data.sh restore
mkdir -p /root/.openclaw
generate_openclaw_config() {
local clean_base
clean_base="$(printf '%s' "${OPENAI_API_BASE:-}" | sed 's|/chat/completions||g' | sed 's|/v1/|/v1|g' | sed 's|/v1$|/v1|g')"
local allow_id
allow_id="${TELEGRAM_ALLOW_ID:-0}"
local primary_model="kilo_gateway/kilo-auto/free"
local nvidia_provider=""
if [ -n "$clean_base" ] && [ -n "${OPENAI_API_KEY:-}" ]; then
primary_model="nvidia/${MODEL:-gpt-5.5}"
nvidia_provider=',
"nvidia": {
"baseUrl": "'"${clean_base}"'",
"apiKey": "'"${OPENAI_API_KEY:-}"'",
"api": "openai-completions",
"models": [
{ "id": "'"${MODEL:-gpt-5.5}"'", "name": "'"${MODEL:-gpt-5.5}"'", "contextWindow": 128000 },
{ "id": "'"${VISION_MODEL:-${MODEL:-gpt-5.5}}"'", "name": "Nvidia Vision", "contextWindow": 128000, "input": ["text", "image"] }
]
}'
fi
cat > /root/.openclaw/openclaw.json <<JSONEOF
{
"models": {
"providers": {
"kilo_gateway": {
"baseUrl": "https://api.kilo.ai/api/gateway",
"apiKey": "anonymous",
"api": "openai-completions",
"models": [
{ "id": "kilo-auto/free", "name": "Kilo Auto Free", "contextWindow": 128000, "maxTokens": 16000 }
]
}${nvidia_provider}
}
},
"agents": {
"defaults": {
"model": {
"primary": "${primary_model}",
"fallbacks": ["kilo_gateway/kilo-auto/free"]
},
"imageModel": {
"primary": "${primary_model}"
}
}
},
"commands": { "restart": true },
"browser": {
"enabled": true,
"headless": true,
"noSandbox": true,
"defaultProfile": "openclaw",
"ssrfPolicy": { "dangerouslyAllowPrivateNetwork": true },
"profiles": {
"openclaw": {
"cdpPort": 18800,
"color": "0088FF"
}
}
},
"channels": {
"telegram": {
"enabled": true,
"botToken": "${TELEGRAM_BOT_TOKEN:-}",
"dmPolicy": "allowlist",
"allowFrom": [${allow_id}],
"apiRoot": "${TELEGRAM_API_ROOT}",
"webhookUrl": "${SPACE_URL}/tg-webhook",
"webhookSecret": "${OPENCLAW_GATEWAY_PASSWORD:-}",
"webhookPath": "/tg-webhook",
"webhookHost": "0.0.0.0",
"webhookPort": 8787,
"streaming": {
"mode": "partial"
}
}
},
"gateway": {
"mode": "local",
"bind": "lan",
"port": ${OPENCLAW_PORT},
"trustedProxies": ["0.0.0.0/0"],
"auth": { "mode": "token", "token": "${OPENCLAW_GATEWAY_PASSWORD:-}" },
"http": {
"endpoints": {
"chatCompletions": { "enabled": true }
}
},
"controlUi": {
"enabled": true,
"allowedOrigins": ["${SPACE_URL}"],
"allowInsecureAuth": true,
"dangerouslyDisableDeviceAuth": true,
"dangerouslyAllowHostHeaderOriginFallback": true
}
}
}
JSONEOF
}
config_is_complete() {
python3 - <<'PY'
import json
from pathlib import Path
path = Path('/root/.openclaw/openclaw.json')
if not path.exists():
raise SystemExit(1)
try:
data = json.loads(path.read_text())
except Exception:
raise SystemExit(1)
required_paths = [
('models', 'providers'),
('models', 'providers', 'kilo_gateway'),
('agents', 'defaults'),
('browser',),
('gateway',),
('gateway', 'controlUi'),
('channels', 'telegram'),
]
for parts in required_paths:
cur = data
for part in parts:
if not isinstance(cur, dict) or part not in cur:
raise SystemExit(1)
cur = cur[part]
raise SystemExit(0)
PY
}
if ! config_is_complete; then
echo "Generating full /root/.openclaw/openclaw.json before OpenClaw startup..."
generate_openclaw_config
else
echo "Complete /root/.openclaw/openclaw.json found; keeping it."
fi
python3 - <<'PY'
import json
import os
from pathlib import Path
path = Path('/root/.openclaw/openclaw.json')
api_root = os.environ.get('TELEGRAM_API_ROOT', 'https://tg-relay.markdevil11.workers.dev')
space_url = os.environ.get('SPACE_URL', 'https://elysiadev11-openclaw.hf.space')
if not path.exists():
raise SystemExit(0)
try:
data = json.loads(path.read_text())
except Exception as exc:
print(f'WARN: cannot update Telegram apiRoot in openclaw.json: {exc}')
raise SystemExit(0)
channels = data.setdefault('channels', {})
telegram = channels.setdefault('telegram', {})
old = telegram.get('apiRoot')
providers = data.setdefault('models', {}).setdefault('providers', {})
nvidia = providers.get('nvidia')
if isinstance(nvidia, dict) and not nvidia.get('baseUrl'):
providers.pop('nvidia', None)
agents = data.setdefault('agents', {})
defaults = agents.setdefault('defaults', {})
model = defaults.setdefault('model', {})
if model.get('primary', '').startswith('nvidia/') and 'nvidia' not in providers:
model['primary'] = 'kilo_gateway/kilo-auto/free'
fallbacks = model.setdefault('fallbacks', [])
if 'kilo_gateway/kilo-auto/free' not in fallbacks:
fallbacks.append('kilo_gateway/kilo-auto/free')
image_model = defaults.setdefault('imageModel', {})
if image_model.get('primary', '').startswith('nvidia/') and 'nvidia' not in providers:
image_model['primary'] = model['primary']
telegram['webhookUrl'] = f'{space_url}/tg-webhook'
telegram['webhookPath'] = '/tg-webhook'
telegram['webhookHost'] = '0.0.0.0'
telegram['webhookPort'] = 8787
browser = data.get('browser')
if isinstance(browser, dict):
browser.pop('requirePairing', None)
if isinstance(defaults, dict):
defaults.pop('llm', None)
gateway = data.setdefault('gateway', {})
auth = gateway.setdefault('auth', {})
auth['mode'] = 'token'
auth['token'] = os.environ.get('OPENCLAW_GATEWAY_PASSWORD', '773322')
control_ui = gateway.setdefault('controlUi', {})
control_ui['enabled'] = True
control_ui['allowInsecureAuth'] = True
control_ui['dangerouslyDisableDeviceAuth'] = True
control_ui['dangerouslyAllowHostHeaderOriginFallback'] = True
origins = control_ui.setdefault('allowedOrigins', [])
if space_url not in origins:
origins.append(space_url)
if old != api_root:
telegram['apiRoot'] = api_root
print(f'Updated Telegram apiRoot: {old!r} -> {api_root!r}')
else:
print(f'Telegram apiRoot already set to {api_root}')
print(f'Telegram webhookUrl set to {telegram.get("webhookUrl")}')
path.write_text(json.dumps(data, indent=2) + '\n')
PY
/app/sync-root-data.sh reconcile
/app/sync-root-data.sh loop &
# ── code-server (VS Code) ─────────────────────────────────────────────────────
run_code_server() {
mkdir -p /root/.config/code-server
cat > /root/.config/code-server/config.yaml <<YAML
bind-addr: 127.0.0.1:${CODE_PORT}
auth: password
password: ${OPENCLAW_GATEWAY_PASSWORD}
cert: false
YAML
while true; do
echo "Starting code-server on 127.0.0.1:${CODE_PORT}..."
code-server --config /root/.config/code-server/config.yaml /root/workspace
echo "code-server exited; restarting in 2 seconds..."
sleep 2
done
}
# ─────────────────────────────────────────────────────────────────────────────
run_openclaw() {
while true; do
echo "Starting OpenClaw on 127.0.0.1:${OPENCLAW_PORT}..."
echo "OpenClaw config:"
cat /root/.openclaw/openclaw.json
if [ -n "${OPENCLAW_CMD:-}" ]; then
sh -lc "$OPENCLAW_CMD"
else
openclaw gateway --port "${OPENCLAW_PORT}" --allow-unconfigured &
OPENCLAW_PID=$!
echo "OpenClaw started with PID: $OPENCLAW_PID"
wait $OPENCLAW_PID
fi
echo "OpenClaw exited; restarting in 2 seconds..."
sleep 2
done
}
run_nginx() {
while true; do
envsubst '${PROXY_PORT} ${OPENCLAW_PORT} ${OPENCLAW_GATEWAY_PASSWORD} ${CODE_PORT}' \
< /app/nginx.conf.template > /tmp/nginx.conf
nginx -c /tmp/nginx.conf -g 'daemon off;'
echo "Nginx exited; restarting in 2 seconds..."
sleep 2
done
}
run_simple_webhook() {
while true; do
echo "Starting simple webhook server on port 8787..."
python3 /app/webhook_server.py &
WEBHOOK_PID=$!
echo "Simple webhook server started with PID: $WEBHOOK_PID"
wait $WEBHOOK_PID
echo "Webhook server exited; restarting in 2 seconds..."
sleep 2
done
}
run_openclaw &
run_code_server &
run_nginx &
# Wait for services to start
echo "Waiting for services to start..."
sleep 10
# Check webhook port
echo "Checking webhook port 8787..."
if command -v ss &> /dev/null && ss -tuln 2>/dev/null | grep -q ":8787"; then
echo "Webhook server is listening on port 8787"
curl -s -o /dev/null -w "Webhook test status: %{http_code}\n" http://localhost:8787/tg-webhook || true
elif curl -s http://0.0.0.0:8787/tg-webhook &>/dev/null; then
echo "Webhook server is accessible on port 8787"
else
echo "WARNING: Webhook server is NOT listening on port 8787 — starting fallback..."
run_simple_webhook &
fi
# Check OpenClaw port
echo "Checking OpenClaw port ${OPENCLAW_PORT}..."
if command -v ss &> /dev/null && ss -tuln 2>/dev/null | grep -q ":${OPENCLAW_PORT}"; then
echo "OpenClaw is listening on port ${OPENCLAW_PORT}"
elif curl -s http://127.0.0.1:${OPENCLAW_PORT}/health &>/dev/null; then
echo "OpenClaw is accessible on port ${OPENCLAW_PORT}"
else
echo "WARNING: OpenClaw is NOT listening on port ${OPENCLAW_PORT}"
fi
# Check code-server port
echo "Checking code-server port ${CODE_PORT}..."
if command -v ss &> /dev/null && ss -tuln 2>/dev/null | grep -q ":${CODE_PORT}"; then
echo "code-server is listening on port ${CODE_PORT}"
else
echo "WARNING: code-server is NOT listening on port ${CODE_PORT}"
fi
wait -n
exit 1