yamiclaws commited on
Commit
fd2f0bd
Β·
verified Β·
1 Parent(s): 8acd114

Update start-openclaw.sh

Browse files
Files changed (1) hide show
  1. start-openclaw.sh +101 -232
start-openclaw.sh CHANGED
@@ -1,14 +1,6 @@
1
  #!/bin/bash
2
 
3
- # ─────────────────────────────────────────────────────────────
4
- # OpenClaw Startup Script - FREE MODELS ONLY
5
- # All API keys are read from environment variables (HF Secrets)
6
- # No keys are hardcoded or written to logs
7
- # ─────────────────────────────────────────────────────────────
8
-
9
- set -e
10
-
11
- echo "===== OpenClaw Startup (Free Models Only) ====="
12
 
13
  # ── TRAP: Backup saat container mati ─────────────────────────
14
  trap 'echo ">>> [TRAP] Container stopping β€” final backup..."; python3 /app/sync.py backup; echo ">>> [TRAP] Done."' EXIT SIGTERM SIGINT
@@ -23,143 +15,127 @@ mkdir -p /root/.openclaw/workspace/memory
23
  echo ">>> Directories ready."
24
 
25
  # ── 2. Restore backup ─────────────────────────────────────────
26
- python3 /app/sync.py restore
27
- echo ">>> Restore done."
 
 
 
 
28
 
29
- # ── 3. Fix DNS & Hosts (Telegram Fix) ────────────────────────
30
  echo "nameserver 1.1.1.1" >> /etc/resolv.conf
31
  echo "nameserver 8.8.8.8" >> /etc/resolv.conf
32
  echo "149.154.166.110 api.telegram.org" >> /etc/hosts
33
- echo ">>> DNS fixed for Telegram."
34
-
35
- # ── 4. Chromium for Browser Tool ──────────────────────────────
36
- export PLAYWRIGHT_BROWSERS_PATH=/root/.openclaw/browsers
37
- CHROMIUM_PATH=$(find /root/.openclaw/browsers -name "chrome" -type f 2>/dev/null | head -1)
38
-
39
- if [ -z "$CHROMIUM_PATH" ]; then
40
- echo ">>> Installing Chromium..."
41
- OPENCLAW_NM=$(npm root -g 2>/dev/null)/openclaw/node_modules/playwright-core/cli.js
42
- if timeout 180 node "$OPENCLAW_NM" install chromium 2>/dev/null; then
43
- echo ">>> Chromium installed"
44
- else
45
- echo ">>> WARN: Chromium install skipped (non-critical)"
46
- fi
47
- CHROMIUM_PATH=$(find /root/.openclaw/browsers -name "chrome" -type f 2>/dev/null | head -1)
48
- fi
49
-
50
- # ── 5. Build FREE MODELS PROVIDERS (No API keys in config - use env substitution) ──
51
- # Note: OpenClaw will read ${VAR_NAME} from environment at runtime
52
- # This means API keys NEVER appear in the generated config file
53
 
54
- # Start building providers JSON
55
  PROVIDERS_JSON="{}"
 
56
 
57
- # OpenCode Zen (Free Models) - Primary recommendation
58
  if [ -n "$OPENCODE_API_KEY" ]; then
59
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.opencode = {
60
- "baseUrl": "https://opencode.ai/zen/v1",
61
- "apiKey": "${OPENCODE_API_KEY}",
62
- "api": "openai-completions",
63
- "models": [
64
- {"id": "minimax-m2.5-free", "name": "⭐ MiniMax M2.5 Free", "contextWindow": 200000},
65
- {"id": "kimi-k2.5-free", "name": "⭐ Kimi K2.5 Free", "contextWindow": 256000},
66
- {"id": "glm-5-free", "name": "GLM-5 Free", "contextWindow": 128000}
67
- ]
68
- }')
 
69
  PRIMARY_MODEL="opencode/minimax-m2.5-free"
70
- echo ">>> OpenCode Zen configured (FREE models)"
71
  fi
72
 
73
- # NVIDIA NIM (Free tier - requires API key from build.nvidia.com)
74
  if [ -n "$NVIDIA_NIM_KEY" ]; then
75
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.["nvidia-nim"] = {
76
- "baseUrl": "https://integrate.api.nvidia.com/v1",
77
- "apiKey": "${NVIDIA_NIM_KEY}",
78
- "api": "openai-completions",
79
- "models": [
80
- {"id": "nvidia/Kimi-N-Agent-Preview-1217", "name": "Kimi N (NVIDIA NIM)", "contextWindow": 128000},
81
- {"id": "nvidia/nemotron-3-super-120b", "name": "Nemotron 3 Super", "contextWindow": 128000}
82
- ]
83
- }')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  if [ -z "$PRIMARY_MODEL" ]; then
85
  PRIMARY_MODEL="nvidia-nim/nvidia/Kimi-N-Agent-Preview-1217"
