문제점
프로젝트에서 nginx를 사용하기로 하여, nginx에 .vue 파일을 위치시키고 그 뒤에 springboot를 위치시켰다.
- nginx는 reverse proxy 역할을 하며, 클라이언트의 모든 요청을 받는다.
- 요청 URI가 /api로 시작하면 뒷단 springboot(proxy_pass 이용)로 요청을 보내고, /api로 시작하지 않는다면 vue router에게 URI에 해당하는 vue 페이지를 리턴하도록 한다.
nginx.conf
server{
location ^~/api{
proxy_pass http://127.0.0.1:8080;
}
}
이런식으로 구성을 하여 프로젝트를 진행하였는데, 문제가 발생했다.
바로 springboot 에서 request.getRemoteAddress(); 를 호출하여 client_ip를 얻으면 127.0.0.1 이 찍히는 것이다.
client ip --> nginx(80포트) --127.0.0.1:8080요청--> springboot(8080포트)
그러다보니, client_ip를 LOG에 찍거나 DB에 저장을 할때 모든 ip가 127.0.0.1로 저장되는 문제가 발생하였다.
해결책
구글링을 하니, 가장 많이 나오는게 http header "X-Forwarded-For" 에 실제 client_ip를 넣어서 보내는 것이다.
X-Forwarded-For: client_ip, proxy1_ip, proxy2_ip
이런식으로 porxy를 거칠때마다 뒤에 ip를 붙여서 사용하는 것이다.
우리는 porxy가 하나밖에 없으므로 X-Forwarded-For에 client_ip만을 설정하기로 했다. nginx에서 X-Forwarded-For 헤더를 설정하는 방법은 다음과 같다.
server{
location ^~/api{
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8080;
}
}
nginx를 재기동시킨 후 springboot에서 헤더를 찍어보면 "x-forwarded-for" 이름의 헤더에 실제 client_ip가 나오는 것을 알 수 있다.
이제 실제 client_ip를 얻을 수 있다.
public String getIp(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
return ip != null ? ip : request.getRemoteAddr();
}
대충 이런식으로 사용할 수 있겠다.
XFF가 표준이 아니기 때문에 제품에 따라 헤더의 이름이 다를 수도 있다고하니, 참고하길 바란다.
Filter 를 이용해서 ServletRequest를 상속받은 RequestWrapper를 만들어 getRemoteAddr를 오버라이드한다면, 어느 곳에서나 getRemoteAddr();을 호출해도 실제 client_ip를 얻어올 수 있다.
더 좋은 방법이 있다면 댓글 부탁드립니다. (__)
'프로그래밍 노트 > 인프라' 카테고리의 다른 글
젠킨스 Master/Slave 분산 빌드 환경 도커로 구축하기 (1) | 2021.01.30 |
---|---|
ScaleOut, ScaleUp (스케일아웃, 스케일업) (0) | 2021.01.24 |
[nginx] HTTP관련 환경 설정_2 (0) | 2020.06.02 |
[nginx] HTTP관련 환경 설정_1 (0) | 2020.06.02 |
OpenSSL을 사용하여 ROOT CA 생성 및 SSL 인증서 발급하기_2 (0) | 2020.05.09 |