Anurag commited on
Commit
df97c33
Β·
1 Parent(s): d5203bf

Fix browser launch/detection and gateway port handling issues

Browse files
Files changed (6) hide show
  1. .env.example +2 -9
  2. Dockerfile +2 -0
  3. README.md +3 -3
  4. env-builder.js +11 -30
  5. iframe-fix.cjs +3 -2
  6. start.sh +73 -14
.env.example CHANGED
@@ -248,8 +248,8 @@ LLM_API_KEY_FALLBACK_ENABLED=true
248
  GATEWAY_TOKEN=your_gateway_token_here
249
 
250
  # [OPTIONAL] JupyterLab terminal token for /terminal/
251
- # Defaults to "huggingface" if unset. Set a strong token for private deployments.
252
- JUPYTER_TOKEN=huggingface
253
 
254
  # (Optional) Password auth β€” simpler alternative to token for casual users
255
  # If set, users can log in with this password instead of the token
@@ -288,14 +288,7 @@ HF_TOKEN=hf_your_token_here
288
  # Default: huggingclaw-backup
289
  BACKUP_DATASET_NAME=huggingclaw-backup
290
 
291
- # Git commit identity for workspace syncs
292
- WORKSPACE_GIT_USER=openclaw@example.com
293
- WORKSPACE_GIT_NAME=OpenClaw Bot
294
-
295
  # ── OPTIONAL: Background Services ──
296
- # Keep-alive ping interval (seconds). Default: 300. Set 0 to disable.
297
- KEEP_ALIVE_INTERVAL=300
298
-
299
  # Workspace auto-sync interval (seconds). Default: 180.
300
  SYNC_INTERVAL=180
301
 
 
248
  GATEWAY_TOKEN=your_gateway_token_here
249
 
250
  # [OPTIONAL] JupyterLab terminal token for /terminal/
251
+ # Set a strong token for private deployments. Must NOT be "huggingface".
252
+ JUPYTER_TOKEN=run: openssl rand -hex 32
253
 
254
  # (Optional) Password auth β€” simpler alternative to token for casual users
255
  # If set, users can log in with this password instead of the token
 
288
  # Default: huggingclaw-backup
289
  BACKUP_DATASET_NAME=huggingclaw-backup
290
 
 
 
 
 
291
  # ── OPTIONAL: Background Services ──
 
 
 
292
  # Workspace auto-sync interval (seconds). Default: 180.
293
  SYNC_INTERVAL=180
294
 
Dockerfile CHANGED
@@ -24,6 +24,8 @@ RUN apt-get update && apt-get install -y \
24
  ca-certificates \
25
  jq \
26
  curl \
 
 
27
  python3 \
28
  python3-pip \
29
  chromium \
 
24
  ca-certificates \
25
  jq \
26
  curl \
27
+ dbus \
28
+ dbus-x11 \
29
  python3 \
30
  python3-pip \
31
  chromium \
README.md CHANGED
@@ -104,7 +104,7 @@ Navigate to your new Space's **Settings**, scroll down to the **Variables and se
104
  > [!TIP]
105
  > HuggingClaw is completely flexible! You only need these three secrets to get started. You can set other secrets later.
106
 
107
- Optional: set `DEV_MODE=true` (Variable) to enable JupyterLab support and install Jupyter dependencies at build time. You can also set `JUPYTER_TOKEN` as a Secret to replace the default terminal token (`huggingface`). If you want to pin a specific OpenClaw release instead of `latest`, add `OPENCLAW_VERSION` under **Variables** in your Space settings. For Docker Spaces, HF passes Variables as build args during image build, so these should be Variables, not Secrets (except tokens).
108
 
109
  ### Step 3: Deploy & Run
110
 
@@ -366,12 +366,12 @@ The merged Space includes the Hugging Face JupyterLab template behavior inside t
366
  | :--- | :--- | :--- | :--- |
367
  | `/` | HuggingClaw dashboard | `7861` | Public HF Spaces entrypoint |
