Files
sori.studio/docs/deploy.md

9.7 KiB

배포 가이드

현재 프로젝트는 Nuxt 3 초기 스캐폴딩 상태다. Docker 설정은 파일 기준 초안이 있으며 운영 DB 확정 후 NAS에서 검증한다.

빌드 유형

유형 명령어 용도
개발 npm run dev 로컬 테스트, 개발 서버
프로덕션 npm run build NAS 배포, 운영 서버

npm run dev는 프로젝트 전용 실행 스크립트를 통해 개발 서버, Admin, Tailwind Viewer 링크만 요약 출력한다.


로컬 개발

필수 조건

  • Node.js 22 LTS 권장
  • npm 9+
  • 개발 DB

실행 단계

# 프로젝트 클론
git clone https://git.sori.studio/zenn/sori.studio.git

# 디렉토리 이동
cd sori.studio

# 의존성 설치
npm install

# 개발 환경 변수 설정
# .env.development는 Git에 올리지 않는 로컬 전용 파일
# 새로 만들 때는 .env.example을 복사한 뒤 비밀번호를 랜덤 값으로 교체
cp .env.example .env.development
openssl rand -hex 32
# 로컬 DB 컨테이너를 호스트에서 접근할 때는 127.0.0.1:43119 사용

# 개발 서버 실행 (127.0.0.1:43117)
npm run dev

로컬 개발 DB

로컬 개발 DB는 Docker Compose의 sori-studio-db 서비스만 실행한다.

# Docker daemon 시작
# Docker Desktop을 사용하면 Docker.app을 먼저 실행
# Colima를 사용하면 아래 명령 실행
colima start

# 개발 DB 컨테이너 실행
ENV_FILE=.env.development docker compose --env-file .env.development up -d sori-studio-db

# 개발 DB 마이그레이션 실행
npm run db:migrate:dev

# DB 준비 상태 확인
docker exec sori-studio-db pg_isready -U sori_studio -d sori_studio

# 시드 데이터 확인
docker exec sori-studio-db psql -U sori_studio -d sori_studio -c 'SELECT count(*) AS posts_count FROM posts;'

확인 주소

로컬 DB 확인 방법

로컬 개발 DB는 PostgreSQL이며 호스트에서는 127.0.0.1:43119로 접근한다. 접속 정보는 Git에 포함하지 않는 .env.development 값을 사용한다.

항목
Host 127.0.0.1
Port 43119
Database .env.developmentPOSTGRES_DB
User .env.developmentPOSTGRES_USER
Password .env.developmentPOSTGRES_PASSWORD

터미널에서 바로 확인할 때는 컨테이너 내부 psql을 사용한다.

# DB 준비 상태 확인
docker exec sori-studio-db pg_isready -U sori_studio -d sori_studio

# 게시물 개수 확인
docker exec sori-studio-db psql -U sori_studio -d sori_studio -c 'SELECT count(*) AS posts_count FROM posts;'

# psql 콘솔 접속
docker exec -it sori-studio-db psql -U sori_studio -d sori_studio

GUI로 확인할 때는 DBeaver, TablePlus, DataGrip, CloudBeaver 같은 PostgreSQL 클라이언트에서 위 접속 정보를 입력한다. phpMyAdmin은 MySQL/MariaDB용 도구라 이 프로젝트의 PostgreSQL DB 확인 용도로는 사용하지 않는다.


UGREEN NAS Docker 배포

Dockerfile과 docker-compose 설정은 초안이며 NAS 운영 환경에서는 아직 검증 전이다.

SSH 접속

ssh [NAS_IP]

프로젝트 설치

# 프로젝트 디렉토리로 이동
cd /volume1/docker/sori.studio

# 프로젝트 클론
git clone https://git.sori.studio/zenn/sori.studio.git

# 디렉토리 이동
cd sori.studio

# 운영 환경 변수 설정
# .env.production은 Git에 올리지 않는 운영 전용 파일
cp .env.example .env.production
# .env.production 파일에 운영 DB 연결 정보, 운영 전용 랜덤 비밀번호, APP_PORT=43118 입력
# Docker 내부 앱에서 PostgreSQL에 접근할 때는 sori-studio-db:5432 사용

# Docker 빌드 및 실행
docker compose --env-file .env.production up -d

프로덕션 빌드 (NAS에서)

# 프로덕션 빌드
npm run build

# 또는 Docker로 빌드
docker build -t sori.studio:latest .
docker run -d -p 3000:3000 sori.studio:latest

포트

  • 로컬 개발: 43117
  • NAS Docker 외부: 43118
  • 컨테이너 내부: 3000
  • PostgreSQL 외부: 43119
  • HTTPS: 3001 (SSL 설정 시)

데이터베이스

  • 로컬 개발: .env.developmentDATABASE_URL
  • NAS 운영: .env.productionDATABASE_URL
  • 로컬 개발 예시: postgres://sori_studio:비밀번호@127.0.0.1:43119/sori_studio
  • NAS Docker 예시: postgres://sori_studio:비밀번호@sori-studio-db:5432/sori_studio
  • .env.example에는 실제 비밀번호나 개인 이메일을 기록하지 않음
  • 개발/운영 DB 비밀번호와 관리자 비밀번호는 서로 다른 랜덤 값을 사용
  • 개발 DB와 운영 DB는 반드시 별도 인스턴스 또는 별도 데이터베이스로 분리
  • 운영 DB는 로컬 개발 서버에서 직접 연결하지 않음

이메일 인증(Resend, 선택)

회원가입(일반)·비밀번호 찾기에 이메일 OTP를 쓰려면 npm run db:migrate:dev018_email_otp_challenges.sql을 적용하고, .env에 다음을 설정한다.

