문제

방문자에게 502 Bad Gateway가 뜨고, nginx 에러 로그에 upstream sent too big header while reading response header from upstream이 찍힙니다. 백엔드는 문제가 없습니다 — 요청을 받아 유효한 응답을 보냈습니다. nginx가 그 응답을 넘겨주기 전에 거부한 것인데, 응답의 헤더가 nginx가 읽으려고 잡아 둔 단일 버퍼보다 컸기 때문입니다. 가장 흔한 방아쇠는 로그인이나 OAuth 콜백이 거대한 Set-Cookie를 응답에 쌓는 경우입니다. 먼저 답할 질문은, 이게 특정 한 경로에서만(콜백의 큰 쿠키) 터지는지 아니면 모든 요청에서(버퍼가 진짜 작음) 터지는지입니다 — 그게 설정을 어디까지 손댈지를 가릅니다.

증상

  • 클라이언트는 밋밋한 502 Bad Gateway를 보고, nginx 에러 로그엔 upstream sent too big header while reading response header from upstream이 남는다.
  • 백엔드 자체는 건강해 보인다 — nginx가 502로 바꿔 버린 그 요청을 백엔드는 정상 200/302로 로깅한다.
  • 경로별로 다르다: 로그인, OAuth2/SSO 콜백, 세션을 초기화하는 엔드포인트만 실패하고 나머지는 멀쩡하다.
  • 인증을 추가하거나 새 SSO를 붙이거나 쿠키를 더 세팅하는 미들웨어를 넣은 직후 시작됐다.
  • 백엔드를 재시작하거나 스케일해도 안 바뀐다 — 애초에 백엔드가 문제가 아니었으니까.

이 오류의 실제 의미

nginx가 요청을 프록시할 때, 업스트림 응답의 첫 부분 — 상태 줄과 모든 응답 헤더 — 을 고정 버퍼 하나에 읽어들입니다. HTTP 프록시에서 그 버퍼가 proxy_buffer_size이고, 기본값은 메모리 한 페이지입니다: 대부분 플랫폼에서 4KB, 일부에서 8KB. 헤더 블록 전체가 그 버퍼 하나 안에 들어가야 합니다. 업스트림이 그보다 큰 헤더를 보내면 nginx는 응답을 파싱하지 못해 통째로 버리고 502 Bad Gateway를 돌려줍니다.

사람들이 걸려 넘어지는 건 두 지시어의 역할 차이입니다. proxy_buffer_size는 응답 헤더용 하나짜리 버퍼입니다. proxy_buffers는 응답 본문용 별도 풀입니다(기본 4KB/8KB 버퍼 8개). proxy_buffers를 키워도 헤더 오버플로에는 소용없습니다 — 헤더는 전부 proxy_buffer_size에 삽니다. 그리고 본문이 아니라 헤더라서 proxy_buffering off로도 못 피합니다 — proxy_buffer_size가 여전히 헤더 읽기를 제한합니다. 그래서 해결은 거의 항상 “proxy_buffer_size를 키운다” 아니면 “백엔드가 그렇게 큰 헤더를 못 내보내게 한다”이고, 이 둘을 가려내는 게 실제 작업입니다.

업스트림이 평범한 HTTP 프록시가 아니라 PHP-FPM, uwsgi 위의 파이썬 앱, gRPC라면 같은 실패가 대응 지시어에서 나타납니다 — fastcgi_buffer_size, uwsgi_buffer_size, scgi_buffer_size, grpc_buffer_size. 같은 버퍼, 다른 프로토콜 접두사입니다.