86
  fi
87
- echo ">>> NVIDIA NIM configured (FREE tier)"
88
  fi
89
 
90
- # Groq (Free tier - 30 requests/minute)
91
  if [ -n "$GROQ_API_KEY" ]; then
92
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.groq = {
93
- "baseUrl": "https://api.groq.com/openai/v1",
94
- "apiKey": "${GROQ_API_KEY}",
95
- "api": "openai-completions",
96
- "models": [
97
- {"id": "llama-3.1-70b-versatile", "name": "Llama 3.1 70B (Groq)", "contextWindow": 128000},
98
- {"id": "llama-3.1-8b-instant", "name": "Llama 3.1 8B (Groq)", "contextWindow": 128000},
99
- {"id": "mixtral-8x7b-32768", "name": "Mixtral 8x7B (Groq)", "contextWindow": 32768}
100
- ]
101
- }')
102
- if [ -z "$PRIMARY_MODEL" ]; then
103
- PRIMARY_MODEL="groq/llama-3.1-70b-versatile"
104
- fi
105
- echo ">>> Groq configured (FREE tier - 30 req/min)"
106
- fi
107
-
108
- # OpenRouter (Free models via $1 free credit)
109
- if [ -n "$OPENROUTER_API_KEY" ]; then
110
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.openrouter = {
111
- "baseUrl": "https://openrouter.ai/api/v1",
112
- "apiKey": "${OPENROUTER_API_KEY}",
113
- "api": "openai-completions",
114
- "models": [
115
- {"id": "meta-llama/llama-3.3-70b-instruct:free", "name": "Llama 3.3 70B (Free)", "contextWindow": 128000},
116
- {"id": "google/gemma-3-27b-it:free", "name": "Gemma 3 27B (Free)", "contextWindow": 8000},
117
- {"id": "mistralai/mistral-7b-instruct:free", "name": "Mistral 7B (Free)", "contextWindow": 32768}
118
- ]
119
- }')
120
- if [ -z "$PRIMARY_MODEL" ]; then
121
- PRIMARY_MODEL="openrouter/meta-llama/llama-3.3-70b-instruct:free"
122
  fi
123
- echo ">>> OpenRouter configured (FREE models)"
124
- fi
125
-
126
- # Google Gemini (Free tier - 60 requests/minute)
127
- if [ -n "$GEMINI_API_KEY" ]; then
128
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.google = {
129
- "baseUrl": "https://generativelanguage.googleapis.com/v1beta/openai",
130
- "apiKey": "${GEMINI_API_KEY}",
131
- "api": "openai-completions",
132
- "models": [
133
- {"id": "gemini-2.0-flash", "name": "Gemini 2.0 Flash (Free)", "contextWindow": 1048576},
134
- {"id": "gemini-1.5-flash", "name": "Gemini 1.5 Flash (Free)", "contextWindow": 1048576}
135
- ]
136
- }')
137
  if [ -z "$PRIMARY_MODEL" ]; then
138
- PRIMARY_MODEL="google/gemini-2.0-flash"
139
  fi
140
- echo ">>> Google Gemini configured (FREE tier - 60 req/min)"
141
  fi
142
 
143
- # Fallback to Kilo AI (truly anonymous, no API key needed)
144
  if [ -z "$PRIMARY_MODEL" ]; then
145
- PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | jq '.kilo_gateway = {
146
- "baseUrl": "https://api.kilo.ai/api/gateway",
147
- "apiKey": "anonymous",
148
- "api": "openai-completions",
149
- "models": [
150
- {"id": "kilo-auto/free", "name": "Kilo Auto Free (No API Key)", "contextWindow": 128000}
151
- ]
152
- }')
153
- PRIMARY_MODEL="kilo_gateway/kilo-auto/free"
154
- echo ">>> Kilo AI configured (FALLBACK - no API key needed)"
 
 
155
  fi
156
 
157
- # Set vision model (use same as primary or a specific vision model)
158
- VISION_MODEL="${VISION_MODEL:-$PRIMARY_MODEL}"
 
 
 
159
 
160
- # ── 6. Generate openclaw.json (NO API KEYS IN FILE - uses ${VAR} substitution) ──
161
- # CRITICAL: API keys are stored as ${ENV_VAR} not actual values
162
- # OpenClaw will resolve these at runtime from environment variables
163
  cat > /root/.openclaw/openclaw.json <<EOF
