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
- Create a new Space at huggingface.co/new-space. Choose Docker as the SDK.
- 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.mjsThe Space installs the publishedopenclawnpm package directly instead of cloning/building the full source tree, which is much more reliable on HFcpu-basic.
- This
- 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: useOPENCLAW_GATEWAY_PASSWORDfor password auth; if both are set, token is used.)OPENCLAW_GATEWAY_PASSWORDβ (optional) Gateway password; startup script setsgateway.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 theopencodeprovider.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 tohuggingface/Qwen/Qwen3-8B.OPENCLAW_MODEL_FALLBACK_1β (recommended) First fallback model ref. Default ishuggingface/deepseek-ai/DeepSeek-R1.OPENCLAW_MODEL_FALLBACK_2β (recommended) Second fallback model ref. Default isopenai-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 intogateway.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 togateway.controlUi.allowedOriginsso 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. Default0.OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TOβ (optional) Single fallback chat ID for startup notifier whenOPENCLAW_TELEGRAM_INIT_NOTIFY_CHAT_IDSis 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.
- 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 whenSUPABASE_URL+SUPABASE_KEYare 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
- primary:
- The startup script now writes both
primaryandfallbacks. - Codex fallback only works if Codex itself is already authenticated and usable. If
openai-codex/gpt-5.4still lacks auth, fallback will still fail when traffic reaches it. - OpenCode Zen also works well in Hugging Face Spaces. Set
OPENCODE_API_KEYand use a default model such asopencode/claude-opus-4-6. - Codex auth remains the special case: if your
openai-codex/gpt-5.4path 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 probesgetUpdatesso 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:
- Ask the target user to start the bot first, or add the bot to the target group/channel before using that chat ID.
- Use numeric chat IDs when possible; they are less fragile than usernames.
- The startup notifier now tries several network transports:
fetch-json,https-family4-json,https-family4-form,https-resolve4-json, andcurl-json. - If no explicit startup chat ID is configured, the notifier falls back to
OPENCLAW_STARTUP_NOTIFY_TELEGRAM_TO, thenOPENCLAW_TELEGRAM_ALLOW_FROM, then recentgetUpdateschat IDs. - Startup messages are tagged with both
transport=andpayload=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:
- In Settings β Storage, add persistent storage for the Space.
- The container uses
/datawhen writable (state under/data/.openclaw). If/datais not available, it falls back to/home/user/.openclawso 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:
- 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
);
Add Secrets in your Space:
SUPABASE_URLSUPABASE_KEY
Optional Variables:
OPENCLAW_SUPABASE_TABLE=openclaw_stateOPENCLAW_SYNC_INTERVAL_MS=300000OPENCLAW_SYNC_MAX_FILE_BYTES=5242880OPENCLAW_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)
- Find the proxy IP(s) β In the Space logs, look for
[ws] ... remote=10.20.31.87 .... Theremote=value is the address the gateway sees. Note one or more such IPs. - 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
- Name:
- Restart the Space. The entrypoint runs
setup-hf-config.mjsbefore the gateway; it reads this env and writesgateway.trustedProxiesinto 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:
- Complete
openclaw models auth login --provider openai-codexon another machine. - Copy the resulting
~/.openclaw/agents/main/agent/auth-profiles.json. - Base64-encode it and store it in a Space Secret named
OPENCLAW_AUTH_PROFILES_JSON_B64(orOPENCLAW_AUTH_PROFILES_IMPORT_B64if the first name collides with an existing Variable). - 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).