mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-22 03:14:57 +00:00
Add OpenClaw and NanoClaw scripts for Hetzner Cloud (#6)
Fills the remaining 2 gaps in the agents x clouds matrix: - hetzner/openclaw.sh: provisions Hetzner server with OpenClaw gateway + TUI - hetzner/nanoclaw.sh: provisions Hetzner server with NanoClaw WhatsApp agent Matrix is now 100% complete (3 agents x 2 clouds = 6/6 implemented). Co-authored-by: Sprite <noreply@sprite.dev> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6002e6c7f7
commit
78e009176b
4 changed files with 202 additions and 2 deletions
12
README.md
12
README.md
|
|
@ -75,6 +75,18 @@ Spawn agents on [Hetzner Cloud](https://www.hetzner.com/cloud/) servers. No `hcl
|
|||
bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/claude.sh)
|
||||
```
|
||||
|
||||
#### OpenClaw
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/openclaw.sh)
|
||||
```
|
||||
|
||||
#### NanoClaw
|
||||
|
||||
```bash
|
||||
bash <(curl -fsSL https://openrouter.ai/lab/spawn/hetzner/nanoclaw.sh)
|
||||
```
|
||||
|
||||
### Non-Interactive Mode
|
||||
|
||||
```bash
|
||||
|
|
|
|||
81
hetzner/nanoclaw.sh
Executable file
81
hetzner/nanoclaw.sh
Executable file
|
|
@ -0,0 +1,81 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Source common functions - try local file first, fall back to remote
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
|
||||
if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then
|
||||
source "$SCRIPT_DIR/lib/common.sh"
|
||||
else
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hetzner/lib/common.sh)
|
||||
fi
|
||||
|
||||
log_info "NanoClaw on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "$SERVER_NAME"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "$HETZNER_SERVER_IP"
|
||||
wait_for_cloud_init "$HETZNER_SERVER_IP"
|
||||
|
||||
# 5. Install Node.js deps and clone nanoclaw
|
||||
log_warn "Installing tsx..."
|
||||
run_server "$HETZNER_SERVER_IP" "source ~/.bashrc && bun install -g tsx"
|
||||
|
||||
log_warn "Cloning and building nanoclaw..."
|
||||
run_server "$HETZNER_SERVER_IP" "git clone https://github.com/gavrielc/nanoclaw.git ~/nanoclaw && cd ~/nanoclaw && npm install && npm run build"
|
||||
log_info "NanoClaw installed"
|
||||
|
||||
# 6. Get OpenRouter API key
|
||||
echo ""
|
||||
if [[ -n "$OPENROUTER_API_KEY" ]]; then
|
||||
log_info "Using OpenRouter API key from environment"
|
||||
else
|
||||
OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180)
|
||||
fi
|
||||
|
||||
# 7. Inject environment variables into ~/.zshrc
|
||||
log_warn "Setting up environment variables..."
|
||||
|
||||
ENV_TEMP=$(mktemp)
|
||||
cat > "$ENV_TEMP" << EOF
|
||||
|
||||
# [spawn:env]
|
||||
export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}"
|
||||
export ANTHROPIC_API_KEY="${OPENROUTER_API_KEY}"
|
||||
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
|
||||
EOF
|
||||
|
||||
upload_file "$HETZNER_SERVER_IP" "$ENV_TEMP" "/tmp/env_config"
|
||||
run_server "$HETZNER_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
rm "$ENV_TEMP"
|
||||
|
||||
# 8. Create nanoclaw .env file
|
||||
log_warn "Configuring nanoclaw..."
|
||||
|
||||
DOTENV_TEMP=$(mktemp)
|
||||
cat > "$DOTENV_TEMP" << EOF
|
||||
ANTHROPIC_API_KEY=${OPENROUTER_API_KEY}
|
||||
EOF
|
||||
|
||||
upload_file "$HETZNER_SERVER_IP" "$DOTENV_TEMP" "/root/nanoclaw/.env"
|
||||
rm "$DOTENV_TEMP"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: $SERVER_NAME (ID: $HETZNER_SERVER_ID, IP: $HETZNER_SERVER_IP)"
|
||||
echo ""
|
||||
|
||||
# 9. Start nanoclaw
|
||||
log_warn "Starting nanoclaw..."
|
||||
log_warn "You will need to scan a WhatsApp QR code to authenticate."
|
||||
echo ""
|
||||
interactive_session "$HETZNER_SERVER_IP" "cd ~/nanoclaw && source ~/.zshrc && npm run dev"
|
||||
107
hetzner/openclaw.sh
Executable file
107
hetzner/openclaw.sh
Executable file
|
|
@ -0,0 +1,107 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Source common functions - try local file first, fall back to remote
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)"
|
||||
if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then
|
||||
source "$SCRIPT_DIR/lib/common.sh"
|
||||
else
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/OpenRouterTeam/spawn/main/hetzner/lib/common.sh)
|
||||
fi
|
||||
|
||||
log_info "OpenClaw on Hetzner Cloud"
|
||||
echo ""
|
||||
|
||||
# 1. Resolve Hetzner API token
|
||||
ensure_hcloud_token
|
||||
|
||||
# 2. Generate + register SSH key
|
||||
ensure_ssh_key
|
||||
|
||||
# 3. Get server name and create server
|
||||
SERVER_NAME=$(get_server_name)
|
||||
create_server "$SERVER_NAME"
|
||||
|
||||
# 4. Wait for SSH and cloud-init
|
||||
verify_server_connectivity "$HETZNER_SERVER_IP"
|
||||
wait_for_cloud_init "$HETZNER_SERVER_IP"
|
||||
|
||||
# 5. Install openclaw via bun
|
||||
log_warn "Installing openclaw..."
|
||||
run_server "$HETZNER_SERVER_IP" "source ~/.bashrc && bun install -g openclaw"
|
||||
log_info "OpenClaw installed"
|
||||
|
||||
# 6. Get OpenRouter API key
|
||||
echo ""
|
||||
if [[ -n "$OPENROUTER_API_KEY" ]]; then
|
||||
log_info "Using OpenRouter API key from environment"
|
||||
else
|
||||
OPENROUTER_API_KEY=$(get_openrouter_api_key_oauth 5180)
|
||||
fi
|
||||
|
||||
# 7. Get model preference
|
||||
echo ""
|
||||
log_warn "Browse models at: https://openrouter.ai/models"
|
||||
log_warn "Which model would you like to use?"
|
||||
MODEL_ID=$(safe_read "Enter model ID [openrouter/auto]: ") || MODEL_ID=""
|
||||
MODEL_ID="${MODEL_ID:-openrouter/auto}"
|
||||
|
||||
# 8. Inject environment variables into ~/.zshrc
|
||||
log_warn "Setting up environment variables..."
|
||||
|
||||
ENV_TEMP=$(mktemp)
|
||||
cat > "$ENV_TEMP" << EOF
|
||||
|
||||
# [spawn:env]
|
||||
export OPENROUTER_API_KEY="${OPENROUTER_API_KEY}"
|
||||
export ANTHROPIC_API_KEY="${OPENROUTER_API_KEY}"
|
||||
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
|
||||
EOF
|
||||
|
||||
upload_file "$HETZNER_SERVER_IP" "$ENV_TEMP" "/tmp/env_config"
|
||||
run_server "$HETZNER_SERVER_IP" "cat /tmp/env_config >> ~/.zshrc && rm /tmp/env_config"
|
||||
rm "$ENV_TEMP"
|
||||
|
||||
# 9. Configure openclaw
|
||||
log_warn "Configuring openclaw..."
|
||||
|
||||
run_server "$HETZNER_SERVER_IP" "rm -rf ~/.openclaw && mkdir -p ~/.openclaw"
|
||||
|
||||
# Generate a random gateway token
|
||||
GATEWAY_TOKEN=$(openssl rand -hex 16)
|
||||
|
||||
OPENCLAW_CONFIG_TEMP=$(mktemp)
|
||||
cat > "$OPENCLAW_CONFIG_TEMP" << EOF
|
||||
{
|
||||
"env": {
|
||||
"OPENROUTER_API_KEY": "${OPENROUTER_API_KEY}"
|
||||
},
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"auth": {
|
||||
"token": "${GATEWAY_TOKEN}"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "openrouter/${MODEL_ID}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
upload_file "$HETZNER_SERVER_IP" "$OPENCLAW_CONFIG_TEMP" "/root/.openclaw/openclaw.json"
|
||||
rm "$OPENCLAW_CONFIG_TEMP"
|
||||
|
||||
echo ""
|
||||
log_info "Hetzner server setup completed successfully!"
|
||||
log_info "Server: $SERVER_NAME (ID: $HETZNER_SERVER_ID, IP: $HETZNER_SERVER_IP)"
|
||||
echo ""
|
||||
|
||||
# 10. Start openclaw gateway in background and launch TUI
|
||||
log_warn "Starting openclaw..."
|
||||
run_server "$HETZNER_SERVER_IP" "source ~/.zshrc && nohup openclaw gateway > /tmp/openclaw-gateway.log 2>&1 &"
|
||||
sleep 2
|
||||
interactive_session "$HETZNER_SERVER_IP" "source ~/.zshrc && openclaw tui"
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
"sprite/openclaw": "implemented",
|
||||
"sprite/nanoclaw": "implemented",
|
||||
"hetzner/claude": "implemented",
|
||||
"hetzner/openclaw": "missing",
|
||||
"hetzner/nanoclaw": "missing"
|
||||
"hetzner/openclaw": "implemented",
|
||||
"hetzner/nanoclaw": "implemented"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue