claw / README.md
jkes6203's picture
Fix Codex auth profile import shape
70972f0
metadata
title: OpenClaw Gateway
emoji: 🦞
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860

OpenClaw Gateway on Hugging Face Spaces

This Space runs the OpenClaw gateway so you can use the Control UI and connect clients over the internet.

Quick start

  1. Create a new Space at huggingface.co/new-space. Choose Docker as the SDK.
  2. Copy the contents of this folder into your Space repo:
    • This README.md (including the YAML block above)
    • This repo's Dockerfile
    • This repo's setup-hf-config.mjs
    • This repo's import-auth-profiles.mjs The Space installs the published openclaw npm package directly instead of cloning/building the full source tree, which is much more reliable on HF cpu-basic.
  3. Add Secrets in your Space Settings β†’ Secrets (all optional except one auth method for UI access):
    • OPENCLAW_GATEWAY_TOKEN β€” long random string (e.g. openssl rand -hex 24). Paste this in the Control UI to log in. Recommended. (Alternative: use OPENCLAW_GATEWAY_PASSWORD for password auth; if both are set, token is used.)
    • OPENCLAW_GATEWAY_PASSWORD β€” (optional) Gateway password; startup script sets gateway.auth.mode: "password". Use when you prefer password over token.
    • HF_TOKEN β€” your Hugging Face token with Make calls to Inference Providers. Needed only when you want to use the Hugging Face provider; without it, choose another provider such as Gemini or OpenCode.
    • GEMINI_API_KEY β€” (optional) Google Gemini API key. Not needed for the default DeepSeek -> Qwen -> Codex chain.
    • OPENCODE_API_KEY β€” (optional) OpenCode Zen API key. OpenClaw reads this directly from the gateway environment for the opencode provider.
    • SUPABASE_URL β€” (recommended) Supabase project URL for external state backup.
    • SUPABASE_KEY β€” (recommended) Supabase service key or project API key with insert/update access to your sync table.
    • OPENCLAW_MODEL_PRIMARY β€” (recommended) Primary model ref. This repo now defaults to huggingface/Qwen/Qwen3-8B.
    • OPENCLAW_MODEL_FALLBACK_1 β€” (recommended) First fallback model ref. Default is huggingface/deepseek-ai/DeepSeek-R1.
    • OPENCLAW_MODEL_FALLBACK_2 β€” (recommended) Second fallback model ref. Default is openai-codex/gpt-5.4.
    • OPENCLAW_GATEWAY_TRUSTED_PROXIES β€” (optional) Comma-separated proxy IPs (e.g. 10.20.31.87,10.20.26.157). The startup script writes this into gateway.trustedProxies; set if you see β€œProxy headers detected from untrusted address” or pairing/unauthorized. Use Variables if you prefer (IPs need not be secret).
    • OPENCLAW_CONTROL_UI_ALLOWED_ORIGINS β€” (optional) Comma-separated origins (e.g. https://your-space.hf.space). Written to gateway.controlUi.allowedOrigins so only those origins can open the Control UI; useful to lock down to your Space URL.
    • TELEGRAM_BOT_TOKEN β€” (optional) Telegram BotFather token. Required for Telegram channel support and startup notifications.
    • OPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDS β€” (optional) Comma-separated chat IDs to receive startup notifications from the init script. Recommended if you want an explicit "boot completed" signal.
    • OPENCLAW_TELEGRAM_INIT_NOTIFY_MESSAGE β€” (optional) Extra plain-text line appended to the startup notification.
    • OPENCLAW_TELEGRAM_DROP_PENDING_UPDATES_ON_START β€” (optional) 1 / 0; when startup finds a webhook and removes it, also drops queued Telegram updates. Default 0.
    • OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TO β€” (optional) Single fallback chat ID for startup notifier when OPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDS is not set.
    • OPENCLAW_TELEGRAM_DM_POLICY / OPENCLAW_TELEGRAM_ALLOW_FROM / OPENCLAW_TELEGRAM_GROUP_POLICY / OPENCLAW_TELEGRAM_GROUP_ALLOW_FROM / OPENCLAW_TELEGRAM_REQUIRE_MENTION β€” (optional) Advanced Telegram access-control settings.
  4. Build and run β€” push to the Space repo; the Space will build and start the gateway. Startup writes config so the default model chain is Qwen3-8B -> DeepSeek-R1 -> openai-codex/gpt-5.4, the Control UI accepts token-only connections (no device pairing), and Supabase sync starts automatically when SUPABASE_URL + SUPABASE_KEY are present.

When the logs show listening on ws://0.0.0.0:7860, open your Space’s URL (e.g. https://your-username-openclaw-gateway.hf.space) and paste the gateway token in Settings β†’ token (or use https://your-space.hf.space#token=YOUR_TOKEN).

DeepSeek Primary, Qwen and Codex Fallback, and Telegram

  • Default behavior in this repo is now:
    • primary: huggingface/Qwen/Qwen3-8B
    • fallbacks: huggingface/deepseek-ai/DeepSeek-R1, openai-codex/gpt-5.4
  • The startup script now writes both primary and fallbacks.
  • Codex fallback only works if Codex itself is already authenticated and usable. If openai-codex/gpt-5.4 still lacks auth, fallback will still fail when traffic reaches it.
  • OpenCode Zen also works well in Hugging Face Spaces. Set OPENCODE_API_KEY and use a default model such as opencode/claude-opus-4-6.
  • Codex auth remains the special case: if your openai-codex/gpt-5.4 path depends on OAuth-backed credentials, use a separate environment that can complete the login flow first, or expect the Codex fallback to fail.
  • Telegram minimal setup for OpenClaw itself only needs TELEGRAM_BOT_TOKEN.
  • Telegram startup notification additionally needs OPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDS.
  • HF Spaces receive-path fix in this repo now checks getWebhookInfo, removes leftover webhooks, then probes getUpdates so long-polling bots can receive again.
  • Codex auth remains the special case: in headless Spaces, the reliable path is to complete Codex OAuth elsewhere, then import the resulting OpenClaw auth profile via a Space Secret (see below). Running the interactive OAuth flow inside the Space is usually unreliable.
  • Telegram advanced settings are optional and only needed when you want allowlists, group restrictions, or mention-only behavior.

Minimal example for Qwen -> DeepSeek -> Codex + Supabase + Telegram:

Secrets
OPENCLAW_GATEWAY_TOKEN=<long random token>
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_KEY=<your supabase service key>
TELEGRAM_BOT_TOKEN=<botfather token>

Variables
OPENCLAW_MODEL_PRIMARY=huggingface/Qwen/Qwen3-8B
OPENCLAW_MODEL_FALLBACK_1=huggingface/deepseek-ai/DeepSeek-R1
OPENCLAW_MODEL_FALLBACK_2=openai-codex/gpt-5.4
OPENCLAW_CONTROL_UI_ALLOWED_ORIGINS=https://your-space.hf.space
OPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDS=123456789,-1001234567890
OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TO=123456789
OPENCLAW_TELEGRAM_INIT_NOTIFY_MESSAGE=HF Space boot completed
OPENCLAW_TELEGRAM_DROP_PENDING_UPDATES_ON_START=0
OPENCLAW_SUPABASE_TABLE=openclaw_state
OPENCLAW_SYNC_INTERVAL_MS=300000

Telegram startup notification notes:

  1. Ask the target user to start the bot first, or add the bot to the target group/channel before using that chat ID.
  2. Use numeric chat IDs when possible; they are less fragile than usernames.
  3. The startup notifier now tries several network transports: fetch-json, https-family4-json, https-family4-form, https-resolve4-json, and curl-json.
  4. If no explicit startup chat ID is configured, the notifier falls back to OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TO, then OPENCLAW_TELEGRAM_ALLOW_FROM, then recent getUpdates chat IDs.
  5. Startup messages are tagged with both transport= and payload= in the message body so you can report exactly which path worked.

Keep it running 24/7

  • Free hardware: The Space will sleep after ~48 hours of inactivity. Anyone opening the URL will wake it.
  • Paid hardware: In Settings β†’ Hardware, upgrade to a paid CPU (or other tier). Upgraded Spaces run indefinitely by default. You can set Sleep time to β€œNever” if desired.

Persist config and workspace

Without persistent storage, config and workspace are lost when the Space restarts. To keep them:

  1. In Settings β†’ Storage, add persistent storage for the Space.
  2. The container uses /data when writable (state under /data/.openclaw). If /data is not available, it falls back to /home/user/.openclaw so the app still starts.

External storage

This repo now includes a lightweight Supabase sync worker. It mirrors text state files from .openclaw such as config, session data, memory files, and logs into a Supabase table on a timer. This gives you an external backup even if the Space restarts.

Recommended setup:

  1. Create a Supabase table:
create table if not exists openclaw_state (
  path text primary key,
  kind text not null,
  content text not null,
  sha256 text not null,
  size_bytes bigint not null,
  updated_at timestamptz not null,
  synced_at timestamptz not null
);
  1. Add Secrets in your Space:

    • SUPABASE_URL
    • SUPABASE_KEY
  2. Optional Variables:

    • OPENCLAW_SUPABASE_TABLE=openclaw_state
    • OPENCLAW_SYNC_INTERVAL_MS=300000
    • OPENCLAW_SYNC_MAX_FILE_BYTES=5242880
    • OPENCLAW_SYNC_INCLUDE_EXTENSIONS=.json,.jsonl,.md,.txt

Notes:

  • Supabase is the implemented path in this repo. It is the best fit when you want structured external storage and future RAG/vector expansion.
  • HF Dataset Repo and MongoDB Atlas remain viable alternatives, but they are not automated by this wrapper yet.
  • OpenClaw still runs locally inside the container. The sync worker is an external backup/mirroring layer that avoids data loss across rebuilds and restarts.

Custom install script

The image runs this Space repo's setup-hf-config.mjs at startup to set the default model, gateway auth, and optional Telegram bootstrap config. The Dockerfile installs the published openclaw npm package, copies your helper scripts into /app, and runs them before starting the gateway. This avoids the heavy monorepo build that often OOMs on HF Spaces.

Configuring trusted proxies (no CLI or file edit)

If logs show "Proxy headers detected from untrusted address" or connections close with reason=pairing required / reason=unauthorized, the gateway is behind Hugging Face’s reverse proxy. Add the proxy IP(s) so the gateway trusts them and uses X-Forwarded-For for client detection.

Recommended: use a Secret or Variable (applied at startup)

  1. Find the proxy IP(s) β€” In the Space logs, look for [ws] ... remote=10.20.31.87 .... The remote= value is the address the gateway sees. Note one or more such IPs.
  2. In Settings β†’ Secrets or Settings β†’ Variables, add:
    • Name: OPENCLAW_GATEWAY_TRUSTED_PROXIES
    • Value: comma-separated IPs, e.g. 10.20.31.87,10.20.26.157
  3. Restart the Space. The entrypoint runs setup-hf-config.mjs before the gateway; it reads this env and writes gateway.trustedProxies into the config automatically. No CLI or file edit needed.

Manual fallback (dev mode / shell access)

If you have a shell (e.g. dev mode), you can instead edit /data/.openclaw/openclaw.json and set gateway.trustedProxies: ["10.20.31.87"], or run openclaw config set gateway.trustedProxies '["10.20.31.87"]'. Restart the Space after changing config.

See Gateway security – Reverse proxy for more on gateway.trustedProxies.

Configuration from environment (summary)

The startup script setup-hf-config.mjs reads the following from Secrets or Variables and writes them into openclaw.json on every container start. So you can configure the gateway without CLI or file edit.

Env variable Config path Format
OPENCLAW_MODEL_PRIMARY agents.defaults.model.primary Primary model ref string
OPENCLAW_DEFAULT_MODEL agents.defaults.model.primary Legacy alias for primary model
OPENCLAW_HF_DEFAULT_MODEL agents.defaults.model.primary Legacy alias for primary model
OPENCLAW_MODEL_FALLBACK_1 agents.defaults.model.fallbacks[0] First fallback model ref
OPENCLAW_MODEL_FALLBACK_2 agents.defaults.model.fallbacks[1] Second fallback model ref
OPENCLAW_FALLBACK_MODELS agents.defaults.model.fallbacks Comma-separated fallback model refs
OPENCLAW_GATEWAY_TOKEN gateway.auth.mode + gateway.auth.token Any string
OPENCLAW_GATEWAY_PASSWORD gateway.auth.mode + gateway.auth.password Any string (token wins if both set)
OPENCLAW_GATEWAY_TRUSTED_PROXIES gateway.trustedProxies Comma-separated IPs
OPENCLAW_CONTROL_UI_ALLOWED_ORIGINS gateway.controlUi.allowedOrigins Comma-separated origins (e.g. https://you.hf.space)
OPENCLAW_CONTROL_UI_ALLOWED_ORIGIN gateway.controlUi.allowedOrigins Legacy single-origin alias
OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY channels.telegram.network.autoSelectFamily=false Existing OpenClaw workaround for Telegram network failures on some hosts
OPENCLAW_TELEGRAM_DNS_RESULT_ORDER channels.telegram.network.dnsResultOrder Existing OpenClaw Telegram network workaround; default ipv4first
OPENCLAW_TELEGRAM_PROXY channels.telegram.proxy Optional SOCKS/HTTP proxy URL for Telegram Bot API calls
OPENCLAW_TELEGRAM_NATIVE_COMMANDS channels.telegram.commands.native 1 / 0; default is enabled so the bot menu can appear
OPENCLAW_TELEGRAM_NATIVE_SKILLS channels.telegram.commands.nativeSkills 1 / 0; defaults to the same value as native commands
OPENCLAW_STARTUP_NOTIFY startup notify helper 1 / 0; send a best-effort Telegram startup notification
OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TO startup notify helper Optional explicit Telegram chat id; defaults to first OPENCLAW_TELEGRAM_ALLOW_FROM entry
OPENCLAW_TELEGRAM_API_HOST startup notify helper Optional alternate Telegram Bot API host; default api.telegram.org
OPENCLAW_AUTH_PROFILES_JSON_B64 startup auth import Base64-encoded full auth-profiles.json exported from another OpenClaw host
OPENCLAW_AUTH_PROFILES_IMPORT_B64 startup auth import Alternate secret name for the same full auth-profiles.json import
OPENCLAW_OPENAI_CODEX_PROFILE_B64 startup auth import Base64-encoded JSON object for one openai-codex:default profile
OPENCLAW_LEGACY_OAUTH_JSON_B64 startup auth import Base64-encoded legacy credentials/oauth.json import file
OPENCLAW_ENABLE_GEMINI_CLI_AUTH startup plugin bootstrap 1 / 0; enables google-gemini-cli-auth before gateway start
TELEGRAM_BOT_TOKEN channels.telegram.botToken BotFather token
OPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDS init script startup notification targets Comma-separated chat IDs
OPENCLAW_TELEGRAM_INIT_NOTIFY_MESSAGE init script startup notification body Extra line appended to the generated startup message
OPENCLAW_TELEGRAM_DROP_PENDING_UPDATES_ON_START Telegram startup receive fix 1 / 0; only used when deleting a stale webhook
OPENCLAW_TELEGRAM_DM_POLICY channels.telegram.dmPolicy pairing | allowlist | open | disabled
OPENCLAW_TELEGRAM_ALLOW_FROM channels.telegram.allowFrom Comma-separated Telegram user IDs
OPENCLAW_TELEGRAM_GROUP_POLICY channels.telegram.groupPolicy open | allowlist | disabled
OPENCLAW_TELEGRAM_GROUP_ALLOW_FROM channels.telegram.groupAllowFrom Comma-separated Telegram user IDs
OPENCLAW_TELEGRAM_REQUIRE_MENTION channels.telegram.groups."*".requireMention 1 / 0
SUPABASE_URL sync worker Supabase project URL
SUPABASE_KEY sync worker Supabase key with table write access
OPENCLAW_SUPABASE_TABLE sync worker Destination table; default openclaw_state
OPENCLAW_SYNC_INTERVAL_MS sync worker Background sync interval in ms
OPENCLAW_SYNC_MAX_FILE_BYTES sync worker Per-file size limit
OPENCLAW_SYNC_INCLUDE_EXTENSIONS sync worker Comma-separated extensions to mirror

Could be added the same way (same script pattern; not implemented yet):

Env variable Config path Notes
OPENCLAW_GATEWAY_PORT gateway.port Number; default entrypoint passes --port 7860 so only useful with a custom entrypoint.
OPENCLAW_GATEWAY_BIND gateway.bind lan | loopback | auto | tailnet | custom; entrypoint passes --bind lan.
OPENCLAW_CONTROL_UI_BASE_PATH gateway.controlUi.basePath e.g. /openclaw for reverse-proxy subpath.
OPENCLAW_CONTROL_UI_ALLOW_INSECURE_AUTH gateway.controlUi.allowInsecureAuth 1 / 0; allow token/password over HTTP.
OPENCLAW_CONTROL_UI_ENABLED gateway.controlUi.enabled 0 to disable Control UI.
OPENCLAW_CODEX_OAUTH_* auth profile store Depends on upstream OpenClaw support and your runtime's ability to complete the OAuth flow with persistent auth storage.

Headless Codex OAuth import for Spaces

For openai-codex/gpt-5.4 on Hugging Face Spaces, the reliable path is:

  1. Complete openclaw models auth login --provider openai-codex on another machine.
  2. Copy the resulting ~/.openclaw/agents/main/agent/auth-profiles.json.
  3. Base64-encode it and store it in a Space Secret named OPENCLAW_AUTH_PROFILES_JSON_B64 (or OPENCLAW_AUTH_PROFILES_IMPORT_B64 if the first name collides with an existing Variable).
  4. On startup, this repo imports that file into the Space state automatically.

If you only want the Codex profile instead of the whole file, you can provide a single profile JSON object in OPENCLAW_OPENAI_CODEX_PROFILE_B64. Legacy credentials/oauth.json payloads are also accepted via OPENCLAW_LEGACY_OAUTH_JSON_B64; startup converts them into the current auth-profiles.json OAuth shape automatically.

Example encoding command:

base64 -w0 ~/.openclaw/agents/main/agent/auth-profiles.json

After restart, verify in Space logs that startup printed something like:

[openclaw-hf-auth-import] imported=auth-profiles profiles=...

If the Space still logs No API key found for provider "openai-codex", the startup import either did not run, did not receive the secret, or the imported payload was not a valid auth profile. The most reliable input is the full auth-profiles.json export in OPENCLAW_AUTH_PROFILES_JSON_B64.

To add more, extend setup-hf-config.mjs (or your copy) to read the env, parse it, and set the corresponding keys on config.gateway or config.agents before fs.writeFileSync. Schema reference: Configuration.

Optional Space variables (build args)

You can set these in Settings β†’ Variables (or as build args) to customize the build:

  • OPENCLAW_REPO β€” Git URL of the OpenClaw repo (default: https://github.com/openclaw/openclaw.git).
  • OPENCLAW_REF β€” Branch or tag to clone (default: main).

More