-
[프론트 배포] index.html 에 버저닝과 nginx 프록시로 브라우저 캐시문제 해결Infra 2025. 2. 2. 16:55
nginx 를 활용한 프론트 배포 시스템을 구축하였다.
내가 구축한 시스템구조는 다음과 같다.
우리는 B2C 인 특성 상 적은 트래픽에 많은 사이트를 운영하고 있어서
부하에 견디기 보다는 비용적인 이점을 더 챙기는 구조이다.
여기서 만약 한 서비스에 트래픽이 몰린다면
nginx를 제거하고 ELB 를 사용해서 다른 ec2 인스턴스를 생성하여
스케일 아웃을 하면 된다.
내가 이번에 겪은 문제는
프론트 빌드 결과물인 index.html 을 보면
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1"> <title>s.lab Forwarding</title> <link rel="stylesheet" href="/css/style.css"> <script type="text/javascript" charset="utf-8" src="/js/javascript1.js"></script> <script type="text/javascript" charset="utf-8" src="/js/javascript2.js"></script> </head> <body> </body> </html>
이런 식이다. 이 때 저 css 와 js 를 가져오는 경로를 보면
https://ryeoryeo.com/css/style.css 와 https://ryeoryeo.com/js/javascript1.js 이렇게 요청하게 되는데
매번 저 위치로 새로 배포한 js 나 css 파일을 업로드하면
사용자의 브라우저는 url 경로로 캐싱을 잡기 때문에
바뀐 정적 파일을 보여주는게 아니라 브라우저에서 캐싱하고 있는 내용을 보여줄 것이다.
따라서 배포할 때마다 사용자는 캐시를 전부 날려야 새로 배포된 내용이 적용되는
말도 안되는 상황이 생긴다.
여러 방법으로 해결할 수 있지만
나는 index.html 을 수정하고 nginx location 의 정규식을 활용하여 해결하였다.
수정된 index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1"> <title>s.lab Forwarding</title> <link rel="stylesheet" href="/23/css/style.css"> <script type="text/javascript" charset="utf-8" src="/23/js/javascript1.js"></script> <script type="text/javascript" charset="utf-8" src="/23/js/javascript2.js"></script> </head> <body> </body> </html>
이렇게 경로마다 매 배포 시에 버전 숫자를 하나씩 올려서 지정해준다.
해당 작업을 해주는 jar 를 생성해서 front build 한 결과물을 수정하도록 cicd 파이프라인에 병합하였다.
이 때 매번 정적 파일 이름을 해싱해서 해싱한 값으로 index.html 에 수정해주는 기능이
webpack 에 있다고 하는데 필자는 webpack 기능을 쓰지 않았다.
이유는 로컬에서의 개발 환경에서의 빌드와 배포 시의 빌드를 완전히 동일하게 맞춰주고 싶었기 때문이다.
로컬 빌드마다 webpack 으로 해당 기능을 넣어주면 로컬 환경에서는 굳이 필요 없는 작업을 해야하기에
배포 시에만 추가하게 될텐데 그럼 차이가 생긴다.
이런 점이 싫어서 webpack 의 기능은 쓰지 않았다.
이후 nginx 설정에 대해 설명하겠다.
기존에는
server { listen 80; server_name ryeoryeo.com; include /etc/nginx/mime.types; access_log /var/log/nginx/access.log main_location_format; resolver 8.8.8.8; proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $s3_bucket; proxy_cache my_cache; proxy_cache_valid 200 1y; proxy_intercept_errors on; proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; add_header X-Cache-Status $upstream_cache_status; error_page 404 @spa; # other locations ... # ... location @fallback { return 404 @fallback; } location / { set $s3_bucket "ryeo-bucket.s3.ap-northeast-2.amazonaws.com"; proxy_set_header Host $s3_bucket; proxy_pass https://$s3_bucket/$host$request_uri; proxy_intercept_errors on; error_page 404 = @spa; } location @spa { set $s3_bucket "ryeo-bucket.s3.ap-northeast-2.amazonaws.com"; proxy_set_header Host $s3_bucket; proxy_pass https://$s3_bucket/$host/index.html; proxy_intercept_errors on; } }
이와 같이 모든 프록시한 정적 파일들을 캐싱하고 있었다.
이제는 index.html 에 바뀐 버전 정보는
사용자가 항상 최신 버전으로 알고 있어야 하니 index.html 을 프록시 하는 경우에는
캐싱하지 않도록 설정하고
js 나 css 파일을 가져다 보여줄 때는
정규식으로 앞의 버전 정보는 지워준다.
server { listen 80; server_name ryeoryeo.com; include /etc/nginx/mime.types; access_log /var/log/nginx/access.log main_location_format; resolver 8.8.8.8; proxy_connect_timeout 600; proxy_read_timeout 600; proxy_send_timeout 600; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $s3_bucket; proxy_cache my_cache; proxy_cache_valid 200 1y; proxy_intercept_errors on; proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; add_header X-Cache-Status $upstream_cache_status; error_page 404 @spa; location @fallback { return 404 @fallback; } location ~ ^/([0-9]+)/((?:js|css|main/js)/.*.(js|css))$ { set $s3_bucket "service-manager-conf.s3.ap-northeast-2.amazonaws.com"; set $file_path $2; proxy_set_header Host $s3_bucket; proxy_pass https://$s3_bucket/front/live/$host/$file_path; proxy_intercept_errors on; error_page 400 401 403 404 500 502 503 504 = @fallback; } location / { set $s3_bucket "ryeo-bucket.s3.ap-northeast-2.amazonaws.com"; proxy_set_header Host $s3_bucket; proxy_pass https://$s3_bucket/$host$request_uri; proxy_intercept_errors on; error_page 404 = @spa; } location @spa { set $s3_bucket "ryeo-bucket.s3.ap-northeast-2.amazonaws.com"; proxy_set_header Host $s3_bucket; proxy_pass https://$s3_bucket/$host/index.html; proxy_intercept_errors on; add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0"; add_header Pragma "no-cache"; add_header Expires "0"; proxy_no_cache 1; proxy_cache_bypass 1; error_page 400 401 403 404 500 502 503 504 = @fallback; } }
이렇게 하면 새로 배포를 하여도 사용자는 최신 사이트를 보며 사용할 수 있다.
전에 웹을 지탱하는 기술이라는 책을 읽고
브라우저의 캐시가 어떻게 동작하는지 알게 되었다.
그 지식을 가지고 이렇게 배포 시의 캐싱 문제를 해결할 수 있었다.
웹에 대해서 더 관심을 가지고 공부해야 겠다는 생각을 했다.
'Infra' 카테고리의 다른 글
[Keycloak] 키클락 import error 해결 (4) 2024.10.21 [Network] Virtual Host (0) 2024.08.20 [Network] CDN이 뭔지 알죠? (2) 2024.07.07