GuidesChat and emailAI assistant with OpenClaw

Run OpenClaw with rootless Podman

OpenClaw on Debian 13, the open-source personal AI assistant, in rootless Podman under a user of its own, behind Caddy with HTTPS, a token and browser approval, and asking you before it runs a command.

Tested on OpenClaw 2026.9.6 on Debian 13 (trixie) on a Melonslab server Updated September 27, 2026

Recommended server for this guide

VC-S Micro · 2 vCPU · 8 GB Memory · 250 GB Storage

Month to month, no lock-in 7-day money-back guarantee

€7.99/mo

Deploy now
On this page

What you will set up

OpenClaw is an open-source personal AI assistant. It connects to an AI model at the provider you choose, runs commands, reads and writes files, keeps notes about you, and runs scheduled tasks. You talk to it in its web interface, the Control UI, or from chat apps. On a server it keeps running when your laptop is closed.

Here it runs in rootless Podman under a user of its own called openclaw, behind Caddy from the Podman guide. An agent that runs commands needs a tight fence, so this guide sets up four:

  • the commands it runs stay inside its container, as that unprivileged user;
  • the Control UI asks for a long random token;
  • every new browser must also be approved on the server before it can connect;
  • the agent asks you before it runs a command.

Every step below was run on a Melonslab VC-P Alloy (2 vCPU, 8 GB) with Debian 13:

  • Through OpenRouter's free models, the agent answered in the Control UI, asked for approval before running uname -r, and reported the kernel version once it was allowed.
  • A wrong token was refused, and a browser with the right token still had to be approved on the server.
  • OpenClaw's port could not be reached from the internet, and from inside its container an app that listens only on the server's loopback address could not be reached.
  • The API key's usage stayed at zero, an automatic update to a newer image went through, a restore from backup worked, and everything came back by itself after a reboot.

OpenClaw used about 1 GB of memory. Its image is 3.2 GB: allow 7 GB of disk for it.

Before you start

You need:

  • a server set up as in the Podman guide, with Caddy running, ideally with ufw from the security guide. OpenClaw needs no ports of its own;
  • an A record and an AAAA record for claw.example.com pointing at your server;
  • an API key from a model provider. This guide uses OpenRouter, which has free models: create a key at openrouter.ai/keys, and give it a spending limit.

The examples use claw.example.com for OpenClaw and 203.0.113.10 for your server's IPv4 address. Replace them throughout.

1. Create the user

As root:

useradd -m -s /bin/bash openclaw
loginctl enable-linger openclaw
machinectl shell openclaw@

Everything up to step 3 runs as openclaw.

2. Write the configuration

OpenClaw keeps everything in ~/.openclaw: its settings, your API key, its sessions and its notes. Create the directory, and a first configuration with a random token:

mkdir -m 700 ~/.openclaw
cat > ~/.openclaw/openclaw.json <<EOF
{
  "gateway": {
    "mode": "local",
    "bind": "lan",
    "auth": { "mode": "token", "token": "$(openssl rand -hex 32)" },
    "trustedProxies": ["203.0.113.10"],
    "controlUi": { "allowedOrigins": ["https://claw.example.com"] }
  }
}
EOF
chmod 600 ~/.openclaw/openclaw.json

What the settings do:

  • bind set to lan makes OpenClaw listen on every address inside its container, so that the port published in step 3 reaches it. From outside, only 127.0.0.1 on the server can reach that port. OpenClaw refuses to start this way without a token.
  • auth is the token you log in with. Anyone who has it can use the agent, so keep it as private as a password.
  • trustedProxies is your server's IPv4 address, which is where Caddy's connections appear to come from inside the container. OpenClaw then reads each visitor's real address from Caddy, and refuses proxied requests from anywhere else.
  • allowedOrigins is the address you will open the Control UI at. Browsers on other addresses are turned away.

3. Describe the container

mkdir -p ~/.config/containers/systemd

Create ~/.config/containers/systemd/openclaw.container:

[Unit]
Description=OpenClaw

[Container]
ContainerName=openclaw
Image=ghcr.io/openclaw/openclaw:latest
# The openclaw user outside the container is the user node inside it, so you own the files in ~/.openclaw.
UserNS=keep-id:uid=1000,gid=1000
Volume=%h/.openclaw:/home/node/.openclaw
# Only Caddy, on this server, can reach OpenClaw: the port is not open to the internet.
PublishPort=127.0.0.1:18789:18789
AutoUpdate=registry

[Service]
TimeoutStartSec=300
Restart=always

[Install]
WantedBy=default.target

Start it:

systemctl --user daemon-reload
systemctl --user start openclaw
systemctl --user enable --now podman-auto-update.timer

The first start downloads the image and prepares it for the user mapping, which took about four minutes. OpenClaw is up when its log shows [gateway] ready:

journalctl --user -u openclaw | grep "gateway\] ready"

4. Put Caddy in front

Go back to root with exit, switch to machinectl shell caddy@, and add this block at the end of ~/Caddyfile:

claw.example.com {
    reverse_proxy 127.0.0.1:18789
}

Restart Caddy with systemctl --user restart caddy. Caddy replaces any X-Forwarded-For header a visitor sends with the visitor's real address, which is what OpenClaw expects from a trusted proxy.

5. Add the model and lock it down

Go back to root with exit, and switch to machinectl shell openclaw@ again. Give OpenClaw your OpenRouter key. read -rs asks for it without showing it, and keeps it out of your shell history: paste the key, which starts with sk-or-v1-, and press Enter.

read -rs KEY
echo "$KEY" | podman exec -i openclaw openclaw models auth paste-api-key --provider openrouter
unset KEY
podman exec openclaw openclaw models set openrouter/free

The key is saved in OpenClaw's database in ~/.openclaw/state, which only the openclaw user can read. openrouter/free sends each request to one of OpenRouter's free models. They are slower and rate-limited: for more reliable answers, choose a paid model from openrouter.ai/models with models set, as openrouter/<provider>/<model>, and the spending limit on your key keeps the cost in check.

Other providers are set up the same way, with their own key and model: --provider anthropic or --provider openai in the first command, then a model such as anthropic/<model> or openai/<model>. This guide tested only OpenRouter.

By default, OpenClaw lets the agent run any command without asking, and has an elevated mode for commands outside a sandbox. Make it ask, switch elevated mode off, slow down anyone guessing the token, and restart:

podman exec openclaw openclaw config set tools.exec.mode ask
podman exec openclaw openclaw config set tools.elevated.enabled false
podman exec openclaw openclaw config set gateway.auth.rateLimit '{"maxAttempts": 10, "windowMs": 60000, "lockoutMs": 300000}'
systemctl --user restart openclaw

Then check the setup with OpenClaw's own audit, which should report 0 critical · 0 warn:

podman exec openclaw openclaw security audit

6. Log in and approve your browser

Print your token:

grep '"token"' ~/.openclaw/openclaw.json

Open https://claw.example.com, paste the token into Gateway secret, and choose Connect. The page then shows Approve this browser, with a command such as openclaw devices approve 3f6a.... Leave the page open, and run that command on the server, through the container:

podman exec openclaw openclaw devices approve REQUEST_ID

The page connects by itself. From then on, this browser logs in with a key of its own. Another browser, a private window or cleared site data needs a new approval. podman exec openclaw openclaw devices list lists the approved browsers.

7. Talk to it

Type a message in the box at the bottom and press Enter. The model in use is shown under the box: with openrouter/free, it names the free model that answered.

Ask the agent to run a command, such as uname -r, and it stops with Exec approval needed and the command. Allow once runs it this time, Always allow here runs that command without asking from now on, and Deny refuses. It then answers with the result.

OpenClaw can also answer you in WhatsApp, Telegram, Discord and other chat apps. This guide uses only the Control UI.

8. What the agent can reach

Commands the agent runs stay in its container:

  • they run as the openclaw user, so they cannot read the files of your other apps or of root;
  • apps that listen only on the server's loopback address, as the apps in our other guides do behind Caddy, cannot be reached from the container;
  • the internet, and anything your server serves to the internet, can be reached;
  • the agent can read its own settings in ~/.openclaw, including the token and your API key. Treat what it can do as what anyone with the token can do.

It asks before each command because of tools.exec.mode ask from step 5. Always allow here adds a command to a list that runs without asking, so use it only for commands you would run yourself.

The Control UI also has a Terminal panel, a shell in the container. It is one more reason to keep the token private and to approve only your own browsers. Without the token, a visitor gets only the login page and a health check at /healthz.

9. Keep it up to date

The timer from step 3 checks for a new image every day, and restarts OpenClaw on it. The latest tag follows OpenClaw's stable releases. podman auto-update --dry-run shows whether an update is waiting.

10. Back up

As openclaw:

mkdir -p ~/backup
systemctl --user stop openclaw
tar -czf ~/backup/openclaw.tar.gz -C ~ .openclaw
systemctl --user start openclaw

That saves the settings, the sessions and the agent's notes, and also the token and your API key. Copy ~/backup to another machine, and keep it private. To restore, stop OpenClaw, unpack the archive in the home directory with tar -xzf ~/backup/openclaw.tar.gz -C ~, and start it again.

Troubleshooting

The service restarts over and over, and its log says "Refusing to bind gateway to lan without auth". The token is missing from ~/.openclaw/openclaw.json. Check the file against step 2.

The Control UI says "Browser origin not allowed". The address in your browser is not in allowedOrigins. It must match exactly, with https:// and no slash at the end.

The page shows "Approve this browser" again. You are in a new browser, a private window, or you cleared the site's data. Approve it as in step 6.

curl http://127.0.0.1:18789 on the server gives proxy_attribution_required. That is expected: direct requests come from the trusted proxy address without Caddy's headers, so OpenClaw refuses them. Use https://claw.example.com.

The agent answers "No API key found for provider openrouter". Run the first part of step 5 again, then restart OpenClaw.

After going back to an older image, OpenClaw will not start and its log mentions database schemas. A newer version has already upgraded the data in ~/.openclaw. Go back to latest, or restore a backup made with the older version.

Answers are slow, or stop for a while. Free models are rate-limited. Pick another model with models set in step 5, or a paid one.

Run it on your own server

VC-S Micro

€7.99/mo

vCPU
2
Memory
8 GB
Storage
250 GB
Transfer
10 TB
Standard
HDD · RAID 10
  • Full root access
  • Native /64 IPv6
  • RAID-protected storage
  • Malmö, Sweden
  • Month to month, no lock-in
  • 7-day money-back guarantee
All guides