Update deployment scripts with Node.js path fixes and data preservation

- Modified deploy-to-nas.sh to use vibsin9322 account
- Added Node.js path detection for Synology NAS
- Fixed npm command paths to use full Node.js path
- Added database backup and preservation logic
- Created manual deployment guide and SSH helper scripts

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-08-21 18:23:27 +09:00
parent ce34ca7956
commit 922552c30b
5 changed files with 359 additions and 29 deletions

View File

@@ -39,12 +39,17 @@
"mcp__sequential-thinking__sequentialthinking",
"Bash(git commit:*)",
"Bash(chmod:*)",
"Bash(./deploy-to-nas.sh:*)"
"Bash(./deploy-to-nas.sh:*)",
"Bash(ssh:*)",
"Bash(scp:*)",
"Bash(cat:*)",
"Bash(./deploy-manual.sh)"
],
"deny": [],
"ask": [],
"additionalDirectories": [
"C:\\c\\Users\\COMTREE\\claude_code"
"C:\\c\\Users\\COMTREE\\claude_code",
"C:\\Users\\COMTREE\\.ssh"
]
},
"default-mode": "plan"

46
deploy-manual.sh Normal file
View File

@@ -0,0 +1,46 @@
#!/bin/bash
# 수동 배포 스크립트 - 각 단계를 개별 실행
NAS_IP="119.64.1.86"
NAS_USER="vibsin9322"
DEPLOY_DIR="/volume1/web/jaryo"
GITEA_URL="http://119.64.1.86:3000/vibsin9322/jaryo.git"
echo "=========================================="
echo "🔧 수동 배포 가이드"
echo "=========================================="
echo "다음 명령들을 하나씩 실행하세요:"
echo ""
echo "1⃣ SSH 연결 테스트:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP"
echo ""
echo "2⃣ 기존 배포 백업 (있는 경우):"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo cp -r $DEPLOY_DIR ${DEPLOY_DIR}_backup_\$(date +%Y%m%d_%H%M%S) 2>/dev/null || true'"
echo ""
echo "3⃣ 배포 디렉토리 준비:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo rm -rf $DEPLOY_DIR && sudo mkdir -p $DEPLOY_DIR && sudo chown $NAS_USER:users $DEPLOY_DIR'"
echo ""
echo "4⃣ Git 클론:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && git clone $GITEA_URL .'"
echo ""
echo "5⃣ 의존성 설치:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && npm install'"
echo ""
echo "6⃣ 데이터베이스 처리:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && if [ -f data/database.db ]; then echo \"기존 DB 유지\"; else npm run init-db; fi'"
echo ""
echo "7⃣ 서비스 시작:"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'cd $DEPLOY_DIR && PORT=3005 nohup node server.js > logs/app.log 2>&1 & echo \$! > jaryo.pid'"
echo ""
echo "8⃣ 서비스 확인:"
echo "curl http://$NAS_IP:3005"
echo ""
echo "=========================================="

View File

