1. 시작하며
회사에서 프로젝트를 진행하면서 프론트엔드 팀원분들이 패치 후에도 브라우저가 이전 버전을 유지하는 문제로 어려움을 겪고 있었습니다.
운영 서버에 배포할 때마다 강력 새로고침(Ctrl + Shift + R)을 해야만 최신 화면이 반영되는 상황이었습니다.
이는 사용자 경험(UX)에도 영향을 미치고, 운영 과정에서도 번거로움을 유발했습니다.
1.1 문제 상황
- 패치 후에도 브라우저가 이전 버전의 화면을 유지함
- Nginx를 재시작하지 않으면 새로운 화면이 반영되지 않음
- 사용자가 강제 새로고침을 하지 않으면 변경 사항이 보이지 않음
- 배포 후 매번 "새로고침 해주세요!"라고 안내하는 번거로움이 존재
운영 서버에 배포할 때마다 개발자나 운영팀이 직접 강력 새로고침을 해줘야 하는 상황이 반복되었고, 이는 근본적으로 Nginx의 캐싱 정책 때문이라는 점을 확인했습니다.
이에 따라, 강력 새로고침 없이도 패치 후 최신 화면이 자동 반영되는 배포 방식을 고민하게 되었습니다.
이 글에서는 React(Vite) 프로젝트를 Nginx에서 배포할 때, 최신 버전을 자동으로 반영하는 방법을 정리해보겠습니다.
2. 목표
운영 환경에서 배포 후 자동으로 최신 화면이 반영되도록 설정하는 것이 목표입니다.
index.html
캐싱 방지 (최신 JS 파일을 항상 로드하도록 설정)- JS, CSS 등의 정적 리소스는 캐싱 유지 (파일명이 바뀔 때만 새로 로드됨)
- Nginx 재시작 없이 dist 폴더만 교체하면 즉시 새로운 화면이 적용되도록 설정
3. 배포 방식 이해하기
React(Vite)에서 빌드된 결과물은 dist/
폴더 안에 저장됩니다. 이때 index.html
과 JS 파일의 역할을 이해하는 것이 중요합니다.
3.1 index.html의 역할
- 앱의 진입점(Entry Point)
- React 애플리케이션을 실행하는 JS 파일을 로드하는 역할
- 직접적인 UI 코드 없이 정적 리소스(JS, CSS)를 연결하는 기능
📌 index.html
예시 (Vite 빌드 후)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My React App</title>
<script type="module" crossorigin src="/assets/index-2Qn4qwOy.js"></script>
<link rel="stylesheet" href="/assets/index-Be24iaxl.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
index.html
은 React 애플리케이션을 실행하는 JS 파일을 로드하는 역할을 합니다.- 컴포넌트 변경 시, 새로운 해시값이 포함된 JS 파일이 생성됨 → JS 파일은 자동으로 갱신됨
3.2 JS 파일의 역할
- React 컴포넌트 코드(TypeScript 포함)가 변환된 정적 파일
index-2Qn4qwOy.js
같은 파일명이 자동 생성됨- 파일명이 바뀔 때만 새로운 파일을 로드하여 캐싱 유지
즉, index.html
이 최신 파일을 로드하도록 설정하면 배포 후에도 강제 새로고침 없이 최신 화면이 보일 수 있다.
4. Nginx에서 캐싱 문제 해결하기
이제 패치 후 자동으로 최신 파일이 반영되도록 Nginx 설정을 수정하겠습니다.
4.1 index.html 캐싱 방지 (Nginx 설정 수정)
index.html
이 캐싱되지 않도록 설정하면, 배포할 때마다 새로운 JS 파일을 자동으로 로드할 수 있습니다.
📌 Nginx 설정 예제 (nginx.conf
수정)
location / {
root /var/www/html/dist;
try_files $uri $uri/ /index.html =404;
index index.html index.htm;
# 🔥 index.html 캐싱 방지 (항상 최신 버전을 제공)
location = /index.html {
expires -1;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
add_header Pragma "no-cache";
add_header Expires 0;
}
}
index.html
은 항상 최신 상태 유지- 브라우저가 이전 버전의 index.html을 캐싱하지 않도록 설정
4.2 JS, CSS 파일 자동 갱신 (추가적인 캐싱 설정 불필요)
React(Vite)에서는 빌드시 JS, CSS 파일명에 해시값을 자동 추가하므로, 별도의 캐싱 해제 설정이 필요 없습니다.
📌 Vite(Webpack 포함) 빌드시 자동 생성되는 파일 예시
/assets/index-2Qn4qwOy.js
/assets/index-Be24iaxl.css
- 파일명이 변경될 때마다 새로운 파일이 자동으로 생성됨
- 브라우저는 파일명이 변경되면 새로운 파일을 자동으로 다운로드 (즉, JS/CSS 파일이 변경될 경우 새로운 해시값을 가진 파일이 생성되므로, 자동으로 최신 파일이 반영됨)
📌 JS, CSS 파일은 별도 캐싱 해제 없이 유지 가능 (추가 설정 불필요)
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2?|eot|ttf|svg)$ {
expires 1y;
access_log off;
add_header Cache-Control "public, immutable";
}
- 해당 설정을 유지하면, 변경되지 않은 파일은 브라우저에서 캐싱
- 파일명이 변경되면, 새로운 파일을 자동으로 다운로드
- Vite(Webpack)가 자동으로 해시 기반 파일명을 생성하므로, 추가적인 캐싱 설정이 필요 없음
즉, 신경 써야 할 부분은 index.html
의 캐싱 방지이며, JS/CSS 파일은 별도 설정 없이도 자동으로 최신 파일이 반영됩니다.
5. Nginx 재시작 없이 dist 폴더만 변경하면 최신 화면이 반영될까?
가능합니다. Nginx는 기본적으로 정적 파일을 메모리에 캐싱하지 않으며, 파일이 변경되면 즉시 새로운 파일을 제공하는 구조입니다.
즉, dist 폴더를 변경하는 것만으로도 최신 화면을 반영할 수 있습니다.
5.1 방법 1: 배포 스크립트를 통한 dist 폴더 교체
수동으로 배포할 경우, 기존 dist
폴더를 삭제하고 새롭게 배포된 dist
폴더로 교체하면 됩니다.
배포 자동화를 위해 배포 스크립트를 활용하면 보다 안전하고 빠르게 적용할 수 있습니다.
📌 배포 스크립트 예시 (dist 폴더 교체)
# 1. 기존 배포 폴더를 백업 (문제 발생 시 복구 가능)
mv /var/www/html/dist /var/www/html/dist_backup
# 2. 새로운 dist 폴더 배포 (빌드된 React 프로젝트 적용)
cp -r ./build/dist /var/www/html/dist
# 3. 백업된 폴더 삭제 (정상적으로 배포되었을 경우)
rm -rf /var/www/html/dist_backup
- 배포 후 즉시 최신 화면이 반영됨
- Nginx를 재시작할 필요 없음
- 문제 발생 시 dist_backup 폴더를 이용하여 롤백 가능
5.2 방법 2: Nginx 도커 컨테이너를 사용하는 경우
Nginx가 Docker 컨테이너로 동작하는 경우에도, Nginx를 재시작하지 않고 배포 가능합니다.
도커 환경에서는 볼륨 마운트(Volume Mount)를 활용하면 Nginx 재시작 없이도 정적 파일을 교체할 수 있습니다.
📌 도커 환경에서 dist 폴더 업데이트하는 방법
# 1. 기존 dist 폴더 삭제 (컨테이너 내에서)
docker exec -it nginx_container rm -rf /usr/share/nginx/html/*
# 2. 새로운 dist 폴더를 컨테이너 내부로 복사
docker cp ./build/dist/. nginx_container:/usr/share/nginx/html/
# 3. Nginx를 재시작하지 않아도 새로운 화면이 즉시 반영됨!
- Nginx 컨테이너를 재시작할 필요 없음
- 도커 컨테이너 내의 정적 파일을 실시간으로 업데이트 가능
5.3 도커 환경에서 배포 자동화 (Docker Compose 활용)
배포를 자동화하려면 Docker Compose와 함께 볼륨 마운트를 활용하는 것도 좋은 방법입니다.
📌 Nginx + React(Vite) Docker Compose 예제 (docker-compose.yml
)
services:
nginx:
image: nginx:latest
container_name: my_nginx
ports:
- "80:80"
volumes:
- ./dist:/usr/share/nginx/html # dist 폴더를 마운트하여 실시간 변경 반영
- ./nginx.conf:/etc/nginx/nginx.conf # 커스텀 Nginx 설정 적용
restart: always
- dist 폴더 변경 시 자동으로 반영됨
- Nginx를 재시작하지 않고도 최신 화면 제공 가능
- 배포가 단순화되고, 운영 관리가 쉬워짐
6. 결론
이번 작업을 통해 React(Vite) 프로젝트를 Nginx에서 배포할 때, 패치 후 강력 새로고침 없이도 최신 화면이 자동으로 반영되는 방법을 정리했습니다.
기존에는 배포 후에도 이전 버전이 남아 있는 문제로 인해 강력 새로고침을 해야 하는 번거로움이 있었습니다.
하지만, Nginx 캐싱 정책을 적절히 설정하고, dist 폴더를 올바르게 교체하는 방식으로 문제를 해결할 수 있었습니다.
이번 작업을 통해 얻은 교훈은 다음과 같습니다.
- index.html 캐싱을 방지하면, 항상 최신 JS 파일을 로드할 수 있다.
index.html
은 애플리케이션의 진입점이므로, 캐싱을 방지해야 패치 후 최신 화면이 반영된다.
- JS, CSS 등의 정적 파일은 별도의 캐싱 설정 없이도 자동으로 갱신된다.
- Vite(Webpack)가 파일명에 해시를 추가하여 브라우저가 최신 파일을 자동으로 로드하도록 보장함.
- Nginx를 재시작할 필요 없이 dist 폴더만 교체해도 최신 화면이 반영될 수 있다.
- 운영 환경에서는 dist 폴더를 안전하게 교체하는 배포 스크립트나 Docker 볼륨 마운트를 활용하면 더욱 효과적이다.
- Docker 환경에서는 Nginx를 재시작하지 않고도 배포할 수 있다.
- 컨테이너 내부의 dist 폴더를 교체하거나, Docker Compose에서 볼륨을 활용하면 즉시 최신 화면 반영이 가능하다.
이번 문제를 해결하면서, 운영 환경에서의 배포 방식과 Nginx 캐싱 설정을 더욱 깊이 이해할 수 있는 계기가 되었습니다.
단순히 "새로고침을 하면 된다"는 해결책이 아니라, 사용자 경험(UX)을 개선하고 운영의 번거로움을 줄이는 방식으로 접근하는 것이 중요하다는 점을 깨달았습니다.
이제 React(Vite) 프로젝트를 운영할 때, 배포 후에도 강력 새로고침 없이 자동으로 최신 화면을 반영할 수 있는 환경을 구축할 수 있게 되었습니다.
'DevOps' 카테고리의 다른 글
[Windows Server] 윈도우 서버에서 Nginx 로그 파일을 일자별로 관리하는 방법 (Feat. Power Shell, Windows Task Scheduler) (0) | 2025.02.19 |
---|