164
  {
165
  "models": {
@@ -168,43 +144,7 @@ cat > /root/.openclaw/openclaw.json <<EOF
168
  "agents": {
169
  "defaults": {
170
  "model": {
171
- "primary": "$PRIMARY_MODEL",
172
- "fallbacks": ["kilo_gateway/kilo-auto/free"]
173
- },
174
- "imageModel": {
175
- "primary": "$VISION_MODEL"
176
- }
177
- }
178
- },
179
- "commands": { "restart": true },
180
- "browser": {
181
- "enabled": true,
182
- "requirePairing": false,
183
- "headless": true,
184
- "noSandbox": true,
185
- "executablePath": "$CHROMIUM_PATH",
186
- "defaultProfile": "openclaw",
187
- "ssrfPolicy": { "dangerouslyAllowPrivateNetwork": true },
188
- "profiles": {
189
- "openclaw": {
190
- "cdpPort": 18800,
191
- "color": "0088FF"
192
- }
193
- }
194
- },
195
- "channels": {
196
- "telegram": {
197
- "enabled": true,
198
- "botToken": "\${TELEGRAM_BOT_TOKEN}",
199
- "dmPolicy": "allowlist",
200
- "allowFrom": ["\${TELEGRAM_ALLOW_ID}"],
201
- "webhookUrl": "https://\${SPACE_NAME}.hf.space/telegram/webhook",
202
- "webhookSecret": "\${OPENCLAW_GATEWAY_PASSWORD}",
203
- "webhookPath": "/telegram/webhook",
204
- "webhookHost": "0.0.0.0",
205
- "webhookPort": 8787,
206
- "streaming": {
207
- "mode": "partial"
208
  }
209
  }
210
  },
@@ -213,90 +153,19 @@ cat > /root/.openclaw/openclaw.json <<EOF
213
  "bind": "lan",
214
  "port": 7862,
215
  "trustedProxies": ["0.0.0.0/0"],
216
- "auth": { "mode": "token", "token": "\${OPENCLAW_GATEWAY_PASSWORD}" },
217
- "http": {
218
- "endpoints": {
219
- "chatCompletions": { "enabled": true }
220
- }
221
- },
222
- "controlUi": {
223
- "enabled": true,
224
- "allowInsecureAuth": true,
225
- "dangerouslyDisableDeviceAuth": true,
226
- "dangerouslyAllowHostHeaderOriginFallback": true
227
- }
228
  }
229
  }
230
  EOF
231
 
232
- echo ">>> openclaw.json generated (API keys use \${ENV_VAR} - never exposed)"
233
  echo ">>> Primary Model: $PRIMARY_MODEL"
234
 
235
- # ── 7. Disable Broken Speech Plugin ────────────────────────────
236
  mkdir -p /root/.openclaw/plugins
237
  echo '{"disabled": ["speech"]}' > /root/.openclaw/plugins/config.json
238
- echo ">>> Speech plugin disabled (avoids runtime-api.js error)"
239
 
240
- # ── 8. Node.js reverse proxy (Anti-Timeout) ────────────────────
241
- node -e "
242
- const http = require('http');
243
- const net = require('net');
244
- process.on('uncaughtException', err => console.error('Proxy:', err.message));
245
- function proxyHttp(req, res, targetPort) {
246
- const opts = { hostname: '127.0.0.1', port: targetPort, path: req.url, method: req.method, headers: req.headers };
247
- const pr = http.request(opts, (r) => { res.writeHead(r.statusCode, r.headers); r.pipe(res, { end: true }); });
248
- pr.on('error', () => {
249
- res.writeHead(200, { 'Content-Type': 'text/html' });
250
- res.end('<html style=\"background:#1e1e2e; color:#cdd6f4; text-align:center; padding-top:20%;\"><body><h2>πŸš€ OpenClaw is starting...</h2><p>Please refresh in a few seconds.</p></body></html>');
251
- });
252
- req.pipe(pr, { end: true });
253
- }
254
- function proxyWs(req, socket, head, targetPort) {
255
- const conn = net.connect(targetPort, '127.0.0.1', () => {
256
- conn.write('GET ' + req.url + ' HTTP/1.1\r\n' + Object.entries(req.headers).map(([k,v]) => k+': '+v).join('\r\n') + '\r\n\r\n');
257
- if (head && head.length) conn.write(head);
258
- socket.pipe(conn); conn.pipe(socket);
259
- });
260
- conn.on('error', () => socket.destroy());
261
- socket.on('error', () => conn.destroy());
262
- }
263
- const server = http.createServer((req, res) => {
264
- const port = req.url.startsWith('/telegram/webhook') ? 8787 : 7862;
265
- proxyHttp(req, res, port);
266
- });
267
- server.on('upgrade', (req, socket, head) => {
268
- const port = req.url.startsWith('/telegram/webhook') ? 8787 : 7862;
269
- proxyWs(req, socket, head, port);
270
- });
271
- server.listen(7860, '0.0.0.0', () => console.log('Proxy on port 7860'));
272
- " &
273
- echo ">>> Proxy started on port 7860"
274
-
275
- # ── 9. Backup every 60 minutes ─────────────────────────────────
276
- (
277
- sleep 60
278
- python3 /app/sync.py backup
279
- while true; do
280
- sleep 3600
281
- echo ">>> Scheduled backup..."
282
- python3 /app/sync.py backup
283
- done
284
- ) &
285
-
286
- # ── 10. Run OpenClaw with auto-restart ─────────────────────────
287
- echo ">>> Running openclaw doctor..."
288
  openclaw doctor --fix
