#!/usr/bin/env bash # clawd 一键安装脚本 # 用法:curl -fsSL https://raw.githubusercontent.com/stswangzhiping/clawd/main/install.sh | bash # 需要 root 权限,需要已安装 Node.js >= 18 set -e RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[clawd]${NC} $*"; } warn() { echo -e "${YELLOW}[clawd]${NC} $*"; } error() { echo -e "${RED}[clawd]${NC} $*"; exit 1; } # ── 检查 root ──────────────────────────────────────────────────────────────── if [ "$EUID" -ne 0 ]; then error "请以 root 身份运行(sudo bash install.sh)" fi # ── 检查 Node.js ───────────────────────────────────────────────────────────── if ! command -v node &>/dev/null; then error "未找到 Node.js,请先安装 Node.js >= 18" fi NODE_VER=$(node -e "process.stdout.write(process.versions.node)") MAJOR=$(echo "$NODE_VER" | cut -d. -f1) if [ "$MAJOR" -lt 18 ]; then error "Node.js 版本过低(当前 $NODE_VER),需要 >= 18" fi info "Node.js $NODE_VER ✓" # ── 检查/安装 dnsmasq(WiFi 配网需要)────────────────────────────────────── if ! command -v dnsmasq &>/dev/null; then info "安装 dnsmasq(WiFi 配网所需)..." if command -v apt-get &>/dev/null; then apt-get install -y -qq dnsmasq >/dev/null 2>&1 elif command -v yum &>/dev/null; then yum install -y -q dnsmasq >/dev/null 2>&1 elif command -v apk &>/dev/null; then apk add --quiet dnsmasq >/dev/null 2>&1 else warn "无法自动安装 dnsmasq,WiFi 配网功能可能不可用" fi # 禁止 dnsmasq 系统服务自启(clawd 自己管理) systemctl disable dnsmasq 2>/dev/null || true systemctl stop dnsmasq 2>/dev/null || true fi if command -v dnsmasq &>/dev/null; then info "dnsmasq ✓" fi # ── 启用 NetworkManager(WiFi 配网需要)────────────────────────────────────── if command -v nmcli &>/dev/null; then if ! systemctl is-active --quiet NetworkManager 2>/dev/null; then info "启用 NetworkManager..." systemctl enable --now NetworkManager 2>/dev/null || true fi info "NetworkManager ✓" # 预写 DNS 劫持配置(运行时 /etc 可能为只读) NM_DNSMASQ_DIR="/etc/NetworkManager/dnsmasq-shared.d" mkdir -p "$NM_DNSMASQ_DIR" cat > "$NM_DNSMASQ_DIR/clawd-captive.conf" << 'DNSCONF' # clawd captive portal DNS hijack # All DNS queries resolve to gateway to trigger captive portal address=/#/10.42.0.1 DNSCONF info "DNS 劫持配置已写入 $NM_DNSMASQ_DIR ✓" fi # ── WiFi rfkill 解锁(部分设备默认禁用 WiFi)──────────────────────────────── for rf in /sys/class/rfkill/rfkill*; do if [ -f "$rf/type" ] && [ "$(cat "$rf/type")" = "wlan" ]; then if [ "$(cat "$rf/soft")" = "1" ]; then info "解锁 WiFi ($(basename "$rf"))..." echo 0 > "$rf/soft" fi fi done # 持久化:独立脚本 + systemd 服务,确保开机自动解锁 WiFi RFKILL_SCRIPT="/usr/local/bin/clawd-unblock-wifi.sh" cat > "$RFKILL_SCRIPT" << 'SCRIPT' #!/bin/sh for rf in /sys/class/rfkill/rfkill*; do [ -f "$rf/type" ] || continue if [ "$(cat "$rf/type")" = "wlan" ] && [ "$(cat "$rf/soft")" = "1" ]; then echo 0 > "$rf/soft" echo "clawd-rfkill: unblocked $(basename "$rf")" fi done SCRIPT chmod +x "$RFKILL_SCRIPT" RFKILL_SERVICE="/etc/systemd/system/clawd-rfkill.service" cat > "$RFKILL_SERVICE" << 'UNIT' [Unit] Description=Unblock WiFi for clawd Before=NetworkManager.service clawd.service After=sys-subsystem-net-devices-wlan0.device [Service] Type=oneshot ExecStart=/usr/local/bin/clawd-unblock-wifi.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target UNIT systemctl daemon-reload systemctl enable clawd-rfkill info "WiFi rfkill 解锁服务已创建 ✓" # ── 移除系统自带 ttyd(避免与 clawd 托管的 ttyd 端口冲突)──────────────────── if command -v dpkg &>/dev/null && dpkg -l ttyd 2>/dev/null | grep -q '^ii'; then info "移除系统 ttyd 包(避免端口冲突)..." apt-get remove -y ttyd >/dev/null 2>&1 || true info "系统 ttyd 已移除 ✓" fi # ── 安装 clawd ─────────────────────────────────────────────────────────────── INSTALL_DIR="/opt/clawd" CONFIG_DIR="/etc/clawd" ENV_FILE="$CONFIG_DIR/env" info "安装到 $INSTALL_DIR ..." mkdir -p "$INSTALL_DIR" cd "$INSTALL_DIR" # 下载源码(若目录已有 package.json,视为离线/已解压部署,跳过 git/tarball;避免设备无法访问 github.com) if [ -f "package.json" ]; then info "检测到已有源码,跳过 git/tarball 下载" elif command -v git &>/dev/null; then if [ -d ".git" ]; then git pull --quiet else git clone --depth=1 https://github.com/stswangzhiping/clawd.git . fi else TARBALL_URL="https://github.com/stswangzhiping/clawd/archive/refs/heads/main.tar.gz" curl -fsSL "$TARBALL_URL" | tar -xz --strip-components=1 fi # 安装依赖 info "安装 npm 依赖..." npm install --omit=dev --silent # 创建可执行链接 ln -sf "$INSTALL_DIR/bin/clawd.js" /usr/local/bin/clawd chmod +x "$INSTALL_DIR/bin/clawd.js" info "clawd 已安装到 /usr/local/bin/clawd ✓" # ── 下载 ttyd(Web 终端)──────────────────────────────────────────────────── TTYD_BIN="$CONFIG_DIR/ttyd" TTYD_VERSION="1.7.7" if [ ! -f "$TTYD_BIN" ]; then ARCH=$(uname -m) case "$ARCH" in aarch64|arm64) TTYD_ARCH="aarch64" ;; x86_64) TTYD_ARCH="x86_64" ;; armv7l|armv6l) TTYD_ARCH="armv7l" ;; i686) TTYD_ARCH="i686" ;; *) TTYD_ARCH="x86_64" ;; esac TTYD_URL="https://github.com/tsl0922/ttyd/releases/download/${TTYD_VERSION}/ttyd.${TTYD_ARCH}" info "下载 ttyd ${TTYD_VERSION} (${TTYD_ARCH})..." if curl -fsSL -o "$TTYD_BIN" "$TTYD_URL" && [ -s "$TTYD_BIN" ]; then chmod 755 "$TTYD_BIN" info "ttyd 已安装到 $TTYD_BIN ✓" else rm -f "$TTYD_BIN" warn "ttyd 下载失败(网络问题?),请手动下载并放置到 $TTYD_BIN" warn " 下载地址: $TTYD_URL" fi else info "ttyd 已存在,跳过下载 ✓" fi # ── 创建配置目录 + 环境变量文件 ────────────────────────────────────────────── mkdir -p "$CONFIG_DIR" if [ ! -f "$CONFIG_DIR/config.json" ]; then cat > "$CONFIG_DIR/config.json" < "$ENV_FILE" < "$SERVICE_FILE" < "$JOURNAL_CONF" </dev/null || true info "journald 日志限制已配置 ✓" fi # ── 启用并启动 ────────────────────────────────────────────────────────────── systemctl daemon-reload systemctl enable clawd systemctl restart clawd sleep 2 if systemctl is-active --quiet clawd; then info "clawd 服务运行中 ✓" echo "" echo " 查看日志: journalctl -u clawd -f" echo " 查看状态: systemctl status clawd" echo " 停止服务: systemctl stop clawd" echo " 配置文件: $CONFIG_DIR/config.json" echo " 环境变量: $ENV_FILE" echo " 文件日志: $CONFIG_DIR/logs/clawd.log" echo "" else warn "服务启动失败,请检查日志:" echo " journalctl -u clawd -n 50 --no-pager" fi