Compare commits

...

1 Commits

Author SHA1 Message Date
3eceec64e7 릴리스: v0.1.27 UGREEN NAS 운영 배포 파일 추가 2026-03-26 15:25:28 +09:00
11 changed files with 275 additions and 0 deletions

11
.dockerignore Normal file
View File

@@ -0,0 +1,11 @@
.git
.gitignore
.DS_Store
node_modules
frontend/node_modules
frontend/dist
backend/node_modules
backend/.sessions
backend/uploads
docker-compose.yml
docs

5
.env.production.example Normal file
View File

@@ -0,0 +1,5 @@
MARIADB_ROOT_PASSWORD=change-this-root-password
MARIADB_DATABASE=tier_cursor
MARIADB_USER=tier_cursor
MARIADB_PASSWORD=change-this-db-password
SESSION_SECRET=change-this-session-secret

View File

@@ -39,6 +39,18 @@ VITE_API_ORIGIN=http://localhost:5179 npm run dev
자세한 내용은 [docs/local-mariadb.md](/Users/bicute/Desktop/zenn.dev/tier-cursor/docs/local-mariadb.md)를 참고하세요.
## UGREEN NAS 운영 배포
운영용은 `MariaDB + backend + frontend` 3컨테이너 구조를 권장합니다.
```bash
cp .env.production.example .env.production
docker compose --env-file .env.production -f docker-compose.prod.yml up -d --build
```
- 프로덕션 컴포즈: [docker-compose.prod.yml](/Users/bicute/Desktop/zenn.dev/tier-cursor/docker-compose.prod.yml)
- 배포 가이드: [docs/ugreen-nas-deploy.md](/Users/bicute/Desktop/zenn.dev/tier-cursor/docs/ugreen-nas-deploy.md)
## 사용 흐름(현재 구현)
- **게임 선택**: `/`에서 게임 클릭

15
backend/Dockerfile Normal file
View File

@@ -0,0 +1,15 @@
FROM node:20-alpine
WORKDIR /app
COPY backend/package*.json ./
RUN npm ci --omit=dev
COPY backend/ ./
ENV NODE_ENV=production
ENV PORT=5179
EXPOSE 5179
CMD ["node", "index.js"]

79
docker-compose.prod.yml Normal file
View File

@@ -0,0 +1,79 @@
services:
mariadb:
image: mariadb:11.4
container_name: tmaker-mariadb
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
MARIADB_DATABASE: ${MARIADB_DATABASE}
MARIADB_USER: ${MARIADB_USER}
MARIADB_PASSWORD: ${MARIADB_PASSWORD}
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci
volumes:
- tmaker_mariadb_data:/var/lib/mysql
healthcheck:
test: ["CMD-SHELL", "mariadb-admin ping -h 127.0.0.1 -u$$MARIADB_USER -p$$MARIADB_PASSWORD --silent"]
interval: 10s
timeout: 5s
retries: 10
backend:
build:
context: .
dockerfile: backend/Dockerfile
container_name: tmaker-backend
restart: unless-stopped
depends_on:
mariadb:
condition: service_healthy
environment:
PORT: 5179
DB_HOST: mariadb
DB_PORT: 3306
DB_USER: ${MARIADB_USER}
DB_PASSWORD: ${MARIADB_PASSWORD}
DB_NAME: ${MARIADB_DATABASE}
SESSION_SECRET: ${SESSION_SECRET}
SESSION_COOKIE_SECURE: "true"
SESSION_COOKIE_SAME_SITE: "lax"
CORS_ORIGINS: https://tmaker.sori.studio
TRUST_PROXY: 1
volumes:
- tmaker_uploads:/app/uploads
- tmaker_sessions:/app/.sessions
frontend:
build:
context: .
dockerfile: frontend/Dockerfile
args:
VITE_API_ORIGIN: https://tmaker.sori.studio
container_name: tmaker-frontend
restart: unless-stopped
depends_on:
- backend
ports:
- "8080:80"
phpmyadmin:
image: phpmyadmin:5.2-apache
container_name: tmaker-phpmyadmin
restart: unless-stopped
profiles: ["admin"]
depends_on:
mariadb:
condition: service_healthy
environment:
PMA_HOST: mariadb
PMA_PORT: 3306
PMA_USER: ${MARIADB_USER}
PMA_PASSWORD: ${MARIADB_PASSWORD}
ports:
- "8081:80"
volumes:
tmaker_mariadb_data:
tmaker_uploads:
tmaker_sessions:

