Files
uniare.sori.studio/docs/deploy.md
zenn f3b7ac6cf0 v4.0.7: 덱 목록 JS 캐시 무효화 및 UaDeckFavorites.init 방어 처리
구 deck-favorites.js가 CDN에 남아 init 호출이 덱 로드를 막던 문제를 스크립트 ?v= 쿼리와 optional init로 수정한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 16:19:03 +09:00

7.1 KiB

UNIARE 실행·배포 가이드

필요한 부분만 골라서 읽으면 된다.

  1. 내 컴퓨터에서 실행: 1. 로컬 실행
  2. NAS에 처음 설치: 2. NAS 최초 배포
  3. 이미지나 카드 데이터 반영: 3. 정적 파일 업데이트
  4. API나 Docker 설정 반영: 4. 전체 업데이트

로컬 주소는 http://localhost:44082, 운영 주소는 https://uniare.sori.studio이다. Git 저장소는 https://git.sori.studio/zenn/union-arena-deck-builder.git이다.

시작 전 확인

  • 명령은 프로젝트 폴더에서 실행한다.
  • 로컬과 NAS는 각각 다른 .env와 DB를 사용한다.
  • .env, DB, 비밀번호는 Git에 올리지 않는다.
  • 카드 이미지는 Git LFS로 관리한다.
  • 로컬 위치는 <LOCAL_PROJECT_DIR>/uniare.sori.studio, NAS 위치는 <NAS_PROJECT_DIR>/uniare.sori.studio로 표기한다.

1. 로컬 실행

최초 한 번 프로젝트 폴더에서 cp .env.example .env를 실행한다.

.env에서 다음 값을 변경한다.

JWT_SECRET=32자_이상의_랜덤_문자열
ADMIN_EMAIL=관리자_이메일
ADMIN_PASSWORD=8자_이상의_비밀번호
WEB_PORT=44082

랜덤 문자열은 openssl rand -hex 32로 만들 수 있다.

실행은 npm start, 종료는 npm stop, 로그 확인은 npm run logs를 사용한다. 실행 후 브라우저에서 http://localhost:44082에 접속한다.

2. NAS 최초 배포

NAS에 Git, Git LFS, Docker, Docker Compose가 설치되어 있어야 한다.

저장소를 받는다.

cd <NAS_PROJECT_DIR>
git clone https://git.sori.studio/zenn/union-arena-deck-builder.git uniare.sori.studio
cd uniare.sori.studio
git lfs pull
cp .env.example .env

.env에서 다음 값을 운영 환경에 맞게 변경한다.

JWT_SECRET=32자_이상의_랜덤_문자열
ADMIN_EMAIL=관리자_이메일
ADMIN_PASSWORD=8자_이상의_비밀번호
ADMIN_USERNAME=admin
WEB_PORT=44082
CORS_ORIGINS=https://uniare.sori.studio

Docker 실행: docker compose -f docker-compose.prod.yml up -d --build

상태 확인: docker compose -f docker-compose.prod.yml ps

API 확인: curl -fsS http://localhost:44082/api/v1/health

정상이면 {"ok":true,"version":"4.0.3"}이 표시된다.

NAS 리버스 프록시는 https://uniare.sori.studio을 http://<NAS_IP>:44082로 연결한다.

3. 정적 파일 업데이트

이미지, 카드 데이터, HTML, CSS, 프론트 JavaScript는 Docker 이미지를 다시 빌드하지 않아도 된다.

이미지만 변경

NAS 프로젝트 폴더에서 git pull --ff-only와 git lfs pull을 실행한 뒤 브라우저를 강력 새로고침한다. 컨테이너 재시작은 필요 없다.