289
 
290
- RESTART_COUNT=0
291
- while true; do
292
- RESTART_COUNT=$((RESTART_COUNT + 1))
293
- echo ">>> [Loop #$RESTART_COUNT] Starting OpenClaw gateway..."
294
-
295
- openclaw gateway run --port 7862
296
- EXIT_CODE=$?
297
-
298
- echo ">>> Gateway stopped (exit: $EXIT_CODE) β€” backing up..."
299
- python3 /app/sync.py backup
300
- echo ">>> Restarting in 5 seconds..."
301
- sleep 5
302
- done
 
1
  #!/bin/bash
2
 
3
+ echo "===== OpenClaw Startup ====="
 
 
 
 
 
 
 
 
4
 
5
  # ── TRAP: Backup saat container mati ─────────────────────────
6
  trap 'echo ">>> [TRAP] Container stopping β€” final backup..."; python3 /app/sync.py backup; echo ">>> [TRAP] Done."' EXIT SIGTERM SIGINT
 
15
  echo ">>> Directories ready."
16
 
17
  # ── 2. Restore backup ─────────────────────────────────────────
18
+ if [ -n "$HF_DATASET" ] && [ -n "$HF_TOKEN" ]; then
19
+ python3 /app/sync.py restore
20
+ echo ">>> Restore done."
21
+ else
22
+ echo ">>> No HF_DATASET or HF_TOKEN - skipping restore"
23
+ fi
24
 
25
+ # ── 3. Fix DNS for Telegram ────────────────────────────────────
26
  echo "nameserver 1.1.1.1" >> /etc/resolv.conf
27
  echo "nameserver 8.8.8.8" >> /etc/resolv.conf
28
  echo "149.154.166.110 api.telegram.org" >> /etc/hosts
29
+ echo ">>> DNS fixed."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
+ # ── 4. Build providers JSON (Pure bash - no jq required) ──────
32
  PROVIDERS_JSON="{}"
33
+ PRIMARY_MODEL=""
34
 
35
+ # OpenCode Zen
36
  if [ -n "$OPENCODE_API_KEY" ]; then
37
+ PROVIDERS_JSON='{
38
+ "opencode": {
39
+ "baseUrl": "https://opencode.ai/zen/v1",
40
+ "apiKey": "'"$OPENCODE_API_KEY"'",
41
+ "api": "openai-completions",
42
+ "models": [
43
+ {"id": "minimax-m2.5-free", "name": "MiniMax M2.5 Free", "contextWindow": 200000},
44
+ {"id": "kimi-k2.5-free", "name": "Kimi K2.5 Free", "contextWindow": 256000}
45
+ ]
46
+ }
47
+ }'
48
  PRIMARY_MODEL="opencode/minimax-m2.5-free"
49
+ echo ">>> OpenCode Zen configured"
50
  fi
51
 
52
+ # NVIDIA NIM
53
  if [ -n "$NVIDIA_NIM_KEY" ]; then
