#!/usr/bin/env bash # ============================================================================ # setup-deploy-user.sh # 在「生产服务器」上一键做好 CI 自动部署所需的系统配置: # 1) 新建 deploy 用户(低权限,禁止密码登录,只能 key 登录) # 2) 生成 ed25519 SSH 密钥对(私钥你粘去 Gitea Secrets DEPLOY_SSH_KEY) # 3) 加入 docker 组,允许 docker compose 操作 # 4) 给 /opt/byw-voicehub 目录读写权限(setfacl) # 5) 打印私钥内容 & 公钥指纹,便于你检查和复制 # # 用法(在生产服务器上,sudo 运行): # sudo bash scripts/setup-deploy-user.sh [--deploy-dir /opt/byw-voicehub] # ============================================================================ set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[1;36m'; NC='\033[0m' info(){ echo -e "${GREEN}[INFO]${NC} $*"; } warn(){ echo -e "${YELLOW}[WARN]${NC} $*"; } err(){ echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } ok(){ echo -e "${CYAN}[ OK ]${NC} $*"; } DEPLOY_DIR="/opt/byw-voicehub" DEPLOY_USER="deploy" while [[ $# -gt 0 ]]; do case "$1" in --deploy-dir) DEPLOY_DIR="$2"; shift 2 ;; --user) DEPLOY_USER="$2"; shift 2 ;; -h|--help) sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//' exit 0 ;; *) err "未知参数 $1(--help 查看帮助)" ;; esac done [[ $EUID -eq 0 ]] || err "请用 sudo 运行本脚本" command -v docker >/dev/null 2>&1 || err "先装完 Docker 再跑本脚本(路径一的教程里有)" command -v setfacl >/dev/null 2>&1 || { warn "没装 acl 工具,现在 apt install" apt-get update && apt-get install -y acl } # -------- 1. 建用户 -------- if ! id -u "${DEPLOY_USER}" >/dev/null 2>&1; then useradd --create-home --shell /usr/bin/bash --disabled-password "${DEPLOY_USER}" ok "新建用户:${DEPLOY_USER}(无密码,仅 SSH key 登录)" else info "用户 ${DEPLOY_USER} 已存在,跳过创建" fi # -------- 2. 加入 docker 组 -------- usermod -aG docker "${DEPLOY_USER}" ok "${DEPLOY_USER} 加入 docker 组(有权限执行 docker compose)" # -------- 3. 生成 SSH 密钥(无密码) -------- SSH_DIR="/home/${DEPLOY_USER}/.ssh" mkdir -p "${SSH_DIR}" chmod 700 "${SSH_DIR}" chown "${DEPLOY_USER}:${DEPLOY_USER}" "${SSH_DIR}" KEY_PATH="${SSH_DIR}/id_ed25519" if [[ ! -f "${KEY_PATH}" ]]; then sudo -u "${DEPLOY_USER}" ssh-keygen -t ed25519 \ -C "gitea-actions-deploy-$(hostname)" \ -f "${KEY_PATH}" \ -N "" >/dev/null ok "SSH ed25519 密钥对生成:${KEY_PATH}" else info "密钥对已存在,跳过生成:${KEY_PATH}" fi # 公钥加入 authorized_keys(允许持对应私钥的人以 deploy 用户 ssh 登录) AUTH_KEYS="${SSH_DIR}/authorized_keys" touch "${AUTH_KEYS}" PUBKEY_CONTENT="$(cat "${KEY_PATH}.pub")" if ! grep -qF "${PUBKEY_CONTENT}" "${AUTH_KEYS}" 2>/dev/null; then echo "${PUBKEY_CONTENT}" >> "${AUTH_KEYS}" ok "公钥已写入 authorized_keys" fi chmod 600 "${AUTH_KEYS}" chmod 644 "${KEY_PATH}.pub" chmod 600 "${KEY_PATH}" chown -R "${DEPLOY_USER}:${DEPLOY_USER}" "${SSH_DIR}" # -------- 4. sshd 加固(只允许公钥登录;别让 root 密码登录;deploy 禁止转发)-------- SSHD_SNIPPET="/etc/ssh/sshd_config.d/99-deploy-user.conf" if [[ ! -f "${SSHD_SNIPPET}" ]]; then mkdir -p /etc/ssh/sshd_config.d cat > "${SSHD_SNIPPET}" </dev/null || service ssh reload || true ok "sshd 配置已加固(deploy 只允许公钥登录,并禁用端口转发)" fi # -------- 5. 创建部署目录并给 deploy 权限 -------- mkdir -p "${DEPLOY_DIR}" # 既设组权限,又加 ACL,确保后续新建文件也有 setfacl -R -m "u:${DEPLOY_USER}:rwX" "${DEPLOY_DIR}" setfacl -R -d -m "u:${DEPLOY_USER}:rwX" "${DEPLOY_DIR}" ok "部署目录 ${DEPLOY_DIR} 已给 ${DEPLOY_USER} 完整读写权限(+ 新建文件继承权限)" # 如果目录里有 compose/环境文件,顺便改一下属组,避免「root 建的文件 deploy 改不了」 chgrp -R docker "${DEPLOY_DIR}" 2>/dev/null || true chmod -R g+rwX "${DEPLOY_DIR}" 2>/dev/null || true # -------- 6. 验证 docker 是否真能用(不报错)-------- DOCKER_RC=0 sudo -u "${DEPLOY_USER}" docker ps >/dev/null 2>&1 || DOCKER_RC=$? if [[ ${DOCKER_RC} -eq 0 ]]; then ok "✅ ${DEPLOY_USER} 可以执行 docker 命令" else warn "⚠️ ${DEPLOY_USER} 暂时跑不了 docker(可能需要重新登录一次刷新组),部署时不会有影响(但验证时会再触发一次)" fi # -------- 7. 打印信息 -------- FINGERPRINT="$(ssh-keygen -l -f "${KEY_PATH}.pub" 2>/dev/null || true)" PUBKEY_CONTENT="$(cat "${KEY_PATH}.pub")" PRIVATE_CONTENT="$(cat "${KEY_PATH}")" clear echo -e "${GREEN}================================================================================${NC}" echo -e "${GREEN} 🎉 部署用户 & SSH 密钥 配置完成!${NC}" echo -e "${GREEN}================================================================================${NC}" echo -e " 👤 部署用户名 :${CYAN}${DEPLOY_USER}${NC}" echo -e " 📂 部署目录 :${CYAN}${DEPLOY_DIR}${NC}" echo -e " 🔑 私钥文件路径 :${CYAN}${KEY_PATH}${NC}" echo -e " 🧾 公钥指纹 :${FINGERPRINT}" echo -e " 🧾 公钥内容(方便核对):" echo -e " ${PUBKEY_CONTENT}" echo "" echo -e "${YELLOW}================================================================================${NC}" echo -e "${YELLOW} ⚠️ 下面这一整段是【私钥】,完整复制(从 BEGIN 到 END 包括两行)到:${NC}" echo -e "${YELLOW} Gitea 仓库 → Settings → Secrets and variables → Actions → New Secret${NC}" echo -e "${YELLOW} Name = DEPLOY_SSH_KEY${NC}" echo -e "${YELLOW} Value = 粘贴下面一整段(包括 -----BEGIN/END-----)${NC}" echo -e "${YELLOW}================================================================================${NC}" echo "" echo "${PRIVATE_CONTENT}" echo "" echo -e "${YELLOW}================================================================================${NC}" echo -e "${YELLOW} ⚠️ 上面就是 DEPLOY_SSH_KEY,不要在任何地方贴到别的文档或聊天。看完 Ctrl+L 清屏。${NC}" echo -e "${YELLOW}================================================================================${NC}" echo "" echo -e "${CYAN}👉 同时你还需要补以下几个 Repository Secrets(都在同一页添加):${NC}" echo -e " • DEPLOY_HOST = 你的服务器公网 IP 或域名" echo -e " • DEPLOY_PORT = SSH 端口(一般 22)" echo -e " • DEPLOY_USER = ${DEPLOY_USER}(就是这个用户名)" echo -e " • REGISTRY_TOKEN = 你的 Gitea 个人访问令牌(Package 读写权限)" echo -e " • REGISTRY_PULL_USER = 同 REGISTRY_USER(服务器上拉镜像用,一般和 REGISTRY_USER 一样)" echo -e " • REGISTRY_PULL_TOKEN= 上面令牌同一个或新建一个仅 pull 权限的更安全" echo -e " • NUXT_PUBLIC_SITE_URL = https://你的域名.com(用来显示部署成功后的跳转按钮)" echo ""