Spaces:
Running
Running
feat: auto-enable terminal when GATEWAY_TOKEN is set
Browse files- health-server.js: JUPYTER_ENABLED is true when GATEWAY_TOKEN is set,
no DEV_MODE required
- start.sh: auto-sets DEV_MODE_ENABLED when GATEWAY_TOKEN is present
and DEV_MODE was not explicitly configured; GATEWAY_TOKEN used as
JUPYTER_TOKEN fallback inside start_jupyter_once()
- README: update all references to reflect new out-of-the-box behavior
Users with GATEWAY_TOKEN set get the terminal button and terminal access
automatically. Set DEV_MODE=false to opt out. Set JUPYTER_TOKEN to
override the credential.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- README.md +7 -5
- health-server.js +4 -1
- start.sh +13 -0
README.md
CHANGED
|
@@ -20,7 +20,7 @@ secrets:
|
|
| 20 |
- name: GATEWAY_TOKEN
|
| 21 |
description: "Strong token to secure your OpenClaw Control UI (generate: openssl rand -hex 32)."
|
| 22 |
- name: JUPYTER_TOKEN
|
| 23 |
-
description: "Optional
|
| 24 |
- name: CLOUDFLARE_WORKERS_TOKEN
|
| 25 |
description: "Cloudflare API token β auto-creates a Worker proxy and KeepAlive monitor."
|
| 26 |
- name: TELEGRAM_ALLOWED_USERS
|
|
@@ -78,7 +78,7 @@ secrets:
|
|
| 78 |
- π **Visual Dashboard:** Beautiful Web UI to monitor uptime, sync status, and active models.
|
| 79 |
- π **Webhooks:** Get notified on restarts or backup failures via standard webhooks.
|
| 80 |
- π **Flexible Auth:** Secure the Control UI with either a gateway token or password.
|
| 81 |
-
- π» **
|
| 82 |
- π **100% HF-Native:** Runs entirely on HuggingFaceβs free infrastructure (2 vCPU, 16GB RAM).
|
| 83 |
|
| 84 |
## π₯ Video Tutorial
|
|
@@ -104,7 +104,9 @@ 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 |
-
|
|
|
|
|
|
|
| 108 |
|
| 109 |
### Step 3: Deploy & Run
|
| 110 |
|
|
@@ -366,12 +368,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
|
| 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 |
-
>
|
| 375 |
|
| 376 |
## π Merge Comparison
|
| 377 |
|
|
|
|
| 20 |
- name: GATEWAY_TOKEN
|
| 21 |
description: "Strong token to secure your OpenClaw Control UI (generate: openssl rand -hex 32)."
|
| 22 |
- name: JUPYTER_TOKEN
|
| 23 |
+
description: "Optional token for the JupyterLab terminal at /terminal/. Defaults to GATEWAY_TOKEN when set β no extra secret needed."
|
| 24 |
- name: CLOUDFLARE_WORKERS_TOKEN
|
| 25 |
description: "Cloudflare API token β auto-creates a Worker proxy and KeepAlive monitor."
|
| 26 |
- name: TELEGRAM_ALLOWED_USERS
|
|
|
|
| 78 |
- π **Visual Dashboard:** Beautiful Web UI to monitor uptime, sync status, and active models.
|
| 79 |
- π **Webhooks:** Get notified on restarts or backup failures via standard webhooks.
|
| 80 |
- π **Flexible Auth:** Secure the Control UI with either a gateway token or password.
|
| 81 |
+
- π» **Terminal Out of the Box:** JupyterLab is available at `/terminal/` automatically when `GATEWAY_TOKEN` is set β no extra config needed. `GATEWAY_TOKEN` is reused as the terminal auth token. Set `DEV_MODE=false` explicitly to opt out.
|
| 82 |
- π **100% HF-Native:** Runs entirely on HuggingFaceβs free infrastructure (2 vCPU, 16GB RAM).
|
| 83 |
|
| 84 |
## π₯ Video Tutorial
|
|
|
|
| 104 |
> [!TIP]
|
| 105 |
> HuggingClaw is completely flexible! You only need these three secrets to get started. You can set other secrets later.
|
| 106 |
|
| 107 |
+
**Terminal auto-enables when `GATEWAY_TOKEN` is set** β no extra secrets needed. `GATEWAY_TOKEN` is reused as `JUPYTER_TOKEN`, so the terminal is protected by the same credential as the Control UI. To set a different token, add `JUPYTER_TOKEN` as a Secret. To disable the terminal entirely, set `DEV_MODE=false` as a Variable.
|
| 108 |
+
|
| 109 |
+
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).
|
| 110 |
|
| 111 |
### Step 3: Deploy & Run
|
| 112 |
|
|
|
|
| 368 |
| :--- | :--- | :--- | :--- |
|
| 369 |
| `/` | HuggingClaw dashboard | `7861` | Public HF Spaces entrypoint |
|
| 370 |
| `/app/` | OpenClaw Control UI | `7860` | Mounted behind the local reverse proxy |
|
| 371 |
+
| `/terminal/` | JupyterLab terminal | `8888` | Auto-enabled when `GATEWAY_TOKEN` is set; uses `GATEWAY_TOKEN` as auth token unless `JUPYTER_TOKEN` is set separately. Set `DEV_MODE=false` to disable. |
|
| 372 |
|
| 373 |
When enabled, the terminal notebook root is `/home/node`, so you can inspect HuggingClaw files, logs, workspace state, and runtime scripts from the browser.
|
| 374 |
|
| 375 |
> [!IMPORTANT]
|
| 376 |
+
> No extra secret needed β `GATEWAY_TOKEN` is automatically reused as `JUPYTER_TOKEN`. Set a separate `JUPYTER_TOKEN` secret only if you want a different terminal credential.
|
| 377 |
|
| 378 |
## π Merge Comparison
|
| 379 |
|
health-server.js
CHANGED
|
@@ -20,9 +20,12 @@ const GATEWAY_HOST = "127.0.0.1";
|
|
| 20 |
const JUPYTER_PORT = Number.parseInt(process.env.JUPYTER_PORT || "8888", 10);
|
| 21 |
const JUPYTER_HOST = "127.0.0.1";
|
| 22 |
const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
|
|
|
|
| 23 |
const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
|
|
|
|
|
|
|
| 24 |
const JUPYTER_ENABLED = /^(true|1|yes|on)$/i.test(
|
| 25 |
-
process.env.HUGGINGCLAW_JUPYTER_ENABLED || (DEV_MODE_ENABLED ? "true" : "false")
|
| 26 |
);
|
| 27 |
const startTime = Date.now();
|
| 28 |
const LLM_MODEL = process.env.LLM_MODEL || "Not Set";
|
|
|
|
| 20 |
const JUPYTER_PORT = Number.parseInt(process.env.JUPYTER_PORT || "8888", 10);
|
| 21 |
const JUPYTER_HOST = "127.0.0.1";
|
| 22 |
const JUPYTER_BASE = normalizeBase(process.env.JUPYTER_BASE, "/terminal");
|
| 23 |
+
const GATEWAY_TOKEN = (process.env.GATEWAY_TOKEN || "").trim();
|
| 24 |
const DEV_MODE_ENABLED = isTrue(process.env.DEV_MODE);
|
| 25 |
+
// Auto-enable Jupyter when DEV_MODE=true, HUGGINGCLAW_JUPYTER_ENABLED=true, or GATEWAY_TOKEN is set.
|
| 26 |
+
// GATEWAY_TOKEN doubles as JUPYTER_TOKEN in start.sh β no extra secret needed.
|
| 27 |
const JUPYTER_ENABLED = /^(true|1|yes|on)$/i.test(
|
| 28 |
+
process.env.HUGGINGCLAW_JUPYTER_ENABLED || (DEV_MODE_ENABLED ? "true" : GATEWAY_TOKEN ? "true" : "false")
|
| 29 |
);
|
| 30 |
const startTime = Date.now();
|
| 31 |
const LLM_MODEL = process.env.LLM_MODEL || "Not Set";
|
start.sh
CHANGED
|
@@ -90,6 +90,12 @@ DEV_MODE_ENABLED=false
|
|
| 90 |
if hc_is_true "$DEV_MODE_NORMALIZED"; then
|
| 91 |
DEV_MODE_ENABLED=true
|
| 92 |
fi
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
SYNC_INTERVAL="$(trim_var "${SYNC_INTERVAL:-180}")"
|
| 94 |
DEVDATA_DATASET_NAME="$(trim_var "${DEVDATA_DATASET_NAME:-huggingclaw-devdata}")"
|
| 95 |
DEVDATA_SYNC_INTERVAL="$(trim_var "${DEVDATA_SYNC_INTERVAL:-180}")"
|
|
@@ -848,6 +854,13 @@ start_jupyter_once() {
|
|
| 848 |
return 0
|
| 849 |
fi
|
| 850 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 851 |
# Security guard: refuse to start JupyterLab with the insecure default token.
|
| 852 |
# JupyterLab exposes a full shell β a weak token is equivalent to no auth.
|
| 853 |
if [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; then
|
|
|
|
| 90 |
if hc_is_true "$DEV_MODE_NORMALIZED"; then
|
| 91 |
DEV_MODE_ENABLED=true
|
| 92 |
fi
|
| 93 |
+
# Auto-enable DEV_MODE when GATEWAY_TOKEN is set and DEV_MODE was not explicitly configured.
|
| 94 |
+
# GATEWAY_TOKEN doubles as JUPYTER_TOKEN (see start_jupyter_once) β no extra secret required.
|
| 95 |
+
if [ "$DEV_MODE_ENABLED" != "true" ] && [ -z "${DEV_MODE:-}" ] && [ -n "${GATEWAY_TOKEN:-}" ]; then
|
| 96 |
+
DEV_MODE_ENABLED=true
|
| 97 |
+
echo "GATEWAY_TOKEN set and DEV_MODE not explicitly configured β auto-enabling terminal (set DEV_MODE=false to opt out)"
|
| 98 |
+
fi
|
| 99 |
SYNC_INTERVAL="$(trim_var "${SYNC_INTERVAL:-180}")"
|
| 100 |
DEVDATA_DATASET_NAME="$(trim_var "${DEVDATA_DATASET_NAME:-huggingclaw-devdata}")"
|
| 101 |
DEVDATA_SYNC_INTERVAL="$(trim_var "${DEVDATA_SYNC_INTERVAL:-180}")"
|
|
|
|
| 854 |
return 0
|
| 855 |
fi
|
| 856 |
|
| 857 |
+
# GATEWAY_TOKEN fallback: if JUPYTER_TOKEN is unset or still the insecure default,
|
| 858 |
+
# reuse GATEWAY_TOKEN. Both protect the same Space, so the credential is equivalent.
|
| 859 |
+
if { [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; } && [ -n "${GATEWAY_TOKEN:-}" ]; then
|
| 860 |
+
JUPYTER_TOKEN="$GATEWAY_TOKEN"
|
| 861 |
+
echo "JUPYTER_TOKEN not set β using GATEWAY_TOKEN as terminal auth token"
|
| 862 |
+
fi
|
| 863 |
+
|
| 864 |
# Security guard: refuse to start JupyterLab with the insecure default token.
|
| 865 |
# JupyterLab exposes a full shell β a weak token is equivalent to no auth.
|
| 866 |
if [ -z "${JUPYTER_TOKEN:-}" ] || [ "${JUPYTER_TOKEN}" = "huggingface" ]; then
|