From 0c74f994fdeb7904fb98ebe9e557e4696927ef53 Mon Sep 17 00:00:00 2001 From: zenn Date: Fri, 19 Jun 2026 11:26:50 +0900 Subject: [PATCH] fix: allow Nginx to read NAS card assets --- AGENTS.md | 3 +++ Dockerfile | 4 ++++ docs/deploy.md | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/history.md | 8 +++++++ docs/spec.md | 2 ++ docs/update.md | 2 ++ 6 files changed, 76 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index cf7ed46..603333a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -150,6 +150,9 @@ function createGameCardInstances(importedCards) { `/volume1/docker/projects/apps/uniare/config/www/images`를 컨테이너에 읽기 전용으로 연결하고 `/card-assets` 경로로 제공한다. - 기존 Uniare의 `config/www/images`에는 쓰기 작업을 수행하지 않는다. +- NAS 카드 파일 소유자 UID가 `1000`이므로 Nginx 워커는 `cardreader` + 사용자(UID 1000)로 실행한다. 이 기준을 바꾸기 전에는 실제 NAS 파일 + 소유자를 다시 확인한다. - 로컬 Socket.IO 서버 기본 포트는 `31873`을 사용한다. - 운영 환경에서는 Socket.IO 포트를 브라우저에 직접 노출하지 않고 같은 도메인의 `/socket.io` 경로로 리버스 프록시한다. diff --git a/Dockerfile b/Dockerfile index c574049..982a9e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,8 +10,12 @@ RUN npm run build FROM nginx:1.27-alpine AS runtime +RUN adduser -D -H -u 1000 -G wheel cardreader \ + && sed -i 's/user nginx;/user cardreader wheel;/' /etc/nginx/nginx.conf + COPY docker/nginx.conf /etc/nginx/conf.d/default.conf COPY --from=builder /app/dist /usr/share/nginx/html +RUN chmod -R a+rX /usr/share/nginx/html EXPOSE 80 diff --git a/docs/deploy.md b/docs/deploy.md index 631cf88..1c66b39 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -242,6 +242,10 @@ docker exec playuniare-web ls /srv/uniare-card-images 이 경로 역시 같은 시리즈 폴더를 보여야 한다. +Play Uniare의 Nginx 작업 프로세스는 기존 카드 파일 소유자와 같은 UID +`1000`의 `cardreader` 사용자로 실행된다. 원본 카드 폴더는 계속 읽기 전용으로 +마운트되므로 시뮬레이터가 파일을 수정하거나 삭제할 수 없다. + ## 새 버전 업데이트 ### 안전한 권장 순서 @@ -375,6 +379,59 @@ docker compose \ 컨테이너 내부의 80 포트는 다른 컨테이너와 같아도 괜찮다. `.env`에 설정하는 NAS 호스트 포트만 겹치지 않으면 된다. +## 카드 이미지가 `403 Forbidden`인 경우 + +로그에 다음 내용이 있으면 Nginx 작업 사용자가 NAS 카드 파일을 읽지 못한 +것이다. + +```text +open() "/srv/uniare-card-images/..." failed (13: Permission denied) +``` + +현재 Docker 이미지는 기존 카드 파일 소유자 UID `1000`에 맞춘 `cardreader` +사용자를 사용한다. 최신 소스를 받은 후 이미지를 반드시 다시 빌드한다. + +```bash +cd /volume1/docker/projects/apps/playuniare +git pull + +docker compose \ + -f compose.test.yaml \ + -f compose.test.nas.yaml \ + down + +docker compose \ + -f compose.test.yaml \ + -f compose.test.nas.yaml \ + up -d --build +``` + +Nginx 워커 사용자를 확인하려면: + +```bash +docker exec playuniare-test-web ps aux +``` + +`nginx: worker process`가 `cardreader`로 표시되어야 한다. + +카드 파일 읽기를 직접 확인하려면: + +```bash +docker exec playuniare-test-web \ + su -s /bin/sh cardreader -c \ + 'head -c 10 /srv/uniare-card-images/ua03/EX01BT_HTR-2-001.png >/dev/null && echo READ_OK' +``` + +`READ_OK`가 나오면 다음 주소에서 카드가 보여야 한다. + +```text +http://NAS_IP:41808/card-assets/ua03/EX01BT_HTR-2-001.png +``` + +NAS에서 카드 파일 소유자의 UID가 `1000`이 아닌 경우에는 임의로 폴더 권한을 +`777`로 변경하지 말고, 실제 UID를 확인한 뒤 Docker 실행 사용자 정책을 +조정한다. + ## 배포 체크리스트 - [ ] 로컬 `npm run build` 성공 diff --git a/docs/history.md b/docs/history.md index f6ef761..d2ac11f 100644 --- a/docs/history.md +++ b/docs/history.md @@ -50,3 +50,11 @@ - 기존 테스트 포트 `18080`이 NAS의 다른 서비스와 충돌했다. - 테스트 기본 포트를 `41808`, 운영 기본 포트를 `41809`로 변경했다. - NAS별 포트 충돌에 대응할 수 있도록 `.env`와 Compose 변수로 관리한다. + +## 2026-06-19: NAS 카드 이미지 ACL 대응 + +- NAS 카드 파일은 POSIX 권한이 열려 있어도 ACL 때문에 기본 Nginx UID + `101`에서 읽기가 거부되었다. +- 카드 파일 소유자 UID가 `1000`인 것을 확인했다. +- Nginx 워커를 UID `1000`의 `cardreader` 사용자로 실행하도록 변경했다. +- Vue 정적 파일에는 빌드 단계에서 명시적인 읽기 권한을 적용했다. diff --git a/docs/spec.md b/docs/spec.md index fd8ec7a..7a93bde 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -116,5 +116,7 @@ Play Uniare 컨테이너 내부: - `config/www`는 기존 `index.html`이 존재하는 실제 웹 루트다. - Docker bind mount는 `images` 폴더만 읽기 전용으로 연결한다. - Play Uniare는 기존 카드 이미지를 읽을 수 있지만 수정하거나 삭제할 수 없다. +- Nginx 작업 프로세스는 NAS 카드 파일 소유자와 같은 UID `1000`의 + `cardreader` 사용자로 실행한다. - 카드 이미지 URL은 `/card-assets//` 형식을 사용한다. - 같은 Play Uniare 도메인으로 제공되므로 별도의 CORS 설정이 필요하지 않다. diff --git a/docs/update.md b/docs/update.md index dd67ede..c4e759e 100644 --- a/docs/update.md +++ b/docs/update.md @@ -15,3 +15,5 @@ 문서화했다. - NAS HTTP 포트 충돌을 해결하기 위해 테스트·운영 포트를 환경변수로 변경하고 `port is already allocated` 복구 절차를 추가했다. +- NAS ACL로 인한 카드 이미지와 favicon의 403 오류를 해결하기 위해 Nginx + 워커 UID와 정적 파일 권한을 조정했다.