View File

@@ -98,3 +98,7 @@
## 2026-03-26 v0.1.26
- 아이콘 크기는 사용자 취향 차이가 큰 요소이므로, 고정값 하나보다 기본 `80px`에 단계형 크기 선택을 제공하는 편이 더 낫다고 판단했다.
## 2026-03-26 v0.1.27
- NAS 운영은 리버스 프록시 설정을 단순하게 유지하는 편이 좋으므로, 프런트 컨테이너 하나만 외부 공개하고 `/api`, `/uploads`는 내부 프록시로 넘기는 구조를 채택했다.
- 운영은 로컬 개발 컴포즈와 분리된 전용 `docker-compose.prod.yml`을 두고, 환경변수는 `.env.production`으로 분리해 관리하기로 결정했다.

View File

@@ -6,6 +6,7 @@
- 데이터 저장소: MariaDB(MySQL 호환)
- 세션 저장소: `session-file-store` 기반 파일 세션
- 업로드 저장소: 로컬 파일 시스템(`backend/uploads/`)
- 운영 배포: `frontend(Nginx 정적 서빙 + /api,/uploads 프록시) + backend + mariadb` Docker Compose 구조
## 데이터 저장 구조
- 메인 데이터베이스: MariaDB `tier_cursor` (기본값)
@@ -138,6 +139,11 @@
- `SESSION_COOKIE_SECURE`: `true`면 HTTPS 전용 쿠키
- `SESSION_COOKIE_SAME_SITE`: 기본 `lax`
## 운영 배포 메모
- 프로덕션 컴포즈 파일은 [docker-compose.prod.yml](/Users/bicute/Desktop/zenn.dev/tier-cursor/docker-compose.prod.yml)이다.
- 외부 도메인 `tmaker.sori.studio``frontend` 컨테이너의 `8080` 포트로 리버스 프록시하고, `/api`, `/uploads`, `/health`는 프런트 Nginx가 내부 `backend:5179`로 전달한다.
- 운영 볼륨은 MariaDB 데이터, 업로드 파일, 세션 파일을 각각 분리해 유지한다.
## NAS 배포 메모
- 현재 구조는 MariaDB/MySQL 계열이므로 NAS에 MariaDB를 올리면 phpMyAdmin 또는 Adminer로 직접 데이터 확인이 가능하다.
- 추천 구성:

78
docs/ugreen-nas-deploy.md Normal file
View File

