← 전체 글로 돌아가기

서버 운영

Nginx에서 gzip을 켰는데 JSON 응답만 그대로였던 이유

gzip on만 보고 압축이 적용됐다고 착각했던 설정 문제를 짧게 정리했다.

숫자가 이상했다

정적 파일은 압축이 잘 되는 것 같았는데, API JSON 응답은 크기가 거의 그대로였다. 서버 설정에는 분명히 gzip on;이 있었다. 그래서 처음에는 브라우저 개발자도구가 압축 전 크기를 보여 주는 줄 알고 넘어가려 했다.

확인은 curl로 했다.

curl -I -H 'Accept-Encoding: gzip' https://example.com/api/items

응답 헤더에 Content-Encoding: gzip이 없었다. 즉 브라우저 표시 문제가 아니라 실제로 압축이 적용되지 않은 상태였다.

gzip on만으로는 부족했다

Nginx는 압축할 MIME 타입을 설정으로 제한한다. 기본값만 믿으면 내가 기대한 타입이 빠질 수 있다. 설정을 열어 보니 gzip_types에 JSON이 없었다.

gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types
  text/plain
  text/css
  application/javascript
  application/json
  application/rss+xml
  image/svg+xml;

추가 후에는 설정 검사를 먼저 했다.

sudo nginx -t
sudo systemctl reload nginx

여기서 restart 대신 reload를 쓴 이유는 설정만 다시 읽으면 충분했기 때문이다. 물론 nginx -t가 실패하면 reload도 하지 않았다.

프록시 응답에서 확인한 것

내 API는 Node 서버 뒤에 있었고 Nginx가 reverse proxy 역할을 했다. 그래서 upstream이 이미 압축을 했는지, Nginx가 다시 압축하는지 헷갈렸다. 일단 Node 쪽 압축 미들웨어는 끄고 Nginx에서만 담당하게 했다. 작은 프로젝트에서는 압축 위치가 여러 군데인 것보다 한 군데인 편이 확인하기 쉬웠다.

curl -s -H 'Accept-Encoding: gzip' -D - https://example.com/api/items -o /dev/null

이 명령으로 Content-Encoding만 봐도 적용 여부는 빠르게 알 수 있었다.

적용 전 체크리스트

  • Accept-Encoding: gzip을 보낸 요청으로 확인한다.
  • gzip_types에 실제 응답의 Content-Type이 들어 있는지 본다.
  • 너무 작은 응답은 gzip_min_length 때문에 압축되지 않을 수 있다.
  • 이미지처럼 이미 압축된 파일은 gzip 효과가 거의 없다.
  • 설정 변경 뒤 nginx -t를 먼저 실행한다.

마무리

이번 실수는 설정 한 줄을 봤다고 전체 동작을 안다고 생각한 데서 나왔다. 압축은 켰는지가 아니라, 내가 줄이려는 응답에 실제로 Content-Encoding이 붙는지까지 확인해야 끝이었다.