#!/bin/bash # 다른 서버에 설치된 웹메이커의 "코드만" 갱신하고 재시작한다 (data/ 와 사이트 파일은 건드리지 않음). # 사용: deploy/remote-update.sh [app-dir] [service] set -euo pipefail HOST=${1:?ssh host}; APPDIR=${2:-/home/master/webmaker}; SVC=${3:-webmaker} SRC=$(cd "$(dirname "$0")/.." && pwd) echo "== 코드 전송 → $HOST:$APPDIR ($(git -C "$SRC" log --oneline -1 2>/dev/null || echo 'no git'))" tar -C "$SRC" --exclude=./data --exclude=./.git --exclude=./node_modules -cf - . | ssh "$HOST" "tar -C $APPDIR -xf - && sed -i 's#/home/master/work/WebHoting_AI_Agent/hooks/guard.sh#$APPDIR/hooks/guard.sh#' $APPDIR/hooks/settings.json" # v1.5.13: 재시작 전에 실행 중인 AI 작업이 끝날 때까지 기다린다 — claude 뿐 아니라 codex(OpenAI 서버 로그인 엔진)도. 최대 30분 (2026-10-14 11:29 UTC 배포가 codex 작업을 끊은 것을 보고 고침) ssh "$HOST" "for i in \$(seq 1 360); do pgrep -u \$(id -un) -f '[c]laude -p|[c]odex exec' >/dev/null 2>&1 && { [ \$i -eq 1 ] && echo ' AI 작업 실행 중 — 끝날 때까지 기다립니다 (최대 30분)'; sleep 5; } || break; done; sudo -n systemctl restart $SVC && sleep 1 && systemctl is-active $SVC && curl -s -o /dev/null -w 'local app: %{http_code}\n' http://127.0.0.1:\$(grep -oP 'PORT=\K[0-9]+' /etc/systemd/system/$SVC.service | head -1)/login?direct=1" # v1.5.7 (요구 1~4): 설정 파일로 옮기기(없는 항목만) · 초기 설정 페이지 서비스(webmaker-setup) 설치/재시작 · 설치된 연동 서비스 등록 점검 # v1.5.11 (요구 2): 설정 페이지 기본 포트 8795(0.0.0.0) — 유닛에 본 서비스와 같은 DATA_ROOT 를 넣고, 방화벽은 그 포트를 모든 곳에서 허용(토큰·관리자 로그인으로 보호), 옛 3081 규칙은 지운다 ssh "$HOST" bash -s "$APPDIR" "$SVC" <<'REMOTE' set -e; APPDIR=$1; SVC=$2; cd "$APPDIR" UNIT=/etc/systemd/system/$SVC.service # 본 서비스 유닛의 DATA_ROOT(있으면)를 이 셸과 설정 페이지 유닛에도 쓴다 — 같은 설정 파일·관리자 계정·토큰을 보도록. # (v1.5.11 배포 때 확인: 유닛이 DATA_ROOT=/data/webmaker 인 서버에서 이것을 빼먹으면 아래 node 명령이 앱 폴더의 data/ 에 엉뚱한 설정 파일을 만든다) DR=$(grep -oP '^Environment=DATA_ROOT=\K.*' "$UNIT" | head -1 || true) [ -n "$DR" ] && export DATA_ROOT="$DR" node scripts/config.js import-env --unit "$UNIT" >/dev/null && node scripts/config.js set service.systemdUnit "$SVC" >/dev/null mk_setup_unit() { sed -e "s#/home/master/work/WebHoting_AI_Agent#$APPDIR#g" -e "s#^Environment=PATH=.*#Environment=PATH=$HOME/.local/bin:$HOME/.npm-global/bin:/usr/local/bin:/usr/bin:/bin#" -e "s#^Environment=HOME=.*#Environment=HOME=$HOME#" -e "s#^User=.*#User=$(id -un)#" -e "s#^Group=.*#Group=$(id -gn)#" deploy/webmaker-setup.service \ | { if [ -n "$DR" ]; then sed -e "s#^\# Environment=DATA_ROOT=.*#Environment=DATA_ROOT=$DR#"; else cat; fi; } | sudo -n tee /etc/systemd/system/webmaker-setup.service >/dev/null } if [ ! -f /etc/systemd/system/webmaker-setup.service ] || { [ -n "$DR" ] && ! grep -q "^Environment=DATA_ROOT=$DR" /etc/systemd/system/webmaker-setup.service; }; then mk_setup_unit printf '%s ALL=(root) NOPASSWD: /usr/bin/systemctl restart %s, /usr/bin/systemctl restart webmaker-setup\n' "$(id -un)" "$SVC" | sudo -n tee /etc/sudoers.d/webmaker-setup >/dev/null && sudo -n chmod 440 /etc/sudoers.d/webmaker-setup sudo -n systemctl daemon-reload && sudo -n systemctl enable --now webmaker-setup >/dev/null && echo "webmaker-setup 설치 (초기 설정 페이지)" fi sudo -n systemctl restart webmaker-setup; sleep 1 # 방화벽(ufw): 설정 페이지 포트를 허용(접속은 토큰·관리자 로그인·시도 제한으로 보호). 1.5.7 의 3081 사설망 규칙은 지운다 SP=$(node scripts/config.js get service.setupPort); SP=${SP:-8795} if command -v ufw >/dev/null 2>&1 && sudo -n ufw status 2>/dev/null | grep -q '^Status: active'; then for net in 192.168.20.0/24 192.168.10.0/24; do sudo -n ufw delete allow from "$net" to any port 3081 proto tcp >/dev/null 2>&1 || true; done sudo -n ufw allow "$SP"/tcp comment 'AI Webmaker setup page' >/dev/null fi deploy/install-services.sh --check --service "$SVC" 2>&1 | sed 's/^/ /' || true # v1.6.31 (요구 29): 재시작·코드 교체 전에 데이터를 백업한다 (DATA_ROOT/backups, 최근 10개 보관) echo " == 데이터 백업"; node scripts/backup-data.js --tag update 2>&1 | sed 's/^/ /' || echo " 백업 실패 — 그래도 갱신을 계속합니다 (수동 백업 권장)" # v1.5.31 (요구 4): 서비스 유닛의 보안 옵션(NoNewPrivileges·ProtectSystem) 점검 — 문제가 있으면 드롭인으로 보정하는 명령을 안내한다 (scripts/unit-check.js). # FIX_UNIT=1 로 실행하면 드롭인을 만들고(재시작은 아래 서비스 재시작이 겸한다) 운영자가 유닛 파일을 손으로 고치지 않아도 된다. echo " == 서비스 유닛 권한 점검"; if [ "${FIX_UNIT:-0}" = "1" ]; then sudo -n node scripts/unit-check.js --fix --unit "$SVC" 2>&1 | sed 's/^/ /' && sudo -n systemctl daemon-reload || true; else node scripts/unit-check.js --unit "$SVC" 2>&1 | sed 's/^/ /' || true; fi # v1.5.17 (요구 1): 서버에 미리 받아 둔 와일드카드 인증서 감지 (적용은 재시작된 서비스가 기동 때 함) echo " == 와일드카드 인증서"; node scripts/ssl-wildcard.js 2>&1 | sed 's/^/ /' || true echo "초기 설정 페이지: $(node scripts/config.js setup-url | head -1)" REMOTE