chore: restore initial vtuber source snapshot
This commit is contained in:
79
deploy/apply-nginx-110-live-fallback.sh
Executable file
79
deploy/apply-nginx-110-live-fallback.sh
Executable file
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ENV_FILE="${SCRIPT_DIR}/.env.prod"
|
||||
if [ ! -f "${ENV_FILE}" ]; then
|
||||
echo "❌ 找不到 deploy/.env.prod,請先建立後再執行。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "${ENV_FILE}"
|
||||
|
||||
DEPLOY_HOST="${DEPLOY_HOST:-}"
|
||||
DEPLOY_USER="${DEPLOY_USER:-}"
|
||||
DEPLOY_PORT="${DEPLOY_PORT:-22}"
|
||||
APP_DOMAIN="${APP_DOMAIN:-vtuber.wooo.work}"
|
||||
NGINX_SERVER_CONFIG="${NGINX_SERVER_CONFIG:-}"
|
||||
SNIPPET_SRC="${SCRIPT_DIR}/vtuber-nginx-110-live-fallback.conf"
|
||||
SNIPPET_REMOTE="/etc/nginx/snippets/vtuber-nginx-110-live-fallback.conf"
|
||||
|
||||
if [ -z "${DEPLOY_HOST}" ] || [ -z "${DEPLOY_USER}" ]; then
|
||||
echo "❌ deploy/.env.prod 缺少 DEPLOY_HOST / DEPLOY_USER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REMOTE="${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
SSH_OPTS=(-p "${DEPLOY_PORT}")
|
||||
SCP_OPTS=(-P "${DEPLOY_PORT}")
|
||||
NGINX_SNIPPET_TAG="vtuber-nginx-110-live-fallback.conf"
|
||||
TMP_SNIPPET="/tmp/vtuber-nginx-110-live-fallback.conf"
|
||||
|
||||
if [ -z "${NGINX_SERVER_CONFIG}" ]; then
|
||||
echo "未指定 NGINX_SERVER_CONFIG,開始自動偵測..."
|
||||
NGINX_SERVER_CONFIG="$(
|
||||
ssh "${SSH_OPTS[@]}" "${REMOTE}" "
|
||||
if [ -f '/etc/nginx/conf.d/vtuber.wooo.conf' ]; then
|
||||
echo '/etc/nginx/conf.d/vtuber.wooo.conf'
|
||||
elif [ -f \"/etc/nginx/sites-available/${APP_DOMAIN}\" ]; then
|
||||
echo '/etc/nginx/sites-available/${APP_DOMAIN}'
|
||||
elif [ -f '/etc/nginx/sites-enabled/vtuber.wooo.work' ]; then
|
||||
echo '/etc/nginx/sites-enabled/vtuber.wooo.work'
|
||||
else
|
||||
grep -R -l \"server_name[[:space:]]\\+.*${APP_DOMAIN}\" /etc/nginx/sites-enabled /etc/nginx/sites-available /etc/nginx/conf.d 2>/dev/null | head -n 1
|
||||
fi
|
||||
"
|
||||
)"
|
||||
fi
|
||||
|
||||
if [ -z "${NGINX_SERVER_CONFIG}" ]; then
|
||||
echo "❌ 無法自動找出 vtuber 的 nginx 設定檔,請手動指定 NGINX_SERVER_CONFIG 環境變數"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "目標主機:${REMOTE}"
|
||||
echo "目標網域:${APP_DOMAIN}"
|
||||
echo "目標 Nginx 設定:${NGINX_SERVER_CONFIG}"
|
||||
|
||||
ssh "${SSH_OPTS[@]}" "${REMOTE}" "test -f '${SNIPPET_REMOTE}' && sudo chmod 644 '${SNIPPET_REMOTE}' || true"
|
||||
ssh "${SSH_OPTS[@]}" "${REMOTE}" "test -f '${NGINX_SERVER_CONFIG}' || { echo 'Nginx 設定檔不存在:${NGINX_SERVER_CONFIG}' >&2; exit 1; }"
|
||||
scp "${SCP_OPTS[@]}" "${SNIPPET_SRC}" "${REMOTE}:${TMP_SNIPPET}"
|
||||
ssh "${SSH_OPTS[@]}" "${REMOTE}" "sudo cp '${TMP_SNIPPET}' '${SNIPPET_REMOTE}' && sudo chmod 644 '${SNIPPET_REMOTE}'"
|
||||
|
||||
ssh "${SSH_OPTS[@]}" "${REMOTE}" "
|
||||
set -euo pipefail
|
||||
sudo cp '${NGINX_SERVER_CONFIG}' '${NGINX_SERVER_CONFIG}.bak.\$(date +%F_%H%M%S)'
|
||||
if ! sudo grep -q '${NGINX_SNIPPET_TAG}' '${NGINX_SERVER_CONFIG}'; then
|
||||
sudo sed -i '/^[[:space:]]*server_name[[:space:]]\\+[^;]*;/ a\\
|
||||
include /etc/nginx/snippets/vtuber-nginx-110-live-fallback.conf;\\
|
||||
' '${NGINX_SERVER_CONFIG}'
|
||||
fi
|
||||
sudo nginx -t
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
sudo systemctl reload nginx
|
||||
else
|
||||
sudo service nginx reload
|
||||
fi
|
||||
"
|
||||
|
||||
echo "✅ 110 Nginx 404 fallback 已提交。"
|
||||
65
deploy/deploy-prod.sh
Executable file
65
deploy/deploy-prod.sh
Executable file
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
source "${SCRIPT_DIR}/.env.prod"
|
||||
|
||||
if [ -z "${DEPLOY_HOST:-}" ] || [ -z "${DEPLOY_USER:-}" ] || [ -z "${DEPLOY_DIR:-}" ]; then
|
||||
echo "請先建立 deploy/.env.prod 並設定 DEPLOY_HOST / DEPLOY_USER / DEPLOY_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SSH_OPTS=(-p "${DEPLOY_PORT:-22}")
|
||||
REMOTE="${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
|
||||
echo "Preparing deployment content to ${REMOTE}:${DEPLOY_DIR}"
|
||||
|
||||
synced=0
|
||||
|
||||
if ssh "${SSH_OPTS[@]}" "$REMOTE" "[ -d \"${DEPLOY_DIR}/.git\" ]"; then
|
||||
ssh "${SSH_OPTS[@]}" "$REMOTE" "
|
||||
set -euo pipefail
|
||||
cd \"${DEPLOY_DIR}\"
|
||||
if git show-ref --verify --quiet \"refs/heads/${DEPLOY_BRANCH}\"; then
|
||||
git fetch --all || true
|
||||
git checkout \"${DEPLOY_BRANCH}\" || true
|
||||
git pull origin \"${DEPLOY_BRANCH}\" || true
|
||||
exit 0
|
||||
else
|
||||
echo \"[warn] 遠端 git 無法找到 ${DEPLOY_BRANCH},改用 rsync 同步部署檔案。\"\n
|
||||
exit 1
|
||||
fi
|
||||
" && synced=1 || synced=0
|
||||
# 分支存在但拉取失敗時,fallback 改為 rsync
|
||||
if [ ${synced} -ne 1 ]; then
|
||||
ssh "${SSH_OPTS[@]}" "$REMOTE" "[ -d \"${DEPLOY_DIR}\" ] || mkdir -p \"${DEPLOY_DIR}\""
|
||||
fi
|
||||
else
|
||||
synced=0
|
||||
fi
|
||||
|
||||
if [ ${synced} -ne 1 ]; then
|
||||
echo "遠端未完成 git 同步,改用 rsync 直接推送部署內容..."
|
||||
rsync -av --delete \
|
||||
--exclude 'node_modules' \
|
||||
--exclude '.next' \
|
||||
--exclude '.turbo' \
|
||||
--exclude 'dist' \
|
||||
--exclude 'coverage' \
|
||||
--exclude '.env' \
|
||||
--exclude '*.log' \
|
||||
-e "ssh ${SSH_OPTS[*]}" \
|
||||
"${ROOT_DIR}/" "$REMOTE:${DEPLOY_DIR}/"
|
||||
fi
|
||||
|
||||
ssh "${SSH_OPTS[@]}" "$REMOTE" "
|
||||
set -euo pipefail
|
||||
cd \"${DEPLOY_DIR}\"
|
||||
cp deploy/.env.prod .env
|
||||
|
||||
docker compose -f deploy/docker-compose.prod.yml --env-file deploy/.env.prod down || true
|
||||
docker compose -f deploy/docker-compose.prod.yml --env-file deploy/.env.prod up -d --build
|
||||
"
|
||||
|
||||
echo "VTuber production deploy sent to ${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
69
deploy/docker-compose.prod.yml
Normal file
69
deploy/docker-compose.prod.yml
Normal file
@@ -0,0 +1,69 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:16
|
||||
container_name: vtuber-db
|
||||
environment:
|
||||
- POSTGRES_DB=vtuber
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=vtuber_local_pwd
|
||||
volumes:
|
||||
- vtuber-pg-data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres -d vtuber"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
restart: always
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/api/Dockerfile
|
||||
container_name: vtuber-api
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- PORT=${API_PORT:-4000}
|
||||
- DATABASE_URL=${DATABASE_URL}
|
||||
ports:
|
||||
- "${API_PORT:-4000}:4000"
|
||||
restart: always
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/web/Dockerfile
|
||||
container_name: vtuber-web
|
||||
depends_on:
|
||||
- api
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_PUBLIC_API_BASE_URL=http://api:4000/api
|
||||
- NEXT_PUBLIC_APP_DOMAIN=${APP_DOMAIN}
|
||||
- PORT=3000
|
||||
ports:
|
||||
- "${WEB_PORT:-3200}:3000"
|
||||
restart: always
|
||||
|
||||
admin:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: apps/admin/Dockerfile
|
||||
container_name: vtuber-admin
|
||||
depends_on:
|
||||
- api
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_PUBLIC_API_BASE_URL=http://api:4000/api
|
||||
- NEXT_PUBLIC_APP_DOMAIN=${APP_DOMAIN}
|
||||
- PORT=3001
|
||||
ports:
|
||||
- "${ADMIN_PORT:-3201}:3001"
|
||||
restart: always
|
||||
|
||||
volumes:
|
||||
vtuber-pg-data:
|
||||
11
deploy/vtuber-nginx-110-live-fallback.conf
Normal file
11
deploy/vtuber-nginx-110-live-fallback.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
# 追加到正式主機前台 Nginx server 區塊內
|
||||
# vtuber-nginx-110-live-fallback
|
||||
# 功能:發生 404 時自動導回首頁,避免走錯 host/path 看到空白頁
|
||||
# 引用方式:在 server { ... } 中加
|
||||
# include /etc/nginx/snippets/vtuber-nginx-110-live-fallback.conf;
|
||||
|
||||
error_page 404 = @vtuber_live_demo_fallback;
|
||||
|
||||
location @vtuber_live_demo_fallback {
|
||||
return 302 /live/demo;
|
||||
}
|
||||
Reference in New Issue
Block a user