Daylogs/Nginx
nginx 에서 proxy_set_header 재정의할 때 주의할 점
ohgyun
2014. 12. 11. 21:46
발생일: 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 룰은 자꾸 봐도 익숙치가 않다. ㅎㅎㅎㅎ
반응형