Self-Host NanoClaw on Hetzner
May 2026 · Tutorial

NanoClaw is the easy part. The interesting part is where you run it.
NanoClaw raised $12 million earlier this week. The persona thesis behind the round is that a recurring agent is a coworker with a name, a schedule, and a memory. This post is the operational follow-up: how to put one on a box you control, with a portable construct as its persona, without quietly handing a stranger production access.
The short version: provision a dedicated Hetzner AX box, harden it the way you would harden any single-tenant production host, install NanoClaw, gate access through Tailscale, keep secrets out of the container, mount source read-only, and drop a construct from the registry into groups/<agent>/CLAUDE.md. The long version is below.
Why Self-Host at All
A recurring agent is a process that wakes up on a schedule, reads its instructions, calls a model, takes actions, writes to memory, and pings a human. Every one of those verbs is a trust surface. The agent has access to the secrets you give it, the network it can reach, the directories you mount, and the channels it can post to. None of that is hypothetical. The agent is the threat model.
That is the case for running it on a host you own. A managed-SaaS agent service has the same trust surface plus a vendor in the middle: their incident, their key custody, their data center, their privacy posture, their next-quarter pricing change. A self-hosted agent on a dedicated box inverts every one of those. You hold the keys. You see the logs. You decide which network the agent can reach. If the vendor goes down or pivots, your agent does not.
There is a second reason that matters more for some readers than others: where the data physically lives. NanoCo is a Tel Aviv company, but the open-source binary they ship has no opinion about your data center. If you need to keep the agent and its memory inside the EU for GDPR, or inside a specific jurisdiction for a customer contract, self-hosting is the only way to be sure.
Why Hetzner Specifically
A recurring agent is a single-tenant workload. It wakes up on a schedule, runs for a few minutes, writes some files, sleeps. It does not need elastic scale, multi-AZ failover, or a serverless billing model. It needs a fast CPU, plenty of RAM, NVMe, and a host that does not throttle when a neighbor gets noisy. Dedicated bare-metal at the low end of the price curve fits this shape almost perfectly.
Hetzner's AX line is the obvious starting point. The AX42-U ships an 8-core AMD Ryzen 7 PRO 8700GE, 64 GB DDR5, two NVMe Gen 4 drives, and unlimited traffic; pricing on the matrix page is materially below comparable hyperscaler instances for the same RAM. That is enough headroom for several recurring agents, their memory volumes, a Postgres for shared state, a log collector, and reverse proxies, with room left for the surprise. If you only plan to run one agent, the AX41-NVMe (Ryzen 5 3600, 64 GB) is a cheaper baseline.
On data center location: the German sites (Falkenstein, Nuremberg) and the Finnish site (Helsinki) are all EU, which closes the GDPR question by default. Hetzner's privacy policy is unambiguous about who the controller and processor are.
Alternatives worth a glance. Fly.io and Railway are convenient but reintroduce the shared-tenancy problem and a vendor in the middle, which is exactly what self-hosting was supposed to solve. A Mac mini at home is plausible if you already run a homelab, but the agent will outlive your internet provider and ISP-grade NAT will frustrate at least one of the channels. The dedicated box is the boring, correct answer.
Provisioning and Initial Hardening
Order the box through the Hetzner robot UI and pick an EU site. While it provisions, decide on a hostname; the agent is going to live on this name for years, so something decent is worth a minute (agents-01.example.com beats srv-1234).
First SSH after provisioning is the only one that matters. Do not type the rescue-image root password into anything persistent. Install your SSH key, disable password auth, move SSH to a non-standard port, and stand up a firewall before you do anything else.
# Create the human operator user first so AllowUsers does not lock you out
useradd -m -s /bin/bash agentops
usermod -aG sudo agentops
mkdir -p /home/agentops/.ssh
# Paste your public key into /home/agentops/.ssh/authorized_keys, then:
chown -R agentops:agentops /home/agentops/.ssh
chmod 700 /home/agentops/.ssh
chmod 600 /home/agentops/.ssh/authorized_keys
# Edit /etc/ssh/sshd_config with these directives, then reload sshd.
# (The new port does NOT take effect until sshd reloads.)
# Port 2222
# PermitRootLogin prohibit-password
# PasswordAuthentication no
# PubkeyAuthentication yes
# AllowUsers agentops
sshd -t && systemctl reload ssh
# nftables baseline (Debian / Ubuntu)
apt update && apt install -y nftables fail2ban unattended-upgrades
systemctl enable --now nftables fail2ban unattended-upgrades
# Write the ruleset to /etc/nftables.conf so it survives reboot.
# Without this, the next reboot drops your firewall AND locks you out.
cat > /etc/nftables.conf <<'EOF'
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0 ; policy drop ;
ct state established,related accept
iifname "lo" accept
ip protocol icmp accept
ip6 nexthdr icmpv6 accept
tcp dport 2222 accept
}
}
EOF
chmod 600 /etc/nftables.conf
nft -c -f /etc/nftables.conf && systemctl reload nftablesOpen a second SSH session with the new user and the new port BEFORE you log out of the rescue system. The number of operators who have locked themselves out of a fresh Hetzner box at this exact step is non-trivial.
That is the smallest firewall that lets you in and keeps everything else out. Exactly one more inbound opens in the next section (Tailscale's UDP), and never a public web port. NanoClaw's UI lives on the private network, full stop.
Unattended upgrades is worth the two lines. The most common way a single-tenant box gets compromised is a kernel CVE that the operator meant to patch six months ago.
Tailscale for Access
Public-port management is a chore that only gets harder. Tailscale collapses the chore into one daemon and one ACL file. The agent host joins your tailnet; you reach NanoClaw's UI and the agent's logs from your laptop only when the laptop is also on the tailnet. Public exposure is zero.
curl -fsSL https://tailscale.com/install.sh | sh tailscale up --ssh --hostname agents-01 # In Tailscale admin: tag the host 'tag:agents', allow tag:dev to reach # tag:agents on port 22 and the NanoClaw UI port. Nothing else.
Two cheap wins: --sshreplaces the public SSH listener with Tailscale-authenticated SSH, and ACL tags keep your laptop's access scoped to what it actually needs. Keep the port 2222 rule as a failsafe; if Tailscale ever fails (key rotation, control-plane outage, daemon crash), the alternate-port SSH is your way back in.
Install Docker and NanoClaw
Use the official Docker Engine install rather than the distro package; the distro version lags and the agent needs current container features. Resist the urge to add agentops to the docker group: membership is root-equivalent because a container can mount the host file system. Invoke the daemon with sudo from a tightly scoped sudoers rule instead, or run rootless Docker for the agent's containers specifically.
Then NanoClaw itself, per its README:
# As the agentops user, in a directory under /opt git clone https://github.com/nanocoai/nanoclaw.git nanoclaw cd nanoclaw bash nanoclaw.sh # walks you to a first named agent
The install script bootstraps Node, pnpm, and Docker if they are missing, scaffolds the directory layout, and takes you through naming the first agent. Per the official docs, every agent group lives under groups/<name>/ with its own CLAUDE.md, its own memory, its own container, and only the mounts you allow. That last clause is doing real work; the next sections exercise it.
Secrets Stay Outside the Container
The default move is to drop API keys into .env. Do not. The reasons stack quickly: the file lands on disk in cleartext, a future container layer bakes it into an image, a misconfigured volume mount exposes it to a different group, and rotating it means visiting the box. Pick a real secrets store and inject at runtime.
Three working choices, in roughly increasing operational cost:
Doppler. Hosted, friendly CLI, fine for solo operators. Pull secrets at container start with doppler run -- docker compose up.
Infisical. Open source, self-hostable if you want zero vendors. The agent host pulls with infisical export > /run/secrets/agent.env into a tmpfs mount.
HashiCorp Vault. Heavier, but the right answer if you already operate Vault for something else.
Whichever store you pick, the file the container sees should be in tmpfs (so it dies with the container) and the host file system should not retain a persistent copy. Rotate quarterly; the agent will not notice if you do it during its sleep window.
Mount Strategy
The mounts are the agent's actual blast radius. Two rules that have aged well:
Source is read-only. If the agent reads code from a repo, mount the repo at :ro. The agent should propose a patch as a string the host then commits, not commit directly. This survives the agent going off the rails for any reason, including a model behaving badly after a silent update.
No docker.sock. Mounting /var/run/docker.sock into a container is a privilege escalation in a single line. If the agent legitimately needs to start sibling containers, run a privileged sidecar with an HTTP API the agent container calls. Almost no agent actually needs this.
Memory and scratch are different. Each group gets a persistent named volume for groups/<name>/memory/, and a tmpfs-backed /scratch inside the container that gets blown away on restart. The persona stays on the host. The ephemeral state lives in RAM.
Drop in a Construct
The persona is the part of the agent that does not change when the harness does. Constructs are written as Markdown and read by any harness that respects an instruction file. For NanoClaw, the file is groups/<name>/CLAUDE.md. To start with a real persona instead of an empty one:
mkdir -p groups/margot curl -fsSL https://constructs.sh/curator/senior-code-reviewer/raw \ > groups/margot/CLAUDE.md # Edit groups/margot/CLAUDE.md if you want to add company-specific # context (which services exist, which review standards are local). # The base persona is the construct; the additions are the trim.
That is the full integration story. The Senior Code Reviewer construct is now the agent named Margot, and Margot will wake up on whatever schedule you tell NanoClaw about (e.g. @Andy schedule margot daily 23:00 to review yesterday's merged PRs). When a new construct ships and you want to try it, replace the file. When the harness updates and CLAUDE.md conventions drift, the construct still reads.
Two more patterns from the registry that pair well with a recurring schedule: Brand Strategist for a Sunday landing-page audit, and Design Compliance for a weekly accessibility sweep. Same shape: download the raw, drop into a group, schedule.
Monitoring and Backup
A recurring agent that fails silently is worse than no agent at all. The minimum bar is: every run emits a structured log line, every failure pages a human, and the memory volume gets backed up to off-host storage on a schedule.
For logs, ship to a centralized place rather than letting them rot in /var/log. Better Stack and Axiom both have free tiers that fit a small fleet; both ingest via OTLP or a Vector sidecar. Grafana Cloud is the option if you already think in Loki / Prometheus.
For backup, the memory volume is the only thing that matters; the agent and its persona are reproducible from source. restic to Hetzner Storage Box once a day, with one-week retention, is enough for an individual operator. For team use, point restic at an offsite bucket in a different provider so a Hetzner-wide incident does not eat your history.
What You Do Not Do
The honest-disclosure section. Self-hosting solves a real class of problems and creates a new one: you are the operator. The agent has the access you give it; the host has the patches you apply; the memory has the entries you let in. A short list of mistakes that have hurt other operators worth not making again:
Do not expose NanoClaw's UI publicly. Tailscale or nothing. A public NanoClaw login page is a phishing target with a memory of your repos.
Do not give the agent docker.sock. One mount, full host. There is no convenience that justifies it; almost everything you would use it for has a safer shape.
Do not share a memory volume between agents. Two agents writing to the same memory race each other and corrupt each other's state. One agent, one volume, one set of mounts.
Do not skip the dry-run. Before scheduling a destructive action, let the agent run in propose-only mode for a week. Read what it would have done. Adjust the construct. Then enable.
Do not commit your groups/<name>/memory/ directory to git. It will contain transient quotes from private channels. Backup yes, source-control no. The one-liner: echo 'groups/*/memory/' >> .gitignore before the first commit.
Closer
The agent's code is portable. The agent's secrets are not. Hetzner lets you keep the second one without giving up the first. The registry is where the personas accumulate. The box is where they wake up.
Related: NanoClaw and the Recurring Agent, Teaching Machines to Have Opinions, Constructs Are the New Resume.