#Docker run grab .env variables and build openclaw.json

1 messages · Page 1 of 1 (latest)

tawdry flume
#

Hi all,

How can i automate the creation of openclaw.json based on my predefined .env variables?
I'm a noob, and I rebuold the container very often

deft ivyBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> ✅ Mark Solution

slender ridgeBOT
# tawdry flume Hi all, How can i automate the creation of openclaw.json based on my predefined...

First, quick sanity check: what does openclaw --version show? Docker behavior has moved around a bit.

For the rebuild-often case, I’d avoid regenerating openclaw.json if you can. The Docker docs say Compose bind-mounts OPENCLAW_CONFIG_DIR to /home/node/.openclaw, and that mounted dir is where openclaw.json, auth profiles, and .env live. So the cleanest setup is:

OPENCLAW_CONFIG_DIR=/path/on/host/openclaw-config
OPENCLAW_WORKSPACE_DIR=/path/on/host/openclaw-workspace
OPENCLAW_GATEWAY_TOKEN=your-token
DISCORD_BOT_TOKEN=your-discord-token

Then in /path/on/host/openclaw-config/openclaw.json, reference env vars instead of writing secrets directly:

{
  gateway: {
slender ridgeBOT
slender ridgeBOT
# tawdry flume Hi all, How can i automate the creation of openclaw.json based on my predefined...

That way the file is stable, rebuilds are cheap, and secrets stay in .env / Compose env.

If you really want to create/update config from env on every boot, use the CLI rather than hand-building JSON where possible, e.g. after the gateway container exists:

docker compose run --rm openclaw-cli config set channels.discord.token \
  --ref-provider default --ref-source env --ref-id DISCORD_BOT_TOKEN

Docs:
https://docs.openclaw.ai/install/docker
https://docs.openclaw.ai/gateway/configuration
https://docs.openclaw.ai/gateway/secrets

tawdry flume
#

node@openclaw:/app$ openclaw --version
OpenClaw 2026.3.25

slender ridgeBOT
# tawdry flume node@openclaw:/app$ openclaw --version OpenClaw 2026.3.25

Thanks. 2026.3.25 should be new enough for the env-backed SecretRef approach.

For your case, I’d make the config persistent and let it point at env vars, instead of rebuilding the JSON each time. Example shape:

{
  gateway: {
    mode: "local",
    bind: "lan",
    auth: {
      mode: "token",
      token: { source: "env", provider: "default", id: "OPENCLAW_GATEWAY_TOKEN" },
    },
  },
  channels: {
    discord: {
slender ridgeBOT
# tawdry flume node@openclaw:/app$ openclaw --version OpenClaw 2026.3.25
      enabled: true,
      token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },
    },
  },
}

Then make sure your container gets those env vars and that /home/node/.openclaw is backed by a host volume/bind mount. In the official Docker flow that’s controlled by OPENCLAW_CONFIG_DIR.

After editing, validate from inside the container:

openclaw doctor
openclaw status --all
slender ridgeBOT
tawdry flume
#

I want these settings

{
"gateway": {
"auth": {
"mode": "token",
"token": "18494ce009481af3123a641eb885173c6c00384b94d208a39"
},
"controlUi": {
"allowedOrigins": [
"https://openclaw.max.local"
]
},
"mode": "local",
"port": 18789,
"bind": "lan",
"tailscale": {
"mode": "off",
"resetOnExit": false

"models": {
"mode": "merge",
"providers": {
"lmstudio": {
"baseUrl": "http://192.168.168.20:1234/v1",
"api": "openai-completions",
"auth": "api-key",
"apiKey": "LM_API_TOKEN",
"models": [
{

},
"auth": {
"profiles": {
"lmstudio:default": {
"provider": "lmstudio",
"mode": "api_key"
}

slender ridgeBOT
# tawdry flume I want these settings { "gateway": { "auth": { "mode": "token", ...

Two important things:

  1. You pasted a live-looking gateway token in a public indexed help thread. Treat it as leaked and rotate it.
  2. Your snippet is structurally broken: models and top-level auth should not be nested inside gateway.tailscale.

A cleaned-up version would look like this. Put the real secret values in .env, not directly in the JSON:

OPENCLAW_GATEWAY_TOKEN=replace-with-new-rotated-token
LM_API_TOKEN=your-lmstudio-token
{
  gateway: {
    mode: "local",
slender ridgeBOT
slender ridgeBOT
slender ridgeBOT
tawdry flume
#

give me .env varaibles for all of those keys

slender ridgeBOT
# tawdry flume give me .env varaibles for all of those keys

Yep. I’d use these names:

# Gateway
OPENCLAW_GATEWAY_TOKEN=replace-with-new-rotated-token
OPENCLAW_GATEWAY_MODE=local
OPENCLAW_GATEWAY_PORT=18789
OPENCLAW_GATEWAY_BIND=lan
OPENCLAW_CONTROL_UI_ORIGIN=https://openclaw.max.local
OPENCLAW_TAILSCALE_MODE=off
OPENCLAW_TAILSCALE_RESET_ON_EXIT=false

# LM Studio
LMSTUDIO_BASE_URL=http://192.168.168.20:1234/v1
LMSTUDIO_API=\\openai-completions
LMSTUDIO_AUTH=api-key
slender ridgeBOT
# tawdry flume give me .env varaibles for all of those keys
LM_API_TOKEN=your-lmstudio-token
LMSTUDIO_MODEL_ID=replace-with-exact-model-id-from-lm-studio
LMSTUDIO_MODEL_NAME=LM Studio local model

Small correction: for OpenClaw itself, env refs are best for secrets like gateway.auth.token and models.providers.lmstudio.apiKey. For regular config values like port/bind/origin/model id, either keep them directly in openclaw.json, or generate openclaw.json from a template with something like envsubst.

So the stable openclaw.json I’d pair with that .env is:

{
  gateway: {
    mode: "local",
    port: 18789,
    bind: "lan",
slender ridgeBOT
# tawdry flume give me .env varaibles for all of those keys
    auth: {
      mode: "token",
      token: { source: "env", provider: "default", id: "OPENCLAW_GATEWAY_TOKEN" },
    },
    controlUi: {
      allowedOrigins: ["https://openclaw.max.local"],
    },
    tailscale: {
      mode: "off",
      resetOnExit: false,
    },
  },

  models: {
    mode: "merge",
slender ridgeBOT
# tawdry flume give me .env varaibles for all of those keys
    providers: {
      lmstudio: {
        baseUrl: "http://192.168.168.20:1234/v1",
        api: "openai-completions",
        auth: "api-key",
        apiKey: { source: "env", provider: "default", id: "LM_API_TOKEN" },
        models: [
          {
            id: "REPLACE_WITH_EXACT_MODEL_ID",
            name: "LM Studio local model",
          },
        ],
      },
    },
  },
slender ridgeBOT
tawdry flume
#

can you pass me to a human?