Ingress: terminal landing page + external gateway link; add gateway_public_url; bump 0.4.3
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
name: Moltbot Assistant
|
name: Moltbot Assistant
|
||||||
version: "0.4.2"
|
version: "0.4.3"
|
||||||
slug: moltbot_assistant
|
slug: moltbot_assistant
|
||||||
description: Run Moltbot Assistant (Clawdbot-compatible) as a Home Assistant add-on.
|
description: Run Moltbot Assistant (Clawdbot-compatible) as a Home Assistant add-on.
|
||||||
url: https://github.com/techartdev/ClawdHAAddOn
|
url: https://github.com/techartdev/ClawdHAAddOn
|
||||||
@@ -38,6 +38,10 @@ options:
|
|||||||
gateway_port: 18789
|
gateway_port: 18789
|
||||||
gateway_token: ""
|
gateway_token: ""
|
||||||
|
|
||||||
|
# Public base URL for opening the Gateway Web UI in a new tab (not embedded).
|
||||||
|
# Example: "https://vanevihomeha.duckdns.org:38123" or "http://192.168.1.10:18789"
|
||||||
|
gateway_public_url: ""
|
||||||
|
|
||||||
# Run `clawdbot doctor --fix` on startup (useful after upgrades; slows restarts)
|
# Run `clawdbot doctor --fix` on startup (useful after upgrades; slows restarts)
|
||||||
run_doctor_on_start: false
|
run_doctor_on_start: false
|
||||||
|
|
||||||
@@ -65,6 +69,7 @@ schema:
|
|||||||
gateway_bind: list(loopback|lan)
|
gateway_bind: list(loopback|lan)
|
||||||
gateway_port: int
|
gateway_port: int
|
||||||
gateway_token: str?
|
gateway_token: str?
|
||||||
|
gateway_public_url: str?
|
||||||
run_doctor_on_start: bool
|
run_doctor_on_start: bool
|
||||||
homeassistant_token: str?
|
homeassistant_token: str?
|
||||||
mikrotik_host: str
|
mikrotik_host: str
|
||||||
|
|||||||
@@ -33,73 +33,54 @@ http {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Gateway UI
|
# Landing page (shown inside HA Ingress)
|
||||||
# IMPORTANT: We must not redirect to an absolute "/..." path because Home Assistant Ingress
|
# - Shows the web terminal (if enabled)
|
||||||
# strips the ingress prefix before forwarding to the add-on. An absolute Location would jump
|
# - Provides a button to open the Gateway Web UI in a separate tab (not embedded)
|
||||||
# out of ingress (to the HA host root). So we use a *relative* redirect.
|
|
||||||
|
|
||||||
# Only redirect the root document to add token in the browser URL.
|
|
||||||
location = / {
|
location = / {
|
||||||
if ($arg_token = "") {
|
default_type text/html;
|
||||||
# Force a trailing slash via a relative redirect.
|
|
||||||
return 302 ./?token=__GATEWAY_TOKEN__;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Proxy the gateway UI.
|
# NOTE: __GATEWAY_PUBLIC_URL__ is configured via add-on option gateway_public_url.
|
||||||
proxy_pass http://127.0.0.1:18789;
|
# We keep it flexible because the right URL depends on how the user exposes HA/gateway
|
||||||
proxy_http_version 1.1;
|
# (Nabu Casa, DuckDNS, LAN, etc.).
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
|
|
||||||
# Debug: expose the ingress path nginx sees (from HA) to the browser.
|
return 200 '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
# Remove once confirmed.
|
<title>Moltbot Assistant</title>
|
||||||
add_header X-Debug-Ingress-Path $http_x_ingress_path always;
|
<style>
|
||||||
|
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif;margin:0;padding:16px;background:#0b0f14;color:#e6edf3}
|
||||||
# Inject the correct WS URL when running behind HA Ingress.
|
a,button{font:inherit}
|
||||||
# HA provides a per-session ingress proxy path in X-Ingress-Path (usually /api/hassio_ingress/<token>).
|
.card{max-width:1100px;margin:0 auto;background:#111827;border:1px solid #1f2937;border-radius:12px;padding:16px}
|
||||||
# The UI loaded at /hassio/ingress/<slug> cannot be used as a WS endpoint on some setups,
|
.row{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
|
||||||
# but /api/hassio_ingress/<token> *can* proxy websocket upgrades.
|
.btn{background:#2563eb;color:white;border:0;border-radius:10px;padding:10px 14px;cursor:pointer;text-decoration:none;display:inline-block}
|
||||||
#
|
.btn.secondary{background:#334155}
|
||||||
# We inject a small script to override the UI's saved websocket URL to:
|
.muted{color:#9ca3af;font-size:14px}
|
||||||
# wss://<host><x-ingress-path>/
|
.term{margin-top:14px;height:70vh;min-height:420px;border:1px solid #1f2937;border-radius:10px;overflow:hidden}
|
||||||
# so the browser connects same-origin + through HA's ingress proxy.
|
iframe{width:100%;height:100%;border:0;background:black}
|
||||||
proxy_set_header Accept-Encoding "";
|
code{background:#0b1220;padding:2px 6px;border-radius:6px}
|
||||||
sub_filter_types text/html;
|
</style>
|
||||||
sub_filter_once on;
|
</head><body>
|
||||||
sub_filter '</head>' '<script>(function(){try{var p="__INGRESS_PATH__"; if(p && p!=="__INGRESS_PATH__"){ var ws=(location.protocol==="https:"?"wss://":"ws://")+location.host+p+"/"; var k="clawdbot.control.settings.v1"; try{var s=localStorage.getItem(k); var o=s?JSON.parse(s):{}; if(o.gatewayUrl!==ws){ o.gatewayUrl=ws; localStorage.setItem(k, JSON.stringify(o)); location.reload(); } }catch(e){} } }catch(e){} })();</script></head>';
|
<div class="card">
|
||||||
sub_filter '__INGRESS_PATH__' "$http_x_ingress_path";
|
<h2 style="margin:0 0 8px 0">Moltbot Assistant</h2>
|
||||||
|
<div class="row" style="margin-bottom:6px">
|
||||||
|
<a class="btn" href="__GATEWAY_PUBLIC_URL__/?token=__GATEWAY_TOKEN__" target="_blank" rel="noopener noreferrer">Open Gateway Web UI</a>
|
||||||
|
<a class="btn secondary" href="/terminal/" target="_self">Open Terminal (full page)</a>
|
||||||
|
</div>
|
||||||
|
<div class="muted">
|
||||||
|
Tip: The gateway UI is intentionally opened outside of Ingress to avoid websocket/proxy issues.
|
||||||
|
Configure <code>gateway_public_url</code> in the add-on options.
|
||||||
|
</div>
|
||||||
|
<div class="term">
|
||||||
|
<iframe src="/terminal/" title="Terminal"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body></html>';
|
||||||
}
|
}
|
||||||
|
|
||||||
# WebSocket endpoint compatibility:
|
# (Optional) Gateway UI via ingress has been intentionally removed.
|
||||||
# Some clients/UIs assume a dedicated /ws path. The gateway websocket endpoint
|
# See landing page link that opens the gateway in a separate tab.
|
||||||
# itself is at /, so we map /ws -> / when proxying.
|
|
||||||
location /ws {
|
|
||||||
proxy_pass http://127.0.0.1:18789/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
proxy_read_timeout 3600s;
|
|
||||||
proxy_send_timeout 3600s;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Everything else (assets, api, etc.) just proxy through.
|
# Everything else: 404
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://127.0.0.1:18789;
|
return 404;
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection "upgrade";
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ MODEL_PRIMARY=$(jq -r '.model_primary // "openai-codex/gpt-5.2"' "$OPTIONS_FILE"
|
|||||||
GW_BIND=$(jq -r '.gateway_bind // "loopback"' "$OPTIONS_FILE")
|
GW_BIND=$(jq -r '.gateway_bind // "loopback"' "$OPTIONS_FILE")
|
||||||
GW_PORT=$(jq -r '.gateway_port // 18789' "$OPTIONS_FILE")
|
GW_PORT=$(jq -r '.gateway_port // 18789' "$OPTIONS_FILE")
|
||||||
GW_TOKEN=$(jq -r '.gateway_token // empty' "$OPTIONS_FILE")
|
GW_TOKEN=$(jq -r '.gateway_token // empty' "$OPTIONS_FILE")
|
||||||
|
GW_PUBLIC_URL=$(jq -r '.gateway_public_url // empty' "$OPTIONS_FILE")
|
||||||
HA_TOKEN=$(jq -r '.homeassistant_token // empty' "$OPTIONS_FILE")
|
HA_TOKEN=$(jq -r '.homeassistant_token // empty' "$OPTIONS_FILE")
|
||||||
BRAVE_KEY=$(jq -r '.brave_api_key // empty' "$OPTIONS_FILE")
|
BRAVE_KEY=$(jq -r '.brave_api_key // empty' "$OPTIONS_FILE")
|
||||||
ENABLE_TERMINAL=$(jq -r '.enable_terminal // false' "$OPTIONS_FILE")
|
ENABLE_TERMINAL=$(jq -r '.enable_terminal // false' "$OPTIONS_FILE")
|
||||||
@@ -279,16 +280,17 @@ fi
|
|||||||
# Render nginx config from template with the gateway token.
|
# Render nginx config from template with the gateway token.
|
||||||
# NOTE: This intentionally exposes the token in the browser URL via a redirect.
|
# NOTE: This intentionally exposes the token in the browser URL via a redirect.
|
||||||
# This matches Clawdbot Control UI's current expectations.
|
# This matches Clawdbot Control UI's current expectations.
|
||||||
GW_TOKEN="$GW_TOKEN" python3 - <<'PY'
|
GW_TOKEN="$GW_TOKEN" GW_PUBLIC_URL="$GW_PUBLIC_URL" python3 - <<'PY'
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
tpl = Path('/etc/nginx/nginx.conf.tpl').read_text()
|
tpl = Path('/etc/nginx/nginx.conf.tpl').read_text()
|
||||||
token = os.environ.get('GW_TOKEN','')
|
token = os.environ.get('GW_TOKEN','')
|
||||||
if not token:
|
public_url = os.environ.get('GW_PUBLIC_URL','')
|
||||||
print('WARN: gateway_token is empty; ingress UI will redirect with an empty token and Control UI will not authenticate.')
|
|
||||||
|
|
||||||
conf = tpl.replace('__GATEWAY_TOKEN__', token)
|
conf = tpl.replace('__GATEWAY_TOKEN__', token)
|
||||||
|
conf = conf.replace('__GATEWAY_PUBLIC_URL__', public_url)
|
||||||
|
|
||||||
Path('/etc/nginx/nginx.conf').write_text(conf)
|
Path('/etc/nginx/nginx.conf').write_text(conf)
|
||||||
PY
|
PY
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user