Fix: Use NEXT_PUBLIC_API_URL for all image URLs

This commit is contained in:
AutonetSellCar Deploy
2025-12-30 16:09:06 +09:00
parent a3d5339c84
commit 0ccc2f75c5
5 changed files with 240 additions and 4 deletions

230
DEPLOYMENT_CHECKLIST.md Normal file
View File

@@ -0,0 +1,230 @@
# AutonetSellCar 배포 체크리스트
## 환경 정보
| 항목 | 서버4 (개발) | 서버2 (운영) |
|------|-------------|-------------|
| IP | 192.168.0.204 | 192.168.0.202 |
| OS | Windows | Ubuntu 22.04 |
| Frontend 포트 | 3000 | 3000 (운영), 3001 (스테이징) |
| Backend 포트 | 8000 | 8000 (운영), 8001 (스테이징) |
---
## 1. 서버2 디렉토리 구조
```
/opt/autonet/
├── git/autonet.git/ # Git bare repository
├── staging/ # 스테이징 코드
├── production/ # 운영 코드
│ ├── frontend/
│ │ ├── Dockerfile
│ │ ├── .env.production # ★ NEXT_PUBLIC_API_URL 설정
│ │ └── ...
│ ├── backend/
│ │ ├── Dockerfile
│ │ ├── autonet.db # ★ 데이터베이스
│ │ └── uploads/ # ★ 이미지 파일
│ └── docker-compose.production.yml
├── releases/ # 롤백용 아카이브
├── scripts/ # 배포 스크립트
└── logs/ # 로그
```
---
## 2. 핵심 설정 파일
### 2.1 Frontend 환경변수 (.env.production)
**파일 위치**: `/opt/autonet/production/frontend/.env.production`
```env
NEXT_PUBLIC_API_URL=http://192.168.0.202:8000
```
⚠️ **중요**: Next.js는 **빌드 시점**에 `NEXT_PUBLIC_*` 변수를 코드에 포함시킵니다.
- 런타임에 환경변수를 바꿔도 적용 안됨
- 환경변수 변경 후 반드시 **이미지 재빌드** 필요
### 2.2 Dockerfile (Frontend)
**파일 위치**: `/opt/autonet/production/frontend/Dockerfile`
빌드 시 환경변수 적용을 위해 다음이 포함되어야 함:
```dockerfile
# builder 단계에서
ARG NEXT_PUBLIC_API_URL=http://192.168.0.202:8000
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
```
### 2.3 docker-compose.production.yml
```yaml
version: '3.8'
services:
frontend:
build: ./frontend
container_name: autonet-frontend
ports:
- "3000:3000"
environment:
- NODE_ENV=production
depends_on:
- backend
backend:
build: ./backend
container_name: autonet-backend
ports:
- "8000:8000"
volumes:
- ./backend/uploads:/app/uploads # ★ 이미지 영속화
- ./backend/autonet.db:/app/autonet.db # ★ DB 영속화
```
---
## 3. 데이터 이전 체크리스트
### 3.1 데이터베이스 (autonet.db)
| 단계 | 명령어 | 확인 |
|------|--------|------|
| 서버4에서 복사 | `scp backend/autonet.db damon@192.168.0.202:/tmp/` | [ ] |
| 서버2 컨테이너에 복사 | `docker cp /tmp/autonet.db autonet-backend:/app/` | [ ] |
| 파일 확인 | `docker exec autonet-backend ls -la /app/autonet.db` | [ ] |
| 백엔드 재시작 | `docker restart autonet-backend` | [ ] |
### 3.2 업로드 이미지 (uploads/)
| 단계 | 명령어 | 확인 |
|------|--------|------|
| 서버4에서 압축 | `tar -cvf uploads.tar uploads` | [ ] |
| 서버2로 복사 | `scp uploads.tar damon@192.168.0.202:/tmp/` | [ ] |
| 압축 해제 | `cd /tmp && tar -xvf uploads.tar` | [ ] |
| 컨테이너에 복사 | `docker cp /tmp/uploads/. autonet-backend:/app/uploads/` | [ ] |
| 파일 확인 | `docker exec autonet-backend ls -la /app/uploads/` | [ ] |
---
## 4. 이미지 URL 문제 디버깅
### 4.1 현재 문제
브라우저에서 이미지 요청 URL이 `http://localhost:8000/...`으로 되어 있음.
→ 다른 PC에서 접속하면 localhost가 그 PC를 가리키므로 이미지 안 보임.
### 4.2 올바른 이미지 URL
```
http://192.168.0.202:8000/uploads/cars/39/image_0.jpg
```
### 4.3 원인 분석
1. **api.ts에서 API_BASE_URL 설정 확인**
- 파일: `frontend/src/lib/api.ts`
- `NEXT_PUBLIC_API_URL` 환경변수 사용 여부
2. **이미지 URL 생성 로직 확인**
- 이미지 URL이 어디서 생성되는지
- 백엔드에서 전체 URL 반환? vs 프론트엔드에서 조합?
3. **빌드 시점 환경변수 확인**
- `.env.production` 파일 존재 여부
- Dockerfile에서 ARG/ENV 설정 여부
---
## 5. 디버깅 명령어
### 5.1 프론트엔드 환경변수 확인
```bash
# 컨테이너 환경변수
docker exec autonet-frontend printenv | grep API
# .env.production 파일 내용
cat /opt/autonet/production/frontend/.env.production
```
### 5.2 백엔드 API 테스트
```bash
# 이미지 직접 접근 테스트
curl -I http://192.168.0.202:8000/uploads/cars/39/image_0.jpg
# API 응답에서 이미지 URL 확인
curl http://192.168.0.202:8000/api/cars/39 | jq '.images'
```
### 5.3 컨테이너 상태 확인
```bash
docker ps -a
docker logs autonet-frontend --tail 20
docker logs autonet-backend --tail 20
```
---
## 6. 재빌드 절차
### 6.1 Frontend 재빌드 (환경변수 변경 시)
```bash
cd /opt/autonet/production
# 1. 컨테이너 중지/삭제
docker rm -f autonet-frontend
# 2. 이미지 삭제
docker rmi production_frontend
# 3. .env.production 확인
cat frontend/.env.production
# 4. 재빌드
docker build --no-cache -t production_frontend ./frontend
# 5. 실행
docker run -d \
--name autonet-frontend \
--network autonet-production-network \
-p 3000:3000 \
production_frontend
# 6. 확인
docker ps | grep frontend
docker logs autonet-frontend --tail 10
```
---
## 7. 현재 상태 점검 명령어
서버2에서 순서대로 실행:
```bash
# 1. 컨테이너 상태
docker ps -a
# 2. 프론트엔드 환경변수
docker exec autonet-frontend printenv | grep -E "(API|NODE)"
# 3. .env.production 파일
cat /opt/autonet/production/frontend/.env.production
# 4. Dockerfile 환경변수 설정
grep -A2 "ARG NEXT_PUBLIC" /opt/autonet/production/frontend/Dockerfile
grep "ENV NEXT_PUBLIC" /opt/autonet/production/frontend/Dockerfile
# 5. 백엔드 이미지 파일 존재 확인
docker exec autonet-backend ls /app/uploads/cars/ | head -5
# 6. 백엔드 이미지 직접 접근 테스트
curl -I http://localhost:8000/uploads/cars/39/image_0.jpg
```

