BE/SpringBoot
nginx client ip 얻기 ( X-Forwarded-For )
veee2
2023. 9. 5. 15:17
먼저 글을 작성하게 된 이유를 설명하겠습니다.
로그인 시/로그인 실패 시에 접속 이력을 남기려고 하였습니다.
접속 이력에 들어가는 내용 중에 클라이언트 IP가 필요하였고, 클라이언트 IP 얻는 방법을 검색해보니 일반적인 방법으로 아래의 코드와 같은 내용이 나왔습니다.
// 클라이언트 IP 확인
public static String getClientIp(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
System.out.println("ip1 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
System.out.println("ip2 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
System.out.println("ip3 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
System.out.println("ip4 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
System.out.println("ip5 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-RealIP");
System.out.println("ip6 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("REMOTE_ADDR");
System.out.println("ip7 = " + ip);
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
System.out.println("ip8 = " + ip);
}
if(ip.equals("0:0:0:0:0:0:0:1") || ip.equals("127.0.0.1") || ip.equals("49.247.128.42")) {
ip = getServerIpAddress();
System.out.println("ip9 = " + ip);
}
return ip;
}
// 클라이언트 아이피를 정상적으로 받아오지 못하여도 오류 안나게 처리하는 부분입니다.
private static String getServerIpAddress() {
try {
InetAddress address = InetAddress.getLocalHost();
return address.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
return "Unknown";
}
}
해당 내용으로 함수를 만들었고, 당연히 정상적으로 실행될거라 생각하였지만 성공하지 못하였습니다.
원인은 웹서버로 엔진엑스(NGNIX)를 사용하고 있는데 nginx.conf 파일에서 클라이언트 IP값을 가져올 수 있게 처리를 더 해주어야합니다.
아래는 제가 참고했던 글입니다.
nginx client ip 얻기 ( X-Forwarded-For )
클라이언트 -> nginx (proxy_pass) -> spring boot 서버
Spring boot 서버 에서는 java 코드로 아래와 같이 클라이언트 아이피를 구했다.
private String getClientAddr(HttpServletRequest request) {
String clientAddr = request.getHeader("X-Forwarded-for");
if (clientAddr != null && clientAddr.length() > 0 ){
return clientAddr;
}
return request.getRemoteAddr();
}
위와 같은 호출 순서에서 applicaton서버에서 아이피를 체크하면, "X-Forwarded-for"값에서
항상 nginx 서버의 IP가 얻어 졌다.
나는 Client IP가 얻고 싶은데, 이거 왜 이럴까??
nginx.conf 기본 설정
location / {
proxy_pass http://123.123.123.123:9000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
해결방법
X-Forwaed-For 아이피에 실제 client ip를 넣어서 보내는 설정이 가능했다.
아래 설정을 추가시에 실제 client ip 를 얻을수 있었다.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
해결 설정 최종 값
server {
listen 8080 ssl;
server_name *.ynkim.kr;
ssl_certificate /cloud/_webserver/nginx-1.21.6/ssl/cert.pem;
ssl_certificate_key /cloud/_webserver/nginx-1.21.6/ssl/PrivateKey.pem;
ssl_password_file /cloud/_webserver/nginx-1.21.6/ssl/ssl.pass;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
charset utf-8;
location / {
proxy_pass http://123.123.123.123:9000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
-----
저도 여기서 아래의 부분을 확인하였고 해당 부분을 추가 후 sudo service nginx restart 를 해주었더니 정상작동하였습니다.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
여러분들도 저와 같은 상황이라면 위의 방법들을 시도해보시기 바랍니다.
감사합니다.