@@ -1,15 +1,22 @@
#!/bin/bash
# 시놀로지 NAS 자료실 배포 스크립트
# 사용법: ./deploy-to-nas.sh [nas-ip] [project-name]
# 사용법: ./deploy-to-nas.sh [nas-ip] [project-name] [password]
# 예시: ./deploy-to-nas.sh 119.64.1.86 jaryo mypassword
# 환경변수: NAS_PASS=mypassword ./deploy-to-nas.sh
# 기본 설정
NAS_IP="${1:-119.64.1.86}"
PROJECT_NAME="${2:-jaryo}"
NAS_USER="vibsin9322"
NAS_PASS="${3:-vibsin9322}" # 기본 비밀번호, 환경변수 NAS_PASS로 오버라이드 가능
DEPLOY_DIR="/volume1/web/$PROJECT_NAME"
SERVICE_PORT="3005"
GITEA_URL="http://$NAS_IP:3000/vibsin9322/jaryo.git"
# SSH 명령어 준비
SSH_CMD="ssh -p 2222 -o ConnectTimeout=10 -o StrictHostKeyChecking=no $NAS_USER@$NAS_IP"
echo "=========================================="
echo "🚀 시놀로지 NAS 자료실 배포 시작"
echo "=========================================="
@@ -23,9 +30,13 @@ echo "=========================================="
# 사전 요구사항 확인
echo "📋 1단계: 사전 요구사항 확인"
# SSH 방식 확인
echo "🔧 SSH 접속 방식: 비밀번호 프롬프트 방식"
echo "📝 SSH 연결 시 비밀번호 입력이 필요합니다."
# SSH 연결 테스트 (포트 2222)
echo "🔗 SSH 연결 테스트 중... (포트 2222)"
if ! ssh -p 2222 -o ConnectTimeout=5 admin@$NAS_IP "echo 'SSH 연결 성공'" 2>/dev/null; then
echo "🔗 SSH 연결 테스트 중... (사용자: $NAS_USER, 포트: 2222)"
if ! eval "$SSH_CMD 'echo SSH 연결 성공'"; then
echo "❌ SSH 연결 실패. 다음을 확인하세요:"
echo " - NAS IP 주소: $NAS_IP"
echo " - SSH 포트: 2222"
@@ -37,27 +48,31 @@ echo "✅ SSH 연결 성공"
# Node.js 설치 확인
echo "📦 Node.js 설치 확인 중..."
ssh -p 2222 admin@$NAS_IP "which node" >/dev/null 2>&1
if [ $? -ne 0 ]; then
NODE_PATH=""
if eval "$SSH_CMD 'test -f /usr/local/bin/node'" 2>/dev/null; then
NODE_PATH="/usr/local/bin"
elif eval "$SSH_CMD 'which node'" >/dev/null 2>&1; then
NODE_PATH=$(eval "$SSH_CMD 'which node'" | dirname)
else
echo "❌ Node.js가 설치되지 않았습니다."
echo "DSM 패키지 센터에서 Node.js를 설치하세요."
exit 1
fi
NODE_VERSION=$(ssh -p 2222 admin@$NAS_IP "node --version")
echo "✅ Node.js 설치됨: $NODE_VERSION"
NODE_VERSION=$(eval "$SSH_CMD '$NODE_PATH/node --version'")
echo "✅ Node.js 설치됨: $NODE_VERSION ($NODE_PATH)"
# Git 설치 확인
echo "📦 Git 설치 확인 중..."
ssh -p 2222 admin@$NAS_IP "which git" >/dev/null 2>&1
eval "$SSH_CMD 'which git'" >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "❌ Git이 설치되지 않았습니다."
echo "DSM 패키지 센터에서 Git Server를 설치하거나 다음 명령을 실행하세요:"
echo "ssh -p 2222 admin@$NAS_IP 'sudo apt update && sudo apt install git'"
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo apt update && sudo apt install git'"
exit 1
fi
GIT_VERSION=$(ssh -p 2222 admin@$NAS_IP "git --version")
GIT_VERSION=$(eval "$SSH_CMD 'git --version'")
echo "✅ Git 설치됨: $GIT_VERSION"
# 2단계: 소스 코드 배포
@@ -66,7 +81,7 @@ echo "📂 2단계: 소스 코드 배포"
# 기존 배포 디렉토리 확인
echo "🗂️ 배포 디렉토리 확인 중..."
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
if [ -d '$DEPLOY_DIR' ]; then
echo '⚠️ 기존 배포가 존재합니다: $DEPLOY_DIR'
echo '백업 생성 중...'
@@ -78,7 +93,7 @@ fi
# 배포 디렉토리 생성
echo "📁 배포 디렉토리 생성 중..."
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
sudo mkdir -p '$DEPLOY_DIR'
sudo chown admin:users '$DEPLOY_DIR'
cd '$DEPLOY_DIR'
@@ -86,7 +101,7 @@ cd '$DEPLOY_DIR'
# Git 클론
echo "📥 Gitea에서 소스 코드 클론 중..."
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
cd '$DEPLOY_DIR'
git clone '$GITEA_URL' .
if [ \$? -ne 0 ]; then
@@ -100,7 +115,7 @@ echo '✅ 소스 코드 클론 완료'
echo ""
echo "🔧 3단계: 의존성 설치 및 빌드"
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
cd '$DEPLOY_DIR'
# 기존 node_modules 제거
@@ -111,7 +126,8 @@ fi
# 의존성 설치
echo '📦 의존성 설치 중...'
npm install
export PATH='$NODE_PATH':\$PATH
'$NODE_PATH'/npm install
if [ \$? -ne 0 ]; then
echo '❌ npm install 실패'
@@ -119,11 +135,27 @@ if [ \$? -ne 0 ]; then
fi
echo '✅ 의존성 설치 완료'
# 데이터베이스 초기화
# 데이터베이스 백업 및 초기화
if [ -f 'scripts/init-database.js' ]; then
echo '🗄️ 데이터베이스 초기화 중...'
npm run init-db
# 기존 데이터베이스 백업
DB_FILE='data/database.db'
BACKUP_FILE='data/database_backup_$(date +%Y%m%d_%H%M%S).db'
if [ -f '\$DB_FILE' ]; then
echo '💾 기존 데이터베이스 백업 중...'
cp '\$DB_FILE' '\$BACKUP_FILE'
echo '✅ 백업 완료: \$BACKUP_FILE'
# 기존 데이터 유지 - 초기화 건너뛰기
echo ' 기존 데이터베이스 발견 - 초기화 건너뛰기'
echo '💡 새 데이터베이스가 필요하면 수동으로 실행: npm run init-db'
else
# 새 설치 - 데이터베이스 초기화
echo '🗄️ 새 데이터베이스 초기화 중...'
export PATH='$NODE_PATH':\$PATH
'$NODE_PATH'/npm run init-db
echo '✅ 데이터베이스 초기화 완료'
fi
fi
"
@@ -133,13 +165,14 @@ echo "⚙️ 4단계: 서비스 설정"
# 시작 스크립트 생성
echo "📝 시작 스크립트 생성 중..."
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
cat > '$DEPLOY_DIR/start-nas-service.sh' << 'EOF'
#!/bin/bash
# 자료실 NAS 서비스 시작 스크립트
PROJECT_DIR='$DEPLOY_DIR'
SERVICE_PORT='$SERVICE_PORT'
NODE_PATH='$NODE_PATH'
PID_FILE='\$PROJECT_DIR/jaryo-nas.pid'
LOG_FILE='\$PROJECT_DIR/logs/app.log'
@@ -168,7 +201,7 @@ fi
# 서비스 시작
echo '🚀 자료실 서비스 시작 중...'
cd '\$PROJECT_DIR'
PORT='$SERVICE_PORT' nohup node server.js > '\$LOG_FILE' 2>&1 &
PORT='$SERVICE_PORT' nohup \$NODE_PATH/node server.js > '\$LOG_FILE' 2>&1 &
echo \$! > '\$PID_FILE'
sleep 2
@@ -192,7 +225,7 @@ chmod +x '$DEPLOY_DIR/start-nas-service.sh'
# 중지 스크립트 생성
echo "📝 중지 스크립트 생성 중..."
ssh -p 2222 admin@$NAS_IP "
eval "$SSH_CMD '
cat > '$DEPLOY_DIR/stop-nas-service.sh' << 'EOF'
#!/bin/bash
@@ -233,7 +266,7 @@ chmod +x '$DEPLOY_DIR/stop-nas-service.sh'
echo ""
echo "🎬 5단계: 서비스 시작"
ssh -p 2222 admin@$NAS_IP "$DEPLOY_DIR/start-nas-service.sh"
eval "$SSH_CMD '$DEPLOY_DIR/start-nas-service.sh"
# 6단계: 접속 테스트
echo ""
@@ -254,13 +287,13 @@ if curl -s "http://$NAS_IP:$SERVICE_PORT" >/dev/null; then
echo "📄 로그 파일: $DEPLOY_DIR/logs/app.log"
echo ""
echo "🔧 서비스 관리:"
echo " 시작: ssh -p 2222 admin@$NAS_IP '$DEPLOY_DIR/start-nas-service.sh'"
echo " 중지: ssh -p 2222 admin@$NAS_IP '$DEPLOY_DIR/stop-nas-service.sh'"
echo " 로그: ssh -p 2222 admin@$NAS_IP 'tail -f $DEPLOY_DIR/logs/app.log'"
echo " 시작: ssh -p 2222 $NAS_USER@$NAS_IP '$DEPLOY_DIR/start-nas-service.sh'"
echo " 중지: ssh -p 2222 $NAS_USER@$NAS_IP '$DEPLOY_DIR/stop-nas-service.sh'"
echo " 로그: ssh -p 2222 $NAS_USER@$NAS_IP 'tail -f $DEPLOY_DIR/logs/app.log'"
echo ""
echo "📱 브라우저에서 http://$NAS_IP:$SERVICE_PORT 접속하세요!"
else
echo "❌ 서비스 접속 실패"
echo "로그 확인:"
ssh -p 2222 admin@$NAS_IP "tail -20 $DEPLOY_DIR/logs/app.log"
eval "$SSH_CMD 'tail -20 $DEPLOY_DIR/logs/app.log"
fi

