TPR Mirror for Dongtan Stub
Find a file
2025-12-04 09:01:18 +09:00
public feat: migrate next.js 2025-10-23 12:36:53 +09:00
scripts feat: update 2025-10-25 17:22:38 +09:00
src feat: update 2025-10-25 17:22:38 +09:00
systemd feat: migrate next.js 2025-10-23 12:36:53 +09:00
.env.example feat: add some features 2025-10-25 01:57:41 +09:00
.gitignore feat: migrate next.js 2025-10-23 12:36:53 +09:00
bun.lock HOTFIX: fixed security issue with update dependencies 2025-12-04 09:01:18 +09:00
eslint.config.mjs feat: mirror status for all 2025-10-24 15:39:21 +09:00
LICENSE feat: LICENSE 2025-11-24 15:59:31 +09:00
next.config.ts feat: migrate next.js 2025-10-23 12:36:53 +09:00
package.json HOTFIX: fixed security issue with update dependencies 2025-12-04 09:01:18 +09:00
README.md Update README.md 2025-11-24 16:00:15 +09:00
tsconfig.json feat: migrate next.js 2025-10-23 12:36:53 +09:00

TPR Mirror

개인이 운영하는 비영리 미러서버 웹사이트

기술 스택

  • Framework: Next.js 16.0.0 (App Router)
  • Runtime: Bun
  • Language: TypeScript
  • Styling: SCSS
  • UI: React 19.2.0

설치 및 실행

1. 의존성 설치

bun install

2. 환경 변수 설정

.env.example 파일을 복사하여 .env 파일을 생성하고 필요한 값을 설정합니다.

cp .env.example .env

주요 환경 변수:

  • SERVER_HOST: 서버 호스트 (기본값: 0.0.0.0)
  • SERVER_PORT: 서버 포트 (기본값: 3000)
  • NODE_ENV: 환경 (development/production/test)
  • SERVER_SECRET: API 인증 시크릿 키 (프로덕션에서 반드시 변경!)
  • CORS_ORIGIN: CORS 허용 도메인
  • CONFIG_FILE: 미러 설정 파일 경로 (기본값: mirrors.json)

3. 개발 서버 실행

bun run dev

브라우저에서 http://localhost:3000을 열어 확인합니다.

4. 프로덕션 빌드

bun run build
bun run start

API 엔드포인트

GET /api/mirrors

미러 목록을 조회합니다.

응답 예시:

[
    {
        "id": "1234567890",
        "name": "Fedora",
        "path": "/fedora",
        "last_sync_at": "2025-10-23T00:00:00.000Z",
        "status": 0
    }
]

상태 코드:

  • 0: SUCCESS (성공)
  • 1: FAILED (실패)
  • 2: SYNCING (동기화 중)

POST /api/mirrors

미러 정보를 생성 또는 업데이트합니다.

헤더:

Authorization: your-secret-key

요청 본문:

{
    "id": "1234567890",
    "name": "Fedora",
    "path": "/fedora",
    "last_sync_at": "2025-10-23T00:00:00.000Z",
    "status": 0
}

응답:

{
    "ok": 1
}

미러 데이터 관리

초기화

서버가 처음 시작될 때, CONFIG_FILE에 지정된 파일(기본값: mirrors.json)이 없으면 자동으로 빈 배열로 생성됩니다.

데이터 구조

interface MirrorData {
    id: string;              // 고유 ID
    name: string;            // 표시 이름 (예: "Fedora", "Linux Mint Packages")
    path: string;            // 미러 경로 (예: "/fedora", "/linuxmint-packages")
    last_sync_at: Date;      // 마지막 동기화 시간
    status: MirrorStatus;    // 상태 (0: SUCCESS, 1: FAILED, 2: SYNCING)
}

