Deploy an always-on AI development agent on a $6/mo DigitalOcean droplet. Hardened, Tailscale-secured, and ready to ship code while you sleep.
Gather these accounts and credentials first so you don't get blocked midway through setup.
1. A fresh Ubuntu 24.04 DigitalOcean droplet and root SSH access.
2. A local machine with an SSH key pair (for example ~/.ssh/id_ed25519.pub).
3. Accounts for Tailscale, GitHub, and your messaging channel (Telegram/Discord/WhatsApp).
4. AI provider credentials (Anthropic and/or OpenAI) ready for TinyClaw setup.
5. 45 to 60 uninterrupted minutes for first-time configuration and verification.
Provision a fresh droplet, create a locked-down user, and eliminate password-based access. Everything runs as a non-root user from here on.
SSH into your fresh droplet as root. Update everything and install essentials.
apt update && apt upgrade -y
apt autoremove -y
apt install -y curl git tmux bash ufw fail2ban jqNever run your agent as root. Create a dedicated user with sudo access.
adduser youruser
usermod -aG sudo youruserCopy your public key from your local machine (e.g., ~/.ssh/id_ed25519.pub), then set it up on the server.
mkdir -p /home/youruser/.ssh
chmod 700 /home/youruser/.ssh
# Paste your full public key into this file
nano /home/youruser/.ssh/authorized_keys
chown -R youruser:youruser /home/youruser/.ssh
chmod 600 /home/youruser/.ssh/authorized_keysDisable root login and password authentication. Only key-based access is allowed from this point forward.
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 4
LoginGraceTime 30systemctl restart sshyouruser. If key authentication fails, you still have your root session open to fix it.Switch to the youruser user. Set up UFW with deny-all defaults and enable Fail2Ban for brute-force protection.
su - youruser
# Firewall โ temporarily allow SSH until Tailscale is ready
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw --force enable
# Fail2Ban โ auto-ban repeat offenders
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# Automatic security updates
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgrades
# Answer: YesReplace public SSH with Tailscale's encrypted mesh network. After this phase, SSH is accessible only through your Tailscale network โ no public exposure.
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
# Follow the URL in your browser โ approve at login.tailscale.com/admin/machinesssh youruser@your-droplet) instead of IP address.Remove the public SSH rule and restrict all inbound traffic to the Tailscale interface. After this step, your server stops accepting connections from the public internet.
# Remove public SSH โ Tailscale only after this
sudo ufw delete allow OpenSSH
# Allow traffic only on Tailscale interface
sudo ufw allow in on tailscale0
# Optional: allow Tailscale UDP for direct peer connections
sudo ufw allow 41641/udp
sudo ufw reload
# Enable Tailscale SSH (identity-based, no keys needed)
sudo tailscale set --ssh41641/udp if you want a stricter lockdown. Tailscale will still work via relay nodes, with potentially lower direct-connection performance.Install the toolchain your agent needs to build and ship: Node.js via NVM (Node Version Manager), Yarn, Expo/EAS, and the GitHub CLI.
Minimal setup is preselected. Enable advanced tools only if your project needs them.
# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash
source ~/.bashrc
# Install & activate Node LTS
nvm install --lts
nvm use --lts
nvm alias default lts/*
# Verify
node -v # ~v24.x
npm -v
# Add GitHub CLI apt repository
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
# Install & authenticate
sudo apt update
sudo apt install gh -y
gh auth loginInstall the AI engine and the orchestration layer that turns it into an always-on agent you can message from anywhere.
curl -fsSL https://claude.ai/install.sh | bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
# Verify & authenticate
claude --version
claudeTinyClaw is the orchestration layer. It connects Claude Code to messaging channels (such as Telegram) and manages multi-agent teams.
curl -fsSL https://raw.githubusercontent.com/jlia0/tinyclaw/main/scripts/remote-install.sh | bashVerify the install. If the command isn't found, open a new shell or run source ~/.bashrc.
tinyclaw --versionRun the setup wizard, configure heartbeats, and define specialized agents that can work together as a team.
The interactive wizard walks you through channels, API tokens, workspace path, and heartbeat interval.
tinyclaw start
# Interactive prompts:
# Channel โ Telegram (recommended)
# Workspace โ ~/.tinyclaw-workspace
# Provider โ Anthropic
# Heartbeat โ 1800 (30 min)
# Default agent โ coderChannel โ How you message your agent. Telegram is recommended (simple bot setup, works on mobile).
Workspace โ Where the agent stores files, task lists, and logs.
Provider โ Your AI backend. Needs an Anthropic API key (ANTHROPIC_API_KEY env var).
Heartbeat โ How often the agent pings to confirm it's alive. 1800 = every 30 min.
Default agent โ Receives messages when you don't use an @ prefix.
Create specialized agents with distinct roles, then group them into a coordinated team.
# Create primary coder (skip if wizard already created it)
tinyclaw agent add \
--name coder \
--provider anthropic \
--model opus \
--role "Primary development agent"
# Add a code reviewer
tinyclaw agent add \
--name reviewer \
--provider anthropic \
--model sonnet \
--role "Review code for bugs, optimize for mobile perf"
# Add a build agent
tinyclaw agent add \
--name builder \
--provider anthropic \
--model opus \
--role "Handle EAS builds and deployments"
# Form a team with a leader
tinyclaw team add \
--name mobiledev \
--agents coder,reviewer,builder \
--leader coderYour agent should survive crashes, reboots, and its own self-improvement attempts. This phase ensures it recovers automatically.
A wrapper that ensures TinyClaw is always running inside a tmux session.
#!/bin/bash
SESSION="tinyclaw"
COMMAND="tinyclaw start"
if ! tmux has-session -t "$SESSION" 2>/dev/null; then
tmux new-session -d -s "$SESSION" "$COMMAND"
else
if ! tmux list-panes -t "$SESSION" | grep -q "tinyclaw"; then
tmux send-keys -t "$SESSION" C-c
sleep 3
tmux send-keys -t "$SESSION" "$COMMAND" C-m
fi
fi
tinyclaw statuschmod +x ~/tinyclaw-restart.sh
~/tinyclaw-restart.shRegister TinyClaw as a systemd user service so it starts on boot and auto-restarts on failure.
[Unit]
Description=TinyClaw Always-On Agent
After=network-online.target
[Service]
Type=simple
ExecStart=/home/youruser/tinyclaw-restart.sh
Restart=always
RestartSec=10
Environment="NVM_DIR=/home/youruser/.nvm"
Environment="PATH=/home/youruser/.nvm/versions/node/v24*/bin:/usr/local/bin:/usr/bin:/bin"
WorkingDirectory=/home/youruser
TimeoutStartSec=120
[Install]
WantedBy=default.targetmkdir -p ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable tinyclaw.service
systemctl --user start tinyclaw.service
systemctl --user status tinyclaw.service
# Survive reboots even when not logged in
sudo loginctl enable-linger youruserIf your agent self-updates and breaks itself, the following script restores it from the latest git backup. Pair this with periodic git push backups of the workspace.
#!/usr/bin/env bash
set -euo pipefail
WORKSPACE="$HOME/.tinyclaw-workspace"
SERVICE="tinyclaw.service"
BACKUP_BRANCH="main"
if [ ! -d "$WORKSPACE/.git" ]; then
echo "Workspace is not a git repo: $WORKSPACE"
exit 1
fi
cd "$WORKSPACE"
systemctl --user stop "$SERVICE" || true
tmux kill-session -t tinyclaw 2>/dev/null || true
git fetch origin
git reset --hard "origin/$BACKUP_BRANCH"
git clean -fd
if [ -f package.json ]; then
npm install --silent
fi
systemctl --user start "$SERVICE"
systemctl --user status "$SERVICE" --no-pager -n 20chmod +x ~/.tinyclaw-workspace/resurrect-tinyclaw.sh
# Run once while healthy so you know it works before an outage
~/.tinyclaw-workspace/resurrect-tinyclaw.shtinyclaw logs all. The resurrection script and git history ensure you can always roll back to a known-good state.Your agent is not a chatbot โ it is a system. The rules in this phase define how it thinks, works, and recovers from failure. They go into your AGENTS.md file โ see the Prompt Templates page for ready-to-use versions.
Every meaningful task follows a disciplined cycle. The agent does not make one-shot guesses โ every change requires a verified outcome.
Build the smallest meaningful change โ Test immediately against expected behavior โ Log what changed, what passed/failed, and what to do next โ Decide to iterate, escalate, or close based on evidence.
Start in plan mode for any non-trivial request. Define scope, constraints, and a clear "done" condition before implementation. If facts change or a step fails, pause execution and re-plan.
The agent maintains its own workspace files as the source of truth.
Every completed task requires passing tests, clean and well-understood logs, and observable correctness. Final check: "Would a staff engineer approve this as production-ready?"
Escalate immediately for missing credentials, external outages, or ambiguous requirements. After three failed attempts on the same issue, stop and re-plan before continuing.
Your agent is live. Here's how to interact with it, monitor it, and keep it healthy.
# Attach to the live agent session
tmux attach -t tinyclaw
# ...or
tinyclaw attach
# Check agent status
tinyclaw status
# View all logs
tinyclaw logs all
# Visualize team activity
tinyclaw team visualize mobiledev
# Update TinyClaw
tinyclaw update
# Check systemd service health
systemctl --user status tinyclaw.serviceMessage your agent through the configured channel (e.g., Telegram). TinyClaw routes messages by agent name. Prefix with @agentname to target a specific agent. Messages without a prefix go to the team leader.
@coder Write an Expo component for a settings screen with Swift interop.@reviewer Review the latest PR for performance issues.@builder Trigger an EAS build for iOS production.
Configure the agent for continuous autonomous improvement. Add this to your daily standing instructions:
"Every day, iterate on and improve the codebase. Ship one completed improvement daily that enhances existing workflows."
See the Standing Orders templates for copy-paste versions covering code quality, test coverage, dependency health, and more.
Setup is complete only when every check in the following list passes.
# 1) Service is active
systemctl --user status tinyclaw.service --no-pager
# 2) tmux session exists
tmux ls | grep tinyclaw
# 3) TinyClaw is responsive
tinyclaw status
# 4) Channel roundtrip test
# Send "ping" to your bot and confirm a reply
# 5) Reboot survival
sudo reboot
# Reconnect and repeat checks 1-3โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ You (phone / laptop) โ
โ โโโ Telegram / Discord / WhatsApp โ
โโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
encrypted mesh (Tailscale)
โ
โโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ $6/mo DigitalOcean Droplet โ
โ Ubuntu 24.04 ยท no public SSH ยท fail2ban โ
โ โ
โ โโ TinyClaw โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ systemd ยท tmux ยท auto-restart โ โ
โ โ โ โ
โ โ @coder โ Claude Opus (development) โ โ
โ โ @reviewer โ Claude Sonnet (review) โ โ
โ โ @builder โ Claude Opus (deployment) โ โ
โ โ โ โ
โ โ heartbeat โ lightweight model (pings) โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ
โ Node v24 ยท gh ยท eas-cli ยท git backups โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