Files
diary-news/scripts/deploy_remote.sh

159 lines
4.1 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# 部署脚本:在远程服务器上跑一次
# 用法: bash /root/deploy_news.sh
set -euo pipefail
# === 配置 ===
GITEA_URL="http://124.223.26.33:3000/xiaji/diary-news.git"
APP_DIR="/srv/news"
DOMAIN="" # 留空走 IP
log() { echo "[$(date +'%H:%M:%S')] $*"; }
fail() { echo "[FAIL] $*" >&2; exit 1; }
# === 1. 系统初始化 ===
log "1/8 系统更新 + 基础包"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get install -y --no-install-recommends curl git ufw fail2ban openssl ca-certificates
# === 2. 创建非 root 用户(后续切过去) ===
if ! id news &>/dev/null; then
log "2/8 创建 news 用户"
adduser --disabled-password --gecos "" news
echo "news ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/news
fi
# === 3. Docker ===
if ! command -v docker &>/dev/null; then
log "3/8 安装 Docker"
curl -fsSL https://get.docker.com -o /tmp/get-docker.sh
sh /tmp/get-docker.sh
usermod -aG docker news
fi
docker --version
# === 4. 防火墙 ===
log "4/8 防火墙"
SSHD_PORT="${SSHD_PORT:-22}" # 自定义 SSH 端口(默认 22)
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow "${SSHD_PORT}/tcp" comment 'ssh'
ufw allow 80/tcp comment 'http'
ufw allow 443/tcp comment 'https'
ufw --force enable
ufw status verbose
# === 5. 拉代码 ===
log "5/8 拉代码到 $APP_DIR"
mkdir -p "$APP_DIR"
if [ ! -d "$APP_DIR/.git" ]; then
sudo -u news git clone "$GITEA_URL" "$APP_DIR"
else
cd "$APP_DIR" && sudo -u news git pull --rebase
fi
chown -R news:news "$APP_DIR"
# === 6. 写 .env(自动生成密码) ===
log "6/8 生成 .env"
if [ ! -f "$APP_DIR/.env" ]; then
cat > "$APP_DIR/.env" <<EOF
TZ=Asia/Hong_Kong
LOG_LEVEL=INFO
POSTGRES_USER=news
POSTGRES_PASSWORD=$(openssl rand -hex 24)
POSTGRES_DB=news
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=$(openssl rand -hex 24)
REDIS_DB=0
JWT_SECRET=$(openssl rand -hex 64)
JWT_ALGORITHM=HS256
ACCESS_TOKEN_TTL_MIN=60
REFRESH_TOKEN_TTL_DAY=14
TENCENTCLOUD_SECRET_ID=__FILL_ME__
TENCENTCLOUD_SECRET_KEY=__FILL_ME__
TENCENTCLOUD_REGION=ap-hongkong
TENCENT_TMT_ENDPOINT=tmt.tencentcloudapi.com
TENCENT_TMT_QUOTA_MONTH=5000000
TENCENT_TMT_QUOTA_BUFFER=0.05
TENCENT_TMT_MAX_CHARS_PER_REQ=4500
LOCAL_TRANSLATE_ENABLED=false
LOCAL_TRANSLATE_MODEL=nllb-200-distilled-600M
LOCAL_TRANSLATE_DEVICE=cpu
FETCH_GLOBAL_QPS=4
FETCH_TIMEOUT=20
FETCH_FAIL_PAUSE_THRESHOLD=3
FETCH_MAX_RETRIES=2
DOMAIN=$DOMAIN
ACME_EMAIL=
EOF
chown news:news "$APP_DIR/.env"
chmod 600 "$APP_DIR/.env"
log "已生成 .env(随机密码已写入,TENCENTCLOUD_SECRET 仍待填)"
fi
# === 7. 启动 docker compose ===
log "7/8 docker compose up"
cd "$APP_DIR"
# news 用户需要 docker 组权限,用 sg 临时切换(写成函数避免引号问题)
dc() { sg docker -c "docker compose $*"; }
dc up -d --build
# 等健康
log " 等待 postgres / redis healthy..."
for i in {1..30}; do
if dc exec -T postgres pg_isready -U news -d news &>/dev/null; then
break
fi
sleep 2
done
for i in {1..30}; do
if dc exec -T redis redis-cli -a "$(grep ^REDIS_PASSWORD $APP_DIR/.env | cut -d= -f2)" ping 2>/dev/null | grep -q PONG; then
break
fi
sleep 2
done
# === 8. 初始化 ===
log "8/8 数据库迁移 + 用户 + 源"
dc exec -T api alembic upgrade head
# 创建 owner(从 env 或自动生成,避免后台跑卡在 read)
if [ -n "${OWNER_PASS:-}" ]; then
log " 使用环境变量 OWNER_PASS"
else
OWNER_PASS="$(openssl rand -hex 12)"
log " 自动生成 owner 密码(写入 /root/.owner_pass): $OWNER_PASS"
fi
dc exec -T api python -m app.scripts.create_user --username owner --password "$OWNER_PASS" || true
echo "$OWNER_PASS" > /root/.owner_pass
chmod 600 /root/.owner_pass
# 种子
dc exec -T api python -m app.scripts.seed_sources
# 健康检查
log " 健康检查"
sleep 3
curl -s http://localhost/api/v1/healthz && echo
echo
echo "================================================"
echo " 部署完成!"
echo " 访问: http://$(curl -s ifconfig.me)/"
echo " 账号: owner"
echo " 密码: 写入到 /root/.owner_pass (chmod 600)"
echo " 后续: docker compose -f $APP_DIR/docker-compose.yml logs -f"
echo "================================================"