동작 방식

  • 자동 생성: mirrors.json 파일이 없으면 서버 시작 시 자동으로 빈 배열([])로 생성됩니다.
  • 업데이트: POST 요청으로 미러 정보를 전송하면, 동일한 id를 가진 미러의 정보가 업데이트됩니다.
  • 유동적 관리: 파일 시스템 기반으로 동작하여, 직접 mirrors.json을 편집하거나 API를 통해 관리할 수 있습니다.

프로젝트 구조

tpr-mirror/
├── src/
│   ├── app/              # Next.js App Router
│   │   ├── api/          # API 라우트
│   │   │   └── mirrors/  # 미러 API
│   │   ├── layout.tsx    # 루트 레이아웃
│   │   ├── page.tsx      # 메인 페이지
│   │   └── globals.scss  # 전역 스타일
│   ├── components/       # React 컴포넌트
│   │   ├── Card.tsx
│   │   ├── Header.tsx
│   │   └── Mirror.tsx
│   ├── lib/              # 유틸리티 및 타입
│   │   ├── env.ts        # 환경 변수 검증
│   │   ├── snowflake_id.ts
│   │   └── types.ts      # TypeScript 타입
│   └── services/         # 비즈니스 로직
│       └── mirror.ts     # 미러 서비스
├── public/               # 정적 파일
├── .env.example          # 환경 변수 예제
└── mirrors.json.example  # 미러 설정 예제

반응형 디자인

  • 데스크톱 (1024px+): 2열 그리드
  • 태블릿 (768px - 1023px): 2열 그리드, 최적화된 간격
  • 모바일 (767px 이하): 1열 그리드
  • 소형 모바일 (560px 이하): 폰트 크기 및 간격 조정

프로덕션 배포

Standalone 모드로 배포하기

이 프로젝트는 Next.js의 Standalone 출력 모드를 사용하여 최적화된 프로덕션 배포를 지원합니다.

자동 설치 (권장)

제공된 설치 스크립트를 사용하여 자동으로 배포할 수 있습니다:

sudo bash scripts/install.sh

설치 스크립트가 수행하는 작업:

  1. Next.js 애플리케이션을 프로덕션 모드로 빌드
  2. 기존 설치 백업 (있는 경우)
  3. /usr/share/tpr-mirror/에 애플리케이션 파일 복사
  4. 환경 변수 설정
  5. systemd 서비스 설치 및 활성화
  6. 서비스 시작

수동 설치

수동으로 배포하려면 다음 단계를 따르세요:

1. 프로덕션 빌드

bun run build

빌드가 완료되면 .next/standalone 폴더가 생성됩니다.

2. 파일 복사

