169 lines
7.8 KiB
Bash
169 lines
7.8 KiB
Bash
#!/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
|
||
# 注意:Ubuntu 22.04/24.04 的 useradd 没有 --disabled-password 选项
|
||
# (那是 adduser 命令的参数,之前脚本写错了命令)。
|
||
# 这里用 useradd 原生参数:
|
||
# -m = 创建 home
|
||
# -s = 指定登录 shell
|
||
# -p '*' = 密码设置为「*」(锁定,禁止用密码登录,只能 SSH 密钥)
|
||
# 这样和之前「只允许 SSH 密钥登录、无密码」的意图完全一致。
|
||
useradd -m -s /usr/bin/bash -p '*' "${DEPLOY_USER}"
|
||
# Ubuntu/Debian 额外保险:锁定密码字段,避免 shadow 被改
|
||
usermod -L "${DEPLOY_USER}" 2>/dev/null || true
|
||
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}" <<SSHD
|
||
# 针对 deploy 用户:仅允许公钥登录,禁用 TCP 转发等
|
||
Match User ${DEPLOY_USER}
|
||
PasswordAuthentication no
|
||
PubkeyAuthentication yes
|
||
PermitTTY yes
|
||
AllowTcpForwarding no
|
||
X11Forwarding no
|
||
SSHD
|
||
systemctl reload sshd 2>/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 ""
|