368
  | `/app/` | OpenClaw Control UI | `7860` | Mounted behind the local reverse proxy |
369
- | `/terminal/` | JupyterLab terminal (DEV_MODE only) | `8888` | Available only when `DEV_MODE=true`; token login uses `JUPYTER_TOKEN` (default `huggingface`) |
370
 
371
  When enabled, the terminal notebook root is `/home/node`, so you can inspect HuggingClaw files, logs, workspace state, and runtime scripts from the browser.
372
 
373
  > [!IMPORTANT]
374
- > For real deployments, set a strong `JUPYTER_TOKEN` secret. The `huggingface` default exists only to match the duplicateable Hugging Face JupyterLab template.
375
 
376
  ## πŸ” Merge Comparison
377
 
 
104
  > [!TIP]
105
  > HuggingClaw is completely flexible! You only need these three secrets to get started. You can set other secrets later.
106
 
107
+ Optional: set `DEV_MODE=true` (Variable) to enable JupyterLab support and install Jupyter dependencies at build time. You can also set `JUPYTER_TOKEN` as a Secret to set a strong terminal token (must not be `huggingface`). If you want to pin a specific OpenClaw release instead of `latest`, add `OPENCLAW_VERSION` under **Variables** in your Space settings. For Docker Spaces, HF passes Variables as build args during image build, so these should be Variables, not Secrets (except tokens).
108
 
109
  ### Step 3: Deploy & Run
110
 
 
366
  | :--- | :--- | :--- | :--- |
367
  | `/` | HuggingClaw dashboard | `7861` | Public HF Spaces entrypoint |
368
  | `/app/` | OpenClaw Control UI | `7860` | Mounted behind the local reverse proxy |
369
+ | `/terminal/` | JupyterLab terminal (DEV_MODE only) | `8888` | Available only when `DEV_MODE=true`; token login uses `JUPYTER_TOKEN` (set a strong value) |
370
 
371
  When enabled, the terminal notebook root is `/home/node`, so you can inspect HuggingClaw files, logs, workspace state, and runtime scripts from the browser.
372
 
373
  > [!IMPORTANT]
374
+ > For real deployments, set a strong `JUPYTER_TOKEN` secret. Do not use `huggingface`; generate a strong token with `openssl rand -hex 32`.
375
 
376
  ## πŸ” Merge Comparison
377
 
env-builder.js CHANGED
@@ -482,6 +482,15 @@ const FIELDS = [
482
  "common": 1,
483
  "tag": "build"
484
  },
 
 
 
 
 
 
 
 
 