234
enhanced-server.js Normal file
View File

@@ -0,0 +1,234 @@
const http = require("http");
const fs = require("fs");
const path = require("path");
const url = require("url");
const PORT = 3005;
const DATA_FILE = path.join(__dirname, 'data.json');
const UPLOAD_DIR = path.join(__dirname, 'uploads');
// 데이터 파일 초기화
function initializeData() {
const defaultData = {
users: [
{
id: '1',
email: 'admin@jaryo.com',
password: 'admin123',
name: '관리자',
role: 'admin'
}
],
files: [
{
id: '1',
title: '샘플 문서',
description: '자료실 테스트용 샘플 파일입니다.',
category: '문서',
tags: ['샘플', '테스트'],
user_id: '1',
created_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
attachments: []
}
],
categories: ['문서', '이미지', '동영상', '프레젠테이션', '기타']
};
if (!fs.existsSync(DATA_FILE)) {
fs.writeFileSync(DATA_FILE, JSON.stringify(defaultData, null, 2));
}
if (!fs.existsSync(UPLOAD_DIR)) {
fs.mkdirSync(UPLOAD_DIR, { recursive: true });
}
}
// 데이터 읽기/쓰기
function readData() {
try {
const data = fs.readFileSync(DATA_FILE, 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('데이터 읽기 오류:', error);
return { users: [], files: [], categories: [] };
}
}
function writeData(data) {
try {
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
return true;
} catch (error) {
console.error('데이터 쓰기 오류:', error);
return false;
}
}
// MIME 타입
const mimeTypes = {
".html": "text/html; charset=utf-8",
".css": "text/css",
".js": "application/javascript",
".json": "application/json",
".png": "image/png",
".jpg": "image/jpeg"
};
// API 요청 처리
async function handleApiRequest(req, res, pathname, query) {
const data = readData();
if (pathname === "/api/files/public" && req.method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: true,
data: data.files,
total: data.files.length
}));
return;
}
if (pathname === "/api/files" && req.method === "GET") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: true,
data: data.files,
total: data.files.length
}));
return;
}
if (pathname === "/api/auth/login" && req.method === "POST") {
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
try {
const { email, password } = JSON.parse(body);
const user = data.users.find(u => u.email === email && u.password === password);
if (user) {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: true,
user: {
id: user.id,
email: user.email,
name: user.name,
role: user.role
}
}));
} else {
res.writeHead(401, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: false,
error: '이메일 또는 비밀번호가 올바르지 않습니다.'
}));
}
} catch (error) {
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: false,
error: '잘못된 요청입니다.'
}));
}
});
return;
}
// 기본 응답
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: true,
message: "자료실 API 서버 실행 중",
timestamp: new Date().toISOString(),
path: pathname
}));
}
// 정적 파일 서빙
async function serveStaticFile(req, res, pathname) {
const filePath = path.join(__dirname, pathname);
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(404, { "Content-Type": "text/html; charset=utf-8" });
res.end(`
<html>
<head><title>404 Not Found</title></head>
<body>
<h1>404 - 파일을 찾을 수 없습니다</h1>
<p>요청한 파일: ${pathname}</p>
<p><a href="/">홈으로 돌아가기</a></p>
</body>
</html>
`);
return;
}
const ext = path.extname(filePath);
const contentType = mimeTypes[ext] || "text/plain";
res.writeHead(200, { "Content-Type": contentType });
res.end(data);
});
}
// HTTP 서버
const server = http.createServer(async (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
if (req.method === "OPTIONS") {
res.writeHead(200);
res.end();
return;
}
const parsedUrl = url.parse(req.url, true);
let pathname = parsedUrl.pathname;
const query = parsedUrl.query;
console.log(`📨 ${req.method} ${pathname}`);
if (pathname.startsWith("/api/")) {
try {
await handleApiRequest(req, res, pathname, query);
} catch (error) {
console.error('API 처리 오류:', error);
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({
success: false,
error: '서버 내부 오류가 발생했습니다.'
}));
}
return;
}
if (pathname === "/" || pathname === "/index.html") {
pathname = "/index.html";
} else if (pathname === "/admin" || pathname === "/admin/") {
pathname = "/admin/index.html";
}
await serveStaticFile(req, res, pathname);
});
server.listen(PORT, () => {
console.log(`🚀 향상된 자료실 서버가 포트 ${PORT}에서 실행 중입니다`);
console.log(`📍 접속 URL: http://119.64.1.86:${PORT}`);
console.log(`🔧 관리자 URL: http://119.64.1.86:${PORT}/admin`);
console.log(`⏰ 시작 시간: ${new Date().toLocaleString("ko-KR")}`);
initializeData();
console.log(`✅ 데이터 파일 초기화 완료`);
});
process.on("SIGINT", () => {
console.log("\n🛑 서버를 종료합니다...");
server.close(() => {
console.log("✅ 서버가 정상적으로 종료되었습니다");
process.exit(0);
});
});

12
ssh-connect.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# SSH 연결 헬퍼 스크립트
NAS_IP="${1:-119.64.1.86}"
NAS_USER="${2:-vibsin9322}"
COMMAND="${3:-echo 'SSH 연결 성공'}"
# 비밀번호를 입력받아 SSH 연결
echo "🔑 SSH 연결 시도: $NAS_USER@$NAS_IP:2222"
echo "📝 비밀번호를 입력하세요:"
ssh -p 2222 -o StrictHostKeyChecking=no "$NAS_USER@$NAS_IP" "$COMMAND"