BIN
backend/uploads.tar Normal file

Binary file not shown.

View File

@@ -103,13 +103,15 @@ const FUEL_TYPES = [
{ value: 'LPG', label: 'LPG' },
];
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
// 이미지 URL 변환 (로컬 경로는 백엔드 URL 추가)
const getImageUrl = (url: string | undefined): string => {
if (!url) return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return `http://localhost:8000${url}`;
return `${API_BASE_URL}${url}`;
};
const YEAR_OPTIONS = Array.from({ length: 15 }, (_, i) => 2024 - i);

View File

@@ -33,13 +33,15 @@ const defaultFormData: BannerFormData = {
car_id: null,
};
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
// 이미지 URL 변환 (로컬 경로는 백엔드 URL 추가)
const getImageUrl = (url: string | undefined): string => {
if (!url) return '';
if (url.startsWith('http://') || url.startsWith('https://')) {
return url;
}
return `http://localhost:8000${url}`;
return `${API_BASE_URL}${url}`;
};
export default function HeroBannersPage() {
@@ -97,7 +99,7 @@ export default function HeroBannersPage() {
.map((b: any) => b.car_id);
if (carIds.length > 0) {
try {
const response = await fetch('http://localhost:8000/api/carmodoo/pdf-status', {
const response = await fetch(`${API_BASE_URL}/api/carmodoo/pdf-status`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(carIds),

View File

@@ -324,6 +324,8 @@ interface BannerCardProps {
height: number;
}
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000';
// 이미지 URL 변환 (로컬 경로는 백엔드 URL 추가)
const getImageUrl = (url: string): string => {
if (!url) return '';
@@ -331,7 +333,7 @@ const getImageUrl = (url: string): string => {
return url;
}
// 로컬 경로인 경우 백엔드 URL 추가
return `http://localhost:8000${url}`;
return `${API_BASE_URL}${url}`;
};
// Helper to get localized title/subtitle based on language