From daf534c328e021e66539acf3fc0ae10a0c8d2f43 Mon Sep 17 00:00:00 2001 From: zenn Date: Fri, 19 Jun 2026 11:10:47 +0900 Subject: [PATCH] fix: make NAS HTTP ports configurable --- .env.example | 2 + AGENTS.md | 3 ++ compose.test.yaml | 2 +- compose.yaml | 2 +- docs/deploy.md | 96 +++++++++++++++++++++++++++++++++++++++++------ docs/history.md | 6 +++ docs/spec.md | 3 ++ docs/update.md | 2 + 8 files changed, 102 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index bb13491..3280a57 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,4 @@ +PLAYUNIARE_TEST_HTTP_PORT=41808 +PLAYUNIARE_PRODUCTION_HTTP_PORT=41809 VITE_CARD_ASSET_BASE_URL=/card-assets VITE_SOCKET_SERVER_URL=http://localhost:31873 diff --git a/AGENTS.md b/AGENTS.md index eab37ed..cf7ed46 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -154,6 +154,9 @@ function createGameCardInstances(importedCards) { - 운영 환경에서는 Socket.IO 포트를 브라우저에 직접 노출하지 않고 같은 도메인의 `/socket.io` 경로로 리버스 프록시한다. - 컨테이너 내부 포트 중복은 허용되지만 NAS 호스트 공개 포트 중복은 금지한다. +- 테스트·운영 HTTP 호스트 포트는 Compose에 숫자를 직접 추가하지 않고 + `PLAYUNIARE_TEST_HTTP_PORT`, `PLAYUNIARE_PRODUCTION_HTTP_PORT` 환경변수로 + 관리한다. - URL 길이 문제를 고려해 장기적으로 덱 코드 또는 `deckId` 방식을 도입한다. - URL, 로그, Git에 사용자 토큰이나 비밀값을 남기지 않는다. - 오류가 있는 카드 한 장 때문에 전체 덱 불러오기가 중단되지 않도록 오류 diff --git a/compose.test.yaml b/compose.test.yaml index f1f208e..fad7385 100644 --- a/compose.test.yaml +++ b/compose.test.yaml @@ -8,4 +8,4 @@ services: container_name: playuniare-test-web restart: unless-stopped ports: - - '18080:80' + - '${PLAYUNIARE_TEST_HTTP_PORT:-41808}:80' diff --git a/compose.yaml b/compose.yaml index 9f2bd58..86a57bb 100644 --- a/compose.yaml +++ b/compose.yaml @@ -8,4 +8,4 @@ services: container_name: playuniare-web restart: unless-stopped ports: - - '18081:80' + - '${PLAYUNIARE_PRODUCTION_HTTP_PORT:-41809}:80' diff --git a/docs/deploy.md b/docs/deploy.md index 0e64556..631cf88 100644 --- a/docs/deploy.md +++ b/docs/deploy.md @@ -87,7 +87,34 @@ cd playuniare 비공개 저장소가 인증을 요구하면 비밀번호 대신 Git 서버에서 발급한 접근 토큰을 사용하는 것을 권장한다. 토큰을 명령문이나 문서에 저장하지 않는다. -### 2. 테스트 컨테이너 빌드 및 실행 +### 2. NAS 전용 환경변수 파일 만들기 + +프로젝트를 처음 설치한 경우 예시 파일을 복사한다. + +```bash +cp .env.example .env +``` + +기본 포트는 다음과 같다. + +```text +PLAYUNIARE_TEST_HTTP_PORT=41808 +PLAYUNIARE_PRODUCTION_HTTP_PORT=41809 +``` + +NAS에서 이미 사용 중인 포트라면 `.env`를 열어 앞쪽 숫자만 다른 값으로 +변경한다. `.env`는 Git에 올라가지 않으므로 NAS별 설정을 안전하게 유지할 수 +있다. + +현재 Docker 컨테이너가 공개하고 있는 포트는 다음 명령으로 확인한다. + +```bash +docker ps --format "table {{.Names}}\t{{.Ports}}" +``` + +사용 중인 숫자를 피해서 `1024`보다 큰 포트를 선택한다. + +### 3. 테스트 컨테이너 빌드 및 실행 ```bash docker compose \ @@ -100,19 +127,19 @@ docker compose \ - 최신 소스 코드로 Docker 이미지 생성 - 테스트 컨테이너 실행 -- NAS의 18080 포트와 컨테이너 연결 +- NAS의 `PLAYUNIARE_TEST_HTTP_PORT`와 컨테이너의 80 포트 연결 -### 3. 브라우저에서 확인 +### 4. 브라우저에서 확인 NAS의 내부 IP가 `192.168.0.20`이라면 다음 주소로 접속한다. ```text -http://192.168.0.20:18080 +http://192.168.0.20:41808 ``` -실제 NAS IP는 공유기 또는 UGREEN 관리 화면에서 확인한다. +실제 NAS IP와 `.env`에 입력한 테스트 포트에 맞춰 접속한다. -### 4. 테스트 로그 확인 +### 5. 테스트 로그 확인 화면이 열리지 않으면 다음을 실행한다. @@ -130,7 +157,7 @@ docker compose \ `Up` 또는 `running` 상태인지 확인한다. -### 5. 테스트 버전 중지 +### 6. 테스트 버전 중지 ```bash docker compose \ @@ -167,10 +194,11 @@ docker compose \ up -d --build ``` -운영 컨테이너는 NAS의 18081 포트를 사용한다. +운영 컨테이너는 기본적으로 NAS의 `41809` 포트를 사용한다. `.env`의 +`PLAYUNIARE_PRODUCTION_HTTP_PORT`를 변경했다면 해당 포트를 사용한다. ```text -http://NAS_IP:18081 +http://NAS_IP:41809 ``` ### 3. 도메인 연결 @@ -179,10 +207,12 @@ UGREEN NAS 또는 사용 중인 리버스 프록시에서 다음과 같이 연 ```text 외부 도메인: https://playuniare.sori.studio -내부 대상: http://127.0.0.1:18081 +내부 대상: http://127.0.0.1:41809 ``` - 외부 접속은 HTTPS를 사용한다. +- `.env`에서 운영 포트를 변경했다면 리버스 프록시의 내부 대상 포트도 같은 + 값으로 변경한다. - 공유기에서 컨테이너 포트를 그대로 외부에 노출하기보다 리버스 프록시를 사용한다. - 인증서 자동 갱신이 설정되어 있는지 확인한다. @@ -192,7 +222,7 @@ UGREEN NAS 또는 사용 중인 리버스 프록시에서 다음과 같이 연 브라우저에서 실제 카드 파일 하나를 직접 연다. ```text -http://NAS_IP:18081/card-assets/ua03/EX01BT_HTR-2-001.png +http://NAS_IP:41809/card-assets/ua03/EX01BT_HTR-2-001.png ``` 이미지가 보이면 읽기 전용 마운트와 Nginx 경로가 정상이다. 파일명이 실제로 @@ -233,7 +263,8 @@ docker compose \ up -d --build ``` -브라우저에서 `http://NAS_IP:18080`을 확인한다. +브라우저에서 `http://NAS_IP:41808`을 확인한다. `.env`에서 테스트 포트를 +변경했다면 해당 포트로 접속한다. ### 운영 버전 업데이트 @@ -303,6 +334,47 @@ docker compose -f compose.yaml -f compose.nas.yaml restart - `logs`: 최근 오류 확인 - `restart`: 같은 이미지로 컨테이너 재시작 +## `port is already allocated` 오류 + +다음 오류는 Docker 이미지 빌드 문제가 아니라 NAS 호스트 포트 충돌이다. + +```text +Bind for 0.0.0.0:<포트> failed: port is already allocated +``` + +먼저 실패하며 생성된 테스트 컨테이너를 정리한다. + +```bash +docker compose \ + -f compose.test.yaml \ + -f compose.test.nas.yaml \ + down +``` + +현재 사용 중인 Docker 포트를 확인한다. + +```bash +docker ps --format "table {{.Names}}\t{{.Ports}}" +``` + +`.env`에서 테스트 포트를 사용하지 않는 숫자로 변경한다. + +```text +PLAYUNIARE_TEST_HTTP_PORT=41818 +``` + +그다음 다시 실행한다. + +```bash +docker compose \ + -f compose.test.yaml \ + -f compose.test.nas.yaml \ + up -d --build +``` + +컨테이너 내부의 80 포트는 다른 컨테이너와 같아도 괜찮다. `.env`에 설정하는 +NAS 호스트 포트만 겹치지 않으면 된다. + ## 배포 체크리스트 - [ ] 로컬 `npm run build` 성공 diff --git a/docs/history.md b/docs/history.md index 6eed562..f6ef761 100644 --- a/docs/history.md +++ b/docs/history.md @@ -44,3 +44,9 @@ - NAS 호스트 공개 포트만 중복되지 않도록 관리한다. - 운영 환경에서는 포트를 직접 공개하지 않고 `/socket.io` 리버스 프록시를 사용한다. + +## 2026-06-19: NAS HTTP 포트 환경변수화 + +- 기존 테스트 포트 `18080`이 NAS의 다른 서비스와 충돌했다. +- 테스트 기본 포트를 `41808`, 운영 기본 포트를 `41809`로 변경했다. +- NAS별 포트 충돌에 대응할 수 있도록 `.env`와 Compose 변수로 관리한다. diff --git a/docs/spec.md b/docs/spec.md index a8a6380..fd8ec7a 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -77,6 +77,9 @@ - 로컬 Socket.IO 서버 기본 포트는 `31873`이다. - Docker 컨테이너 내부 포트는 다른 컨테이너와 같아도 충돌하지 않는다. - NAS 호스트에 공개하는 포트는 다른 서비스와 겹치면 안 된다. +- 테스트 HTTP 호스트 포트 기본값은 `41808`, 운영 기본값은 `41809`다. +- HTTP 호스트 포트는 `.env`의 `PLAYUNIARE_TEST_HTTP_PORT`와 + `PLAYUNIARE_PRODUCTION_HTTP_PORT`로 변경한다. - 운영 브라우저는 Socket.IO 포트를 직접 호출하지 않고 `https://playuniare.sori.studio/socket.io`처럼 같은 도메인의 리버스 프록시 경로를 사용한다. diff --git a/docs/update.md b/docs/update.md index db53baf..dd67ede 100644 --- a/docs/update.md +++ b/docs/update.md @@ -13,3 +13,5 @@ 설정과 `/card-assets` Nginx 경로를 추가했다. - 로컬 Socket.IO 기본 포트를 `31873`으로 변경하고 운영 리버스 프록시 원칙을 문서화했다. +- NAS HTTP 포트 충돌을 해결하기 위해 테스트·운영 포트를 환경변수로 + 변경하고 `port is already allocated` 복구 절차를 추가했다.