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;

여러분들도 저와 같은 상황이라면 위의 방법들을 시도해보시기 바랍니다.

 

감사합니다.