주요 원인 3가지

  1. 로그인·OAuth 콜백의 거대한 Set-Cookie. 압도적으로 흔합니다. SSO/OAuth 흐름, 세션 라이브러리, 또는 상태를 쿠키에 저장하는 프레임워크가 콜백 응답에 크고 여러 개인 Set-Cookie 헤더를 씁니다. 헤더 블록이 기본 4KB/8KB 버퍼를 넘어서 nginx가 그 한 경로만 502를 냅니다. 신호: 인증 관련 엔드포인트만 실패하고, 인증을 추가·변경한 시점에 시작됐다.
  2. 헤더가 많은 앱인데 버퍼가 기본값 그대로. 한 페이지 기본값은 평범한 앱엔 충분하고, 큰 헤더를 정당하게 내보내는 앱엔 작습니다 — 되돌려 보내는 큰 JWT, 많은 쿠키, 모든 응답에 붙는 장황한 커스텀 헤더. 신호: 한 경로가 아니라 전부 터진다.
  3. 프록시·WAF·디버그 계층이 응답 헤더를 부풀림. nginx와 클라이언트 사이의 중간 장비, 또는 디버그 모드의 앱 프레임워크가 자기 헤더를 덧붙입니다(추적 ID, 헤더에 쑤셔 넣은 스택 트레이스, 잔뜩 쌓인 보안 헤더). 응답이 앱에선 작았다가 nginx가 읽을 즈음 커집니다. 신호: 한 환경(디버그 켜진 스테이징)에서만 뜨거나 프록시·WAF 변경 후에 뜬다.

DechoNet으로 진단

  • HTTP 점검은 외부에서 URL을 요청해 실제로 통과하는 상태와 응답 헤더를 보여줍니다. 사이트 대부분에선 깨끗한 200인데 로그인·콜백 경로에서만 502가 나오면, 실패가 경로별이라는 걸 확인한 셈입니다 — 전역적으로 버퍼가 작은 게 아니라 그 응답의 큰 Set-Cookie를 가리킵니다. 결정적 후속은 서버에서 하세요: 실패하는 경로에 대해 nginx를 우회해 업스트림에 직접 curl -sI를 날려 응답 헤더를 재보세요 — Set-Cookie나 헤더 블록이 현재 proxy_buffer_size보다 크면 범인을 찾은 겁니다.

해결 체크리스트

  • nginx 에러 로그에서 정확한 문구를 확인하세요: upstream sent too big header while reading response header from upstream. 이 문구는 클라이언트 요청 헤더가 아니라 응답 쪽 문제라는 뜻입니다.
  • HTTP 점검으로 범위를 잡으세요: 한 경로만 502인가, 전부인가? 한 경로 → 그 응답의 큰 쿠키·헤더. 전부 → 앱에 비해 버퍼가 작음.
  • 범인을 재세요. 서버에서 실패 경로에 업스트림 직접 curl -sI를 날려 총 헤더 크기, 특히 Set-Cookie를 보세요. 현재 proxy_buffer_size와 비교하세요.
  • 본문 풀이 아니라 헤더 버퍼를 키우세요: 해당 location/http 블록에 proxy_buffer_size 16k;(아주 큰 토큰이면 32k)를 넣고, proxy_busy_buffers_size를 최소 같은 값으로 두세요. PHP-FPM/uwsgi/gRPC면 대응하는 fastcgi_buffer_size / uwsgi_buffer_size / grpc_buffer_size를 쓰세요. nginx를 reload합니다.
  • 헤더가 정말 비대하면 근원을 고치는 게 낫습니다: 세션 상태를 쿠키에서 서버측 저장소로 옮기거나, OAuth/SSO 계층이 쓰는 걸 줄여, 매 요청마다 킬로바이트짜리 쿠키를 나르지 않게 하세요.
  • 만능 해결이랍시고 모든 연결에 거대한 버퍼를 주지 마세요 — 연결당 과대 버퍼는 메모리·DoS 지뢰입니다. 실제 헤더 총량에 여유분만 더해 크기를 잡고, 살찐 쿠키는 근원에서 고치세요.

에스컬레이션 시점

  • 관측된 헤더에 비해 버퍼가 충분한데도 간헐적으로만 502가 나면, 앱과 nginx 사이에서 헤더를 재작성·중복시키는 중간 장비나 업스트림과의 keep-alive·HTTP 버전 불일치를 찾으세요 — 단순 헤더 오버플로와는 다른 실패입니다.
  • proxy_buffer_size를 키워 해소됐는데 쿠키가 시간이 갈수록 계속 커지면, 그건 결국 어떤 버퍼든 넘길 애플리케이션 설계 문제(무한정 커지는 쿠키 상태)입니다 — 숫자를 계속 올리지 말고 앱에서 고치세요.

내 도메인에서 바로 확인

무료, 가입 불필요. 이 가이드가 다루는 항목을 바로 검사하고 조치 방법을 알려드립니다.