485
  {
486
  "g": "Startup",
487
  "icon": "⚑",
@@ -842,22 +851,12 @@ const FIELDS = [
842
  "g": "Core",
843
  "icon": "⚑",
844
  "k": "JUPYTER_TOKEN",
845
- "lbl": "Jupyter access token",
846
  "type": "password",
847
- "ph": "huggingface",
848
  "common": 1,
849
  "tag": "credential"
850
  },
851
- {
852
- "g": "Core",
853
- "icon": "⚑",
854
- "k": "KEEP_ALIVE_INTERVAL",
855
- "lbl": "Keep-alive ping interval (seconds)",
856
- "type": "number",
857
- "ph": "300",
858
- "common": 1,
859
- "tag": "advanced"
860
- },
861
  {
862
  "g": "Core",
863
  "icon": "⚑",
@@ -966,24 +965,6 @@ const FIELDS = [
966
  "ph": "/home/node",
967
  "tag": "advanced"
968
  },
969
- {
970
- "g": "Backup",
971
- "icon": "πŸ’Ύ",
972
- "k": "WORKSPACE_GIT_USER",
973
- "lbl": "Workspace git author email",
974
- "type": "text",
975
- "ph": "openclaw@example.com",
976
- "tag": "optional"
977
- },
978
- {
979
- "g": "Backup",
980
- "icon": "πŸ’Ύ",
981
- "k": "WORKSPACE_GIT_NAME",
982
- "lbl": "Workspace git author name",
983
- "type": "text",
984
- "ph": "OpenClaw Bot",
985
- "tag": "optional"
986
- },
987
  {
988
  "g": "Provider Keys",
989
  "icon": "πŸ”‘",
 
482
  "common": 1,
483
  "tag": "build"
484
  },
485
+ {
486
+ "g": "Startup",
487
+ "icon": "🩺",
488
+ "k": "AUTO_DOCTOR",
489
+ "lbl": "Auto-fix config on boot (openclaw doctor --fix)",
490
+ "type": "toggle",
491
+ "ph": "false",
492
+ "tag": "advanced"
493
+ },
494
  {
495
  "g": "Startup",
496
  "icon": "⚑",
 
851
  "g": "Core",
852
  "icon": "⚑",
853
  "k": "JUPYTER_TOKEN",
854
+ "lbl": "Jupyter access token (Must NOT be 'huggingface'. Run: openssl rand -hex 32)",
855
  "type": "password",
856
+ "ph": "change_this_to_a_strong_token",
857
  "common": 1,
858
  "tag": "credential"
859
  },
 
 
 
 
 
 
 
 
 
 
860
  {
861
  "g": "Core",
862
  "icon": "⚑",
 
965
  "ph": "/home/node",
966
  "tag": "advanced"
967
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
968
  {
969
  "g": "Provider Keys",
970
  "icon": "πŸ”‘",
iframe-fix.cjs CHANGED
@@ -19,9 +19,10 @@ http.Server.prototype.emit = function (event, ...args) {
19
  if (event === "request") {
20
  const [, res] = args;
21
 
22
- // Only intercept on the main OpenClaw server (port 7860)
 
23
  const serverPort = this.address && this.address() && this.address().port;
24
- if (serverPort && serverPort !== 7860) {
25
  return origEmit.apply(this, [event, ...args]);
26
  }
27
 
 
19
  if (event === "request") {
20
  const [, res] = args;
21
 
22
+ // Only intercept on the main OpenClaw server (respects GATEWAY_PORT env var)
23
+ const expectedPort = Number(process.env.GATEWAY_PORT || 7860);
24
  const serverPort = this.address && this.address() && this.address().port;
25
+ if (serverPort && serverPort !== expectedPort) {
26
  return origEmit.apply(this, [event, ...args]);
27
  }
28
 
start.sh CHANGED
@@ -99,6 +99,9 @@ DEVDATA_ENABLED=true
99
  if ! hc_is_true "$DEVDATA_NORMALIZED"; then
100
  DEVDATA_ENABLED=false
101
  fi
 
 
 
102
  if [ -n "${SPACE_HOST:-}" ]; then
103
  OPENCLAW_CONSOLE_LOG_LEVEL="${OPENCLAW_CONSOLE_LOG_LEVEL:-warn}"
104
  OPENCLAW_FILE_LOG_LEVEL="${OPENCLAW_FILE_LOG_LEVEL:-info}"
@@ -506,12 +509,24 @@ inject_provider_models_from_env "github-copilot" "GITHUB_COPILOT_MODELS" "COPILO
506
 
507
  # Browser configuration (managed local Chromium in HF/Docker)
508
  BROWSER_EXECUTABLE_PATH=""
509
- for candidate in /usr/bin/chromium /usr/bin/chromium-browser /snap/bin/chromium; do
 
 
 
 
 
 
 
 
 
510
  if [ -x "$candidate" ]; then
511
  BROWSER_EXECUTABLE_PATH="$candidate"
512
  break
513
  fi
514
  done
 
 
 
515
 
516
  BROWSER_SHOULD_ENABLE=false
517
  if [ "$BROWSER_PLUGIN_MODE" = "enabled" ] && [ -n "$BROWSER_EXECUTABLE_PATH" ] && [ -x "$BROWSER_EXECUTABLE_PATH" ]; then
@@ -569,7 +584,22 @@ if [ "$BROWSER_SHOULD_ENABLE" = "true" ]; then
569
  "defaultProfile": "openclaw",
570
  "headless": true,
571
  "noSandbox": true,
572
- "executablePath": $execPath
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
573
  }
574
  | .agents.defaults.sandbox.browser.allowHostControl = true' <<<"$CONFIG_JSON")
575
  fi
@@ -758,7 +788,13 @@ fi
758
  if [ -n "${CLOUDFLARE_PROXY_URL:-}" ]; then
759
  echo "Proxy : ${CLOUDFLARE_PROXY_URL}"
760
  fi
761
- RUNTIME_JUPYTER_ENABLED="$DEV_MODE_ENABLED"
 
 
 
 
 
 
762
  # Add user bin to PATH for jupyter-lab (installed in Dockerfile when DEV_MODE=true)
763
  export PATH="$HOME/.local/bin:$PATH"
764
 
@@ -817,20 +853,24 @@ graceful_shutdown() {
817
  }
818
  trap graceful_shutdown SIGTERM SIGINT
819
 
 
820
  warmup_browser() {
821
  [ "$BROWSER_SHOULD_ENABLE" = "true" ] || return 0
 
 
 
822
 
823
  (
824
- sleep 5
825
 
826
  local attempt
827
- for attempt in 1 2 3 4 5; do
828
  if openclaw browser --browser-profile openclaw start >/dev/null 2>&1; then
829
  openclaw browser --browser-profile openclaw open about:blank >/dev/null 2>&1 || true
830
  echo "Managed browser ready."
831
  return 0
832
  fi
833
- sleep 2
834
  done
835
 
836
  echo "Warning: managed browser warm-up did not complete; first browser action may need a retry."
@@ -1438,7 +1478,9 @@ if [ -n "${HUGGINGCLAW_OPENCLAW_PLUGINS:-}" ]; then
1438
  fi
1439
 
1440
  # ── Fix config before running startup commands ──
1441
- openclaw doctor --fix || true
 
 
1442
 
1443
  # ── Arbitrary startup commands from HF Variables/Secrets ──
1444
  # Recommended: use one variable, HUGGINGCLAW_RUN, as a full bash script. If the
@@ -1556,6 +1598,16 @@ start_guardian_once() {
1556
  echo "WhatsApp Guardian started (PID: $GUARDIAN_PID)"
1557
  }
1558
 
 
 
 
 
 
 
 
 
 
 
1559
  while true; do
1560
  # Check health-server process - restart if died unexpectedly
1561
  if [ -n "${HEALTH_PID:-}" ] && ! kill -0 "$HEALTH_PID" 2>/dev/null; then
@@ -1581,10 +1633,12 @@ while true; do
1581
  fi
1582
  fi
1583
 
1584
- openclaw doctor --fix || true
1585
- echo "Launching OpenClaw gateway on port 7860..."
 
 
1586
 
1587
- GATEWAY_ARGS=(gateway run --port 7860 --bind lan)
1588
  if [ "${GATEWAY_VERBOSE:-0}" = "1" ]; then
1589
  GATEWAY_ARGS+=(--verbose)
1590
  echo "Gateway verbose logging enabled (GATEWAY_VERBOSE=1)"
@@ -1603,7 +1657,7 @@ while true; do
1603
  GATEWAY_READY_TIMEOUT="${GATEWAY_READY_TIMEOUT:-90}"
1604
  ready=false
1605
  for ((i=0; i<GATEWAY_READY_TIMEOUT; i++)); do
1606
- if (echo > /dev/tcp/127.0.0.1/7860) 2>/dev/null; then
1607
  ready=true
1608
  break
1609
  fi
@@ -1618,9 +1672,14 @@ while true; do
1618
  echo "Gateway failed to start. Last 30 lines of log:"
1619
  echo "────────────────────────────────────────────"
1620
  tail -30 /home/node/.openclaw/gateway.log
1621
- echo "Gateway failed β€” JupyterLab and env-builder still running. Retrying in 10s..."
1622
- sleep 10
1623
- continue
 
 
 
 
 
1624
  fi
1625
 
1626
  # 11. Start WhatsApp Guardian after the gateway is accepting connections
 
99
  if ! hc_is_true "$DEVDATA_NORMALIZED"; then
100
  DEVDATA_ENABLED=false
101
  fi
102
+ # On HF Spaces, browser is disabled by default (no display server).
103
+ # To enable: set BROWSER_PLUGIN_MODE=enabled as an HF Space secret.
104
+ # WARNING: requires at least CPU Upgrade tier (2 vCPU / 16GB RAM).
105
  if [ -n "${SPACE_HOST:-}" ]; then
106
  OPENCLAW_CONSOLE_LOG_LEVEL="${OPENCLAW_CONSOLE_LOG_LEVEL:-warn}"
107
  OPENCLAW_FILE_LOG_LEVEL="${OPENCLAW_FILE_LOG_LEVEL:-info}"
 
509
 
510
  # Browser configuration (managed local Chromium in HF/Docker)
511
  BROWSER_EXECUTABLE_PATH=""
512
+ # On Debian/Ubuntu, /usr/bin/chromium is a shell wrapper; the real ELF binary
513
+ # lives at /usr/lib/chromium/chromium. Check the real binary first, then fall
514
+ # back to wrapper scripts (which are also valid executablePath values for
515
+ # Playwright/OpenClaw β€” they re-exec the real binary internally).
516
+ for candidate in \
517
+ /usr/lib/chromium/chromium \
518
+ /usr/lib/chromium-browser/chromium-browser \
519
+ /usr/bin/chromium \
520
+ /usr/bin/chromium-browser \
521
+ /snap/bin/chromium; do
522
  if [ -x "$candidate" ]; then
523
  BROWSER_EXECUTABLE_PATH="$candidate"
524
  break
525
  fi
526
  done
527
+ if [ -z "$BROWSER_EXECUTABLE_PATH" ]; then
528
+ echo "Warning: No real Chromium binary found. Browser plugin will be disabled."
529
+ fi
530
 
531
  BROWSER_SHOULD_ENABLE=false
532
  if [ "$BROWSER_PLUGIN_MODE" = "enabled" ] && [ -n "$BROWSER_EXECUTABLE_PATH" ] && [ -x "$BROWSER_EXECUTABLE_PATH" ]; then
 
584
  "defaultProfile": "openclaw",
585
  "headless": true,
586
  "noSandbox": true,
587
+ "executablePath": $execPath,
588
+ "localLaunchTimeoutMs": 45000,
589
+ "localCdpReadyTimeoutMs": 30000,
590
+ "extraArgs": [
591
+ "--no-sandbox",
592
+ "--disable-setuid-sandbox",
593
+ "--no-zygote",
594
+ "--disable-dev-shm-usage",
595
+ "--disable-gpu",
596
+ "--no-first-run",
597
+ "--disable-background-networking",
598
+ "--disable-sync",
599
+ "--disable-translate",
600
+ "--disable-notifications",
601
+ "--disable-speech-api"
602
+ ]
603
  }
604
  | .agents.defaults.sandbox.browser.allowHostControl = true' <<<"$CONFIG_JSON")
605
  fi
 
788
  if [ -n "${CLOUDFLARE_PROXY_URL:-}" ]; then
789
  echo "Proxy : ${CLOUDFLARE_PROXY_URL}"
790
  fi
791
+ # HUGGINGCLAW_JUPYTER_ENABLED env var se override allow karo
792
+ # (env-builder "Enable Jupyter terminal" toggle yahi set karta hai)
793
+ if hc_is_true "${HUGGINGCLAW_JUPYTER_ENABLED:-false}"; then
794
+ RUNTIME_JUPYTER_ENABLED=true
795
+ else
796
+ RUNTIME_JUPYTER_ENABLED="$DEV_MODE_ENABLED"
797
+ fi
798
  # Add user bin to PATH for jupyter-lab (installed in Dockerfile when DEV_MODE=true)
799
  export PATH="$HOME/.local/bin:$PATH"
800
 
 
853
  }
854
  trap graceful_shutdown SIGTERM SIGINT
855
 
856
+ BROWSER_WARMED_UP=false
857
  warmup_browser() {
858
  [ "$BROWSER_SHOULD_ENABLE" = "true" ] || return 0
859
+ # Only warm up once β€” gateway restarts should not re-spawn new warmup jobs.
860
+ [ "$BROWSER_WARMED_UP" = "false" ] || return 0
861
+ BROWSER_WARMED_UP=true
862
 
863
  (
864
+ sleep 8
865
 
866
  local attempt
867
+ for attempt in 1 2 3 4 5 6; do
868
  if openclaw browser --browser-profile openclaw start >/dev/null 2>&1; then
869
  openclaw browser --browser-profile openclaw open about:blank >/dev/null 2>&1 || true
870
  echo "Managed browser ready."
871
  return 0
872
  fi
873
+ sleep 5
874
  done
875
 
876
  echo "Warning: managed browser warm-up did not complete; first browser action may need a retry."
 
1478
  fi
1479
 
1480
  # ── Fix config before running startup commands ──
1481
+ if [ "${AUTO_DOCTOR:-false}" = "true" ]; then
1482
+ openclaw doctor --fix || true
1483
+ fi
1484
 
1485
  # ── Arbitrary startup commands from HF Variables/Secrets ──
1486
  # Recommended: use one variable, HUGGINGCLAW_RUN, as a full bash script. If the
 
1598
  echo "WhatsApp Guardian started (PID: $GUARDIAN_PID)"
1599
  }
1600
 
1601
+ # ── Start D-Bus session (once, before gateway loop) ──
1602
+ if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
1603
+ if command -v dbus-launch >/dev/null 2>&1; then
1604
+ eval "$(dbus-launch --sh-syntax 2>/dev/null)" || true
1605
+ export DBUS_SESSION_BUS_ADDRESS="${DBUS_SESSION_BUS_ADDRESS:-disabled:}"
1606
+ else
1607
+ export DBUS_SESSION_BUS_ADDRESS="disabled:"
1608
+ fi
1609
+ fi
1610
+
1611
  while true; do
1612
  # Check health-server process - restart if died unexpectedly
1613
  if [ -n "${HEALTH_PID:-}" ] && ! kill -0 "$HEALTH_PID" 2>/dev/null; then
 
1633
  fi
1634
  fi
1635
 
1636
+ if [ "${AUTO_DOCTOR:-false}" = "true" ]; then
1637
+ openclaw doctor --fix || true
1638
+ fi
1639
+ echo "Launching OpenClaw gateway on port ${GATEWAY_PORT}..."
1640
 
1641
+ GATEWAY_ARGS=(gateway run --port "${GATEWAY_PORT}" --bind lan)
1642
  if [ "${GATEWAY_VERBOSE:-0}" = "1" ]; then
1643
  GATEWAY_ARGS+=(--verbose)
1644
  echo "Gateway verbose logging enabled (GATEWAY_VERBOSE=1)"
 
1657
  GATEWAY_READY_TIMEOUT="${GATEWAY_READY_TIMEOUT:-90}"
1658
  ready=false
1659
  for ((i=0; i<GATEWAY_READY_TIMEOUT; i++)); do
1660
+ if (echo > /dev/tcp/127.0.0.1/${GATEWAY_PORT}) 2>/dev/null; then
1661
  ready=true
1662
  break
1663
  fi
 
1672
  echo "Gateway failed to start. Last 30 lines of log:"
1673
  echo "────────────────────────────────────────────"
1674
  tail -30 /home/node/.openclaw/gateway.log
1675
+ if [ "$DEV_MODE_ENABLED" = "true" ]; then
1676
+ echo "Gateway failed β€” DEV_MODE active, retrying in 10s..."
1677
+ sleep 10
1678
+ continue
1679
+ else
1680
+ echo "Gateway failed β€” exiting."
1681
+ exit 1
1682
+ fi
1683
  fi
1684
 
1685
  # 11. Start WhatsApp Guardian after the gateway is accepting connections