@@ -0,0 +1,78 @@
# UGREEN NAS 배포 가이드
## 개요
- 운영 기본 컨테이너는 `mariadb`, `backend`, `frontend` 3개다.
- `phpmyadmin`은 필요할 때만 `admin` 프로필로 추가 실행한다.
- 외부 공개는 `frontend` 컨테이너 하나만 하고, `/api`, `/uploads`, `/health`는 내부적으로 `backend`로 프록시한다.
- 도메인은 `https://tmaker.sori.studio` 기준으로 설정한다.
## 파일
- 프로덕션 컴포즈: [docker-compose.prod.yml](/Users/bicute/Desktop/zenn.dev/tier-cursor/docker-compose.prod.yml)
- 백엔드 이미지: [backend/Dockerfile](/Users/bicute/Desktop/zenn.dev/tier-cursor/backend/Dockerfile)
- 프런트 이미지: [frontend/Dockerfile](/Users/bicute/Desktop/zenn.dev/tier-cursor/frontend/Dockerfile)
- 프런트 Nginx 프록시: [frontend/nginx.conf](/Users/bicute/Desktop/zenn.dev/tier-cursor/frontend/nginx.conf)
- 환경변수 예시: [.env.production.example](/Users/bicute/Desktop/zenn.dev/tier-cursor/.env.production.example)
## 1. 프로젝트 업로드
- NAS 작업 폴더에 현재 프로젝트를 그대로 업로드한다.
- 기존 로컬 MariaDB 내용은 무시하고 새 운영 DB로 시작해도 된다.
## 2. 환경변수 파일 준비
- 루트에서 `.env.production.example`를 복사해 `.env.production`으로 만든다.
- 최소 변경값:
- `MARIADB_ROOT_PASSWORD`
- `MARIADB_PASSWORD`
- `SESSION_SECRET`
예시:
```env
MARIADB_ROOT_PASSWORD=very-strong-root-password
MARIADB_DATABASE=tier_cursor
MARIADB_USER=tier_cursor
MARIADB_PASSWORD=very-strong-app-password
SESSION_SECRET=very-strong-random-session-secret
```
## 3. 컨테이너 실행
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml up -d --build
```
- phpMyAdmin까지 같이 띄우려면:
```bash
docker compose --env-file .env.production -f docker-compose.prod.yml --profile admin up -d --build
```
## 4. NAS 리버스 프록시
- 외부 도메인: `tmaker.sori.studio`
- 내부 대상 프로토콜: `http`
- 내부 대상 호스트: NAS IP 또는 `localhost`
- 내부 대상 포트: `8080`
즉 NAS 리버스 프록시는 `frontend` 컨테이너의 `8080`만 바라보면 된다.
## 5. HTTPS / 쿠키
- 현재 프로덕션 컴포즈는 `SESSION_COOKIE_SECURE=true`를 사용한다.
- 따라서 `tmaker.sori.studio`에는 HTTPS 인증서가 연결되어 있어야 한다.
- NAS 리버스 프록시가 HTTPS 종료를 하고 내부는 `http://frontend:80` 또는 `localhost:8080`으로 전달하면 된다.
## 6. 데이터 위치
- MariaDB 데이터: Docker volume `tmaker_mariadb_data`
- 업로드 파일: Docker volume `tmaker_uploads`
- 세션 파일: Docker volume `tmaker_sessions`
## 7. 점검 포인트
- 메인 접속: `https://tmaker.sori.studio`
- 헬스체크: `https://tmaker.sori.studio/health`
- 관리자 로그인 후:
- 게임 생성
- 썸네일 업로드
- 티어표 저장
- 이미지 다운로드
## 8. 참고
- 현재 업로드 이미지는 서버 저장 전에 리사이즈/압축하지 않는다.
- 운영 중 원본 이미지가 많이 쌓이면 이후 `sharp` 기반 최적화 단계를 추가하는 것이 좋다.

View File

@@ -1,5 +1,10 @@
# 업데이트 로그
## 2026-03-26 v0.1.27
- **UGREEN NAS 배포 파일 추가**: `backend`, `frontend`용 Dockerfile과 프런트 Nginx 프록시 설정, 프로덕션 전용 `docker-compose.prod.yml` 추가
- **운영 환경 예시 추가**: `.env.production.example`로 MariaDB/세션 시크릿 환경변수 템플릿 제공
- **배포 문서화**: `tmaker.sori.studio` 기준 NAS 리버스 프록시, 컨테이너 실행, 볼륨 구성 가이드를 문서에 정리
## 2026-03-26 v0.1.26
- **아이콘 크기 조절 추가**: 티어표 편집기에서 `48 / 60 / 80 / 100 / 120` 단계로 아이콘 크기를 직접 바꿀 수 있도록 추가
- **기본 아이콘 크기 상향**: 기본 `.thumb` 크기를 `80px` 기준으로 조정하고, 보드와 우측 아이템 목록에 함께 반영되도록 정리

22
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,22 @@
FROM node:20-alpine AS build
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
ARG VITE_API_ORIGIN=https://tmaker.sori.studio
ENV VITE_API_ORIGIN=${VITE_API_ORIGIN}
RUN npm run build
FROM nginx:1.27-alpine
COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

38
frontend/nginx.conf Normal file
View File

@@ -0,0 +1,38 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://backend:5179/api/;
proxy_http_version 1.1;
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;
}
location /uploads/ {
proxy_pass http://backend:5179/uploads/;
proxy_http_version 1.1;
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;
}
location /health {
proxy_pass http://backend:5179/health;
proxy_http_version 1.1;
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;
}
}