#!/bin/bash ############################################################################### # OpenClaw System Deployment & Management Script # # Features: # - One-click deployment of OpenClaw with systemd services # - Auto-healing configuration # - Health monitoring # - Rollback support via git # - Telegram notifications # # Usage: # ./deploy.sh install - Install and start all services # ./deploy.sh start - Start all services # ./deploy.sh stop - Stop all services # ./deploy.sh restart - Restart all services # ./deploy.sh status - Show service status # ./deploy.sh logs - Show recent logs # ./deploy.sh health - Run health check # ./deploy.sh rollback - Rollback to previous git commit # ./deploy.sh backup - Create backup of current state # ./deploy.sh debug-stop - Stop ALL services (including monitor) for debugging # ./deploy.sh debug-start - Start ALL services after debugging # ./deploy.sh fix-service - Re-inject EnvironmentFile= after OpenClaw UI upgrade ############################################################################### set -e WORKSPACE="/root/.openclaw/workspace" LOG_DIR="/root/.openclaw/workspace/logs/system" TIMESTAMP=$(date +%Y%m%d-%H%M%S) # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } ensure_log_dir() { mkdir -p "$LOG_DIR" } install_services() { log_info "Installing OpenClaw systemd services..." # Step 1: Enable linger for user-level systemd (CRITICAL for VPS/server deployments) log_info "Enabling user linger for persistent user-level services..." loginctl enable-linger $(whoami) # Step 2: Export required environment variables setup_user_env if [ ! -d "$XDG_RUNTIME_DIR" ]; then log_error "XDG_RUNTIME_DIR not found: $XDG_RUNTIME_DIR" log_warning "Creating runtime directory..." mkdir -p "$XDG_RUNTIME_DIR" chmod 700 "$XDG_RUNTIME_DIR" fi # Step 3: Install user-level gateway services log_info "Installing user-level gateway services..." mkdir -p ~/.config/systemd/user/ cp "$WORKSPACE/systemd/openclaw-gateway-user.service" ~/.config/systemd/user/openclaw-gateway.service cp "$WORKSPACE/systemd/agent-life.service" ~/.config/systemd/user/openclaw-gateway-life.service systemctl --user daemon-reload systemctl --user enable openclaw-gateway systemctl --user enable openclaw-gateway-life # Step 4: Install system-level agent monitor log_info "Installing system-level agent monitor..." cp "$WORKSPACE/systemd/openclaw-agent-monitor.service" /etc/systemd/system/ systemctl daemon-reload systemctl enable openclaw-agent-monitor # Step 5: Inject EnvironmentFile references fix_service_files # Step 6: Start services log_info "Starting services..." systemctl --user start openclaw-gateway systemctl --user start openclaw-gateway-life systemctl start openclaw-agent-monitor sleep 3 log_success "OpenClaw services installed and started!" log_info "Gateway: ws://localhost:18789" log_info "Life Agent: openclaw-gateway-life.service" log_info "User service logs: journalctl --user -u openclaw-gateway -f" log_info "Life agent logs: journalctl --user -u openclaw-gateway-life -f" log_info "Monitor logs: journalctl -u openclaw-agent-monitor -f" } setup_user_env() { export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus" } start_services() { log_info "Starting OpenClaw services..." setup_user_env systemctl --user start openclaw-gateway systemctl --user start openclaw-gateway-life systemctl start openclaw-agent-monitor log_success "All services started (gateway + life + monitor)" } stop_services() { log_info "Stopping OpenClaw services..." setup_user_env systemctl --user stop openclaw-gateway systemctl --user stop openclaw-gateway-life systemctl stop openclaw-agent-monitor log_success "All services stopped" } restart_services() { log_info "Restarting OpenClaw services..." setup_user_env systemctl --user restart openclaw-gateway systemctl --user restart openclaw-gateway-life systemctl restart openclaw-agent-monitor log_success "All services restarted (gateway + life + monitor)" } debug_stop() { log_warning "=== DEBUG MODE: Stopping ALL services ===" log_warning "Monitor will NOT auto-restart gateway while in debug mode." log_warning "Run './deploy.sh debug-start' when done debugging." setup_user_env systemctl stop openclaw-agent-monitor 2>/dev/null || true systemctl --user stop openclaw-gateway 2>/dev/null || true systemctl --user stop openclaw-gateway-life 2>/dev/null || true log_success "All services stopped. Safe to debug." echo "" log_info "Useful debug commands:" log_info " openclaw gateway start # start gateway in foreground" log_info " journalctl --user -u openclaw-gateway -n 100" log_info " journalctl --user -u openclaw-gateway-life -n 100" } debug_start() { log_info "=== Exiting DEBUG MODE: Restarting ALL services ===" setup_user_env systemctl --user start openclaw-gateway systemctl --user start openclaw-gateway-life systemctl start openclaw-agent-monitor sleep 2 log_success "All services restored. Monitor is active again." health_check } fix_service_files() { log_info "Ensuring EnvironmentFile= is present in installed service files..." setup_user_env local gateway_svc="$HOME/.config/systemd/user/openclaw-gateway.service" local life_svc="$HOME/.config/systemd/user/openclaw-gateway-life.service" local gateway_env="$WORKSPACE/systemd/gateway.env" local life_env="$WORKSPACE/systemd/life-gateway.env" local changed=0 if [ -f "$gateway_svc" ]; then if ! grep -q "EnvironmentFile=.*gateway.env" "$gateway_svc" 2>/dev/null; then sed -i "/^\[Service\]/a EnvironmentFile=-${gateway_env}" "$gateway_svc" log_info "Injected EnvironmentFile into openclaw-gateway.service" changed=1 else log_info "openclaw-gateway.service already has EnvironmentFile" fi fi if [ -f "$life_svc" ]; then if ! grep -q "EnvironmentFile=.*life-gateway.env" "$life_svc" 2>/dev/null; then sed -i "/^\[Service\]/a EnvironmentFile=-${life_env}" "$life_svc" log_info "Injected EnvironmentFile into openclaw-gateway-life.service" changed=1 else log_info "openclaw-gateway-life.service already has EnvironmentFile" fi fi if [ $changed -eq 1 ]; then systemctl --user daemon-reload log_success "Service files updated. Run './deploy.sh restart' to apply." else log_success "All service files are up to date." fi } show_status() { setup_user_env echo "" log_info "=== OpenClaw Gateway (User Service) ===" systemctl --user status openclaw-gateway --no-pager -l 2>&1 || true echo "" log_info "=== Life Agent (User Service) ===" systemctl --user status openclaw-gateway-life --no-pager -l 2>&1 || true echo "" log_info "=== Agent Monitor (System Service) ===" systemctl status openclaw-agent-monitor --no-pager -l 2>&1 || true echo "" log_info "=== Recent Gateway Logs ===" journalctl --user -u openclaw-gateway --no-pager -n 10 echo "" log_info "=== Recent Life Agent Logs ===" journalctl --user -u openclaw-gateway-life --no-pager -n 10 echo "" log_info "=== Recent Monitor Logs ===" journalctl -u openclaw-agent-monitor --no-pager -n 10 } show_logs() { setup_user_env log_info "Showing recent gateway logs (last 50 lines)..." journalctl --user -u openclaw-gateway --no-pager -n 50 echo "" log_info "Showing recent life agent logs (last 50 lines)..." journalctl --user -u openclaw-gateway-life --no-pager -n 50 echo "" log_info "Showing recent monitor logs (last 50 lines)..." journalctl -u openclaw-agent-monitor --no-pager -n 50 } rollback() { log_warning "This will rollback the workspace to the previous git commit!" read -p "Are you sure? (y/N): " confirm if [[ $confirm =~ ^[Yy]$ ]]; then cd "$WORKSPACE" # Create backup before rollback backup # Show current commit log_info "Current commit:" git log -1 --oneline # Rollback git reset --hard HEAD~1 log_success "Rolled back to previous commit!" log_info "Restarting services to apply changes..." restart_services else log_info "Rollback cancelled." fi } rollback_to() { if [ -z "$1" ]; then log_error "Please specify a commit hash or tag" exit 1 fi log_warning "This will rollback the workspace to commit: $1" read -p "Are you sure? (y/N): " confirm if [[ $confirm =~ ^[Yy]$ ]]; then cd "$WORKSPACE" backup git reset --hard "$1" log_success "Rolled back to commit: $1" restart_services else log_info "Rollback cancelled." fi } backup() { local backup_dir="/root/.openclaw/backups" mkdir -p "$backup_dir" log_info "Creating backup..." # Backup workspace tar -czf "$backup_dir/workspace-$TIMESTAMP.tar.gz" \ --exclude='.git' \ --exclude='logs' \ -C /root/.openclaw workspace # Backup config cp /root/.openclaw/openclaw.json "$backup_dir/openclaw-config-$TIMESTAMP.json" 2>/dev/null || true log_success "Backup created: $backup_dir/workspace-$TIMESTAMP.tar.gz" } health_check() { log_info "Running health check..." setup_user_env local issues=0 if systemctl --user is-active --quiet openclaw-gateway 2>/dev/null; then log_success "✓ Gateway is running" else log_error "✗ Gateway is not running" ((issues++)) fi if systemctl --user is-active --quiet openclaw-gateway-life 2>/dev/null; then log_success "✓ Life Agent is running" else log_error "✗ Life Agent is not running" ((issues++)) fi if systemctl is-active --quiet openclaw-agent-monitor; then log_success "✓ Agent Monitor is running" else log_error "✗ Agent Monitor is not running" ((issues++)) fi # Check disk space local disk_usage=$(df -h /root | tail -1 | awk '{print $5}' | sed 's/%//') if [ "$disk_usage" -lt 80 ]; then log_success "✓ Disk usage: ${disk_usage}%" else log_warning "⚠ Disk usage: ${disk_usage}%" ((issues++)) fi # Check memory local mem_usage=$(free | grep Mem | awk '{printf("%.0f", $3/$2 * 100.0)}') if [ "$mem_usage" -lt 80 ]; then log_success "✓ Memory usage: ${mem_usage}%" else log_warning "⚠ Memory usage: ${mem_usage}%" ((issues++)) fi # Check XDG_RUNTIME_DIR if [ -d "$XDG_RUNTIME_DIR" ]; then log_success "✓ XDG_RUNTIME_DIR exists: $XDG_RUNTIME_DIR" else log_warning "⚠ XDG_RUNTIME_DIR not found" ((issues++)) fi # Check linger status if loginctl show-user $(whoami) -p Linger | grep -q "yes"; then log_success "✓ User linger is enabled" else log_warning "⚠ User linger is NOT enabled (run: loginctl enable-linger)" ((issues++)) fi echo "" if [ $issues -eq 0 ]; then log_success "All health checks passed!" return 0 else log_error "$issues health check(s) failed!" return 1 fi } show_help() { echo "OpenClaw System Management Script" echo "" echo "Usage: $0 " echo "" echo "Commands:" echo " install - Install and start all systemd services" echo " start - Start all services (gateway + life + monitor)" echo " stop - Stop all services" echo " restart - Restart all services" echo " status - Show service status" echo " logs - Show recent logs" echo " health - Run health check" echo " backup - Create backup of current state" echo " rollback - Rollback to previous git commit" echo " rollback-to - Rollback to specific commit" echo " debug-stop - Stop ALL services including monitor (safe for debugging)" echo " debug-start - Restart all services after debugging" echo " fix-service - Re-inject EnvironmentFile after OpenClaw UI upgrade" echo " help - Show this help message" echo "" } # Main case "${1:-help}" in install) install_services ;; start) start_services ;; stop) stop_services ;; restart) restart_services ;; status) show_status ;; logs) show_logs ;; health) health_check ;; backup) backup ;; rollback) rollback ;; rollback-to) rollback_to "$2" ;; debug-stop) debug_stop ;; debug-start) debug_start ;; fix-service) fix_service_files ;; help|--help|-h) show_help ;; *) log_error "Unknown command: $1" show_help exit 1 ;; esac