Back to blog
January 1, 1970OpenClawDockerDiscordInfrastructure

How to Run an OpenClaw Discord Agent on a VM with Docker

A practical guide to running an OpenClaw-powered Discord agent on an Ubuntu VM with Docker, persistent config, secure secrets handling, and fewer troubleshooting nightmares.

By Jordan DiGiacomo

How to Run an OpenClaw Discord Agent on a VM with Docker

How to Run an OpenClaw Discord Agent on a VM with Docker

If you want a Discord-based OpenClaw agent running on a VM inside Docker, this is the clean version of the setup.

No leaked tokens. No weird internal junk. No hand-wavy “just configure it” nonsense.

This guide covers:
- the host VM
- the Docker container
- OpenClaw config
- Discord setup
- secrets handling
- useful commands
- common failure modes
- basic security hardening

---

1) What You’re Building

The target setup looks like this:

- **Ubuntu VM** as the host
- **Docker** running the OpenClaw container
- **Discord bot token** connected to a server
- **Persistent config + state** mounted into the container
- **Workspace files** mounted or stored persistently
- Optional API keys (like Brave) stored in `secrets.json`

At a high level:

1. The VM runs Docker
2. Docker runs OpenClaw
3. OpenClaw connects to Discord
4. Your agent responds in channels / threads
5. Config and secrets live in persistent mounted storage

---

2) Host VM Prerequisites

Use an Ubuntu VM and install:

- Docker
- Docker Compose plugin
- Python 3 (nice to have for quick config edits)

Install Docker on Ubuntu

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

Verify Docker

---

3) Create Persistent Directories

Do **not** keep config only inside the container filesystem unless you enjoy losing changes.

Example host layout:

Recommended meaning:

- `config/` → OpenClaw config files
- `state/` → runtime state, sessions, caches, etc.
- `workspace/` → your editable agent files

---

4) Create the OpenClaw Config

Create:

Example baseline config:

Notes

- Replace `YOUR_DISCORD_BOT_TOKEN` with your bot token
- Replace `YOUR_USER_ID` with your Discord user ID if you want DM allowlisting
- Keep `groupPolicy` on **`allowlist`**, not `open`
- `tools.profile: "coding"` is useful if you want file + exec capabilities
- `tools.exec.ask: "off"` avoids approval loops in trusted private setups

If you expose this to multiple people, tighten it further.

---

5) Store Secrets Properly

Some keys belong in secrets storage instead of chat or random notes.

Create:

Example:

Safer way to update with Python

Important

If a key gets pasted into a public/shared Discord channel, rotate it.
Treat it as compromised immediately.

---

6) Create a Docker Compose File

Create:

Example:

Why the mounts matter

This is the entire game.

If you do **not** mount config/state/workspace properly:
- edits can disappear
- restarts won’t reflect what you changed
- secrets may vanish
- you’ll waste hours debugging the wrong file

---

7) Start the Container

From the project directory:

Check status:

---

8) Create the Discord Bot

In the Discord Developer Portal:

1. Create a new application
2. Add a bot user
3. Copy the bot token
4. Enable only what you actually need
5. Invite the bot to your server

Recommended server permissions

At minimum, depending on what you want the bot to do:

- View Channels
- Send Messages
- Send Messages in Threads
- Create Public Threads
- Read Message History
- Add Reactions

If you want channel management too:
- Manage Channels

If you want permission overwrites / role operations:
- Manage Roles

Do **not** give admin just because you’re lazy.

---

9) Verify OpenClaw Status

Once running, check status from the host:

Or if running directly in the container shell:

Useful follow-up commands:

---

10) Common Commands You’ll Actually Use

Restart the container

Or:

Pull latest image and recreate

Inspect mounts

Show config files

View secrets file

Check directory permissions

---

11) Security Hardening You Should Actually Do

This is where most people do dumb shit.

A. Lock down the OpenClaw state directory

If your state directory is world-writable, fix it:

If your actual runtime path is `/home/node/.openclaw`, then inside the container or mapped source it should end up equivalent to:

B. Do not leave Discord group access wide open

Bad:

Better:

If the bot is in shared servers and has runtime/file tools, open access is asking for chaos.

C. Keep runtime/file tools constrained

If the agent is exposed to group chats:
- avoid broad runtime access unless you trust the room
- keep filesystem access limited to workspace where possible
- use sandboxing if available in your setup

D. Never trust leaked keys

If somebody pastes a key in a public/shared channel:
1. rotate it
2. replace it in secrets
3. restart the container if needed

---

12) If Config Changes Don’t Seem to Work

This is one of the most common failures.

Check 1: Are you editing the real config file?

You may think you are editing:

But your container may actually be reading a mounted file from somewhere like:

Find out what is really mounted:

Check 2: Are you restarting the container, not just the app?

A soft app restart may not be enough.

Use:

or:

Check 3: Are your changes being overwritten?

If the file inside the container changes but the host mount is stale, or vice versa, you’re editing the wrong copy.

Check 4: Are you using the right config format?

If both exist, document which one actually wins in your install:
- `openclaw.json`
- `openclaw.mjs`

Do not assume.
Verify.

---

13) If Exec Keeps Asking for Approval

In a trusted private setup, the usual config fix is:

Then restart the container.

If it still does not work:
- you are probably editing the wrong config file
- or the container did not reload the mounted config

---

14) If Web Search Does Not Work

If OpenClaw says Brave search needs an API key:

1. store the key in `secrets.json`
2. make sure the correct secrets path is mounted into the container
3. restart the container
4. test again

If it still fails:
- verify the key name is correct
- verify the container can read the secrets file
- verify you did not store it in a dead copy of the config/state path

---

15) Suggested Workspace Files

A good agent workspace usually includes:

- `AGENTS.md` → workspace rules
- `SOUL.md` → voice/personality
- `USER.md` → user profile and preferences
- `TOOLS.md` → local environment notes
- `IDENTITY.md` → quick identity summary
- `HEARTBEAT.md` → proactive checks / reminders

These are not strictly required for OpenClaw to run, but they make the assistant much more usable.

---

16) Suggested Validation Checklist

After setup or any major change, verify:

Container

OpenClaw

Discord

- bot appears online
- bot can reply in a test channel
- bot can reply in a thread
- bot can mention/respond as expected

Tools

- exec works if you intended it to
- message tool actions work
- files persist after restart
- secrets are still present

---

17) Minimal Troubleshooting Flow

If something breaks, do this in order:

1. Check container is running
```bash
docker compose ps
```

2. Check logs
```bash
docker logs --tail 100 openclaw-gateway
```

3. Check what config is mounted
```bash
docker inspect openclaw-gateway | grep -A20 Mounts
```

4. Check the actual config file contents
```bash
cat ~/openclaw-agent/config/openclaw.json
```

5. Check secrets
```bash
cat ~/openclaw-agent/state/secrets.json
```

6. Restart the container
```bash
docker compose restart
```

7. Re-run status
```bash
docker exec -it openclaw-gateway openclaw status
```

If you skip steps and start guessing, you’ll just waste time.

---

18) Final Recommendation

If you want this setup to stay sane:

- keep config and state mounted persistently
- keep Discord access tight
- keep secrets out of chat
- document the actual host paths
- prefer container restarts over vague “maybe it reloaded” optimism
- run `openclaw status` and `openclaw security audit` after meaningful changes

That’s it.

Simple setup. Persistent files. Tight permissions. Fewer mysteries.

If you want, the next step is turning this into:
1. a **copy-paste deployment guide**, or
2. a **polished blog post with intro/outro and screenshots**.

Next step

Want the setup without the headache?

Remoras helps founders and operators get AI workflows running fast without wasting weekends on setup, integrations, and trial-and-error.