sudo mkdir -p /usr/share/tpr-mirror
sudo cp -r .next/standalone/* /usr/share/tpr-mirror/
sudo cp -r public /usr/share/tpr-mirror/
sudo cp -r .next/static /usr/share/tpr-mirror/.next/
sudo cp .env.production /usr/share/tpr-mirror/.env

3. 환경 변수 설정

sudo nano /usr/share/tpr-mirror/.env

중요: SERVER_SECRET을 강력한 랜덤 문자열로 변경하세요!

# 랜덤 시크릿 생성 예시
openssl rand -base64 32

4. systemd 서비스 설치

서비스 파일은 템플릿이므로, 사용자 정보를 치환하여 설치해야 합니다:

# 현재 사용자와 그룹 정보로 서비스 파일 생성
CURRENT_USER=$(whoami)
CURRENT_GROUP=$(id -gn)

sudo sed -e "s/{{USER}}/$CURRENT_USER/g" \
    -e "s/{{GROUP}}/$CURRENT_GROUP/g" \
    systemd/tpr-mirror.service > /tmp/tpr-mirror.service

sudo mv /tmp/tpr-mirror.service /etc/systemd/system/tpr-mirror.service
sudo systemctl daemon-reload
sudo systemctl enable tpr-mirror
sudo systemctl start tpr-mirror

또는 간단하게:

# 설치 스크립트 사용 (자동으로 사용자 정보 치환)
sudo npm run install

5. 서비스 상태 확인

sudo systemctl status tpr-mirror

nginx 리버스 프록시 설정

Next.js 애플리케이션은 포트 3000에서 실행됩니다. nginx를 리버스 프록시로 설정하여 80/443 포트에서 서빙할 수 있습니다.

nginx 설정 예시

/etc/nginx/conf.d/tpr-mirror.conf:

upstream tpr_mirror {
    server localhost:3000;
    keepalive 64;
}

server {
    listen 80;
    server_name your-domain.com;  # 도메인으로 변경

    # Next.js 애플리케이션
    location / {
        proxy_pass http://tpr_mirror;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }

    # 미러 파일 직접 서빙 (예시)
    location /fedora {
        alias /srv/mirror/fedora/;
        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
    }
}

설정 후 nginx 재시작:

sudo nginx -t  # 설정 검증
sudo systemctl reload nginx

서비스 관리

# 서비스 시작
sudo systemctl start tpr-mirror

# 서비스 중지
sudo systemctl stop tpr-mirror

# 서비스 재시작
sudo systemctl restart tpr-mirror

# 서비스 상태 확인
sudo systemctl status tpr-mirror

# 로그 확인
sudo journalctl -u tpr-mirror -f

# 최근 50줄 로그
sudo journalctl -u tpr-mirror -n 50

제거

애플리케이션을 완전히 제거하려면:

sudo bash scripts/uninstall.sh

제거 스크립트는 다음을 수행합니다:

  • 서비스 중지 및 비활성화
  • 설치 디렉토리 백업 및 제거
  • 로그 제거 (선택 사항)
  • 이전 백업 정리 (선택 사항)

업데이트

새 버전으로 업데이트하려면:

# 1. 최신 코드 가져오기
git pull

# 2. 의존성 업데이트 (필요시)
bun install

# 3. 재설치
sudo bash scripts/install.sh

기존 설치는 자동으로 백업되며, 문제 발생 시 /usr/share/tpr-mirror.backup.YYYYMMDD_HHMMSS/에서 복원할 수 있습니다.

배포 구조

/usr/share/tpr-mirror/     # 애플리케이션 루트
├── server.js              # Standalone 서버
├── .next/                 # Next.js 빌드 출력
│   └── static/            # 정적 리소스
├── public/                # Public 파일
├── package.json           # 최소 의존성
├── node_modules/          # 필수 모듈만 포함
├── .env                   # 환경 변수
└── mirrors.json           # 미러 데이터 (자동 생성)

/var/log/tpr-mirror/       # 로그 디렉토리
/etc/systemd/system/
└── tpr-mirror.service     # systemd 서비스

문제 해결

서비스가 시작되지 않을 때

# 상세 로그 확인
sudo journalctl -u tpr-mirror -n 100 --no-pager

# 환경 변수 확인
sudo cat /usr/share/tpr-mirror/.env

# 권한 확인
ls -la /usr/share/tpr-mirror/

# 수동 실행 테스트
cd /usr/share/tpr-mirror
node server.js

포트 충돌

다른 애플리케이션이 3000 포트를 사용 중이면:

  1. .env 파일에서 SERVER_PORT 변경
  2. nginx 설정에서 proxy_pass 포트 변경
  3. 서비스 재시작

mirrors.json 권한 문제

sudo chown devproje:devproje /usr/share/tpr-mirror/mirrors.json
sudo chmod 644 /usr/share/tpr-mirror/mirrors.json

미러 동기화 스크립트

개요

scripts/sync-mirror.sh는 rsync를 사용하여 미러를 동기화하고, API를 통해 웹 UI에 실시간 상태를 업데이트하는 스크립트입니다.

설치

# 스크립트를 /usr/bin으로 복사 (또는 심볼릭 링크)
sudo cp scripts/sync-mirror.sh /usr/bin/sync-mirror.sh
sudo chmod +x /usr/bin/sync-mirror.sh

# 또는 심볼릭 링크 사용
sudo ln -s /usr/share/tpr-mirror/scripts/sync-mirror.sh /usr/bin/sync-mirror.sh

사용법

sync-mirror.sh <mirror_url> <target_mirror_path> <mirror_name> [mirror_id]

인자:

  • mirror_url: rsync URL (예: rsync://mirrors.kernel.org/fedora/)
  • target_mirror_path: 디렉토리 이름 (예: fedora)
  • mirror_name: 표시 이름 (예: "Fedora")
  • mirror_id: 고유 ID (선택, 환경 변수 MIRROR_ID로도 설정 가능)

환경 변수:

  • MIRROR_ID: 미러 고유 ID (필수, 인자 또는 환경 변수로 제공)
  • API_URL: API 서버 주소 (기본값: http://localhost:3000)
  • API_SECRET: API 인증 키 (기본값: your-secret-key-here, .envSERVER_SECRET과 동일하게 설정)

예시

# 기본 사용 (ID를 인자로 전달)
sync-mirror.sh rsync://mirrors.kernel.org/fedora/ fedora "Fedora" 1234567890

# 환경 변수로 ID 전달
MIRROR_ID=1234567890 sync-mirror.sh rsync://mirrors.kernel.org/fedora/ fedora "Fedora"

# API 설정과 함께
API_URL=http://localhost:3000 \
API_SECRET=your-production-secret \
MIRROR_ID=1234567890 \
sync-mirror.sh rsync://mirrors.kernel.org/fedora/ fedora "Fedora"

Crontab 설정

# /etc/cron.d/tpr-mirror 또는 crontab -e

# 환경 변수 설정
API_URL=http://localhost:3000
API_SECRET=your-production-secret-here

# Linux Mint Packages (매 2시간마다)
MIRROR_ID=1234567890
0 */2 * * * root /usr/bin/sync-mirror.sh "rsync-packages.linuxmint.com::packages/" "linuxmint-packages" "Linux Mint Packages" >> /var/log/rsync_sync_l_mint_pkg.log 2>&1

