Compare commits
10 Commits
6f68196127
...
ec2e9abcad
Author | SHA1 | Date | |
---|---|---|---|
ec2e9abcad | |||
922552c30b | |||
ce34ca7956 | |||
6477a488c2 | |||
c6ec1c3720 | |||
08894eeb66 | |||
ec5da4db32 | |||
ce29d6bc3b | |||
43d0802442 | |||
9b9eb7f321 |
@@ -36,12 +36,20 @@
|
|||||||
"Bash(tasklist)",
|
"Bash(tasklist)",
|
||||||
"Bash(start http://localhost:8000)",
|
"Bash(start http://localhost:8000)",
|
||||||
"Bash(npm --version)",
|
"Bash(npm --version)",
|
||||||
"mcp__sequential-thinking__sequentialthinking"
|
"mcp__sequential-thinking__sequentialthinking",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(chmod:*)",
|
||||||
|
"Bash(./deploy-to-nas.sh:*)",
|
||||||
|
"Bash(ssh:*)",
|
||||||
|
"Bash(scp:*)",
|
||||||
|
"Bash(cat:*)",
|
||||||
|
"Bash(./deploy-manual.sh)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": [],
|
"ask": [],
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"C:\\c\\Users\\COMTREE\\claude_code"
|
"C:\\c\\Users\\COMTREE\\claude_code",
|
||||||
|
"C:\\Users\\COMTREE\\.ssh"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"default-mode": "plan"
|
"default-mode": "plan"
|
||||||
|
@@ -29,7 +29,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
header h1 {
|
||||||
color: #4a5568;
|
color: #667eea;
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
298
alternative-git-servers.md
Normal file
298
alternative-git-servers.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
# 시놀로지 NAS 대안 Git 서버 설치 방안
|
||||||
|
|
||||||
|
## 🚀 개요
|
||||||
|
|
||||||
|
시놀로지 Git Server 패키지가 작동하지 않을 때 사용할 수 있는 대안적인 Git 서버 설치 방법들을 제공합니다.
|
||||||
|
|
||||||
|
## 🐳 방법 1: Docker를 이용한 Gitea 설치 (권장)
|
||||||
|
|
||||||
|
### 1.1 장점
|
||||||
|
- 웹 기반 Git 관리 인터페이스
|
||||||
|
- GitHub와 유사한 사용자 경험
|
||||||
|
- 이슈 관리, 위키, 프로젝트 관리 기능
|
||||||
|
- 가벼움 (Go 언어 기반)
|
||||||
|
|
||||||
|
### 1.2 설치 과정
|
||||||
|
|
||||||
|
#### Docker 설치 확인
|
||||||
|
```bash
|
||||||
|
# DSM > 패키지 센터 > Docker 설치
|
||||||
|
# 또는 SSH에서 확인
|
||||||
|
docker --version
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Gitea 컨테이너 실행
|
||||||
|
```bash
|
||||||
|
# SSH로 NAS 접속
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# Gitea 데이터 디렉토리 생성
|
||||||
|
sudo mkdir -p /volume1/docker/gitea
|
||||||
|
|
||||||
|
# Gitea 컨테이너 실행
|
||||||
|
docker run -d \
|
||||||
|
--name gitea \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-p 222:22 \
|
||||||
|
-v /volume1/docker/gitea:/data \
|
||||||
|
-e USER_UID=1000 \
|
||||||
|
-e USER_GID=1000 \
|
||||||
|
gitea/gitea:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 웹 설정
|
||||||
|
1. 브라우저에서 `http://your-nas-ip:3000` 접속
|
||||||
|
2. 초기 설정 완료:
|
||||||
|
- 데이터베이스: SQLite3 (기본)
|
||||||
|
- 관리자 계정 생성
|
||||||
|
- 저장소 루트 경로: `/data/git/repositories`
|
||||||
|
|
||||||
|
### 1.3 저장소 생성 및 연결
|
||||||
|
```bash
|
||||||
|
# 웹 인터페이스에서 새 저장소 'jaryo-file-manager' 생성
|
||||||
|
# 로컬에서 연결
|
||||||
|
git remote add gitea http://your-nas-ip:3000/username/jaryo-file-manager.git
|
||||||
|
git push gitea master
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📦 방법 2: 순수 Git 서버 설치
|
||||||
|
|
||||||
|
### 2.1 수동 Git 설치
|
||||||
|
```bash
|
||||||
|
# SSH로 NAS 접속
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# 패키지 관리자 업데이트
|
||||||
|
sudo apt update
|
||||||
|
|
||||||
|
# Git 설치
|
||||||
|
sudo apt install git git-daemon-run
|
||||||
|
|
||||||
|
# 버전 확인
|
||||||
|
git --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2 Git 서비스 설정
|
||||||
|
```bash
|
||||||
|
# Git 사용자 생성
|
||||||
|
sudo adduser git
|
||||||
|
sudo su git
|
||||||
|
cd /home/git
|
||||||
|
|
||||||
|
# SSH 키 디렉토리 생성
|
||||||
|
mkdir .ssh && chmod 700 .ssh
|
||||||
|
touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys
|
||||||
|
|
||||||
|
# Git 저장소 디렉토리 생성
|
||||||
|
mkdir /home/git/repositories
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 systemd 서비스 설정
|
||||||
|
```bash
|
||||||
|
# Git daemon 서비스 파일 생성
|
||||||
|
sudo tee /etc/systemd/system/git-daemon.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Git Daemon
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/home/git/repositories --export-all --verbose --enable=receive-pack
|
||||||
|
Restart=always
|
||||||
|
User=git
|
||||||
|
Group=git
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 서비스 활성화
|
||||||
|
sudo systemctl enable git-daemon
|
||||||
|
sudo systemctl start git-daemon
|
||||||
|
sudo systemctl status git-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.4 저장소 생성
|
||||||
|
```bash
|
||||||
|
# git 사용자로 전환
|
||||||
|
sudo su git
|
||||||
|
cd /home/git/repositories
|
||||||
|
|
||||||
|
# bare 저장소 생성
|
||||||
|
git init --bare jaryo-file-manager.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 방법 3: GitLab CE Docker 설치
|
||||||
|
|
||||||
|
### 3.1 특징
|
||||||
|
- 기업급 Git 관리 플랫폼
|
||||||
|
- CI/CD 파이프라인 지원
|
||||||
|
- 이슈 추적, 위키, 프로젝트 관리
|
||||||
|
- 더 많은 리소스 필요
|
||||||
|
|
||||||
|
### 3.2 설치 과정
|
||||||
|
```bash
|
||||||
|
# GitLab 데이터 디렉토리 생성
|
||||||
|
sudo mkdir -p /volume1/docker/gitlab/{config,logs,data}
|
||||||
|
|
||||||
|
# GitLab 컨테이너 실행 (최소 4GB RAM 권장)
|
||||||
|
docker run -d \
|
||||||
|
--hostname your-nas-ip \
|
||||||
|
--name gitlab \
|
||||||
|
-p 8080:80 \
|
||||||
|
-p 8443:443 \
|
||||||
|
-p 8022:22 \
|
||||||
|
-v /volume1/docker/gitlab/config:/etc/gitlab \
|
||||||
|
-v /volume1/docker/gitlab/logs:/var/log/gitlab \
|
||||||
|
-v /volume1/docker/gitlab/data:/var/opt/gitlab \
|
||||||
|
gitlab/gitlab-ce:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 초기 설정
|
||||||
|
```bash
|
||||||
|
# 컨테이너 시작 대기 (2-3분)
|
||||||
|
docker logs -f gitlab
|
||||||
|
|
||||||
|
# 브라우저에서 http://your-nas-ip:8080 접속
|
||||||
|
# 초기 root 비밀번호 확인
|
||||||
|
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 방법 4: Forgejo (Gitea Fork) 설치
|
||||||
|
|
||||||
|
### 4.1 특징
|
||||||
|
- Gitea의 커뮤니티 중심 포크
|
||||||
|
- 더 빠른 개발 주기
|
||||||
|
- 오픈소스 중심
|
||||||
|
|
||||||
|
### 4.2 설치 과정
|
||||||
|
```bash
|
||||||
|
# Forgejo 데이터 디렉토리 생성
|
||||||
|
sudo mkdir -p /volume1/docker/forgejo
|
||||||
|
|
||||||
|
# Forgejo 컨테이너 실행
|
||||||
|
docker run -d \
|
||||||
|
--name forgejo \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-p 222:22 \
|
||||||
|
-v /volume1/docker/forgejo:/data \
|
||||||
|
-e USER_UID=1000 \
|
||||||
|
-e USER_GID=1000 \
|
||||||
|
codeberg.org/forgejo/forgejo:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 방법 5: 간단한 HTTP Git 서버
|
||||||
|
|
||||||
|
### 5.1 Python 기반 간단 서버
|
||||||
|
```bash
|
||||||
|
# Python Git HTTP 서버 스크립트 생성
|
||||||
|
cat > /volume1/web/git-http-server.py << 'EOF'
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import http.server
|
||||||
|
import socketserver
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
class GitHTTPHandler(http.server.SimpleHTTPRequestHandler):
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path.endswith('.git/info/refs'):
|
||||||
|
# Git 정보 요청 처리
|
||||||
|
self.send_response(200)
|
||||||
|
self.send_header('Content-type', 'text/plain')
|
||||||
|
self.end_headers()
|
||||||
|
|
||||||
|
repo_path = self.path.split('/')[1]
|
||||||
|
git_dir = f'/volume1/git/{repo_path}'
|
||||||
|
|
||||||
|
if os.path.exists(git_dir):
|
||||||
|
proc = Popen(['git', 'upload-pack', '--advertise-refs', git_dir],
|
||||||
|
stdout=PIPE, stderr=PIPE)
|
||||||
|
output, _ = proc.communicate()
|
||||||
|
self.wfile.write(output)
|
||||||
|
else:
|
||||||
|
self.wfile.write(b'Repository not found')
|
||||||
|
else:
|
||||||
|
super().do_GET()
|
||||||
|
|
||||||
|
PORT = 8000
|
||||||
|
with socketserver.TCPServer(("", PORT), GitHTTPHandler) as httpd:
|
||||||
|
print(f"Git HTTP Server running on port {PORT}")
|
||||||
|
httpd.serve_forever()
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 실행 권한 부여
|
||||||
|
chmod +x /volume1/web/git-http-server.py
|
||||||
|
|
||||||
|
# 서버 실행
|
||||||
|
python3 /volume1/web/git-http-server.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔀 방법별 비교표
|
||||||
|
|
||||||
|
| 방법 | 난이도 | 리소스 사용량 | 기능 | 웹 UI | 권장도 |
|
||||||
|
|------|--------|---------------|------|-------|--------|
|
||||||
|
| Gitea | 쉬움 | 낮음 | 풍부 | ✅ | ⭐⭐⭐⭐⭐ |
|
||||||
|
| 순수 Git | 보통 | 매우 낮음 | 기본 | ❌ | ⭐⭐⭐ |
|
||||||
|
| GitLab CE | 어려움 | 높음 | 매우 풍부 | ✅ | ⭐⭐⭐⭐ |
|
||||||
|
| Forgejo | 쉬움 | 낮음 | 풍부 | ✅ | ⭐⭐⭐⭐ |
|
||||||
|
| Python 서버 | 보통 | 낮음 | 제한적 | ❌ | ⭐⭐ |
|
||||||
|
|
||||||
|
## 🚀 빠른 시작 가이드 (Gitea 권장)
|
||||||
|
|
||||||
|
### 1단계: Docker 설치 확인
|
||||||
|
```bash
|
||||||
|
# DSM 패키지 센터에서 Docker 설치
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2단계: Gitea 설치
|
||||||
|
```bash
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
sudo mkdir -p /volume1/docker/gitea
|
||||||
|
docker run -d --name gitea -p 3000:3000 -p 222:22 -v /volume1/docker/gitea:/data gitea/gitea:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3단계: 웹 설정
|
||||||
|
- `http://your-nas-ip:3000` 접속
|
||||||
|
- 초기 설정 완료
|
||||||
|
- 관리자 계정 생성
|
||||||
|
|
||||||
|
### 4단계: 저장소 생성 및 연결
|
||||||
|
```bash
|
||||||
|
# 웹에서 새 저장소 생성
|
||||||
|
# 로컬에서 연결
|
||||||
|
cd /c/Users/COMTREE/claude_code/jaryo
|
||||||
|
git remote add gitea http://your-nas-ip:3000/admin/jaryo-file-manager.git
|
||||||
|
git push gitea master
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ 문제 해결
|
||||||
|
|
||||||
|
### Docker 관련 문제
|
||||||
|
```bash
|
||||||
|
# 컨테이너 상태 확인
|
||||||
|
docker ps -a
|
||||||
|
|
||||||
|
# 로그 확인
|
||||||
|
docker logs gitea
|
||||||
|
|
||||||
|
# 컨테이너 재시작
|
||||||
|
docker restart gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
### 포트 충돌 문제
|
||||||
|
```bash
|
||||||
|
# 사용 중인 포트 확인
|
||||||
|
sudo netstat -tulpn | grep :3000
|
||||||
|
|
||||||
|
# 다른 포트 사용
|
||||||
|
docker run -d --name gitea -p 3001:3000 -p 223:22 -v /volume1/docker/gitea:/data gitea/gitea:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### 권한 문제
|
||||||
|
```bash
|
||||||
|
# 데이터 디렉토리 권한 수정
|
||||||
|
sudo chown -R 1000:1000 /volume1/docker/gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
이 가이드를 통해 시놀로지 NAS Git Server 패키지 문제를 우회하여 안정적인 Git 서버를 구축할 수 있습니다.
|
@@ -5,20 +5,31 @@ const API_BASE_URL = '';
|
|||||||
|
|
||||||
// API 요청 헬퍼 함수
|
// API 요청 헬퍼 함수
|
||||||
async function apiRequest(url, options = {}) {
|
async function apiRequest(url, options = {}) {
|
||||||
|
console.log(`🔗 API 요청: ${url}`);
|
||||||
|
|
||||||
|
try {
|
||||||
const response = await fetch(`${API_BASE_URL}${url}`, {
|
const response = await fetch(`${API_BASE_URL}${url}`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
...options.headers
|
...options.headers
|
||||||
},
|
},
|
||||||
|
timeout: 10000, // 10초 타임아웃
|
||||||
...options
|
...options
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(`📡 응답 상태: ${response.status} ${response.statusText}`);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const error = await response.text();
|
const error = await response.text();
|
||||||
|
console.error(`❌ API 오류: ${response.status} - ${error}`);
|
||||||
throw new Error(`API Error: ${response.status} - ${error}`);
|
throw new Error(`API Error: ${response.status} - ${error}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`🚨 네트워크 오류:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 공개 파일 목록 조회
|
// 공개 파일 목록 조회
|
||||||
|
40
api/files.js
Normal file
40
api/files.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// 파일 API
|
||||||
|
module.exports = (req, res) => {
|
||||||
|
// CORS 헤더 설정
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.status(200).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 샘플 파일 데이터
|
||||||
|
const files = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '샘플 문서',
|
||||||
|
description: '데모용 파일입니다',
|
||||||
|
category: '문서',
|
||||||
|
tags: ['샘플', '테스트'],
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
file_url: '#'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '이미지 파일',
|
||||||
|
description: '예시 이미지',
|
||||||
|
category: '이미지',
|
||||||
|
tags: ['샘플'],
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
file_url: '#'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: files,
|
||||||
|
message: '파일 목록을 성공적으로 불러왔습니다.'
|
||||||
|
});
|
||||||
|
};
|
4
api/index.js
Normal file
4
api/index.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
const app = require('../server');
|
||||||
|
|
||||||
|
// Vercel 서버리스 함수로 export
|
||||||
|
module.exports = app;
|
124
api/simple.js
Normal file
124
api/simple.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// Vercel Serverless 함수 핸들러
|
||||||
|
module.exports = function handler(req, res) {
|
||||||
|
// CORS 헤더 설정
|
||||||
|
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');
|
||||||
|
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.status(200).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { url, method } = req;
|
||||||
|
|
||||||
|
// 헬스 체크
|
||||||
|
if (url === '/health' || url === '/api/health') {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Jaryo File Manager is running',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
environment: process.env.NODE_ENV || 'production',
|
||||||
|
path: url
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 루트 경로
|
||||||
|
if (url === '/' || url === '/api') {
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end(`
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Jaryo File Manager</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background-color: #f5f5f5; }
|
||||||
|
.container { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
|
||||||
|
h1 { color: #333; text-align: center; }
|
||||||
|
.status { background: #e8f5e8; border: 1px solid #4caf50; padding: 15px; border-radius: 5px; margin: 20px 0; }
|
||||||
|
.feature { background: #f0f8ff; border: 1px solid #2196f3; padding: 15px; border-radius: 5px; margin: 10px 0; }
|
||||||
|
.button { background: #4caf50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; text-decoration: none; display: inline-block; margin: 5px; }
|
||||||
|
.button:hover { background: #45a049; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>🚀 Jaryo File Manager</h1>
|
||||||
|
<div class="status">
|
||||||
|
<h3>✅ 배포 성공!</h3>
|
||||||
|
<p>Vercel Serverless에서 성공적으로 실행 중입니다.</p>
|
||||||
|
<p><strong>시간:</strong> ${new Date().toLocaleString('ko-KR')}</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<h3>🔧 API 엔드포인트</h3>
|
||||||
|
<p><a href="/health" class="button">헬스 체크</a></p>
|
||||||
|
<p><a href="/api/files" class="button">파일 목록 API</a></p>
|
||||||
|
<p><a href="/api/files/public" class="button">공개 파일 API</a></p>
|
||||||
|
</div>
|
||||||
|
<div class="feature">
|
||||||
|
<h3>📱 페이지</h3>
|
||||||
|
<p><a href="/index.html" class="button">메인 페이지</a></p>
|
||||||
|
<p><a href="/admin/index.html" class="button">관리자 페이지</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// API 라우트들
|
||||||
|
if (url === '/api/files' || url === '/api/files/public') {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
title: '샘플 문서',
|
||||||
|
description: '데모용 파일입니다',
|
||||||
|
category: '문서',
|
||||||
|
tags: ['샘플', '테스트'],
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
file_url: '#'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
title: '이미지 파일',
|
||||||
|
description: '예시 이미지',
|
||||||
|
category: '이미지',
|
||||||
|
tags: ['샘플'],
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
file_url: '#'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
message: url.includes('public') ? '공개 파일 목록' : '파일 목록 API (데모 모드)'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url === '/api/categories') {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: [
|
||||||
|
{ id: 1, name: '문서', description: '문서 파일' },
|
||||||
|
{ id: 2, name: '이미지', description: '이미지 파일' },
|
||||||
|
{ id: 3, name: '동영상', description: '동영상 파일' },
|
||||||
|
{ id: 4, name: '프레젠테이션', description: '프레젠테이션 파일' },
|
||||||
|
{ id: 5, name: '기타', description: '기타 파일' }
|
||||||
|
],
|
||||||
|
message: '카테고리 목록'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 404 핸들러
|
||||||
|
res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
error: '요청한 리소스를 찾을 수 없습니다.',
|
||||||
|
path: url,
|
||||||
|
method: method
|
||||||
|
});
|
||||||
|
}
|
21
api/test.js
Normal file
21
api/test.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// 테스트용 간단한 API
|
||||||
|
module.exports = (req, res) => {
|
||||||
|
// CORS 헤더 설정
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
||||||
|
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.status(200).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 간단한 응답
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
message: 'API가 정상 작동합니다!',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
url: req.url,
|
||||||
|
method: req.method
|
||||||
|
});
|
||||||
|
};
|
141
create-git-repo.sh
Normal file
141
create-git-repo.sh
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 시놀로지 NAS Git 저장소 생성 스크립트 (개선 버전)
|
||||||
|
# 사용법: ./create-git-repo.sh [repo-name] [git-dir]
|
||||||
|
|
||||||
|
# 기본 설정
|
||||||
|
DEFAULT_GIT_DIR="/volume1/git"
|
||||||
|
DEFAULT_REPO_NAME="jaryo-file-manager"
|
||||||
|
|
||||||
|
# 매개변수 처리
|
||||||
|
REPO_NAME="${1:-$DEFAULT_REPO_NAME}"
|
||||||
|
GIT_DIR="${2:-$DEFAULT_GIT_DIR}"
|
||||||
|
REPO_PATH="$GIT_DIR/$REPO_NAME.git"
|
||||||
|
|
||||||
|
echo "=== 시놀로지 NAS Git 저장소 생성 ==="
|
||||||
|
echo "저장소 이름: $REPO_NAME"
|
||||||
|
echo "Git 디렉토리: $GIT_DIR"
|
||||||
|
echo "저장소 경로: $REPO_PATH"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# 권한 확인
|
||||||
|
if [ "$EUID" -ne 0 ] && [ "$(whoami)" != "admin" ]; then
|
||||||
|
echo "⚠️ 경고: 관리자 권한이 필요할 수 있습니다."
|
||||||
|
echo "sudo 또는 admin 계정으로 실행하세요."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Git 설치 확인
|
||||||
|
if ! command -v git &> /dev/null; then
|
||||||
|
echo "❌ Git이 설치되지 않았습니다."
|
||||||
|
echo "패키지 센터에서 Git Server를 설치하거나 다음 명령어를 실행하세요:"
|
||||||
|
echo "sudo apt update && sudo apt install git"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Git 디렉토리 확인 및 생성
|
||||||
|
echo "📁 Git 디렉토리 확인 중..."
|
||||||
|
if [ ! -d "$GIT_DIR" ]; then
|
||||||
|
echo "Git 디렉토리가 없습니다. 생성 중..."
|
||||||
|
mkdir -p "$GIT_DIR" || {
|
||||||
|
echo "❌ Git 디렉토리 생성 실패. 권한을 확인하세요."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 권한 설정
|
||||||
|
if command -v chown &> /dev/null; then
|
||||||
|
chown admin:users "$GIT_DIR" 2>/dev/null || echo "⚠️ chown 권한 부족"
|
||||||
|
fi
|
||||||
|
chmod 755 "$GIT_DIR" 2>/dev/null || echo "⚠️ chmod 권한 부족"
|
||||||
|
echo "✅ Git 디렉토리 생성 완료: $GIT_DIR"
|
||||||
|
else
|
||||||
|
echo "✅ Git 디렉토리 존재 확인: $GIT_DIR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 기존 저장소 확인
|
||||||
|
if [ -d "$REPO_PATH" ]; then
|
||||||
|
echo "⚠️ 저장소가 이미 존재합니다: $REPO_PATH"
|
||||||
|
read -p "삭제 후 재생성하시겠습니까? (y/N): " confirm
|
||||||
|
if [[ $confirm =~ ^[Yy]$ ]]; then
|
||||||
|
rm -rf "$REPO_PATH"
|
||||||
|
echo "🗑️ 기존 저장소 삭제 완료"
|
||||||
|
else
|
||||||
|
echo "❌ 작업을 취소합니다."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 저장소 디렉토리 생성
|
||||||
|
echo "📂 저장소 디렉토리 생성 중..."
|
||||||
|
mkdir -p "$REPO_PATH" || {
|
||||||
|
echo "❌ 저장소 디렉토리 생성 실패"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Git 저장소 초기화
|
||||||
|
echo "🔧 Git 저장소 초기화 중..."
|
||||||
|
cd "$REPO_PATH" || exit 1
|
||||||
|
git init --bare || {
|
||||||
|
echo "❌ Git 저장소 초기화 실패"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 권한 설정
|
||||||
|
echo "🔐 권한 설정 중..."
|
||||||
|
if command -v chown &> /dev/null; then
|
||||||
|
chown -R admin:users "$REPO_PATH" 2>/dev/null || echo "⚠️ chown 권한 부족"
|
||||||
|
fi
|
||||||
|
chmod -R 755 "$REPO_PATH" 2>/dev/null || echo "⚠️ chmod 권한 부족"
|
||||||
|
|
||||||
|
# Git hooks 설정 (선택사항)
|
||||||
|
echo "🪝 Git hooks 설정 중..."
|
||||||
|
cat > "$REPO_PATH/hooks/post-receive" << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# 자동 배포 hook (선택사항)
|
||||||
|
echo "푸시 완료: $(date)"
|
||||||
|
echo "저장소: $PWD"
|
||||||
|
EOF
|
||||||
|
chmod +x "$REPO_PATH/hooks/post-receive" 2>/dev/null
|
||||||
|
|
||||||
|
# 저장소 설명 파일 생성
|
||||||
|
echo "📄 저장소 설명 파일 생성 중..."
|
||||||
|
cat > "$REPO_PATH/description" << EOF
|
||||||
|
Jaryo File Manager - 시놀로지 NAS 자료실 파일 관리 시스템
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Git 서비스 확인 및 시작
|
||||||
|
echo "🔄 Git 서비스 상태 확인 중..."
|
||||||
|
NAS_IP=$(hostname -I | awk '{print $1}' | tr -d ' ')
|
||||||
|
|
||||||
|
# 다양한 방법으로 IP 확인
|
||||||
|
if [ -z "$NAS_IP" ]; then
|
||||||
|
NAS_IP=$(ip route get 1 | awk '{print $7; exit}' 2>/dev/null)
|
||||||
|
fi
|
||||||
|
if [ -z "$NAS_IP" ]; then
|
||||||
|
NAS_IP="your-nas-ip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Git 저장소 생성 완료!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "📋 저장소 정보:"
|
||||||
|
echo " - 이름: $REPO_NAME"
|
||||||
|
echo " - 경로: $REPO_PATH"
|
||||||
|
echo " - 설명: 자료실 파일 관리 시스템"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 연결 URL:"
|
||||||
|
echo " SSH: ssh://admin@$NAS_IP$REPO_PATH"
|
||||||
|
echo " HTTP: http://$NAS_IP:3000/git/$REPO_NAME.git"
|
||||||
|
echo ""
|
||||||
|
echo "🔗 로컬에서 연결하는 방법:"
|
||||||
|
echo " git remote add nas ssh://admin@$NAS_IP$REPO_PATH"
|
||||||
|
echo " git push nas master"
|
||||||
|
echo ""
|
||||||
|
echo "📝 다음 단계:"
|
||||||
|
echo " 1. 로컬 프로젝트에서 원격 저장소 추가"
|
||||||
|
echo " 2. 첫 번째 push 실행"
|
||||||
|
echo " 3. Git 서비스 동작 확인"
|
||||||
|
echo ""
|
||||||
|
echo "🔧 Git 서비스 수동 시작 (필요시):"
|
||||||
|
echo " sudo systemctl start git-daemon"
|
||||||
|
echo " sudo git daemon --base-path=$GIT_DIR --export-all --reuseaddr &"
|
||||||
|
echo ""
|
||||||
|
echo "📖 자세한 설정은 synology-git-diagnostic.md 파일을 참조하세요."
|
46
deploy-manual.sh
Normal file
46
deploy-manual.sh
Normal 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 "=========================================="
|
299
deploy-to-nas.sh
Normal file
299
deploy-to-nas.sh
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 시놀로지 NAS 자료실 배포 스크립트
|
||||||
|
# 사용법: ./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 "=========================================="
|
||||||
|
echo "NAS IP: $NAS_IP"
|
||||||
|
echo "프로젝트: $PROJECT_NAME"
|
||||||
|
echo "배포 경로: $DEPLOY_DIR"
|
||||||
|
echo "서비스 포트: $SERVICE_PORT"
|
||||||
|
echo "Gitea URL: $GITEA_URL"
|
||||||
|
echo "=========================================="
|
||||||
|
|
||||||
|
# 사전 요구사항 확인
|
||||||
|
echo "📋 1단계: 사전 요구사항 확인"
|
||||||
|
|
||||||
|
# SSH 방식 확인
|
||||||
|
echo "🔧 SSH 접속 방식: 비밀번호 프롬프트 방식"
|
||||||
|
echo "📝 SSH 연결 시 비밀번호 입력이 필요합니다."
|
||||||
|
|
||||||
|
# SSH 연결 테스트 (포트 2222)
|
||||||
|
echo "🔗 SSH 연결 테스트 중... (사용자: $NAS_USER, 포트: 2222)"
|
||||||
|
if ! eval "$SSH_CMD 'echo SSH 연결 성공'"; then
|
||||||
|
echo "❌ SSH 연결 실패. 다음을 확인하세요:"
|
||||||
|
echo " - NAS IP 주소: $NAS_IP"
|
||||||
|
echo " - SSH 포트: 2222"
|
||||||
|
echo " - SSH 서비스 활성화 (DSM > 제어판 > 터미널 및 SNMP)"
|
||||||
|
echo " - 방화벽 설정 (포트 2222 허용)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✅ SSH 연결 성공"
|
||||||
|
|
||||||
|
# Node.js 설치 확인
|
||||||
|
echo "📦 Node.js 설치 확인 중..."
|
||||||
|
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=$(eval "$SSH_CMD '$NODE_PATH/node --version'")
|
||||||
|
echo "✅ Node.js 설치됨: $NODE_VERSION ($NODE_PATH)"
|
||||||
|
|
||||||
|
# Git 설치 확인
|
||||||
|
echo "📦 Git 설치 확인 중..."
|
||||||
|
eval "$SSH_CMD 'which git'" >/dev/null 2>&1
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "❌ Git이 설치되지 않았습니다."
|
||||||
|
echo "DSM 패키지 센터에서 Git Server를 설치하거나 다음 명령을 실행하세요:"
|
||||||
|
echo "ssh -p 2222 $NAS_USER@$NAS_IP 'sudo apt update && sudo apt install git'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
GIT_VERSION=$(eval "$SSH_CMD 'git --version'")
|
||||||
|
echo "✅ Git 설치됨: $GIT_VERSION"
|
||||||
|
|
||||||
|
# 2단계: 소스 코드 배포
|
||||||
|
echo ""
|
||||||
|
echo "📂 2단계: 소스 코드 배포"
|
||||||
|
|
||||||
|
# 기존 배포 디렉토리 확인
|
||||||
|
echo "🗂️ 배포 디렉토리 확인 중..."
|
||||||
|
eval "$SSH_CMD '
|
||||||
|
if [ -d '$DEPLOY_DIR' ]; then
|
||||||
|
echo '⚠️ 기존 배포가 존재합니다: $DEPLOY_DIR'
|
||||||
|
echo '백업 생성 중...'
|
||||||
|
sudo cp -r '$DEPLOY_DIR' '${DEPLOY_DIR}_backup_$(date +%Y%m%d_%H%M%S)'
|
||||||
|
echo '기존 배포 제거 중...'
|
||||||
|
sudo rm -rf '$DEPLOY_DIR'
|
||||||
|
fi
|
||||||
|
"
|
||||||
|
|
||||||
|
# 배포 디렉토리 생성
|
||||||
|
echo "📁 배포 디렉토리 생성 중..."
|
||||||
|
eval "$SSH_CMD '
|
||||||
|
sudo mkdir -p '$DEPLOY_DIR'
|
||||||
|
sudo chown admin:users '$DEPLOY_DIR'
|
||||||
|
cd '$DEPLOY_DIR'
|
||||||
|
"
|
||||||
|
|
||||||
|
# Git 클론
|
||||||
|
echo "📥 Gitea에서 소스 코드 클론 중..."
|
||||||
|
eval "$SSH_CMD '
|
||||||
|
cd '$DEPLOY_DIR'
|
||||||
|
git clone '$GITEA_URL' .
|
||||||
|
if [ \$? -ne 0 ]; then
|
||||||
|
echo '❌ Git 클론 실패'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo '✅ 소스 코드 클론 완료'
|
||||||
|
"
|
||||||
|
|
||||||
|
# 3단계: 의존성 설치 및 빌드
|
||||||
|
echo ""
|
||||||
|
echo "🔧 3단계: 의존성 설치 및 빌드"
|
||||||
|
|
||||||
|
eval "$SSH_CMD '
|
||||||
|
cd '$DEPLOY_DIR'
|
||||||
|
|
||||||
|
# 기존 node_modules 제거
|
||||||
|
if [ -d 'node_modules' ]; then
|
||||||
|
echo '🗑️ 기존 node_modules 제거 중...'
|
||||||
|
rm -rf node_modules package-lock.json
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 의존성 설치
|
||||||
|
echo '📦 의존성 설치 중...'
|
||||||
|
export PATH='$NODE_PATH':\$PATH
|
||||||
|
'$NODE_PATH'/npm install
|
||||||
|
|
||||||
|
if [ \$? -ne 0 ]; then
|
||||||
|
echo '❌ npm install 실패'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo '✅ 의존성 설치 완료'
|
||||||
|
|
||||||
|
# 데이터베이스 백업 및 초기화
|
||||||
|
if [ -f 'scripts/init-database.js' ]; then
|
||||||
|
# 기존 데이터베이스 백업
|
||||||
|
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
|
||||||
|
"
|
||||||
|
|
||||||
|
# 4단계: 서비스 설정
|
||||||
|
echo ""
|
||||||
|
echo "⚙️ 4단계: 서비스 설정"
|
||||||
|
|
||||||
|
# 시작 스크립트 생성
|
||||||
|
echo "📝 시작 스크립트 생성 중..."
|
||||||
|
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'
|
||||||
|
|
||||||
|
# 로그 디렉토리 생성
|
||||||
|
mkdir -p '\$PROJECT_DIR/logs'
|
||||||
|
|
||||||
|
# 기존 프로세스 확인 및 종료
|
||||||
|
if [ -f '\$PID_FILE' ]; then
|
||||||
|
OLD_PID=\$(cat '\$PID_FILE')
|
||||||
|
if kill -0 '\$OLD_PID' 2>/dev/null; then
|
||||||
|
echo '기존 서비스 종료 중... (PID: '\$OLD_PID')'
|
||||||
|
kill '\$OLD_PID'
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
rm -f '\$PID_FILE'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 포트 사용 확인
|
||||||
|
if netstat -tulpn | grep :'$SERVICE_PORT' >/dev/null; then
|
||||||
|
echo '⚠️ 포트 '$SERVICE_PORT'가 이미 사용 중입니다.'
|
||||||
|
echo '사용 중인 프로세스:'
|
||||||
|
netstat -tulpn | grep :'$SERVICE_PORT'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 서비스 시작
|
||||||
|
echo '🚀 자료실 서비스 시작 중...'
|
||||||
|
cd '\$PROJECT_DIR'
|
||||||
|
PORT='$SERVICE_PORT' nohup \$NODE_PATH/node server.js > '\$LOG_FILE' 2>&1 &
|
||||||
|
echo \$! > '\$PID_FILE'
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 시작 확인
|
||||||
|
if kill -0 \$(cat '\$PID_FILE') 2>/dev/null; then
|
||||||
|
echo '✅ 자료실 서비스 시작 완료!'
|
||||||
|
echo '📍 접속 URL: http://$NAS_IP:$SERVICE_PORT'
|
||||||
|
echo '📋 PID: '\$(cat '\$PID_FILE')
|
||||||
|
echo '📄 로그: '\$LOG_FILE'
|
||||||
|
else
|
||||||
|
echo '❌ 서비스 시작 실패'
|
||||||
|
echo '로그 확인:'
|
||||||
|
tail -20 '\$LOG_FILE'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x '$DEPLOY_DIR/start-nas-service.sh'
|
||||||
|
"
|
||||||
|
|
||||||
|
# 중지 스크립트 생성
|
||||||
|
echo "📝 중지 스크립트 생성 중..."
|
||||||
|
eval "$SSH_CMD '
|
||||||
|
cat > '$DEPLOY_DIR/stop-nas-service.sh' << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 자료실 NAS 서비스 중지 스크립트
|
||||||
|
PROJECT_DIR='$DEPLOY_DIR'
|
||||||
|
PID_FILE='\$PROJECT_DIR/jaryo-nas.pid'
|
||||||
|
|
||||||
|
if [ -f '\$PID_FILE' ]; then
|
||||||
|
PID=\$(cat '\$PID_FILE')
|
||||||
|
if kill -0 '\$PID' 2>/dev/null; then
|
||||||
|
echo '🛑 자료실 서비스 중지 중... (PID: '\$PID')'
|
||||||
|
kill '\$PID'
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 강제 종료 확인
|
||||||
|
if kill -0 '\$PID' 2>/dev/null; then
|
||||||
|
echo '⚡ 강제 종료 중...'
|
||||||
|
kill -9 '\$PID'
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f '\$PID_FILE'
|
||||||
|
echo '✅ 자료실 서비스 중지 완료'
|
||||||
|
else
|
||||||
|
echo '⚠️ 프로세스가 이미 종료됨'
|
||||||
|
rm -f '\$PID_FILE'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo '⚠️ PID 파일이 없습니다. 수동으로 프로세스를 확인하세요.'
|
||||||
|
echo '실행 중인 Node.js 프로세스:'
|
||||||
|
ps aux | grep 'node.*server.js' | grep -v grep
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x '$DEPLOY_DIR/stop-nas-service.sh'
|
||||||
|
"
|
||||||
|
|
||||||
|
# 5단계: 서비스 시작
|
||||||
|
echo ""
|
||||||
|
echo "🎬 5단계: 서비스 시작"
|
||||||
|
|
||||||
|
eval "$SSH_CMD '$DEPLOY_DIR/start-nas-service.sh"
|
||||||
|
|
||||||
|
# 6단계: 접속 테스트
|
||||||
|
echo ""
|
||||||
|
echo "🧪 6단계: 접속 테스트"
|
||||||
|
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo "🌐 서비스 상태 확인 중..."
|
||||||
|
if curl -s "http://$NAS_IP:$SERVICE_PORT" >/dev/null; then
|
||||||
|
echo "✅ 자료실 서비스 정상 작동!"
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "🎉 배포 완료!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "📍 접속 URL: http://$NAS_IP:$SERVICE_PORT"
|
||||||
|
echo "🔧 관리자 URL: http://$NAS_IP:$SERVICE_PORT/admin"
|
||||||
|
echo "📂 배포 경로: $DEPLOY_DIR"
|
||||||
|
echo "📄 로그 파일: $DEPLOY_DIR/logs/app.log"
|
||||||
|
echo ""
|
||||||
|
echo "🔧 서비스 관리:"
|
||||||
|
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 "로그 확인:"
|
||||||
|
eval "$SSH_CMD 'tail -20 $DEPLOY_DIR/logs/app.log"
|
||||||
|
fi
|
234
enhanced-server.js
Normal file
234
enhanced-server.js
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
328
manual-nas-deployment-guide.md
Normal file
328
manual-nas-deployment-guide.md
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
# 시놀로지 NAS 수동 배포 가이드
|
||||||
|
|
||||||
|
## 🚀 시놀로지 NAS에서 자료실 서비스 배포하기
|
||||||
|
|
||||||
|
### 사전 준비사항 ✅
|
||||||
|
|
||||||
|
1. **DSM 패키지 설치 확인**
|
||||||
|
- Node.js v16+ (패키지 센터에서 설치)
|
||||||
|
- Git Server (패키지 센터에서 설치)
|
||||||
|
- SSH 서비스 활성화 (제어판 > 터미널 및 SNMP)
|
||||||
|
|
||||||
|
2. **방화벽 설정**
|
||||||
|
- SSH 포트: 2222 허용
|
||||||
|
- 서비스 포트: 3005 허용
|
||||||
|
- Gitea 포트: 3000 허용
|
||||||
|
|
||||||
|
### 1단계: SSH 접속 🔗
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows에서 NAS 접속
|
||||||
|
ssh -p 2222 admin@119.64.1.86
|
||||||
|
|
||||||
|
# 접속 후 관리자 권한 확인
|
||||||
|
sudo whoami
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2단계: 배포 디렉토리 준비 📁
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 웹 디렉토리로 이동
|
||||||
|
cd /volume1/web
|
||||||
|
|
||||||
|
# 기존 jaryo 폴더가 있다면 백업
|
||||||
|
if [ -d "jaryo" ]; then
|
||||||
|
sudo mv jaryo jaryo_backup_$(date +%Y%m%d_%H%M%S)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 새 디렉토리 생성
|
||||||
|
sudo mkdir -p jaryo
|
||||||
|
sudo chown admin:users jaryo
|
||||||
|
cd jaryo
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3단계: 소스 코드 클론 📥
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gitea에서 소스 코드 클론
|
||||||
|
git clone http://119.64.1.86:3000/vibsin9322/jaryo.git .
|
||||||
|
|
||||||
|
# 클론 성공 확인
|
||||||
|
ls -la
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4단계: 의존성 설치 📦
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 기존 node_modules 제거 (있다면)
|
||||||
|
rm -rf node_modules package-lock.json
|
||||||
|
|
||||||
|
# npm 의존성 설치
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 설치 확인
|
||||||
|
ls -la node_modules
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5단계: 데이터베이스 초기화 🗄️
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# SQLite 데이터베이스 초기화
|
||||||
|
npm run init-db
|
||||||
|
|
||||||
|
# 데이터베이스 파일 확인
|
||||||
|
ls -la *.db
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6단계: 서비스 시작 스크립트 생성 📝
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 시작 스크립트 생성
|
||||||
|
cat > start-jaryo.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 자료실 서비스 시작 스크립트
|
||||||
|
PROJECT_DIR="/volume1/web/jaryo"
|
||||||
|
SERVICE_PORT="3005"
|
||||||
|
PID_FILE="$PROJECT_DIR/jaryo.pid"
|
||||||
|
LOG_FILE="$PROJECT_DIR/jaryo.log"
|
||||||
|
|
||||||
|
# 로그 디렉토리 생성
|
||||||
|
mkdir -p "$PROJECT_DIR/logs"
|
||||||
|
|
||||||
|
# 기존 프로세스 확인 및 종료
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
OLD_PID=$(cat "$PID_FILE")
|
||||||
|
if ps -p "$OLD_PID" > /dev/null; then
|
||||||
|
echo "기존 서비스 종료 중... (PID: $OLD_PID)"
|
||||||
|
kill "$OLD_PID"
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 포트 사용 확인
|
||||||
|
if netstat -tulpn | grep ":$SERVICE_PORT " > /dev/null; then
|
||||||
|
echo "⚠️ 포트 $SERVICE_PORT가 이미 사용 중입니다."
|
||||||
|
echo "사용 중인 프로세스:"
|
||||||
|
netstat -tulpn | grep ":$SERVICE_PORT "
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 서비스 시작
|
||||||
|
echo "🚀 자료실 서비스 시작 중..."
|
||||||
|
cd "$PROJECT_DIR"
|
||||||
|
PORT="$SERVICE_PORT" nohup node server.js > "$LOG_FILE" 2>&1 &
|
||||||
|
echo $! > "$PID_FILE"
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 시작 확인
|
||||||
|
if ps -p $(cat "$PID_FILE") > /dev/null; then
|
||||||
|
echo "✅ 자료실 서비스 시작 완료!"
|
||||||
|
echo "📍 접속 URL: http://119.64.1.86:$SERVICE_PORT"
|
||||||
|
echo "📋 PID: $(cat "$PID_FILE")"
|
||||||
|
echo "📄 로그: $LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "❌ 서비스 시작 실패"
|
||||||
|
echo "로그 확인:"
|
||||||
|
tail -20 "$LOG_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 실행 권한 부여
|
||||||
|
chmod +x start-jaryo.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7단계: 중지 스크립트 생성 🛑
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 중지 스크립트 생성
|
||||||
|
cat > stop-jaryo.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 자료실 서비스 중지 스크립트
|
||||||
|
PROJECT_DIR="/volume1/web/jaryo"
|
||||||
|
PID_FILE="$PROJECT_DIR/jaryo.pid"
|
||||||
|
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
PID=$(cat "$PID_FILE")
|
||||||
|
if ps -p "$PID" > /dev/null; then
|
||||||
|
echo "🛑 자료실 서비스 중지 중... (PID: $PID)"
|
||||||
|
kill "$PID"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# 강제 종료 확인
|
||||||
|
if ps -p "$PID" > /dev/null; then
|
||||||
|
echo "⚡ 강제 종료 중..."
|
||||||
|
kill -9 "$PID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
echo "✅ 자료실 서비스 중지 완료"
|
||||||
|
else
|
||||||
|
echo "⚠️ 프로세스가 이미 종료됨"
|
||||||
|
rm -f "$PID_FILE"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "⚠️ PID 파일이 없습니다. 수동으로 프로세스를 확인하세요."
|
||||||
|
echo "실행 중인 Node.js 프로세스:"
|
||||||
|
ps aux | grep 'node.*server.js' | grep -v grep
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 실행 권한 부여
|
||||||
|
chmod +x stop-jaryo.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8단계: 서비스 시작 🎬
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 서비스 시작
|
||||||
|
./start-jaryo.sh
|
||||||
|
|
||||||
|
# 로그 확인 (별도 터미널에서)
|
||||||
|
tail -f jaryo.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9단계: 접속 테스트 🧪
|
||||||
|
|
||||||
|
**브라우저에서 접속:**
|
||||||
|
- **메인 페이지**: `http://119.64.1.86:3005`
|
||||||
|
- **관리자 페이지**: `http://119.64.1.86:3005/admin`
|
||||||
|
|
||||||
|
**명령줄에서 테스트:**
|
||||||
|
```bash
|
||||||
|
# 서비스 상태 확인
|
||||||
|
curl -s http://119.64.1.86:3005
|
||||||
|
|
||||||
|
# 프로세스 확인
|
||||||
|
ps aux | grep 'node.*server.js' | grep -v grep
|
||||||
|
|
||||||
|
# 포트 확인
|
||||||
|
netstat -tulpn | grep :3005
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 서비스 관리
|
||||||
|
|
||||||
|
### 일상적인 관리 명령어
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 서비스 시작
|
||||||
|
/volume1/web/jaryo/start-jaryo.sh
|
||||||
|
|
||||||
|
# 서비스 중지
|
||||||
|
/volume1/web/jaryo/stop-jaryo.sh
|
||||||
|
|
||||||
|
# 서비스 재시작
|
||||||
|
/volume1/web/jaryo/stop-jaryo.sh && /volume1/web/jaryo/start-jaryo.sh
|
||||||
|
|
||||||
|
# 로그 확인
|
||||||
|
tail -f /volume1/web/jaryo/jaryo.log
|
||||||
|
|
||||||
|
# 실시간 로그 보기
|
||||||
|
ssh -p 2222 admin@119.64.1.86 'tail -f /volume1/web/jaryo/jaryo.log'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 상태 모니터링
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 서비스 상태 스크립트
|
||||||
|
cat > status-jaryo.sh << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PROJECT_DIR="/volume1/web/jaryo"
|
||||||
|
PID_FILE="$PROJECT_DIR/jaryo.pid"
|
||||||
|
LOG_FILE="$PROJECT_DIR/jaryo.log"
|
||||||
|
|
||||||
|
echo "=== 자료실 서비스 상태 ==="
|
||||||
|
|
||||||
|
if [ -f "$PID_FILE" ]; then
|
||||||
|
PID=$(cat "$PID_FILE")
|
||||||
|
if ps -p "$PID" > /dev/null; then
|
||||||
|
echo "✅ 서비스 실행 중 (PID: $PID)"
|
||||||
|
echo "📊 메모리 사용량:"
|
||||||
|
ps -o pid,ppid,cmd,%mem,%cpu -p "$PID"
|
||||||
|
echo ""
|
||||||
|
echo "🌐 포트 상태:"
|
||||||
|
netstat -tulpn | grep :3005
|
||||||
|
else
|
||||||
|
echo "❌ 서비스 중지됨 (PID 파일 존재하지만 프로세스 없음)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "❌ 서비스 중지됨 (PID 파일 없음)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📄 최근 로그 (최근 5줄):"
|
||||||
|
if [ -f "$LOG_FILE" ]; then
|
||||||
|
tail -5 "$LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "로그 파일이 없습니다."
|
||||||
|
fi
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x status-jaryo.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 자동 시작 설정 (선택사항)
|
||||||
|
|
||||||
|
### DSM 작업 스케줄러 사용
|
||||||
|
|
||||||
|
1. **DSM 로그인** → **제어판** → **작업 스케줄러**
|
||||||
|
2. **생성** → **예약된 작업** → **사용자 정의 스크립트**
|
||||||
|
3. 설정:
|
||||||
|
- **작업 이름**: Jaryo 자료실 자동 시작
|
||||||
|
- **사용자**: root
|
||||||
|
- **스케줄**: 시스템 부팅 시
|
||||||
|
- **스크립트**: `/volume1/web/jaryo/start-jaryo.sh`
|
||||||
|
|
||||||
|
## 🚨 문제 해결
|
||||||
|
|
||||||
|
### 일반적인 문제들
|
||||||
|
|
||||||
|
**1. 포트 충돌**
|
||||||
|
```bash
|
||||||
|
# 포트 사용 확인
|
||||||
|
netstat -tulpn | grep :3005
|
||||||
|
|
||||||
|
# 다른 포트 사용시 (예: 3006)
|
||||||
|
PORT=3006 node server.js
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. 권한 문제**
|
||||||
|
```bash
|
||||||
|
# 디렉토리 권한 수정
|
||||||
|
sudo chown -R admin:users /volume1/web/jaryo
|
||||||
|
chmod -R 755 /volume1/web/jaryo
|
||||||
|
```
|
||||||
|
|
||||||
|
**3. Node.js 버전 문제**
|
||||||
|
```bash
|
||||||
|
# Node.js 버전 확인
|
||||||
|
node --version
|
||||||
|
|
||||||
|
# 최소 요구 버전: v16.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. 데이터베이스 문제**
|
||||||
|
```bash
|
||||||
|
# 데이터베이스 재초기화
|
||||||
|
rm -f jaryo.db
|
||||||
|
npm run init-db
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📱 최종 확인
|
||||||
|
|
||||||
|
배포 완료 후 다음 URL들이 정상 작동하는지 확인:
|
||||||
|
|
||||||
|
- ✅ **메인 페이지**: http://119.64.1.86:3005
|
||||||
|
- ✅ **관리자 페이지**: http://119.64.1.86:3005/admin
|
||||||
|
- ✅ **API 상태**: http://119.64.1.86:3005/api/files
|
||||||
|
- ✅ **Gitea 저장소**: http://119.64.1.86:3000/vibsin9322/jaryo
|
||||||
|
|
||||||
|
## 🎉 배포 완료!
|
||||||
|
|
||||||
|
시놀로지 NAS에서 자료실 서비스가 성공적으로 실행되고 있습니다.
|
||||||
|
서비스 관리는 위의 스크립트들을 사용하여 쉽게 할 수 있습니다.
|
257
nas-git-connection-test.md
Normal file
257
nas-git-connection-test.md
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
# 시놀로지 NAS Git 서버 연결 테스트 가이드
|
||||||
|
|
||||||
|
## 🧪 연결 테스트 단계별 가이드
|
||||||
|
|
||||||
|
### 1단계: 기본 연결 테스트
|
||||||
|
|
||||||
|
#### 1.1 SSH 연결 확인
|
||||||
|
```bash
|
||||||
|
# NAS SSH 연결 테스트
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# 성공시 NAS 터미널에 접속됨
|
||||||
|
# 실패시 확인사항:
|
||||||
|
# - SSH 서비스 활성화 여부
|
||||||
|
# - 방화벽 설정
|
||||||
|
# - IP 주소 정확성
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 Git 설치 확인
|
||||||
|
```bash
|
||||||
|
# NAS에서 Git 명령어 확인
|
||||||
|
which git
|
||||||
|
git --version
|
||||||
|
|
||||||
|
# Git 서비스 상태 확인
|
||||||
|
sudo systemctl status git-daemon
|
||||||
|
ps aux | grep git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2단계: 저장소 생성 및 설정
|
||||||
|
|
||||||
|
#### 2.1 자동 스크립트 실행
|
||||||
|
```bash
|
||||||
|
# 로컬에서 NAS로 스크립트 복사
|
||||||
|
scp create-git-repo.sh admin@your-nas-ip:/tmp/
|
||||||
|
|
||||||
|
# NAS에서 스크립트 실행
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
cd /tmp
|
||||||
|
chmod +x create-git-repo.sh
|
||||||
|
./create-git-repo.sh jaryo-file-manager
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 수동 저장소 생성 (스크립트 실패시)
|
||||||
|
```bash
|
||||||
|
# NAS에서 직접 실행
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# Git 디렉토리 생성
|
||||||
|
sudo mkdir -p /volume1/git
|
||||||
|
sudo chown admin:users /volume1/git
|
||||||
|
cd /volume1/git
|
||||||
|
|
||||||
|
# Bare 저장소 생성
|
||||||
|
mkdir jaryo-file-manager.git
|
||||||
|
cd jaryo-file-manager.git
|
||||||
|
git init --bare
|
||||||
|
sudo chown -R admin:users .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3단계: 로컬에서 연결 테스트
|
||||||
|
|
||||||
|
#### 3.1 기존 프로젝트에 원격 저장소 추가
|
||||||
|
```bash
|
||||||
|
# 현재 jaryo 프로젝트 디렉토리에서
|
||||||
|
cd /c/Users/COMTREE/claude_code/jaryo
|
||||||
|
|
||||||
|
# NAS Git 원격 저장소 추가
|
||||||
|
git remote add nas ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git
|
||||||
|
|
||||||
|
# 원격 저장소 확인
|
||||||
|
git remote -v
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 첫 번째 Push 테스트
|
||||||
|
```bash
|
||||||
|
# 모든 변경사항 커밋 (필요시)
|
||||||
|
git add .
|
||||||
|
git commit -m "Initial commit for NAS deployment"
|
||||||
|
|
||||||
|
# NAS로 푸시
|
||||||
|
git push nas master
|
||||||
|
|
||||||
|
# 성공시 출력 예시:
|
||||||
|
# Enumerating objects: X, done.
|
||||||
|
# Counting objects: 100% (X/X), done.
|
||||||
|
# Delta compression using up to Y threads
|
||||||
|
# Compressing objects: 100% (X/X), done.
|
||||||
|
# Writing objects: 100% (X/X), X.XX KiB | X.XX MiB/s, done.
|
||||||
|
# Total X (delta X), reused X (delta X), pack-reused 0
|
||||||
|
# To ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git
|
||||||
|
# * [new branch] master -> master
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4단계: 클론 테스트
|
||||||
|
|
||||||
|
#### 4.1 다른 디렉토리에서 클론 테스트
|
||||||
|
```bash
|
||||||
|
# 테스트용 디렉토리 생성
|
||||||
|
mkdir /tmp/git-test
|
||||||
|
cd /tmp/git-test
|
||||||
|
|
||||||
|
# NAS에서 클론
|
||||||
|
git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git
|
||||||
|
|
||||||
|
# 성공시 프로젝트 파일들이 다운로드됨
|
||||||
|
cd jaryo-file-manager
|
||||||
|
ls -la
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2 HTTP 클론 테스트 (Git HTTP 서버 실행시)
|
||||||
|
```bash
|
||||||
|
# Git HTTP 서버가 실행 중인 경우
|
||||||
|
git clone http://your-nas-ip:3000/jaryo-file-manager.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5단계: 웹 인터페이스 테스트
|
||||||
|
|
||||||
|
#### 5.1 GitWeb 접속 테스트
|
||||||
|
- 브라우저에서 `http://your-nas-ip/git` 접속
|
||||||
|
- 또는 `http://your-nas-ip:3000` 접속
|
||||||
|
- 저장소 목록에서 `jaryo-file-manager` 확인
|
||||||
|
|
||||||
|
#### 5.2 Git HTTP 서버 상태 확인
|
||||||
|
```bash
|
||||||
|
# NAS에서 Git HTTP 서버 실행 확인
|
||||||
|
sudo netstat -tulpn | grep :3000
|
||||||
|
ps aux | grep git-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚨 문제 해결
|
||||||
|
|
||||||
|
### 연결 실패 시 체크리스트
|
||||||
|
|
||||||
|
#### ❌ "Connection refused" 오류
|
||||||
|
```bash
|
||||||
|
# 1. SSH 서비스 확인
|
||||||
|
ssh -v admin@your-nas-ip
|
||||||
|
|
||||||
|
# 2. 포트 확인 (기본: 22)
|
||||||
|
ssh -p 22 admin@your-nas-ip
|
||||||
|
|
||||||
|
# 3. 방화벽 확인
|
||||||
|
# DSM > 제어판 > 보안 > 방화벽
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ❌ "Permission denied" 오류
|
||||||
|
```bash
|
||||||
|
# 1. 사용자 권한 확인
|
||||||
|
# DSM > 제어판 > 사용자 및 그룹 > admin > 애플리케이션
|
||||||
|
|
||||||
|
# 2. SSH 키 설정 (선택사항)
|
||||||
|
ssh-keygen -t rsa
|
||||||
|
ssh-copy-id admin@your-nas-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ❌ "Repository not found" 오류
|
||||||
|
```bash
|
||||||
|
# 1. 저장소 경로 확인
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
ls -la /volume1/git/
|
||||||
|
ls -la /volume1/git/jaryo-file-manager.git/
|
||||||
|
|
||||||
|
# 2. 권한 확인
|
||||||
|
sudo chown -R admin:users /volume1/git/jaryo-file-manager.git
|
||||||
|
chmod -R 755 /volume1/git/jaryo-file-manager.git
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ❌ Git 명령어 없음
|
||||||
|
```bash
|
||||||
|
# Git 설치 확인
|
||||||
|
which git
|
||||||
|
|
||||||
|
# 패키지 센터에서 Git Server 설치
|
||||||
|
# 또는 수동 설치:
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 네트워크 설정 문제
|
||||||
|
|
||||||
|
#### 내부 네트워크 접속 실패
|
||||||
|
```bash
|
||||||
|
# IP 주소 확인
|
||||||
|
ping your-nas-ip
|
||||||
|
nslookup your-nas-ip
|
||||||
|
|
||||||
|
# 포트 스캔
|
||||||
|
nmap -p 22,3000 your-nas-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 외부 네트워크 접속 설정
|
||||||
|
```bash
|
||||||
|
# 라우터 포트 포워딩 설정
|
||||||
|
# 22 (SSH) -> NAS_IP:22
|
||||||
|
# 3000 (Git HTTP) -> NAS_IP:3000
|
||||||
|
|
||||||
|
# 동적 DNS 설정 (선택사항)
|
||||||
|
# your-domain.dyndns.org -> your-public-ip
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 연결 성공 확인
|
||||||
|
|
||||||
|
### ✅ 성공 지표들
|
||||||
|
|
||||||
|
1. **SSH 연결**: `ssh admin@your-nas-ip` 성공
|
||||||
|
2. **저장소 존재**: `/volume1/git/jaryo-file-manager.git` 확인
|
||||||
|
3. **Push 성공**: `git push nas master` 완료
|
||||||
|
4. **Clone 성공**: 다른 위치에서 클론 가능
|
||||||
|
5. **웹 접속**: 브라우저에서 Git 저장소 확인
|
||||||
|
|
||||||
|
### 📈 성능 테스트
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 대용량 파일 Push 테스트
|
||||||
|
dd if=/dev/zero of=test-large-file.bin bs=1M count=10
|
||||||
|
git add test-large-file.bin
|
||||||
|
git commit -m "Large file test"
|
||||||
|
time git push nas master
|
||||||
|
|
||||||
|
# 클론 속도 테스트
|
||||||
|
time git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git test-clone
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 고급 설정
|
||||||
|
|
||||||
|
### Git Hooks 활용
|
||||||
|
```bash
|
||||||
|
# NAS에서 post-receive hook 설정
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
cd /volume1/git/jaryo-file-manager.git/hooks
|
||||||
|
|
||||||
|
# 자동 배포 hook
|
||||||
|
cat > post-receive << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
echo "코드 푸시 완료: $(date)"
|
||||||
|
# 자동 배포 로직 추가 가능
|
||||||
|
# cd /volume1/web/jaryo && git pull
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x post-receive
|
||||||
|
```
|
||||||
|
|
||||||
|
### 백업 설정
|
||||||
|
```bash
|
||||||
|
# 저장소 백업 스크립트
|
||||||
|
#!/bin/bash
|
||||||
|
BACKUP_DIR="/volume1/backup/git"
|
||||||
|
REPO_DIR="/volume1/git"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
tar -czf "$BACKUP_DIR/git-repos-$DATE.tar.gz" -C "$REPO_DIR" .
|
||||||
|
echo "백업 완료: $BACKUP_DIR/git-repos-$DATE.tar.gz"
|
||||||
|
```
|
||||||
|
|
||||||
|
이 가이드를 따라하면 시놀로지 NAS Git 서버와의 연결을 성공적으로 테스트하고 설정할 수 있습니다.
|
32
package.json
32
package.json
@@ -1,28 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "jaryo-file-manager",
|
"name": "jaryo-file-manager",
|
||||||
"version": "1.0.0",
|
"version": "2.0.0",
|
||||||
"description": "자료실 파일 관리 시스템",
|
"description": "자료실 파일 관리 시스템 - Vercel Serverless",
|
||||||
"main": "server.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node server.js",
|
"dev": "vercel dev",
|
||||||
"dev": "nodemon server.js",
|
"build": "echo 'Build complete'",
|
||||||
"init-db": "node scripts/init-database.js"
|
"start": "vercel dev"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"express": "^4.18.2",
|
|
||||||
"sqlite3": "^5.1.6",
|
|
||||||
"cors": "^2.8.5",
|
|
||||||
"multer": "^1.4.5-lts.1",
|
|
||||||
"path": "^0.12.7",
|
|
||||||
"fs": "^0.0.1-security",
|
|
||||||
"bcrypt": "^5.1.1",
|
|
||||||
"express-session": "^1.17.3",
|
|
||||||
"uuid": "^9.0.1"
|
|
||||||
},
|
},
|
||||||
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.0.1"
|
"vercel": "^32.0.0"
|
||||||
},
|
},
|
||||||
"keywords": ["file-manager", "sqlite", "express", "admin"],
|
"keywords": ["file-manager", "vercel", "serverless", "admin"],
|
||||||
"author": "Claude Code",
|
"author": "Claude Code",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
}
|
}
|
@@ -9,16 +9,21 @@ class PublicFileViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
console.log('🚀 PublicFileViewer 초기화 시작');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.showLoading(true);
|
this.showLoading(true);
|
||||||
|
console.log('📡 파일 목록 로드 중...');
|
||||||
await this.loadFiles();
|
await this.loadFiles();
|
||||||
this.filteredFiles = [...this.files];
|
this.filteredFiles = [...this.files];
|
||||||
|
console.log(`✅ ${this.files.length}개 파일 로드 완료`);
|
||||||
|
|
||||||
this.bindEvents();
|
this.bindEvents();
|
||||||
this.renderFiles();
|
this.renderFiles();
|
||||||
this.updatePagination();
|
this.updatePagination();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('초기화 오류:', error);
|
console.error('❌ 초기화 오류:', error);
|
||||||
this.showNotification('데이터를 불러오는 중 오류가 발생했습니다.', 'error');
|
this.showNotification('데이터를 불러오는 중 오류가 발생했습니다. 페이지를 새로고침 해주세요.', 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.showLoading(false);
|
this.showLoading(false);
|
||||||
}
|
}
|
||||||
|
21
server.js
21
server.js
@@ -16,7 +16,7 @@ const db = new DatabaseHelper();
|
|||||||
|
|
||||||
// 미들웨어 설정
|
// 미들웨어 설정
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: ['http://localhost:3001', 'http://127.0.0.1:3001'],
|
origin: true, // 모든 도메인 허용 (Vercel 배포용)
|
||||||
credentials: true
|
credentials: true
|
||||||
}));
|
}));
|
||||||
app.use(express.json({ limit: '50mb' }));
|
app.use(express.json({ limit: '50mb' }));
|
||||||
@@ -28,7 +28,7 @@ app.use(session({
|
|||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: false, // HTTPS에서는 true로 설정
|
secure: process.env.NODE_ENV === 'production', // Vercel에서는 HTTPS
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 24 * 60 * 60 * 1000 // 24시간
|
maxAge: 24 * 60 * 60 * 1000 // 24시간
|
||||||
}
|
}
|
||||||
@@ -53,6 +53,16 @@ app.get('/', (req, res) => {
|
|||||||
res.redirect('/index.html');
|
res.redirect('/index.html');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 헬스 체크 엔드포인트
|
||||||
|
app.get('/health', (req, res) => {
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: 'Jaryo File Manager is running',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
environment: process.env.NODE_ENV || 'development'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Multer 설정 (파일 업로드)
|
// Multer 설정 (파일 업로드)
|
||||||
const storage = multer.diskStorage({
|
const storage = multer.diskStorage({
|
||||||
destination: (req, file, cb) => {
|
destination: (req, file, cb) => {
|
||||||
@@ -766,7 +776,11 @@ app.use((req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// 서버 시작
|
// Vercel 서버리스 환경을 위한 export
|
||||||
|
module.exports = app;
|
||||||
|
|
||||||
|
// 로컬 개발 환경에서만 서버 시작
|
||||||
|
if (process.env.NODE_ENV !== 'production' || process.env.VERCEL !== '1') {
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`🚀 자료실 서버가 포트 ${PORT}에서 실행중입니다.`);
|
console.log(`🚀 자료실 서버가 포트 ${PORT}에서 실행중입니다.`);
|
||||||
console.log(`📱 Admin 페이지: http://localhost:${PORT}/admin/index.html`);
|
console.log(`📱 Admin 페이지: http://localhost:${PORT}/admin/index.html`);
|
||||||
@@ -786,3 +800,4 @@ process.on('SIGTERM', async () => {
|
|||||||
await db.close();
|
await db.close();
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
}
|
110
simple.html
Normal file
110
simple.html
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Jaryo File Manager - 테스트</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
background: white;
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.status {
|
||||||
|
background: #e8f5e8;
|
||||||
|
border: 1px solid #4caf50;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
background: #4caf50;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.button:hover {
|
||||||
|
background: #45a049;
|
||||||
|
}
|
||||||
|
.test-section {
|
||||||
|
margin: 20px 0;
|
||||||
|
padding: 15px;
|
||||||
|
background: #f0f8ff;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>🚀 Jaryo File Manager</h1>
|
||||||
|
|
||||||
|
<div class="status">
|
||||||
|
<h3>✅ 정적 페이지 테스트</h3>
|
||||||
|
<p>이 페이지가 보인다면 Vercel 배포가 성공한 것입니다!</p>
|
||||||
|
<p><strong>시간:</strong> <span id="currentTime"></span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>🔧 테스트 버튼들</h3>
|
||||||
|
<a href="/index.html" class="button">메인 페이지</a>
|
||||||
|
<a href="/api/test" class="button">API 테스트</a>
|
||||||
|
<a href="/api/files" class="button">파일 API</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="test-section">
|
||||||
|
<h3>📡 AJAX 테스트</h3>
|
||||||
|
<button onclick="testAPI()" class="button">API 연결 테스트</button>
|
||||||
|
<div id="apiResult" style="margin-top: 10px;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 현재 시간 표시
|
||||||
|
document.getElementById('currentTime').textContent = new Date().toLocaleString('ko-KR');
|
||||||
|
|
||||||
|
// API 테스트 함수
|
||||||
|
async function testAPI() {
|
||||||
|
const resultDiv = document.getElementById('apiResult');
|
||||||
|
resultDiv.innerHTML = '🔄 API 테스트 중...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/test');
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
resultDiv.innerHTML = `
|
||||||
|
<div style="background: #e8f5e8; padding: 10px; border-radius: 5px;">
|
||||||
|
<strong>✅ API 연결 성공!</strong><br>
|
||||||
|
메시지: ${data.message}<br>
|
||||||
|
시간: ${data.timestamp}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} catch (error) {
|
||||||
|
resultDiv.innerHTML = `
|
||||||
|
<div style="background: #ffe8e8; padding: 10px; border-radius: 5px;">
|
||||||
|
<strong>❌ API 연결 실패</strong><br>
|
||||||
|
오류: ${error.message}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
ssh-connect.sh
Normal file
12
ssh-connect.sh
Normal 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"
|
@@ -29,7 +29,7 @@ header {
|
|||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
header h1 {
|
||||||
color: #4a5568;
|
color: #667eea;
|
||||||
font-size: 2.5rem;
|
font-size: 2.5rem;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
203
synology-git-diagnostic.md
Normal file
203
synology-git-diagnostic.md
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
# 시놀로지 NAS Git Server 진단 및 해결 가이드
|
||||||
|
|
||||||
|
## 🔍 1단계: Git Server 패키지 상태 확인
|
||||||
|
|
||||||
|
### 1.1 DSM 패키지 센터 점검
|
||||||
|
1. **DSM 로그인** → **패키지 센터**
|
||||||
|
2. **설치됨** 탭에서 "Git Server" 검색
|
||||||
|
3. 상태 확인:
|
||||||
|
- ✅ **실행 중**: 정상 동작
|
||||||
|
- ⚠️ **중지됨**: 서비스 시작 필요
|
||||||
|
- ❌ **미설치**: 패키지 설치 필요
|
||||||
|
|
||||||
|
### 1.2 Git Server 서비스 시작
|
||||||
|
```bash
|
||||||
|
# SSH로 NAS 접속 후
|
||||||
|
sudo systemctl status git-daemon
|
||||||
|
sudo systemctl start git-daemon
|
||||||
|
sudo systemctl enable git-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🛠️ 2단계: 기본 설정 확인
|
||||||
|
|
||||||
|
### 2.1 SSH 서비스 활성화
|
||||||
|
1. **DSM 제어판** → **터미널 및 SNMP**
|
||||||
|
2. **SSH 서비스 활성화** 체크
|
||||||
|
3. 포트 번호 확인 (기본: 22)
|
||||||
|
|
||||||
|
### 2.2 사용자 권한 설정
|
||||||
|
1. **DSM 제어판** → **사용자 및 그룹**
|
||||||
|
2. 사용자 선택 → **편집** → **애플리케이션**
|
||||||
|
3. **Git Server** 권한 부여
|
||||||
|
|
||||||
|
### 2.3 방화벽 설정
|
||||||
|
1. **DSM 제어판** → **보안** → **방화벽**
|
||||||
|
2. 다음 포트 허용:
|
||||||
|
- SSH: 22
|
||||||
|
- Git HTTP: 3000
|
||||||
|
- Git HTTPS: 3001
|
||||||
|
|
||||||
|
## 📁 3단계: Git 디렉토리 구조 확인
|
||||||
|
|
||||||
|
### 3.1 기본 경로 확인
|
||||||
|
```bash
|
||||||
|
# SSH 접속 후 확인
|
||||||
|
ls -la /volume1/
|
||||||
|
ls -la /volume1/git/
|
||||||
|
|
||||||
|
# Git 설정 디렉토리 확인
|
||||||
|
ls -la /usr/local/git/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.2 권한 문제 해결
|
||||||
|
```bash
|
||||||
|
# Git 디렉토리 생성
|
||||||
|
sudo mkdir -p /volume1/git
|
||||||
|
sudo chown -R admin:users /volume1/git
|
||||||
|
sudo chmod 755 /volume1/git
|
||||||
|
|
||||||
|
# Git Server 사용자 추가 (필요시)
|
||||||
|
sudo adduser git
|
||||||
|
sudo usermod -a -G users git
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔧 4단계: 레포지토리 수동 생성
|
||||||
|
|
||||||
|
### 4.1 Bare 레포지토리 생성
|
||||||
|
```bash
|
||||||
|
# SSH로 NAS 접속
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# 프로젝트 디렉토리 생성
|
||||||
|
cd /volume1/git
|
||||||
|
sudo mkdir jaryo-file-manager.git
|
||||||
|
cd jaryo-file-manager.git
|
||||||
|
|
||||||
|
# Bare 레포지토리 초기화
|
||||||
|
sudo git init --bare
|
||||||
|
sudo chown -R admin:users .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 웹 인터페이스 활성화
|
||||||
|
```bash
|
||||||
|
# Git HTTP 서버 시작
|
||||||
|
cd /volume1/git
|
||||||
|
sudo git daemon --reuseaddr --base-path=. --export-all --verbose --enable=receive-pack
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🌐 5단계: 웹 인터페이스 설정
|
||||||
|
|
||||||
|
### 5.1 Git Web 설정
|
||||||
|
```bash
|
||||||
|
# CGit 또는 GitWeb 설치
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install gitweb
|
||||||
|
|
||||||
|
# Apache 설정 (Web Station 사용시)
|
||||||
|
sudo ln -s /usr/share/gitweb /volume1/web/git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 브라우저에서 접속
|
||||||
|
- URL: `http://your-nas-ip/git`
|
||||||
|
- 또는: `http://your-nas-ip:3000`
|
||||||
|
|
||||||
|
## 🚨 6단계: 문제 해결
|
||||||
|
|
||||||
|
### 6.1 "레포지토리 설정이 안보임" 해결
|
||||||
|
**원인 1: Git Server 패키지 미설치**
|
||||||
|
```bash
|
||||||
|
# 패키지 센터에서 Git Server 재설치
|
||||||
|
# 또는 수동 Git 설치
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install git git-daemon-run
|
||||||
|
```
|
||||||
|
|
||||||
|
**원인 2: 서비스 시작 실패**
|
||||||
|
```bash
|
||||||
|
# 서비스 상태 확인
|
||||||
|
sudo systemctl status git-daemon
|
||||||
|
sudo journalctl -u git-daemon
|
||||||
|
|
||||||
|
# 수동 재시작
|
||||||
|
sudo systemctl restart git-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
**원인 3: 권한 문제**
|
||||||
|
```bash
|
||||||
|
# 권한 재설정
|
||||||
|
sudo chown -R www-data:www-data /volume1/git
|
||||||
|
sudo chmod -R 755 /volume1/git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 포트 충돌 해결
|
||||||
|
```bash
|
||||||
|
# 포트 사용 확인
|
||||||
|
sudo netstat -tulpn | grep :3000
|
||||||
|
sudo netstat -tulpn | grep :22
|
||||||
|
|
||||||
|
# 다른 포트로 변경
|
||||||
|
sudo git daemon --port=3001 --reuseaddr --base-path=/volume1/git --export-all
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 7단계: 연결 테스트
|
||||||
|
|
||||||
|
### 7.1 로컬에서 연결 테스트
|
||||||
|
```bash
|
||||||
|
# SSH 연결 테스트
|
||||||
|
ssh admin@your-nas-ip
|
||||||
|
|
||||||
|
# Git 클론 테스트
|
||||||
|
git clone ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git
|
||||||
|
|
||||||
|
# 또는 HTTP 연결
|
||||||
|
git clone http://your-nas-ip:3000/jaryo-file-manager.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.2 기존 프로젝트 푸시
|
||||||
|
```bash
|
||||||
|
# 기존 프로젝트에서
|
||||||
|
git remote add nas ssh://admin@your-nas-ip/volume1/git/jaryo-file-manager.git
|
||||||
|
git push nas master
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🔄 8단계: 자동화 설정
|
||||||
|
|
||||||
|
### 8.1 systemd 서비스 생성
|
||||||
|
```bash
|
||||||
|
# /etc/systemd/system/git-daemon.service
|
||||||
|
sudo tee /etc/systemd/system/git-daemon.service << EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Git Daemon
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/volume1/git --export-all --verbose --enable=receive-pack
|
||||||
|
Restart=always
|
||||||
|
User=git
|
||||||
|
Group=git
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo systemctl enable git-daemon
|
||||||
|
sudo systemctl start git-daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 요약
|
||||||
|
|
||||||
|
레포지토리 설정이 보이지 않는 주요 원인:
|
||||||
|
1. ❌ Git Server 패키지 미설치/미실행
|
||||||
|
2. ❌ SSH 서비스 비활성화
|
||||||
|
3. ❌ 사용자 권한 부족
|
||||||
|
4. ❌ 방화벽 차단
|
||||||
|
5. ❌ Git 디렉토리 부재
|
||||||
|
|
||||||
|
해결 순서:
|
||||||
|
1. 패키지 설치/재시작
|
||||||
|
2. SSH 및 권한 설정
|
||||||
|
3. 수동 레포지토리 생성
|
||||||
|
4. 연결 테스트
|
||||||
|
5. 자동화 설정
|
||||||
|
|
||||||
|
이 가이드를 따라하면 시놀로지 NAS에서 Git 레포지토리를 성공적으로 설정할 수 있습니다.
|
39
vercel.json
39
vercel.json
@@ -1,18 +1,33 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"builds": [
|
|
||||||
{
|
|
||||||
"src": "server.js",
|
|
||||||
"use": "@vercel/node"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
"src": "/(.*)",
|
"src": "/simple",
|
||||||
"dest": "/server.js"
|
"dest": "/simple.html"
|
||||||
}
|
},
|
||||||
],
|
{
|
||||||
"env": {
|
"src": "/api/test",
|
||||||
"NODE_ENV": "production"
|
"dest": "/api/test.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/api/files/public",
|
||||||
|
"dest": "/api/files.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/api/files",
|
||||||
|
"dest": "/api/files.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/(.*\\.(css|js|json|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|html))",
|
||||||
|
"dest": "/$1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/admin/(.*)",
|
||||||
|
"dest": "/admin/$1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/",
|
||||||
|
"dest": "/simple.html"
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user