티스토리 뷰

발생일: 2014.12.09

키워드: nginx, proxy_set_header, proxy_pass, remote_addr, Remote IP, 프록시

문제:
아래와 같은 nginx 리버스 프록시 설정이 있었다.

  location /some/path {
    proxy_pass http://localhost:8000;
  }

프록시 서버에 특정 헤더를 전달하기 위해서 아래와 같이 `proxy_set_header` 디렉티브로 설정을 추가했다.

  location /some/path {
    proxy_set_header foo foo;
    proxy_pass http://localhost:8000;
  }

그런데, 서버 로그를 확인해보니 잘 넘어오던 Remote IP가 127.0.0.1로 설정되어 나온다..
왜 그런 걸까…?


해결책:

`proxy_set_header`로 프록시 서버로 전달하는 설정을 재정의할 때, 상위 레벨에서 상속받던 값이 무시되었던 게 원인이었다.


nginx 가 프록시 서버에 요청할 때엔, 기본적으로 두 가지 헤더를 재정의한다.
하나는 “Host” 헤더이고, 다른 하나는 “Connection” 헤더이다.

기본값은 아래와 같다.

  Host: $proxy_host
  Connection: close

이 두가지 헤더 외 나머지 헤더들은 모두 프록시 서버로 전달되는데, 헤더에 값이 비어있다면 그 헤더들은 프록시 서버로 전달하지 않는다.
만약, 프록시 서버로 전달하는 헤더의 값을 변경하려면 `proxy_set_header` 디렉티브를 사용하면 된다.

  location /some/path {
    proxy_set_header foo foo;
    proxy_set_header bar bar;
    proxy_pass http://localhost:8000;
  }


프록시 서버로 전달할 때 제거하고 싶은 헤더가 있다면, 아래처럼 빈 값을 설정하면 된다.

  proxy_set_header baz “”;


`proxy_set_header` 디렉티브는 `location`상위 블럭에도 정의할 수 있고,
`proxy_pass`가 사용되는 레벨에서 재정의하지 않는다면 상위 레벨의 값이 상속된다.

  proxy_set_header foo foo;
  proxy_set_header bar bar;

  location /some/path {
    # `foo`와 `bar` 헤더가 상속되어 전달된다.
    proxy_pass http://localhost:8000;
  }


주의할 점은, 해당 레벨에서 `proxy_set_header`가 하나라도 정의되어 있다면 상위 레벨의 값은 모두 무시된다는 점이다.

  proxy_set_header foo foo;
  proxy_set_header bar bar;

  location /some/path {
    # 이 블럭에서 `proxy_set_header`가 사용되었기 때문에,
    # 상위 레벨의 `foo`와 `bar` 헤더가 모두 무시된다. (상속되지 않는다)
    proxy_set_header baz baz;
    proxy_pass http://localhost:8000;
  }


문제가 발생했던 환경의 전체 nginx 설정은 대략 아래와 같았다.

  # 상위에 정의된 헤더
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;

  location /some/path {
    proxy_pass http://localhost:8000;
  }


상위에 헤더가 정의되어 있었는데, 아래처럼 새 설정을 추가했었고,
이 설정 때문에 상위 헤더가 전달되지 않아 IP 로그가 올바르게 찍히지 않았던 거였다.

  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;

  location /some/path {
    # 새 헤더 추가 (이 설정으로 상위 헤더가 무시된다)
    proxy_set_header foo foo;
    proxy_pass http://localhost:8000;
  }


아래처럼 모든 헤더를 location 블럭 안에 재정의해주는 걸로 문제를 해결했다.

  location /some/path {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header foo foo;
    proxy_pass http://localhost:8000;
  }



nginx 룰은 자꾸 봐도 익숙치가 않다. ㅎㅎㅎㅎ

반응형
댓글
공지사항