Apache2 캐시 설정 (배포 시 브라우저 캐시 날아가도록)
💡 웹 서버 환경
- Ubuntu 18.04 LTS
- apache2.4.29
💽 Apache2 웹서버 캐시 설정 (소스 배포 시 사용자 브라우저 캐시 날아가도록)
설정하게된 배경: 운영 배포를 진행하였으나 클라이언트의 브라우저에 캐싱이 되어 이전 소스가 남아있는 상황이 발생함. 이 때문에 웹서버에서 새롭게 제공하는 데이터를 브라우저에 남아있는 이전 소스가 처리하지 못하면서 마치 에러가 발생한 것으로 보임. 이를 방지하기 위해 캐시 설정을 알아봄.
📑 사용자 브라우저에 남아있는 캐시를 날리는 여러가지 방법
사용자 브라우저에 남아있는 캐시를 날리는 방법은 Apache 설정 뿐만 아니라 아래와 같이 다른 여러 방법이 있음.
이와 같은 방법을 Cache Busting(캐시 무효화)이라고 함.
1️⃣ 파일 이름에 version 혹은 time stamp 등을 붙여준다.
예제)
testFile.v1.js
→ 배포시 testFile.v2.js
- 장점
- 서버 설정 없이 소스만 수정하여 캐싱을 날릴 수 있음.
- 단점
- 배포 할 때마다 소스의 버전을 수정해줘야함.
- 소스의 git 이력이 날아감. (파일을 삭제하는 것과 동일하기 때문에)
2️⃣ 파일 경로에version 등을 붙여준다.
예제)
/v1/testFile.js → 배포시 /v2/testFile.js
- 장점
- 서버 설정 없이 소스만 수정하여 캐싱을 날릴 수 있음.
- 단점
- 배포 할 때마다 소스의 경로를 수정해줘야함.
- 소스의 git 이력이 날아감. (파일을 삭제하는 것과 동일하기 때문에)
3️⃣ import 시 파일명 뒤에 파라미터로 version 또는 time stamp 등을 붙여준다.
예제)
<link rel="stylesheet" type="text/css" href="theme.css?version=20190416">
- 장점
- 서버 설정 없이 소스만 수정하여 캐싱을 날릴 수 있음.
- 단점
- 배포 할 때마다 소스의 버전이나 뒤에 붙인 파라미터를 수정해줘야함.
4️⃣ Cache에 Expire 기한을 걸어둔다.
- 장점
- 원하는 기한에 캐시를 날릴 수 있음.
- 서버에서 설정 시 소스 수정 없이 가능.
- 단점
- 서버 설정 시 설정 누락 위험이 있음 (추가 증설하거나 비슷한 서비스를 런칭할 때)
- 배포 후 바로 캐시가 날아가기 원할 경우에 Expire 기한을 -1로 설정해야하는데 이 경우 캐시를 사용하지 않는 것과 같아서 성능에 손해가 심하기 때문에 오히려 안하는게 나음.
5️⃣ index.html에 다음과 같은 캐시 컨트롤 헤더를 넣어준다. (비추천)
Cache-Control: no-cache, no-store, must-revalidate
- 장점
- 서버 설정 없이 소스만 수정하여 캐싱을 날릴 수 있음.
- 단점
- 소스 상에 두면 공수가 커질 수 있음.
- 이 부분은 script.jsp 같이 공통으로 header 태그 안에 넣는 스크립트를 빼두었으면 공수가 적을 수 있음.
- 소스 상에 두면 공수가 커질 수 있음.
✅ 배포 시 사용자 브라우저에 남아있는 캐시 날리기 위해 알아야할 캐시 관련 내용
- Apache2 기본 설정
- deplate (gzip)
- 캐시 관련 HTTP 헤더
- 참고자료: 웹 서비스 캐시 똑똑하게 다루기
- 요청 헤더
- If-Modified-Since
- If-None-Match
- 응답 헤더
- Etag
- Last-Modified
- Cache-Control
- no-cache
- no-store
- max-age
- must-revalidate
💽 Apache 설정하여 소스 브라우저 캐시 날아가도록 설정
1️⃣ Apache deplate(gzip) disable 설정
## sudo 권한 필요
$ sudo a2dismod deflate
WARNING: The following essential module will be disabled.
This might result in unexpected behavior and should NOT be done
unless you know exactly what you are doing!
deflate
To continue type in the phrase 'Yes, do as I say!' or retry by passing '-f': Yes, do as I say!
deflate 모듈은 gzip
deflate는 apache 기본 설정이고 성능에 영향을 미치는 설정이라서 그런지 disable 설정 하려고 하면 저렇게 경고 문구와 함께 confirm을 받는 모습을 볼 수 있음.
2️⃣ Apache Header Cache-Control no-cache 설정
참고자료: Apache Header 설정 공식문서
Header 사용장소 : 주서버설정, 가상호스트, directory, .htaccess (여기서는 VirtualHost에 설정했습니다. 전체 설정을 위해서는 apache2.conf 파일에 Header를 설정해주세요.)
## /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80>
...
Header set Cache-Control "no-cache"
...
</VirtualHost>
## 또는 전체설정을 위해서 apache 설정파일에 Header 추가
## /etc/apache2/apache2.conf
...
Header set Cache-Control "no-cache"
3️⃣ 정상적으로 설정됬는지 확인
설정한 서버의 웹페이지 접속하여 개발자 모드 열고 Network 탭 확인
확인 포인트
- 첫 요청 시
- 응답 코드 200
- 받은 결과의 응답 헤더
- Etag : 리소스 파일의 버전 정보 (웹 서버의 파일 정보를 기반으로 만들어짐)
- Last-Modified : 웹 서버에 있는 리소스 파일의 마지막 수정일자
- 두번째 요청 시
- 응답 코드 304 (Not Modified)
- 요청 헤더
- If-Modified-Since: 첫 요청 시 응답 헤더에 있던 Last-Modified 헤더와 동일한 값을 요청.
- If-None-Match: 첫 요청 시 응답 헤더에 있던 Etag 헤더와 동일한 값을 요청
⚠️ 이슈 내용
Apache Etag 버그
- 관련 자료: apache2 deplate + no-cache 설정 시 버그 관련 이슈 내용 링크
- deflate 모듈을 사용하는 경우 Etag의 맨 뒤에 -gzip이라는 문자가 붙는데 이렇게 설정되면 Etag가 정상적으로 동작하지 않아 Cache-Control을 no-cache로 설정했을 때 캐싱이 전혀 되지 않음. 매번 재검증 할때마다 소스파일이 변경되지 않았음에도 새로 받아오는 현상.
- 따라서 deflate 모듈을 disable 설정하고 Cache-Control을 no-cache로 설정하여 의도한 대로 배포 했을 때에만 브라우저에서 새로 파일을 받아오도록 설정.
멀티 서버인 경우 Etag가 서로 달라 캐싱이 안될 수 있음.
- Apache 서버가 여러 개 있고 그 앞에 로드밸런서(LB)가 있는 경우에 발생할 수 있는 상황.
- Etag는 웹 서버의 리소스 파일 정보 기반으로 만들어지기 때문에 물리적으로 서버가 여러 개 인 경우에 브라우저상에서 같은 리소스 파일이어도 서버별로 Etag가 다를 수 있음.
- 이 경우 브라우저에서 요청 시 여러 서버를 번갈아가면서 요청하게 되면 캐싱이 의도대로 동작하지 않을 수 있음.
- 한 번 연결한 서버로 계속 연결이 되도록 설정 해놓았다면 문제 없음. (예를들어 sticky session)
❓ 생각해볼 것
- deflate를 disable 하지 않고 설정할 수 있는 방법은 없는건지?..
- 버그 내용 보면 2000년 후반부터 있음.. 아직도 안고쳐진거 보면 버그 수정이 불가능한걸지도?
- 전체 파일에 대해서 deflate를 해제하는 것보다 일부 파일 유형에 대해서만 해제하고 싶은 경우
- /etc/apache2/mods-available/deflate.conf 파일에서 유형을 지정하는데 제외할 유형에 대해 주석처리
- Header에 Cache-Control도 제외한 유형에 대해서만 no-cache 설정을 해줘야함.
- Request에 대해서 SetEnvIfNoCase(패턴에 대해 대소문자 구분 안함) 또는 SetEnvIfCase(패턴에 대해 대소문자 구분) 활용하여 가능함.
- deflate는 웹 리소스를 압축해서 전송해주는 것인데 이를 해제하면서 처리하는게 나을지 차라리 캐시를 다른 방식으로 해결하고 deflate를 유지하는게 더 나은 방법일 수 있음.
📔 참고 자료
- 웹 서비스 캐시 똑똑하게 다루기 (토스)
- [Web] Cache Busting으로 Cache 문제 해결하기
- apache2 deplate + no-cache 설정 시 버그 관련 이슈 내용 링크