변수 설명
RESEND_API_KEY Resend API 키
RESEND_FROM_EMAIL 발신 주소(Resend에서 허용된 도메인 또는 테스트 발신자)
MEMBER_SESSION_SECRET 세션 쿠키 서명용 비밀값. OTP 해시에 쓰는 pepper로도 사용되므로, EMAIL_OTP_PEPPER를 비워 두면 이 값이 OTP용 비밀 재료가 된다.
EMAIL_OTP_PEPPER 선택. 이메일로 받은 6자리 숫자를 DB에 넣기 전 SHA256 해시할 때 섞는 서버 전용 비밀 문자열이다. DB가 유출돼도 pepper를 모르면 인증번호 역산·무차별 대입이 어렵다. 짧은 숫자 한두 개가 아니라, openssl rand -hex 32처럼 **긴 난수 문자열(32바이트 이상 권장)**을 쓰는 것이 안전하다. 비우면 MEMBER_SESSION_SECRET을 pepper로 쓴다.

RESEND_API_KEYRESEND_FROM_EMAIL이 비어 있으면 기존처럼 이메일 OTP 없이 최초 관리자 가입·일반 가입(OTP 생략)이 동작한다.

  • 관리 도구: CloudBeaver 등으로 추후 연결 가능하게 설계
  • NAS Docker 배포 시 PostgreSQL 초기 스키마는 db/migrations/의 SQL로 생성
  • 로컬 개발 Docker Compose 실행 시 ENV_FILE=.env.development--env-file .env.development를 함께 사용
  • 로컬 개발 DB 마이그레이션은 npm run db:migrate:dev로 실행
  • 네비게이션 계층(parent_id, is_folder)은 017_navigation_hierarchy.sql 적용 후 저장 API가 정상 동작한다(미적용 시 INSERT 컬럼 불일치).
  • 회원 마지막 로그인 표시(previous_last_seen_at, previous_last_seen_ip)는 021_add_member_previous_login.sql 적용 후 정상 동작한다.

개발/운영 DB 분리 검증 절차

검증 전제는 실제 비밀번호나 전체 DATABASE_URL을 화면 공유, 문서, 커밋 메시지에 노출하지 않는 것이다. 확인할 때는 호스트, 포트, DB 이름, 파일명만 대조한다.

  1. .env.development 확인.
# 로컬 개발 DB는 호스트 기준 127.0.0.1:43119를 사용해야 한다.
# DATABASE_URL 전체 값은 공유하지 않는다.
rg -n "^(DATABASE_URL|POSTGRES_DB|POSTGRES_USER|DB_PORT)=" .env.development

기준:

  • DATABASE_URL 호스트가 127.0.0.1
  • DATABASE_URL 포트가 43119
  • DB_PORT=43119
  • 운영 NAS 호스트명, 운영 IP, 운영 DB 이름이 포함되지 않음
  1. .env.production 확인.
# 운영 파일은 Git에 올리지 않는 운영 전용 파일이다.
# 값이 없으면 NAS 배포 전 작성해야 한다.
test -f .env.production && rg -n "^(DATABASE_URL|POSTGRES_DB|POSTGRES_USER|APP_PORT)=" .env.production

기준:

  • NAS Docker 내부 실행 기준이면 DATABASE_URL 호스트가 sori-studio-db
  • NAS 외부 DB를 별도 인스턴스로 쓰는 경우에도 로컬 개발 DB(127.0.0.1:43119)를 가리키지 않음
  • APP_PORT=43118
  • .env.development와 DB 비밀번호, 관리자 비밀번호가 서로 다름
  1. 로컬 개발 DB 연결 확인.
docker exec sori-studio-db pg_isready -U sori_studio -d sori_studio
docker exec sori-studio-db psql -U sori_studio -d sori_studio -c 'SELECT current_database(), current_user;'

기준:

  • accepting connections 표시
  • current_database가 로컬 개발 DB 이름
  • current_user가 로컬 개발 DB 계정
  1. 로컬 개발 서버 연결 확인.
npm run dev

기준:

  • 출력 주소가 http://127.0.0.1:43117
  • 관리자 API 요청에서 127.0.0.1:43119 연결 오류가 발생하지 않음
  1. 커밋 전 민감 정보 확인.
git status --short
git diff -- . ':!package-lock.json'

기준:

  • .env.development, .env.production이 변경 목록에 포함되지 않음
  • 문서와 코드 diff에 실제 DB 비밀번호, 관리자 비밀번호, 운영 접속 주소가 포함되지 않음

업로드 파일

  • 관리자 글쓰기에서 업로드한 이미지는 /uploads/posts/YYYY/MM/ URL로 제공한다.
  • 로컬 개발에서는 실제 파일이 public/uploads/posts/YYYY/MM/ 아래 저장된다.
  • public/uploads/는 Git에 포함하지 않는다.
  • NAS 운영에서는 업로드 파일이 컨테이너 재생성으로 사라지지 않도록 별도 볼륨 연결을 확정해야 한다.
  • MAX_FILE_SIZE 환경 변수로 관리자 이미지 업로드 최대 크기를 제한한다.
  • 관리자 미디어 화면은 현재 업로드 파일 시스템을 기준으로 목록, 파일명 변경, 삭제를 처리한다.

사용자 액션 필요 항목

  • NAS SSH 접속 주소 확인.
  • NAS 프로젝트 루트 경로 확정.
  • 운영 DB 이름, 계정, 권한 확정.
  • 운영 업로드 볼륨 경로 확정.
  • 도메인 sori.studio의 NAS 연결 방식 확정.