54
+ if [ "$PROVIDERS_JSON" != "{}" ]; then
55
+ PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | sed 's/}$//')
56
+ PROVIDERS_JSON="${PROVIDERS_JSON},
57
+ \"nvidia-nim\": {
58
+ \"baseUrl\": \"https://integrate.api.nvidia.com/v1\",
59
+ \"apiKey\": \"$NVIDIA_NIM_KEY\",
60
+ \"api\": \"openai-completions\",
61
+ \"models\": [
62
+ {\"id\": \"nvidia/Kimi-N-Agent-Preview-1217\", \"name\": \"Kimi N (NVIDIA NIM)\"}
63
+ ]
64
+ }
65
+ }"
66
+ else
67
+ PROVIDERS_JSON='{
68
+ "nvidia-nim": {
69
+ "baseUrl": "https://integrate.api.nvidia.com/v1",
70
+ "apiKey": "'"$NVIDIA_NIM_KEY"'",
71
+ "api": "openai-completions",
72
+ "models": [
73
+ {"id": "nvidia/Kimi-N-Agent-Preview-1217", "name": "Kimi N (NVIDIA NIM)"}
74
+ ]
75
+ }
76
+ }'
77
+ fi
78
  if [ -z "$PRIMARY_MODEL" ]; then
79
  PRIMARY_MODEL="nvidia-nim/nvidia/Kimi-N-Agent-Preview-1217"
80
  fi
81
+ echo ">>> NVIDIA NIM configured"
82
  fi
83
 
84
+ # Groq
85
  if [ -n "$GROQ_API_KEY" ]; then
86
+ if [ "$PROVIDERS_JSON" != "{}" ]; then
87
+ PROVIDERS_JSON=$(echo "$PROVIDERS_JSON" | sed 's/}$//')
88
+ PROVIDERS_JSON="${PROVIDERS_JSON},
89
+ \"groq\": {
90
+ \"baseUrl\": \"https://api.groq.com/openai/v1\",
91
+ \"apiKey\": \"$GROQ_API_KEY\",
92
+ \"api\": \"openai-completions\",
93
+ \"models\": [
94
+ {\"id\": \"llama-3.1-70b-versatile\", \"name\": \"Llama 3.1 70B (Groq)\"}
95
+ ]
96
+ }
97
+ }"
98
+ else
99
+ PROVIDERS_JSON='{
100
+ "groq": {
101
+ "baseUrl": "https://api.groq.com/openai/v1",
102
+ "apiKey": "'"$GROQ_API_KEY"'",
103
+ "api": "openai-completions",
104
+ "models": [
105
+ {"id": "llama-3.1-70b-versatile", "name": "Llama 3.1 70B (Groq)"}
106
+ ]
107
+ }
108
+ }'
 
 
 
 
 
 
 
109
  fi
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  if [ -z "$PRIMARY_MODEL" ]; then
111
+ PRIMARY_MODEL="groq/llama-3.1-70b-versatile"
112
  fi
113
+ echo ">>> Groq configured"
114
  fi
115
 
116
+ # Fallback to Kilo (no API key needed)
117
  if [ -z "$PRIMARY_MODEL" ]; then
118
+ PROVIDERS_JSON='{
119
+ "kilo": {
120
+ "baseUrl": "https://api.kilo.ai/api/gateway",
121
+ "apiKey": "anonymous",
122
+ "api": "openai-completions",
123
+ "models": [
124
+ {"id": "kilo-auto/free", "name": "Kilo Auto Free (No API Key Needed)"}
125
+ ]
126
+ }
127
+ }'
128
+ PRIMARY_MODEL="kilo/kilo-auto/free"
129
+ echo ">>> Using Kilo AI fallback (no API key needed)"
130
  fi
131
 
132
+ # Close JSON if it was left open
133
+ if [[ ! "$PROVIDERS_JSON" =~ }$ ]]; then
134
+ PROVIDERS_JSON="${PROVIDERS_JSON}
135
+ }"
136
+ fi
137
 
138
+ # ── 5. Generate openclaw.json ─────────────────────────────────
 
 
139
  cat > /root/.openclaw/openclaw.json <<EOF
140
  {
141
  "models": {
 
144
  "agents": {
145
  "defaults": {
146
  "model": {
147
+ "primary": "$PRIMARY_MODEL"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
  }
150
  },
 
153
  "bind": "lan",
154
  "port": 7862,
155
  "trustedProxies": ["0.0.0.0/0"],
156
+ "auth": { "mode": "token", "token": "${OPENCLAW_GATEWAY_PASSWORD:-openclaw123}" }
 
 
 
 
 
 
 
 
 
 
 
157
  }
158
  }
159
  EOF
160
 
 
161
  echo ">>> Primary Model: $PRIMARY_MODEL"
162
 
163
+ # ── 6. Disable speech plugin ──────────────────────────────────
164
  mkdir -p /root/.openclaw/plugins
165
  echo '{"disabled": ["speech"]}' > /root/.openclaw/plugins/config.json
 
166
 
167
+ # ── 7. Run OpenClaw ─────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  openclaw doctor --fix
169
 
170
+ echo ">>> Starting OpenClaw gateway..."
171
+ exec openclaw gateway run --port 7862