datas/*.js 변경

NAS 프로젝트 폴더에서 다음 명령을 실행한다.

git pull --ff-only
git lfs pull
docker compose -f docker-compose.prod.yml restart uniare-api

API가 카드 데이터를 메모리에 저장하므로 datas/ 변경 시 API만 재시작한다. 이미지와 datas/*.js를 함께 변경한 경우도 같은 절차를 사용한다.

확인할 내용:

  • imgSrc와 실제 이미지 파일명이 같은가?
  • 파일명 대소문자가 같은가?
  • 신규 시리즈가 번역 파일 3개에 등록되어 있는가?
  • 카드 목록과 저장 덱에서 모두 정상 표시되는가?

HTML·일반 CSS·프론트 JavaScript 변경

NAS는 npm이 없어도 된다. style/output.css는 로컬에서 빌드해 Git에 포함되므로 git pull만 하면 스타일이 반영된다.

git pull --ff-only
git lfs pull

배포 후 확인 (NAS 프로젝트 폴더):

wc -c style/output.css    # 약 55000 (55KB) — 44000대면 구버전, pull 누락
head -1 login.html        # output.css?v= 버전 쿼리 포함 여부

브라우저에서도 개발자 도구 → Network → output.css·deck-favorites.js 크기·상태를 확인한다. Cloudflare를 쓰면 구 파일이 immutable로 남을 수 있어 HTML에 ?v= 쿼리를 붙인다 (v4.0.6+ CSS, v4.0.7+ 덱 페이지 JS).

script/deck-favorites.js는 window.UaDeckFavorites.init이 있어야 한다. 없으면 git pull 누락 또는 JS CDN 캐시다.

4. 전체 업데이트

api/, nginx/, Dockerfile, Compose 설정을 변경했다면 NAS 프로젝트 폴더에서 다음 명령을 실행한다.

git pull --ff-only
git lfs pull
docker compose -f docker-compose.prod.yml up -d --build

상태 확인은 docker compose -f docker-compose.prod.yml ps, API 확인은 curl -fsS http://localhost:44082/api/v1/health를 사용한다.

.env를 변경했다면 docker compose -f docker-compose.prod.yml up -d --force-recreate로 컨테이너를 재생성한다.

5. CSS 빌드

Tailwind 클래스를 새로 추가했을 때만 로컬에서 npm install과 npm run build:css를 실행한다. 생성된 style/output.css도 Git에 포함한다. 이미지, 카드 데이터, 기존 CSS만 수정했다면 실행하지 않아도 된다.

6. 자주 쓰는 운영 명령

  • 전체 재시작: docker compose -f docker-compose.prod.yml restart
  • API만 재시작: docker compose -f docker-compose.prod.yml restart uniare-api
  • 로그 확인: docker compose -f docker-compose.prod.yml logs -f
  • 종료: docker compose -f docker-compose.prod.yml down
  • 다시 실행: docker compose -f docker-compose.prod.yml up -d

7. 백업

DB는 Docker 볼륨의 /data/uadeck.db에 있다. 덱 미리보기와 아바타는 api/data/previews/, api/data/avatars/에 있다.

DB 백업:

mkdir -p backup
BACKUP_FILE="uadeck-$(date +%Y%m%d-%H%M%S).db"
docker exec uniare-api node --input-type=module -e "import Database from 'better-sqlite3'; const db = new Database('/data/uadeck.db'); await db.backup('/data/$BACKUP_FILE'); db.close();"
docker cp "uniare-api:/data/$BACKUP_FILE" "./backup/$BACKUP_FILE"
docker exec uniare-api rm "/data/$BACKUP_FILE"

미리보기와 아바타 백업: tar -czf "./backup/uploads-$(date +%Y%m%d-%H%M%S).tar.gz" api/data/previews api/data/avatars

.env는 Git이 아닌 접근 제한된 별도 위치에 보관한다.

8. 롤백

문제가 발생하면 DB를 먼저 백업하고 git log --oneline -10으로 이전 정상 커밋을 확인한다.

git checkout <정상_커밋_해시>
git lfs pull
docker compose -f docker-compose.prod.yml up -d --build

API 확인: curl -fsS http://localhost:44082/api/v1/health

최신 main으로 돌아갈 때는 git checkout main과 git pull --ff-only를 실행한다.

9. 문제가 생겼을 때

웹이 열리지 않으면 docker compose -f docker-compose.prod.yml ps와 docker compose -f docker-compose.prod.yml logs --tail=100을 확인한다.

로그인이나 저장이 안 되면 curl -fsS http://localhost:44082/api/v1/health로 API 상태를 확인한다.

카드 이미지가 보이지 않으면 git lfs pull을 실행하고 datas/*.js의 imgSrc와 실제 이미지 파일명을 비교한다.

완료 확인

  • uniare-web, uniare-api가 실행 중인가?
  • API가 ok: true를 반환하는가?
  • 홈과 카드 이미지가 열리는가?
  • 로그인과 덱 저장이 동작하는가?
  • .env와 DB가 Git에 포함되지 않았는가?