All posts
2026-04-0510 min

Don’t Run OpenClaw as Root: Least Privilege, AppArmor, and Safer Docker Defaults

OpenClawSecurityLinuxAppArmorDockerLeast Privilege

The Signal From X: People Are Finally Talking About Privilege Boundaries

Today’s OpenClaw chatter split into two camps.

The loud camp is posting the usual “agents are the future” takes. The more useful camp is posting the stuff operators actually need: gateway crashes, flaky setups, and the security foot-gun nobody wants to admit they stepped on — running OpenClaw as root because it felt faster during setup.

That is the wrong default.

If your agent can read your inbox, touch files, run shell commands, call external APIs, and potentially execute tools from skills, then “just run it as root” is not convenience. It is collapsing every safety boundary on the machine.

This matters even more for OpenClaw because it is not a toy chatbot sitting in one browser tab. It is an execution system. It can operate across Discord, Telegram, email, calendar, the filesystem, background processes, browser automation, and whatever else you wire into it. Once you see it that way, the old Linux rule becomes obvious again: the account running the service defines the blast radius.

If that account is root, the blast radius is “the whole box.”

---

Why Root Is Such a Bad Fit for OpenClaw

A lot of self-hosters reach for root for boring reasons:

  • permission errors disappear
  • Docker bind mounts “just work”
  • installing dependencies is easier
  • you only plan to “test it quickly”
  • Unfortunately, those are exactly the reasons it becomes sticky. A quick test turns into a real deployment. Then the agent keeps access to everything.

    What does root buy an attacker, a buggy skill, or a bad command approval?

  • read access to sensitive system files
  • write access across the host
  • easier persistence
  • easier credential discovery
  • more dangerous process control
  • less meaningful containment if a tool misbehaves
  • Even if you trust yourself, you should not trust every future instruction, every copied shell snippet, every external skill, or every moment you are tired and click approve too quickly.

    The practical model is simple: OpenClaw should run with enough permission to do its job, and no more.

    ---

    The Safer Host Setup: Dedicated User, Dedicated Workspace

    On a plain Linux host, the clean pattern is:

    1. create a dedicated service user

    2. keep the OpenClaw workspace owned by that user

    3. avoid sudo inside the agent runtime

    4. lock down secrets and memory files

    5. expose nothing publicly unless you absolutely must

    Minimal example:

    <pre><code class="language-bash">sudo useradd --create-home --shell /bin/bash openclaw

    sudo mkdir -p /home/openclaw/.openclaw

    sudo chown -R openclaw:openclaw /home/openclaw/.openclaw

    sudo chmod 700 /home/openclaw/.openclaw</code></pre>

    Then store the environment file with tight permissions:

    <pre><code class="language-bash">sudo chown openclaw:openclaw /home/openclaw/.openclaw/.env

    sudo chmod 600 /home/openclaw/.openclaw/.env</code></pre>

    That already fixes one of the most common mistakes: secrets sitting in a world-readable directory because the service was installed hastily under a shared user.

    If you are using systemd, make the service run as the dedicated user instead of root:

    <pre><code class="language-ini">[Service]

    User=openclaw

    Group=openclaw

    WorkingDirectory=/home/openclaw/.openclaw/workspace

    EnvironmentFile=/home/openclaw/.openclaw/.env

    NoNewPrivileges=true

    PrivateTmp=true

    ProtectSystem=full

    ProtectHome=read-only</code></pre>

    You may need to relax one or two of those systemd hardening flags depending on your exact layout, but the direction is correct: shrink what the process can touch.

    ---

    Docker: Non-Root Is Not Optional Anymore

    Docker makes people overconfident because “it’s in a container” sounds safer than it often is.

    A root process inside a container is still a root process. Namespaces and cgroups help, but they are not magical absolution. Misconfigured mounts, Docker socket exposure, broad capabilities, or a kernel/container escape can turn a sloppy container into a host problem very quickly.

    For OpenClaw, the safer baseline is:

  • run as a non-root UID/GID
  • mount only the directories you actually need
  • avoid host networking
  • do not publish the gateway port to the public internet
  • add memory and process limits
  • drop unnecessary Linux capabilities
  • A sane Compose fragment looks like this:

    <pre><code class="language-yaml">services:

    openclaw:

    image: ghcr.io/openclaw/openclaw:latest

    user: "1001:1001"

    read_only: true

    tmpfs:

    - /tmp

    cap_drop:

    - ALL

    security_opt:

    - no-new-privileges:true

    - apparmor=openclaw-default

    volumes:

    - ./workspace:/home/openclaw/.openclaw/workspace

    - ./env:/run/secrets

    ports:

    - "127.0.0.1:8080:8080"

    restart: unless-stopped

    mem_limit: 2g

    pids_limit: 256</code></pre>

    Notice the important detail in the port binding: <code>127.0.0.1:8080:8080</code>, not <code>0.0.0.0:8080:8080</code>. That means the service is local-only unless you intentionally put a reverse proxy or Tailscale in front of it.

    That single line prevents a shocking number of accidental exposures.

    ---

    AppArmor: Worth the Extra 10 Minutes

    If you run on Ubuntu or another AppArmor-enabled distro, use it.

    AppArmor is not fancy. That is why it is useful. It lets you define what a process can read, write, and execute at the kernel policy layer. If OpenClaw gets a weird instruction or a tool does something stupid, AppArmor gives you one more brake pedal.

    You do not need a perfect profile on day one. Even a modest profile that restricts writes to the workspace and limits unexpected execution paths is better than “hope nothing bad happens.”

    Conceptually, your profile should:

  • allow reads to the app binary and needed shared libraries
  • allow read/write only inside the OpenClaw workspace and approved temp paths
  • deny access to sensitive system locations unless explicitly required
  • restrict execution to known binaries you actually need
  • If you have never used AppArmor before, start in complain mode, observe what the service needs, then tighten it into enforce mode.

    The point is not to create an unbreakable prison. The point is to make a mistake materially less expensive.

    ---

    Exec Is Where Privilege Mistakes Become Real Incidents

    Most OpenClaw security discussions eventually land here, because this is where the system stops being “AI assistant” and becomes “remote operator.”

    If exec is available and the process is root, then any approval mistake becomes a root approval mistake.

    That changes the entire risk profile.

    The safer pattern is:

  • run OpenClaw as a non-root user
  • require approvals for elevated commands
  • keep allowlists narrow where possible
  • treat external-message-driven workflows as untrusted input
  • In other words: least privilege and approval mode are complementary. Approval prompts are not a substitute for sane Unix permissions. They are the second seatbelt, not the first one.

    ---

    The Networking Rule: Zero Public Ports by Default

    There is a boring but correct rule for most OpenClaw installs: do not expose the gateway directly to the internet.

    Use one of these instead:

  • Tailscale Serve for private tailnet access
  • a reverse proxy on localhost with auth and rate limiting
  • SSH tunneling for admin access
  • Avoid the “I’ll just open one port for now” mindset. Agents are high-complexity systems with lots of integrations. They are exactly the wrong thing to casually expose.

    If you absolutely need webhooks, terminate them through a minimal public endpoint that validates signatures and forwards only the specific events you expect. Do not turn your whole agent gateway into a public web service.

    ---

    A 15-Minute Audit You Can Run Right Now

    If you already have OpenClaw running, check these first:

    1. What user owns the process?

    2. Is the gateway bound to localhost or all interfaces?

    3. Are your workspace and <code>.env</code> files readable only by the service user?

    4. Does your container run as root?

    5. Do you have any unnecessary bind mounts?

    6. Is AppArmor or another MAC layer doing anything at all?

    Useful commands:

    <pre><code class="language-bash">ps -o user,pid,cmd -C node

    ss -tulpn | grep openclaw

    stat -c "%U %G %a %n" /home/openclaw/.openclaw /home/openclaw/.openclaw/.env

    docker inspect openclaw --format '{{.Config.User}}'</code></pre>

    If the answers come back as root, public bind, loose permissions, and no confinement, you know what to fix next.

    ---

    TL;DR

    The best OpenClaw hardening move is not exotic.

    It is this:

  • do not run it as root
  • give it a dedicated user
  • keep secrets at <code>600</code> and directories at <code>700</code>
  • bind the gateway to localhost only
  • run Docker as a non-root UID with dropped capabilities
  • add AppArmor if your distro supports it
  • That is how you turn OpenClaw from “cool demo with scary permissions” into something you can actually leave running.

    If your current setup works only because it is root, that is not a stable setup. That is deferred cleanup with extra risk attached. Fix it now while nothing is on fire.

    Want to learn more?

    Our playbook contains 18 detailed chapters — available in English and German.

    Get the Playbook