DEV Community

Mateusz Rusowicz
Mateusz Rusowicz

Posted on

Bare Metal AI: Taming OpenClaw on a Hetzner VPS (and surviving the systemd boss fight)

When you're juggling the logistics of a music festival while simultaneously shipping code in Next.js, Qwik, and Prisma, you don't just want automation—you need an autonomous agent. Relying on locked-down SaaS platforms wasn't cutting it, so I decided to host OpenClaw bare-metal on a Hetzner VPS (Ubuntu arm64).

It sounded simple. Install the CLI, run the daemon, and let the AI handle the emails. Reality, however, was a deep dive into Linux user spaces, headless OAuth, and security architectures. Here is the exact blueprint of how to get OpenClaw running cleanly and securely on bare metal.

1. The Homebrew & Compiler Trap

OpenClaw often relies on Homebrew for external binaries (like gogcli for Gmail integration). On a fresh Hetzner Ubuntu box, installing Homebrew isn't enough; you need the compiler toolchain, or formulae will silently fail to build from source.

The Fix:
Before touching OpenClaw tools, set up the environment properly:

sudo apt update && sudo apt install build-essential -y
brew install gcc

Ensure your agent user (e.g., claw) actually has brew in its path by appending the shellenv to ~/.bashrc. Without this, the agent is flying blind when trying to execute system tools.

## 2. The systemd User Service Nightmare
Running an AI agent via PM2 feels familiar for JS developers, but it restricts the agent's environment access. OpenClaw provides native systemd --user integration, which is vastly superior for logging and path resolution.

However, if you switch to your agent user via su - claw instead of a clean SSH login, you will immediately hit:
Failed to connect to bus: No medium found

**The Fix:**
Linux didn't load the DBUS environment for the user space. You have to inject it manually into the .bashrc and build the service file from scratch:

Enter fullscreen mode Exit fullscreen mode


bash
echo 'export XDG_RUNTIME_DIR=/run/user/$(id -u)' >> ~/.bashrc
echo 'export DBUS_SESSION_BUS_ADDRESS=unix:path=${XDG_RUNTIME_DIR}/bus' >> ~/.bashrc

Then, manually "push" the service file (think of it like running db push in Prisma to materialize your schema) so the agent actually runs the gateway process with the correct PATH:

mkdir -p ~/.config/systemd/user
cat << EOF > ~/.config/systemd/user/openclaw.service
[Unit]
Description=OpenClaw Agent
After=network.target

[Service]
Type=simple
ExecStart=$(which openclaw) gateway
Restart=always
RestartSec=3
Environment="PATH=$PATH"
Environment="NODE_COMPILE_CACHE=/var/tmp/openclaw-compile-cache"
Environment="OPENCLAW_NO_RESPAWN=1"

[Install]
WantedBy=default.target
EOF

systemctl --user daemon-reload
systemctl --user enable --now openclaw
Enter fullscreen mode Exit fullscreen mode

3. Unlocking the Runtimes (ACPX)

If you're using OpenClaw 2026.3+, you might notice your agent complaining that it can't write files or execute commands, throwing errors like plugin not found: fs. The architecture changed. Terminal and file operations are no longer standard plugins; they are governed by the ACPX runtime and Tool Profiles.

The Fix:
Stop editing JSON configs manually. Use the CLI to enable the Anthropic/Model Context Protocol (ACP) runtime and elevate the tool profile:

openclaw plugins enable acpx
openclaw config set tools.profile full
systemctl --user restart openclaw
Enter fullscreen mode Exit fullscreen mode

Now the agent has hands.

4. Headless OAuth (The curl Hack)

To let the agent manage Gmail, I used gogcli. Authenticating an OAuth app on a headless VPS without a TTY or a browser usually requires setting up SSH port forwarding. But there's a faster way.

When you run gog auth add your@email.com, it prints a Google OAuth link and starts a local listener on a random port (e.g., 127.0.0.1:36367).

The Fix:

  1. Copy the Google link to your local laptop browser and approve it.

  2. Google will redirect you to a broken localhost link. Copy that entire broken URL.

  3. SSH into your server in a second terminal window.

Use curl to fire the callback directly at the waiting process:

curl "[http://127.0.0.1:36367/oauth2/callback?state=...&code=](http://127.0.0.1:36367/oauth2/callback?state=...&code=)..."
Enter fullscreen mode Exit fullscreen mode

Boom. Token saved securely. No SSH tunneling required.

5. Security: Revoking Sudo

Just revoke the sudo...

Running AI bare-metal takes a bit of Linux elbow grease, but the result is a deeply integrated, lightning-fast agent that lives right on your infrastructure.

Top comments (0)