# Fedora (매일 새벽 2시)
MIRROR_ID=1234567891
0 2 * * * root /usr/bin/sync-mirror.sh "rsync://mirrors.kernel.org/fedora/" "fedora" "Fedora" >> /var/log/rsync_sync_fedora.log 2>&1

# Kali Linux (매일 새벽 3시)
MIRROR_ID=1234567892
0 3 * * * root /usr/bin/sync-mirror.sh "rsync://archive-4.kali.org/kali/" "kali" "Kali Linux" >> /var/log/rsync_sync_kali.log 2>&1

# Ubuntu (매일 새벽 4시)
MIRROR_ID=1234567893
0 4 * * * root /usr/bin/sync-mirror.sh "rsync://archive.ubuntu.com/ubuntu/" "ubuntu" "Ubuntu" >> /var/log/rsync_sync_ubuntu.log 2>&1

동작 흐름

  1. 동기화 시작: API에 status: 2 (SYNCING) 전송
  2. rsync 실행: 미러 데이터 동기화
  3. 결과 전송: 성공 시 status: 0 (SUCCESS), 실패 시 status: 1 (FAILED) 전송
  4. 웹 UI 업데이트: 실시간으로 상태가 화면에 반영됨

로그

모든 동기화 로그는 /mnt/drive/logs/<mirror_path>.log에 저장됩니다.

# 로그 확인
tail -f /mnt/drive/logs/fedora.log

ID 관리

각 미러는 고유한 ID를 가져야 하며, 한 번 설정한 ID는 변경하지 마세요.

ID 생성 방법:

# Timestamp 기반 ID 생성
echo $(date +%s)000
# 예: 1730000000000

# 또는 간단히 순차적으로
1234567890  # linuxmint-packages
1234567891  # fedora
1234567892  # kali
1234567893  # ubuntu

라이선스

해당 미러의 소스코드 라이선스는 GPL-2.0 License를 따릅니다. 그 이외의 이미지 에셋(파비콘, 이미지 등)은 Project_IO에게 저작권이 있습니다.