729 lines
21 KiB
Bash
729 lines
21 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
#############################################################################
|
|
# Clawdbot Installation & Ubuntu Hardening Script
|
|
#
|
|
# This script is idempotent and can be run multiple times safely.
|
|
# It installs Clawdbot with Docker, hardens Ubuntu 22.04, and configures
|
|
# secure access via Tailscale or SSH tunnel only (no public gateway).
|
|
#
|
|
# Required environment variables:
|
|
# CLAWDBOT_PASSWORD - Strong password for Clawdbot auth (min 16 chars)
|
|
# TAILSCALE_AUTH_KEY - (Optional) Tailscale auth key for auto-join
|
|
#
|
|
# Usage:
|
|
# export CLAWDBOT_PASSWORD="your-strong-password-here"
|
|
# export TAILSCALE_AUTH_KEY="tskey-auth-xxxxx" # optional
|
|
# sudo -E bash install_and_harden.sh
|
|
#############################################################################
|
|
|
|
# Color output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Check if running as root
|
|
if [[ $EUID -ne 0 ]]; then
|
|
log_error "This script must be run as root (use sudo -E)"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate required environment variables
|
|
if [[ -z "${CLAWDBOT_PASSWORD:-}" ]]; then
|
|
log_error "CLAWDBOT_PASSWORD environment variable is required"
|
|
log_error "Example: export CLAWDBOT_PASSWORD='your-strong-password-here'"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate password strength (min 16 characters)
|
|
if [[ ${#CLAWDBOT_PASSWORD} -lt 16 ]]; then
|
|
log_error "CLAWDBOT_PASSWORD must be at least 16 characters long"
|
|
exit 1
|
|
fi
|
|
|
|
# Configuration
|
|
CLAWDBOT_USER="clawdbot"
|
|
CLAWDBOT_HOME="/home/${CLAWDBOT_USER}"
|
|
CLAWDBOT_DIR="${CLAWDBOT_HOME}/clawdbot"
|
|
INSTALL_MARKER="/var/lib/clawdbot-installed"
|
|
|
|
log_info "Starting Clawdbot installation and Ubuntu hardening..."
|
|
|
|
#############################################################################
|
|
# 1. System Updates & Security Patches
|
|
#############################################################################
|
|
log_info "Step 1: Updating system packages..."
|
|
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
if [[ ! -f "${INSTALL_MARKER}.apt-updated" ]]; then
|
|
apt-get update -qq
|
|
apt-get upgrade -y -qq
|
|
touch "${INSTALL_MARKER}.apt-updated"
|
|
log_info "System packages updated"
|
|
else
|
|
log_info "System packages already updated (skipping)"
|
|
fi
|
|
|
|
#############################################################################
|
|
# 2. Install Required Packages
|
|
#############################################################################
|
|
log_info "Step 2: Installing required packages..."
|
|
|
|
REQUIRED_PACKAGES=(
|
|
"docker.io"
|
|
"docker-compose"
|
|
"ufw"
|
|
"fail2ban"
|
|
"unattended-upgrades"
|
|
"apt-listchanges"
|
|
"logrotate"
|
|
"curl"
|
|
"wget"
|
|
"git"
|
|
)
|
|
|
|
for pkg in "${REQUIRED_PACKAGES[@]}"; do
|
|
if ! dpkg -l | grep -q "^ii ${pkg}"; then
|
|
log_info "Installing ${pkg}..."
|
|
apt-get install -y -qq "${pkg}"
|
|
else
|
|
log_info "${pkg} already installed"
|
|
fi
|
|
done
|
|
|
|
#############################################################################
|
|
# 3. Enable Unattended Security Updates
|
|
#############################################################################
|
|
log_info "Step 3: Configuring unattended security updates..."
|
|
|
|
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<'EOF'
|
|
Unattended-Upgrade::Allowed-Origins {
|
|
"${distro_id}:${distro_codename}-security";
|
|
"${distro_id}ESMApps:${distro_codename}-apps-security";
|
|
"${distro_id}ESM:${distro_codename}-infra-security";
|
|
};
|
|
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
|
Unattended-Upgrade::MinimalSteps "true";
|
|
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
|
|
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
|
Unattended-Upgrade::Automatic-Reboot "false";
|
|
EOF
|
|
|
|
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
|
|
APT::Periodic::Update-Package-Lists "1";
|
|
APT::Periodic::Download-Upgradeable-Packages "1";
|
|
APT::Periodic::AutocleanInterval "7";
|
|
APT::Periodic::Unattended-Upgrade "1";
|
|
EOF
|
|
|
|
log_info "Unattended security updates enabled"
|
|
|
|
#############################################################################
|
|
# 4. Create Non-Root User for Clawdbot
|
|
#############################################################################
|
|
log_info "Step 4: Creating non-root user '${CLAWDBOT_USER}'..."
|
|
|
|
if ! id "${CLAWDBOT_USER}" &>/dev/null; then
|
|
useradd -m -s /bin/bash "${CLAWDBOT_USER}"
|
|
usermod -aG docker "${CLAWDBOT_USER}"
|
|
log_info "User '${CLAWDBOT_USER}' created and added to docker group"
|
|
else
|
|
log_info "User '${CLAWDBOT_USER}' already exists"
|
|
usermod -aG docker "${CLAWDBOT_USER}" 2>/dev/null || true
|
|
fi
|
|
|
|
#############################################################################
|
|
# 5. Configure UFW Firewall
|
|
#############################################################################
|
|
log_info "Step 5: Configuring UFW firewall..."
|
|
|
|
# Reset UFW to default state (idempotent)
|
|
ufw --force reset
|
|
|
|
# Default policies
|
|
ufw default deny incoming
|
|
ufw default allow outgoing
|
|
|
|
# Allow SSH (OpenSSH)
|
|
ufw allow OpenSSH
|
|
|
|
# Allow Tailscale (UDP 41641)
|
|
ufw allow 41641/udp comment 'Tailscale'
|
|
|
|
# Enable UFW
|
|
ufw --force enable
|
|
|
|
log_info "UFW firewall configured (SSH and Tailscale allowed, all else blocked)"
|
|
|
|
#############################################################################
|
|
# 6. Configure Fail2ban for SSH Protection
|
|
#############################################################################
|
|
log_info "Step 6: Configuring Fail2ban for SSH brute force protection..."
|
|
|
|
cat > /etc/fail2ban/jail.local <<'EOF'
|
|
[DEFAULT]
|
|
bantime = 3600
|
|
findtime = 600
|
|
maxretry = 5
|
|
destemail = root@localhost
|
|
sendername = Fail2Ban
|
|
action = %(action_mw)s
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = ssh
|
|
logpath = %(sshd_log)s
|
|
backend = %(sshd_backend)s
|
|
maxretry = 3
|
|
bantime = 7200
|
|
EOF
|
|
|
|
systemctl enable fail2ban
|
|
systemctl restart fail2ban
|
|
|
|
log_info "Fail2ban configured and enabled"
|
|
|
|
#############################################################################
|
|
# 7. Install Tailscale
|
|
#############################################################################
|
|
log_info "Step 7: Installing Tailscale..."
|
|
|
|
if ! command -v tailscale &>/dev/null; then
|
|
curl -fsSL https://tailscale.com/install.sh | sh
|
|
log_info "Tailscale installed"
|
|
else
|
|
log_info "Tailscale already installed"
|
|
fi
|
|
|
|
# Start Tailscale if not running
|
|
if ! systemctl is-active --quiet tailscaled; then
|
|
systemctl enable tailscaled
|
|
systemctl start tailscaled
|
|
fi
|
|
|
|
# Authenticate with Tailscale if auth key provided
|
|
if [[ -n "${TAILSCALE_AUTH_KEY:-}" ]]; then
|
|
if ! tailscale status &>/dev/null; then
|
|
log_info "Authenticating with Tailscale..."
|
|
tailscale up --authkey="${TAILSCALE_AUTH_KEY}" --accept-routes
|
|
else
|
|
log_info "Tailscale already authenticated"
|
|
fi
|
|
else
|
|
log_warn "TAILSCALE_AUTH_KEY not provided. Run 'sudo tailscale up' manually to authenticate"
|
|
fi
|
|
|
|
#############################################################################
|
|
# 8. Enable and Start Docker
|
|
#############################################################################
|
|
log_info "Step 8: Enabling Docker service..."
|
|
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
|
|
log_info "Docker service enabled and started"
|
|
|
|
#############################################################################
|
|
# 9. Create Clawdbot Directory Structure
|
|
#############################################################################
|
|
log_info "Step 9: Creating Clawdbot directory structure..."
|
|
|
|
mkdir -p "${CLAWDBOT_DIR}"
|
|
mkdir -p "${CLAWDBOT_DIR}/data"
|
|
mkdir -p "${CLAWDBOT_DIR}/logs"
|
|
|
|
#############################################################################
|
|
# 10. Create Docker Compose Configuration
|
|
#############################################################################
|
|
log_info "Step 10: Creating Docker Compose configuration..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/docker-compose.yml" <<'EOF'
|
|
version: '3.8'
|
|
|
|
services:
|
|
clawdbot:
|
|
image: ghcr.io/anthropics/clawdbot:latest
|
|
container_name: clawdbot
|
|
restart: unless-stopped
|
|
environment:
|
|
- CLAWDBOT_AUTH_MODE=password
|
|
- CLAWDBOT_PASSWORD=${CLAWDBOT_PASSWORD}
|
|
- CLAWDBOT_GATEWAY_BIND=127.0.0.1
|
|
- CLAWDBOT_GATEWAY_PORT=3000
|
|
- CLAWDBOT_DM_POLICY=pairing
|
|
- CLAWDBOT_CHANNEL_ALLOWLIST=
|
|
volumes:
|
|
- ./data:/app/data
|
|
- ./logs:/app/logs
|
|
ports:
|
|
- "127.0.0.1:3000:3000"
|
|
networks:
|
|
- clawdbot-net
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
|
|
networks:
|
|
clawdbot-net:
|
|
driver: bridge
|
|
EOF
|
|
|
|
#############################################################################
|
|
# 11. Create Environment File
|
|
#############################################################################
|
|
log_info "Step 11: Creating environment file..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/.env" <<EOF
|
|
# Clawdbot Configuration
|
|
# DO NOT COMMIT THIS FILE TO GIT
|
|
|
|
# Authentication
|
|
CLAWDBOT_PASSWORD=${CLAWDBOT_PASSWORD}
|
|
|
|
# Gateway Configuration (bind to localhost only - NOT public)
|
|
CLAWDBOT_GATEWAY_BIND=127.0.0.1
|
|
CLAWDBOT_GATEWAY_PORT=3000
|
|
|
|
# Security Settings
|
|
CLAWDBOT_AUTH_MODE=password
|
|
CLAWDBOT_DM_POLICY=pairing
|
|
CLAWDBOT_CHANNEL_ALLOWLIST=
|
|
|
|
# Generated on: $(date)
|
|
EOF
|
|
|
|
chmod 600 "${CLAWDBOT_DIR}/.env"
|
|
|
|
#############################################################################
|
|
# 12. Create Systemd Service for Clawdbot
|
|
#############################################################################
|
|
log_info "Step 12: Creating systemd service for Clawdbot..."
|
|
|
|
cat > /etc/systemd/system/clawdbot.service <<EOF
|
|
[Unit]
|
|
Description=Clawdbot Docker Service
|
|
Requires=docker.service
|
|
After=docker.service network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
RemainAfterExit=yes
|
|
WorkingDirectory=${CLAWDBOT_DIR}
|
|
User=${CLAWDBOT_USER}
|
|
Group=${CLAWDBOT_USER}
|
|
|
|
# Load environment variables
|
|
EnvironmentFile=${CLAWDBOT_DIR}/.env
|
|
|
|
# Start command
|
|
ExecStart=/usr/bin/docker-compose -f ${CLAWDBOT_DIR}/docker-compose.yml up -d
|
|
|
|
# Stop command
|
|
ExecStop=/usr/bin/docker-compose -f ${CLAWDBOT_DIR}/docker-compose.yml down
|
|
|
|
# Restart policy
|
|
Restart=on-failure
|
|
RestartSec=10s
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
systemctl daemon-reload
|
|
|
|
#############################################################################
|
|
# 13. Configure Log Rotation
|
|
#############################################################################
|
|
log_info "Step 13: Configuring log rotation..."
|
|
|
|
cat > /etc/logrotate.d/clawdbot <<EOF
|
|
${CLAWDBOT_DIR}/logs/*.log {
|
|
daily
|
|
rotate 7
|
|
compress
|
|
delaycompress
|
|
missingok
|
|
notifempty
|
|
create 0640 ${CLAWDBOT_USER} ${CLAWDBOT_USER}
|
|
}
|
|
EOF
|
|
|
|
log_info "Log rotation configured"
|
|
|
|
#############################################################################
|
|
# 14. Set Proper Permissions
|
|
#############################################################################
|
|
log_info "Step 14: Setting proper permissions..."
|
|
|
|
chown -R "${CLAWDBOT_USER}:${CLAWDBOT_USER}" "${CLAWDBOT_DIR}"
|
|
chmod 700 "${CLAWDBOT_DIR}"
|
|
chmod 600 "${CLAWDBOT_DIR}/.env"
|
|
|
|
#############################################################################
|
|
# 15. Pull Docker Image and Start Clawdbot
|
|
#############################################################################
|
|
log_info "Step 15: Pulling Clawdbot Docker image..."
|
|
|
|
su - "${CLAWDBOT_USER}" -c "cd ${CLAWDBOT_DIR} && docker-compose pull"
|
|
|
|
log_info "Starting Clawdbot service..."
|
|
|
|
systemctl enable clawdbot
|
|
systemctl restart clawdbot
|
|
|
|
# Wait for service to start
|
|
sleep 5
|
|
|
|
#############################################################################
|
|
# 16. Create Clawdbot Doctor Check Script
|
|
#############################################################################
|
|
log_info "Step 16: Creating Clawdbot doctor check script..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/clawdbot-doctor.sh" <<'DOCTOR_EOF'
|
|
#!/bin/bash
|
|
|
|
echo "=========================================="
|
|
echo "Clawdbot Health Check & Security Audit"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
WARNINGS=0
|
|
|
|
# Check if Clawdbot is running
|
|
echo "[1] Checking Clawdbot container status..."
|
|
if docker ps | grep -q clawdbot; then
|
|
echo " ✓ Clawdbot container is running"
|
|
else
|
|
echo " ✗ WARNING: Clawdbot container is NOT running"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check gateway binding
|
|
echo "[2] Checking gateway binding (should be 127.0.0.1 only)..."
|
|
if docker inspect clawdbot 2>/dev/null | grep -q '"127.0.0.1:3000"'; then
|
|
echo " ✓ Gateway bound to localhost only (secure)"
|
|
else
|
|
echo " ✗ WARNING: Gateway may be exposed publicly!"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check UFW status
|
|
echo "[3] Checking UFW firewall status..."
|
|
if ufw status | grep -q "Status: active"; then
|
|
echo " ✓ UFW firewall is active"
|
|
else
|
|
echo " ✗ WARNING: UFW firewall is NOT active"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check Fail2ban status
|
|
echo "[4] Checking Fail2ban status..."
|
|
if systemctl is-active --quiet fail2ban; then
|
|
echo " ✓ Fail2ban is running"
|
|
else
|
|
echo " ✗ WARNING: Fail2ban is NOT running"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check Tailscale status
|
|
echo "[5] Checking Tailscale status..."
|
|
if tailscale status &>/dev/null; then
|
|
echo " ✓ Tailscale is connected"
|
|
TAILSCALE_IP=$(tailscale ip -4 2>/dev/null)
|
|
if [[ -n "$TAILSCALE_IP" ]]; then
|
|
echo " → Tailscale IP: $TAILSCALE_IP"
|
|
fi
|
|
else
|
|
echo " ✗ WARNING: Tailscale is NOT connected"
|
|
echo " → Run: sudo tailscale up"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check unattended upgrades
|
|
echo "[6] Checking unattended security updates..."
|
|
if systemctl is-enabled unattended-upgrades &>/dev/null || [[ -f /etc/apt/apt.conf.d/20auto-upgrades ]]; then
|
|
echo " ✓ Unattended security updates enabled"
|
|
else
|
|
echo " ✗ WARNING: Unattended security updates NOT configured"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check auth mode
|
|
echo "[7] Checking Clawdbot auth mode..."
|
|
if docker exec clawdbot env 2>/dev/null | grep -q "CLAWDBOT_AUTH_MODE=password"; then
|
|
echo " ✓ Auth mode is set to password"
|
|
else
|
|
echo " ✗ WARNING: Auth mode may not be configured correctly"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check DM policy
|
|
echo "[8] Checking DM policy (should be 'pairing' or allowlist)..."
|
|
DM_POLICY=$(docker exec clawdbot env 2>/dev/null | grep CLAWDBOT_DM_POLICY | cut -d= -f2)
|
|
if [[ "$DM_POLICY" == "pairing" ]] || [[ -n "$DM_POLICY" && "$DM_POLICY" != "open" ]]; then
|
|
echo " ✓ DM policy is secure: $DM_POLICY"
|
|
else
|
|
echo " ✗ WARNING: DM policy may be too permissive: $DM_POLICY"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
fi
|
|
echo ""
|
|
|
|
# Check for public port exposure
|
|
echo "[9] Checking for public port exposure..."
|
|
if netstat -tuln 2>/dev/null | grep -E ':3000.*0.0.0.0|:3000.*::' | grep -v 127.0.0.1; then
|
|
echo " ✗ WARNING: Port 3000 may be exposed publicly!"
|
|
WARNINGS=$((WARNINGS + 1))
|
|
else
|
|
echo " ✓ No public port exposure detected"
|
|
fi
|
|
echo ""
|
|
|
|
# Summary
|
|
echo "=========================================="
|
|
if [[ $WARNINGS -eq 0 ]]; then
|
|
echo "✓ All checks passed! No warnings."
|
|
else
|
|
echo "⚠ Total warnings: $WARNINGS"
|
|
echo "Please review the warnings above."
|
|
fi
|
|
echo "=========================================="
|
|
DOCTOR_EOF
|
|
|
|
chmod +x "${CLAWDBOT_DIR}/clawdbot-doctor.sh"
|
|
chown "${CLAWDBOT_USER}:${CLAWDBOT_USER}" "${CLAWDBOT_DIR}/clawdbot-doctor.sh"
|
|
|
|
#############################################################################
|
|
# 17. Create Tailscale Serve Configuration Script
|
|
#############################################################################
|
|
log_info "Step 17: Creating Tailscale Serve setup script..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/setup-tailscale-serve.sh" <<'SERVE_EOF'
|
|
#!/bin/bash
|
|
# Setup Tailscale Serve to expose Clawdbot on your Tailnet
|
|
|
|
echo "Setting up Tailscale Serve for Clawdbot..."
|
|
|
|
# Enable Tailscale Serve on port 3000
|
|
sudo tailscale serve https / http://127.0.0.1:3000
|
|
|
|
echo ""
|
|
echo "Tailscale Serve configured!"
|
|
echo "Access Clawdbot at: https://$(hostname).$(tailscale status --json | jq -r '.MagicDNSSuffix')"
|
|
echo ""
|
|
echo "To disable: sudo tailscale serve reset"
|
|
SERVE_EOF
|
|
|
|
chmod +x "${CLAWDBOT_DIR}/setup-tailscale-serve.sh"
|
|
chown "${CLAWDBOT_USER}:${CLAWDBOT_USER}" "${CLAWDBOT_DIR}/setup-tailscale-serve.sh"
|
|
|
|
#############################################################################
|
|
# 18. Create README
|
|
#############################################################################
|
|
log_info "Step 18: Creating README..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/README.md" <<'README_EOF'
|
|
# Clawdbot Installation
|
|
|
|
## Access Methods
|
|
|
|
### Option 1: Tailscale Serve (Recommended)
|
|
```bash
|
|
cd /home/clawdbot/clawdbot
|
|
sudo ./setup-tailscale-serve.sh
|
|
```
|
|
|
|
Then access at: `https://<hostname>.<tailnet-name>.ts.net`
|
|
|
|
### Option 2: SSH Tunnel
|
|
```bash
|
|
ssh -L 3000:127.0.0.1:3000 ubuntu@<server-ip>
|
|
```
|
|
|
|
Then access at: `http://localhost:3000`
|
|
|
|
## Management Commands
|
|
|
|
### Check Status
|
|
```bash
|
|
sudo systemctl status clawdbot
|
|
docker ps
|
|
```
|
|
|
|
### View Logs
|
|
```bash
|
|
docker logs clawdbot -f
|
|
```
|
|
|
|
### Restart Service
|
|
```bash
|
|
sudo systemctl restart clawdbot
|
|
```
|
|
|
|
### Stop Service
|
|
```bash
|
|
sudo systemctl stop clawdbot
|
|
```
|
|
|
|
### Run Health Check
|
|
```bash
|
|
cd /home/clawdbot/clawdbot
|
|
./clawdbot-doctor.sh
|
|
```
|
|
|
|
## Security Features
|
|
|
|
- ✓ Gateway bound to localhost only (127.0.0.1)
|
|
- ✓ Password authentication enabled
|
|
- ✓ UFW firewall (SSH + Tailscale only)
|
|
- ✓ Fail2ban for SSH brute force protection
|
|
- ✓ Unattended security updates enabled
|
|
- ✓ Non-root user for running Clawdbot
|
|
- ✓ Log rotation configured
|
|
- ✓ DM policy set to pairing (not open)
|
|
|
|
## Configuration
|
|
|
|
Edit `/home/clawdbot/clawdbot/.env` to change settings (requires restart).
|
|
|
|
## Uninstall
|
|
|
|
See `UNINSTALL.md` for removal instructions.
|
|
README_EOF
|
|
|
|
chown "${CLAWDBOT_USER}:${CLAWDBOT_USER}" "${CLAWDBOT_DIR}/README.md"
|
|
|
|
#############################################################################
|
|
# 19. Create Uninstall Script
|
|
#############################################################################
|
|
log_info "Step 19: Creating uninstall script..."
|
|
|
|
cat > "${CLAWDBOT_DIR}/UNINSTALL.md" <<'UNINSTALL_EOF'
|
|
# Uninstall / Rollback Instructions
|
|
|
|
## Complete Removal
|
|
|
|
```bash
|
|
# Stop and disable Clawdbot service
|
|
sudo systemctl stop clawdbot
|
|
sudo systemctl disable clawdbot
|
|
sudo rm /etc/systemd/system/clawdbot.service
|
|
sudo systemctl daemon-reload
|
|
|
|
# Remove Docker containers and images
|
|
cd /home/clawdbot/clawdbot
|
|
docker-compose down -v
|
|
docker rmi ghcr.io/anthropics/clawdbot:latest
|
|
|
|
# Remove Clawdbot user and files
|
|
sudo userdel -r clawdbot
|
|
|
|
# Remove Tailscale (optional)
|
|
sudo tailscale down
|
|
sudo apt-get remove -y tailscale
|
|
|
|
# Remove Fail2ban (optional)
|
|
sudo systemctl stop fail2ban
|
|
sudo systemctl disable fail2ban
|
|
sudo apt-get remove -y fail2ban
|
|
|
|
# Reset UFW (optional - WARNING: this opens all ports)
|
|
sudo ufw disable
|
|
sudo ufw --force reset
|
|
|
|
# Remove log rotation config
|
|
sudo rm /etc/logrotate.d/clawdbot
|
|
|
|
# Remove installation markers
|
|
sudo rm -f /var/lib/clawdbot-installed*
|
|
```
|
|
|
|
## Partial Rollback (Keep Security Hardening)
|
|
|
|
If you want to remove Clawdbot but keep the security hardening:
|
|
|
|
```bash
|
|
# Stop and remove Clawdbot only
|
|
sudo systemctl stop clawdbot
|
|
sudo systemctl disable clawdbot
|
|
sudo rm /etc/systemd/system/clawdbot.service
|
|
sudo systemctl daemon-reload
|
|
|
|
cd /home/clawdbot/clawdbot
|
|
docker-compose down -v
|
|
docker rmi ghcr.io/anthropics/clawdbot:latest
|
|
|
|
sudo userdel -r clawdbot
|
|
sudo rm /etc/logrotate.d/clawdbot
|
|
```
|
|
|
|
This keeps UFW, Fail2ban, Tailscale, and unattended upgrades active.
|
|
UNINSTALL_EOF
|
|
|
|
chown "${CLAWDBOT_USER}:${CLAWDBOT_USER}" "${CLAWDBOT_DIR}/UNINSTALL.md"
|
|
|
|
#############################################################################
|
|
# 20. Mark Installation Complete
|
|
#############################################################################
|
|
touch "${INSTALL_MARKER}"
|
|
|
|
#############################################################################
|
|
# 21. Run Doctor Check
|
|
#############################################################################
|
|
log_info "Step 20: Running health check..."
|
|
echo ""
|
|
|
|
su - "${CLAWDBOT_USER}" -c "${CLAWDBOT_DIR}/clawdbot-doctor.sh"
|
|
|
|
#############################################################################
|
|
# Final Summary
|
|
#############################################################################
|
|
echo ""
|
|
echo "=========================================="
|
|
log_info "Installation Complete!"
|
|
echo "=========================================="
|
|
echo ""
|
|
echo "Next Steps:"
|
|
echo ""
|
|
echo "1. Authenticate with Tailscale (if not done):"
|
|
echo " sudo tailscale up"
|
|
echo ""
|
|
echo "2. Setup Tailscale Serve for secure access:"
|
|
echo " cd ${CLAWDBOT_DIR}"
|
|
echo " sudo ./setup-tailscale-serve.sh"
|
|
echo ""
|
|
echo "3. Or use SSH tunnel:"
|
|
echo " ssh -L 3000:127.0.0.1:3000 ubuntu@<server-ip>"
|
|
echo ""
|
|
echo "4. Access Clawdbot and login with your password"
|
|
echo ""
|
|
echo "Documentation: ${CLAWDBOT_DIR}/README.md"
|
|
echo "Health Check: ${CLAWDBOT_DIR}/clawdbot-doctor.sh"
|
|
echo "Uninstall: ${CLAWDBOT_DIR}/UNINSTALL.md"
|
|
echo ""
|
|
echo "=========================================="
|