98 lines
6.6 KiB
Markdown
98 lines
6.6 KiB
Markdown
# Git clone + PM2 운영
|
|
|
|
Linux 서버, Node.js 24 이상, MongoDB, 같은 호스트의 HTTPS nginx를 기준으로 한다. 앱은 PM2 fork 프로세스 **1개**만 실행한다. 다른 서버/컨테이너의 프록시를 쓰면 바인딩 주소와 신뢰 프록시 주소를 해당 구성에 맞게 변경한다.
|
|
|
|
## 최초 배포
|
|
|
|
배포할 코드와 새 파일을 먼저 커밋·push한다. 서버에서는 일반 서비스 계정으로 실행한다.
|
|
|
|
```bash
|
|
git clone https://gitea.horoli.kr/horoli/ssessesse-ki-battle.git dragon_ball
|
|
cd dragon_ball
|
|
npm ci
|
|
cp .config.example.json .config.json
|
|
chmod 600 .config.json
|
|
```
|
|
|
|
`.config.json`에서 다음을 설정한다.
|
|
|
|
- `MONGODB_URI`: 서버에서 연결 가능한 MongoDB 주소와 인증 정보. DB 포트를 인터넷에 공개하지 않는다.
|
|
- `MONGODB_DATABASE`: 저장소 이름과 같은 `ssessesse-ki-battle`을 사용한다. 해당 DB가 비어 있을 때 새 데이터로 시작하며, 기존 DB를 자동 삭제하거나 이전하지 않는다.
|
|
- `HOST=127.0.0.1`, `PORT=2100`, `TRUST_PROXY=loopback`: 같은 서버 nginx 전용. `TRUST_PROXY`는 쉼표로 구분한 신뢰 프록시 IP/CIDR 또는 `loopback`이며 직접 접속이면 비운다.
|
|
- `ADMIN_USER`, `ADMIN_PASSWORD`: 둘 다 지정하면 관리자 기능 활성화. 강한 전용 비밀번호를 사용한다.
|
|
- `STUN_URLS`, `TURN_URLS`, `TURN_SHARED_SECRET`: 친구전 ICE 설정. TURN 서버의 공유 비밀과 일치해야 하며 TURN 수신 포트·relay 포트 범위는 별도로 개방한다.
|
|
- `LOG_LEVEL=info`: 운영 로그 수준.
|
|
|
|
```bash
|
|
npm run typecheck
|
|
npm run build
|
|
npm install --global pm2
|
|
pm2 start ecosystem.config.cjs
|
|
pm2 save
|
|
pm2 startup
|
|
```
|
|
|
|
`pm2 startup`이 출력하는 명령을 실행한다. Node 버전 관리자를 변경하면 startup 설정도 갱신한다. PM2는 저장소 루트를 사용하며 `.config.json`이 없거나 형식이 잘못되면 시작하지 않는다. 앱 설정은 이 JSON 파일만 읽으며 같은 이름의 환경변수나 기존 `.env`로 덮어쓰지 않는다. `npm run dev`와 `npm start`는 프로젝트 루트에서 실행한다.
|
|
|
|
JSON의 `PORT`는 숫자, `STUN_URLS`·`TURN_URLS`는 문자열 배열이다. URL이 없으면 `[]`를 사용한다. 로컬과 운영 모두 DB 이름은 `ssessesse-ki-battle`이므로 데이터를 분리하려면 `MONGODB_URI`가 서로 다른 MongoDB 인스턴스를 가리켜야 한다. 같은 인스턴스와 DB 이름을 사용하면 데이터를 공유한다. 설정 수정 후 프로세스를 재시작한다. 누락 시 로그의 `CONFIG_NOT_FOUND`, 형식 오류 시 `INVALID_CONFIG`를 확인한다.
|
|
|
|
기존 `.env` 배포에서 전환할 때는 `.config.example.json`을 `.config.json`으로 복사한 후 기존 값을 옮긴다. 이전 PM2 프로세스에 저장된 `--env-file` 실행 인자를 없애려면 앱 중지·빌드 후 `pm2 delete dragon-ball`, `pm2 start ecosystem.config.cjs`, `pm2 save` 순서로 등록한다. 기존 `.env`는 백업으로 보관할 수 있지만 앱에서 읽지 않는다.
|
|
|
|
```bash
|
|
curl --fail http://127.0.0.1:2100/health
|
|
curl --fail http://127.0.0.1:2100/ready
|
|
pm2 logs ssessesse --lines 50
|
|
```
|
|
|
|
`/health`는 프로세스 응답, `/ready`는 DB 연결을 확인한다.
|
|
|
|
## HTTPS 및 Socket.IO
|
|
|
|
`deploy/nginx.conf.example`의 도메인과 인증서 경로를 교체해 nginx 설정에 추가한다. 해당 도메인의 인증서를 먼저 준비한다. 예시는 인증서 발급을 자동화하지 않는다.
|
|
|
|
```bash
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
외부에서는 HTTPS 주소로 접속한다. `/signal`은 Socket.IO namespace이며 프록시 전송 경로는 `/socket.io/`다. 예시는 WebSocket 업그레이드와 polling을 함께 전달한다. 인터넷에 직접 노출된 nginx가 `X-Forwarded-For`를 실제 접속 IP로 덮어쓴다. CDN/추가 프록시 뒤에서는 원본 IP 검증 구성을 먼저 맞춘다. 앱의 2100 포트는 외부에 개방하지 않는다.
|
|
|
|
앱 API의 IP별 요청 제한과 별도로 nginx는 Socket.IO 요청을 IP당 초당 10회, 순간 초과 40회까지 허용한다. 공유 IP 사용자가 많으면 실제 사용량을 보고 조정한다. TURN 트래픽은 nginx HTTP 프록시를 통과하지 않는다.
|
|
|
|
앱은 IP별 1분 창에서 API 전체 1,200회, 세션 생성 30회, 관리자 HTML/API 합계 60회를 허용한다. 초과하면 HTTP 429와 `Retry-After`를 반환하며 DB 처리 전에 차단한다. 기준값은 `constants/server.ts`에서 관리한다. 제한 상태는 메모리에만 보관하고 재시작 시 초기화한다. 관리자 제한도 공유 IP 기준이므로 관리자가 같은 네트워크를 사용하면 합산된다.
|
|
|
|
랭킹 개인 전적 캐시는 최대 1,000명·5분, 리더보드는 5초 동안 재사용하며 결과 저장 시 무효화한다. 동시 리더보드 요청은 하나의 계산을 공유한다. 캐시가 없거나 만료되면 저장된 경기 기록을 다시 읽으므로 대규모 장기 운영에서 영구 집계를 대신하는 구조는 아니다. 단일 프로세스만 같은 운영 DB에 쓰도록 유지한다.
|
|
|
|
## 업데이트
|
|
|
|
단일 프로세스이므로 배포 중 접속이 중단되며 진행 중 랭킹 경기는 복원되지 않는다. 운영 폴더를 실행 중에 빌드하지 않도록 중지 후 갱신한다.
|
|
|
|
```bash
|
|
pm2 stop ssessesse
|
|
git pull --ff-only
|
|
npm ci
|
|
npm run typecheck
|
|
npm run build
|
|
pm2 restart ecosystem.config.cjs --update-env
|
|
curl --fail http://127.0.0.1:2100/ready
|
|
pm2 save
|
|
```
|
|
|
|
각 명령이 성공한 경우에만 다음 단계로 진행한다. 빌드 실패 시 재시작하지 말고 수정하거나 이전 커밋으로 복구한 후 다시 설치·빌드한다. `.config.json`는 Git에서 제외되어 유지된다. 데이터 백업은 MongoDB를 별도로 관리한다.
|
|
|
|
## 로그 관리 및 운영 확인
|
|
|
|
```bash
|
|
pm2 status
|
|
pm2 logs ssessesse --lines 100
|
|
pm2 install pm2-logrotate
|
|
pm2 set pm2-logrotate:max_size 10M
|
|
pm2 set pm2-logrotate:retain 7
|
|
```
|
|
|
|
로그 회전은 디스크가 무한히 늘어나지 않도록 운영 서버에서 설정한다. 예시 nginx는 access log를 끄지만 nginx 자체 error log에는 URL·IP가 기록될 수 있으므로 서버의 로그 접근권한과 보관 정책도 설정한다.
|
|
|
|
배포 후 서로 다른 인터넷망에서 친구전 연결·재대전, 랭킹 매칭·승패 저장, 관리자 인증을 확인한다. 로컬 테스트 통과가 실제 TURN 경로 검증을 대신하지 않는다.
|
|
|
|
참고: [PM2 설정](https://pm2.keymetrics.io/docs/usage/application-declaration/), [PM2 종료 처리](https://pm2.keymetrics.io/docs/usage/signals-clean-restart/), [nginx WebSocket 프록시](https://nginx.org/en/docs/http/websocket.html).
|