DEV Community

Cover image for What a Hardened OpenClaw Rig Actually Looks Like
v. Splicer
v. Splicer

Posted on • Originally published at Medium

What a Hardened OpenClaw Rig Actually Looks Like

Most people are running a toy that dies when they close their laptop. A real rig survives reboots, API outages, and you being asleep.

Everyone posts the same screenshot. Claude Code running in a terminal, a cool prompt, some autonomous commits. Then 3 days later the agent is dead, the memory is corrupted, and the VPS ran out of disk.

A hardened OpenClaw rig is not a laptop. It's a system designed to stay up.

Here is what mine actually looks like after 6 months of breaking it.

1. The Toy vs. The Rig

The Toy: OpenClaw running on your MacBook, on your home WiFi, in a tmux session you forgot about. Secrets in .env, no backups, public IP if you forwarded a port.

The Rig: Dedicated host, isolated services, tailnet-only access, encrypted secrets, auto-healing, observable, and recoverable in under 5 minutes from a snapshot.

If you want to run Claude Code as a real 24/7 employee, you have to stop treating it like a script and start treating it like infra.

2. Layer 0: The Host

I run two versions. One on a $400 Beelink SER5 Pro in my closet, one on a Hetzner CPX31. Both work. The point is: it is not your daily driver.

  • OS: Ubuntu 24.04 LTS minimal. Nothing else installed.
  • FS: ZFS or Btrfs with snapshots enabled. When Claude goes rogue and fills your disk with logs, you will want this.
  • Base hardening: Unattended-upgrades on, UFW default deny, fail2ban, no root SSH, SSH keys only.
  • Power: If it's physical, it's on a small UPS. The number one killer of persistent agents is not hackers, it's a power flicker at 2am.

This box does one job. Run OpenClaw.

3. Layer 1: Isolation

Never run OpenClaw bare metal as your user.

My stack is Docker Compose behind Caddy. Each service gets its own user, its own volume, and restart policies that actually work.

services:
  openclaw:
    image: openclaw/openclaw:latest
    restart: unless-stopped
    user: "1001:1001"
    mem_limit: 8g
    volumes:
      - ./data:/data
      - ./memory:/memory:rw
    env_file:
      - .env.sops.decrypted
Enter fullscreen mode Exit fullscreen mode

That restart: unless-stopped is the bare minimum. The real trick is the systemd unit that wraps Compose and the watchdog that watches the watcher. I broke down the full persistence wrapper, including systemd timers, health pingers, and memory compaction crons, in the OpenClaw + Claude Code: 24/7 Persistent Agent Playbook (2026).

Without it, your agent will slowly leak memory and die on day 9 every time.

4. Layer 2: Persistence - The Part Everyone Gets Wrong

OpenClaw is stateful. It has a gateway, a memory store, cron jobs, and Claude Code sessions. If any of those die silently, you have a zombie.

A hardened rig has three persistence guarantees:

1. Survives reboot: systemd unit with Restart=always and RestartSec=5. Enabled on boot. Tested by actually rebooting.

2. Survives Claude API downtime: Queue + backoff. I use a small Redis queue in front and a wrapper script that catches 529s and retries with exponential backoff instead of crashing the loop.

3. Survives itself: Nightly memory compaction and weekly full restarts. Claude Code sessions bloat. If you never rotate them, your context window becomes 200k tokens of garbage. My cron wipes and summarizes every night at 3am UTC.

This whole layer is why most people quit. It is not sexy, but it is the difference between a demo and an employee. The exact compose file, compaction prompts, and recovery scripts I use are in the 24/7 Persistent Agent Playbook because I got tired of rebuilding it from scratch.

5. Layer 3: The Operator Workstation

This is the piece no one talks about. Your rig can be perfect, but if your control plane is your trackpad and a random terminal, you will make a mistake and rm -rf prod.

Your laptop should not run the agent. It should operate it.

My workstation is just:

  • Tailscale on everything. No public ports. OpenClaw is only reachable on openclaw.tailnet.ts.net. Caddy gets TLS via Tailscale certs.
  • A single ssh openclaw alias that drops me into a tmuxinator session with logs, shell, and memory viewer.
  • Custom slash commands and a local dashboard that tails the gateway logs.

I call this the Operator Workstation pattern. Your local machine is a cockpit, not a server. I documented my full cockpit setup, including my tmuxinator, SSH config, and the little status bar I use to see if the agent is working or stuck, in the OpenClaw Operator Workstation guide. Once I switched to this, I stopped having that anxiety of "is it still running?"

6. Layer 4: Hardening

If your agent can read your email and push code, it is a high-value target.

  • Secrets: No .env in git. Ever. I use sops with age. The decrypted file only exists in memory via systemd LoadCredential. 1Password Connect is also fine.
  • Network: UFW denies everything inbound. Only Tailscale interface allows 22 and 443. Caddy is the only thing that binds to 0.0.0.0 and it does mTLS.
  • Filesystem: OpenClaw user cannot write to /. AppArmor profile in complain mode for a week, then enforce. Read-only root mounts where possible.
  • Claude Code: Run it with --dangerously-skip-permissions never. Use its permission system. Give it a dedicated GitHub PAT with repo-scoped access, not your personal token.

7. Layer 5: Observability

If you cannot see it, it is already dead.

  • Uptime Kuma pinging /health every 30 seconds, alerting to Telegram.
  • Loki + Grafana for logs. I can see when the agent started looping on the same file.
  • A simple dead-man switch: The agent has to touch a file every 10 minutes. If it does not, systemd restarts it and I get a nudge.

The goal is not pretty dashboards. The goal is knowing it died before your client does.

8. Layer 6: Recovery

Everything fails. The question is how fast you recover.

  • Hourly: Restic backup of /data and /memory to B2. Encrypted.
  • Daily: ZFS snapshot.
  • On demand: One script rig-restore.sh that pulls the last backup onto a fresh Hetzner box. I have timed it. 4 minutes 12 seconds from zero to working agent.

Test your restore. I did not for a month and learned the hard way that I was backing up an empty folder due to a bad mount.

The Full Picture

[ You on Operator Workstation ]
         |  (Tailscale only)
         v
[Caddy with TLS] -> [OpenClaw Gateway + Claude Code]
         |           |-> Postgres (memory)
         |           |-> Redis (queue)
         |           |-> Restic -> B2
[Uptime Kuma / Loki / Grafana]
Enter fullscreen mode Exit fullscreen mode

It is boring. It is intentional. It is supposed to be boring.

You do not need all of this on day one. Start with a dedicated host, tailnet, and real restart policies. Then add backups, then observability.

If you want the exact templates I run, with the systemd units, compose files, and hardening checklist I wish I had at the start:

Build it once, properly. Then forget about it. That is the whole point.

Top comments (0)