From zero to a personalised AI agent.
This is the lived-experience version of the build. Every phase is a single prompt you send to Claude Code, and Claude Code does the work while you approve each step. You don't need to know Linux commands β you need to be able to read what Claude Code proposes and approve or push back.
This tab is written for the single-agent build (one OpenClaw instance). If you want the dual-agent version, toggle the βMulti-agentβ switch at the top of the guide. Most readers should start with single-agent.
All prices shown in AUD. Use the currency selector at the top to change.
Before you start
Overview
What you're building: A single OpenClaw AI agent running on a hardened cloud server, accessible via Telegram (and optionally Discord), with personalised identity files that teach it who you are and how you work, backed up to a private GitHub repo.
ββββββββββββββββββββββββββββββββββββββββ
β You β
β Telegram DMs Β· Optional Discord β
ββββββββββββββ¬ββββββββββββββββββββββββββ
β
ββββββββΌβββββββ
β Agent β
β (OpenClaw) β
β Port 8080 β
ββββββββ¬βββββββ
β
ββββββββΌβββββββββββββββββββββββ
β Hetzner VPS (agent-01) β
β CAX21 Β· ARM64 Β· Ubuntu 24 β
β Helsinki Β· ~$18 AUD/mo β
β Cloudflare Tunnel (opt.) β
ββββββββββββββββββββββββββββββββTotal time: ~3β4 hours of focused work
Total cost: ~$18 AUD/month server + ~$8β40 AUD/month Claude API (single agent)
The build in 7 phases
Each phase is a single Claude Code prompt. Copy-paste, approve each step as Claude Code proposes it, verify the checkpoint, move to the next phase.
| Phase | What | Time |
|---|---|---|
| 1 | Server foundation + SSH lockdown | 15β30 min |
| 2 | System hardening + runtime dependencies | 30β45 min |
| 3 | Cloudflare Tunnel (secure remote access) | 20β30 min |
| 4 | Agent install + first test | 30β45 min |
| 5 | Identity (SOUL.md) + personalisation | ~1 hour |
| 6 | Channels (Telegram primary, Discord optional) | 15β30 min |
| 7 | Backup to GitHub + cleanup | 5β10 min |
Phase 5 is the longest because the creative work β writing who you are and how your agent should behave β takes real thinking time. Everything else is execution.
Pre-build: Accounts and credentials (30 minutes of admin)
Before Phase 1, create these accounts and save all credentials in a password manager (or notes app) with a tag/folder like agent-board:
| Account | Where | What you'll get |
|---|---|---|
| Hetzner Cloud | console.hetzner.cloud | Server hosting (payment method required) |
| Anthropic | console.anthropic.com | API key for the agent |
| Telegram | BotFather on Telegram | Bot token + your numeric user ID |
| Cloudflare | dash.cloudflare.com | Domain for tunnel (free tier is fine) |
| GitHub | github.com | Private repo for backup |
| (Optional) Discord | discord.com/developers | Bot token for a second communication channel |
SSH key: Check if you already have one:
ls -la ~/.ssh/id_ed25519.pubIf not, generate one:
ssh-keygen -t ed25519 -C "your-email@example.com"Accept all the defaults. You'll paste the public key (~/.ssh/id_ed25519.pub) into Hetzner during server creation.
Phase 1: Server Foundation + SSH Lockdown (15β30 min)
Step 1a: Provision the server (manual, Hetzner web console)
Do this manually in the Hetzner web console:
| Setting | Value |
|---|---|
| Location | Helsinki (or nearest available in Europe) |
| Image | Ubuntu 24.04 |
| Type | CAX21 (ARM64, 4 vCPU, 8GB RAM) |
| SSH Key | Add your public key (~/.ssh/id_ed25519.pub) |
| Backups | Enable (+20%, worth it) |
| Name | agent-01 (or whatever you prefer) |
Total cost: ~$18 AUD/month
Firewall setup (Hetzner Cloud Firewall):
- SSH (TCP 22) from your home IP only β run
curl -4 ifconfig.meon your Mac to find it, append/32 - ICMP from anywhere (for ping debugging)
- Apply to your server
The Source IPs field shows as βAny IPv4β / βAny IPv6β chips. Click them to delete the defaults, then type your IP with /32 and press Enter to add it as a new chip.
After creation, save the IP address in your password manager.
Step 1b: First SSH + create a non-root user (safety-net pattern)
This is the one step to do manually, not via Claude Code. The cost of getting locked out is too high.
Open Terminal Window 1 and connect:
ssh root@YOUR_IP_ADDRESSType yes to accept the host key.
Create a non-root user with sudo access. Replace <your-user> with whatever username you want (e.g. agent, admin, your first name):
adduser --gecos "" <your-user>
# Set a password when prompted β save it in your password manager
usermod -aG sudo <your-user>
mkdir -p /home/<your-user>/.ssh
cp /root/.ssh/authorized_keys /home/<your-user>/.ssh/authorized_keys
chown -R <your-user>:<your-user> /home/<your-user>/.ssh
chmod 700 /home/<your-user>/.ssh
chmod 600 /home/<your-user>/.ssh/authorized_keysOpen Terminal Window 2 (this is the safety-net pattern). Test that you can SSH in as the new user:
ssh <your-user>@YOUR_IP_ADDRESS
sudo whoami # should print "root" after entering your passwordIf Window 2 works, keep Window 1 open as your safety net and proceed with the SSH lockdown in Window 1.
In Window 1 (still as root), edit the SSH config:
nano /etc/ssh/sshd_configChange these settings (use Ctrl+W to search for each one):
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
KbdInteractiveAuthentication no
X11Forwarding no
MaxAuthTries 3
AllowUsers <your-user>Save with Ctrl+O, Enter, Ctrl+X.
Restart SSH:
systemctl restart sshOpen a third terminal window and verify the lockdown worked:
ssh root@YOUR_IP_ADDRESS # should FAIL with "Permission denied" β this is what you want
ssh <your-user>@YOUR_IP_ADDRESS # should succeedIf both tests pass, close Window 1 (root) and Window 3. Window 2 (<your-user>) is now your working session.
Step 1c: Set up SSH config shortcut on your Mac (optional but useful)
On your Mac (not the server), edit ~/.ssh/config:
nano ~/.ssh/configAdd:
Host agent-01
HostName YOUR_IP_ADDRESS
User <your-user>Now ssh agent-01 is shorthand for the full command.
You have a hardened server that only your non-root user can SSH into, only from your home IP, using only your SSH key.
Phase 2: System Hardening + Runtime Dependencies (30β45 min)
This is where Claude Code takes over. From here, you're driving with prompts, not commands.
Install Claude Code on the server
SSH in as your user and install Claude Code:
ssh agent-01
curl -fsSL https://claude.ai/install.sh | bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
claude --version # verifyAdd temporary passwordless sudo so Claude Code can run commands without getting stuck on password prompts:
echo "<your-user> ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/<your-user>-nopasswd
sudo chmod 440 /etc/sudoers.d/<your-user>-nopasswdWe'll remove this in Phase 7.
Create a working directory and start Claude Code:
sudo mkdir -p /opt/agent-board
sudo chown <your-user>:<your-user> /opt/agent-board
cd /opt/agent-board
claudeAuthenticate via the browser OAuth flow when prompted.
Phase 2 prompt (send this to Claude Code)
Copy-paste this entire prompt as your first message to Claude Code:
The UFW step β make sure Claude Code runs sudo ufw allow 22/tcp before sudo ufw enable. If it's in the wrong order, say βstop, that's the wrong orderβ before approving.
Any apt command that doesn't have DEBIAN_FRONTEND=noninteractive β push back and ask Claude Code to include it.
Phase 2 complete when Claude Code confirms all verification commands pass.
Phase 3: Cloudflare Tunnel (20β30 min)
Cloudflare Tunnel gives you secure remote access to your server without opening ports. You'll access your agent via subdomains like agent.yourdomain.com without exposing anything to the public internet.
Prerequisite: A domain managed by Cloudflare (free tier is fine). If you don't have one, you can skip this phase entirely β the agent will still work via Telegram, you just won't have a web interface for direct API access.
Phase 3 prompt
The cloudflared tunnel login step requires you to click a URL in your browser and authorise the domain. Claude Code will pause and tell you what to do.
DNS propagation takes 1β2 minutes after routing is set up. Test with curl https://agent.YOUR_DOMAIN_HERE and expect a 404 (because the agent isn't running yet β that's correct).
Skip this phase if you don't have a Cloudflare-managed domain. The agent will work fine via Telegram alone.
Phase 4: Agent Install + First Test (30β45 min)
This is where the agent actually comes to life. You'll install OpenClaw, configure it, and test that it can respond via Telegram.
Phase 4 prompt
Testing the agent
Once Claude Code confirms the service is running, open Telegram on your phone, find your bot (search for the username you created), and send:
Hey, what can you do?
You should get a response within 3β5 seconds. If you do: Phase 4 complete. The agent is alive.
If it doesn't respond
Tell Claude Code:
Common issues Claude Code will catch:
- Wrong API key (no credits loaded, or typo)
- Wrong Telegram user ID in the allowlist
- Service can't read the shared.env (permissions issue)
- OpenClaw defaulting to a wrong base_url
Each of these has a quick fix that Claude Code can apply with your approval.
Phase 5: Identity (SOUL.md) β The Most Important Phase (~1 hour)
This is where the agent stops being a generic chatbot and becomes yours. The identity files teach it who you are, how you work, what rules to follow, and what voice to use.
This phase is mostly creative work, not execution. You're writing content, not running commands. Claude Code's job in this phase is to help you write the files, review them, and deploy them.
What SOUL.md contains
A complete SOUL.md typically has these sections:
- Mission β what this agent exists to do for you
- Who you are β your name, role, context, life situation
- Active priorities β what you're working on right now
- How you work β communication style, pacing, preferences
- Hard rules β things the agent must never do (spending money, posting publicly without approval, sending emails without review)
- Voice & attitude β how the agent should speak (direct, no corporate filler, opinionated when asked)
- Domain knowledge references β pointers to context files for specific projects
The important thing is that SOUL.md is written in your voice, for your life, not a generic template.
Phase 5 prompt (content writing)
Work through this conversationally with Claude Code. It takes about 45β60 minutes of real thinking, but the output is the most valuable thing in the entire build.
Phase 5 deployment prompt (after content is written)
Testing identity loaded correctly
After deployment and service restart, send your bot a knowledge-question test on Telegram:
What do you know about me and what are you here to do?
If you get a specific, personalised response β identity loaded correctly. Phase 5 complete.
If you get a generic βI'm your AI assistantβ response β identity didn't load. Tell Claude Code:
Phase 6: Channels β Telegram Primary, Discord Optional (15β30 min)
Telegram (required β already set up in Phase 4)
Your agent is already responding on Telegram from Phase 4. A few polish items via BotFather:
- Open Telegram, message
@BotFather /setnameβ set a friendly display name for your bot/setuserpicβ upload an avatar/setdescriptionβ one-sentence description/setprivacyβ Disable β required if you ever want the bot to see messages in group chats
That's it for Telegram.
Phase 7: Backup + Cleanup (5β10 min)
Phase 7 prompt
Create the GitHub repo manually
- Go to github.com β New repository
- Name it
agent-board(or whatever you prefer) - Set it to Private
- Don't initialise with a README (we already have one)
- Follow GitHub's βpush an existing repositoryβ instructions
Your build is backed up and the build-session passwordless sudo is removed.
You're done
You now have:
- A hardened cloud server in Europe, invisible to the public internet
- A personalised AI agent with your identity, your rules, your voice
- Accessible via Telegram from anywhere
- (Optional) Cloudflare Tunnel for secure web access
- (Optional) Discord as a second channel
- Backed up to a private GitHub repo
Total time: 3β4 focused hours (vs the two full days our original build took β because you benefited from the lessons we learned the hard way).
What ate the time in our original build (so it won't eat yours)
Our first build took ~10 hours across two days because we were discovering problems as we went. These are the specific things that cost us time, all of which this guide prevents:
| Problem | Time cost | How this guide prevents it |
|---|---|---|
| openssh-server debconf stall on apt upgrade | 30 min | Phase 2 prompt includes DEBIAN_FRONTEND=noninteractive from the start |
| Node 20 β 24 upgrade after install failure | 20 min | Phase 2 prompt specifies Node 24 directly |
| SOUL.md file structure confusion (single vs workspace/) | 60 min | Phase 5 prompt explains the multi-file template system upfront |
| Discovering OGP federation doesn't exist | 30 min | Not mentioned anywhere in this guide |
| Telegram bot-to-bot limitation | 45 min | Not a concern for single-agent builds |
| Hermes defaulting to OpenRouter base_url | 20 min | Not applicable for OpenClaw-only build |
| Device pairing loop after rapid restarts | 30 min | Guide recommends one clean restart after all config changes |
| Sudo password prompts stalling Claude Code | 15 min | Guide sets up temporary passwordless sudo from the start |
That's ~4 hours of troubleshooting we did so you don't have to.
Next steps
Now that you have a working personalised agent:
- Use it for a week. See what you actually reach for it to do. Let the real use cases emerge before adding capabilities.
- Tab 5 (Troubleshooting) β bookmark this tab for when things break
- Tab 4 (Using Claude as Copilot) β read this to understand why the copilot pattern worked and how to use it for future projects
- Consider dual-agent β if you find yourself wishing for a second, more specialised agent, toggle the multi-agent switch at the top of the guide and revisit Phase 4
The agent board only becomes valuable when you treat it like one. Daily use, weekly review, honest feedback to the agent when it gets something wrong. Three months of that and you'll have an agent that genuinely knows you better than most colleagues.