서로 다른 네트워크에서 게시판에 접속했는데, 웹앱 로그에는 두 요청 모두 loopback ip인 127.0.0.1로 남습니다. 같은 서버의 Nginx가 요청을 앱에 넘길때 127.0.0.1은 앱에 실제로 연결한 상대의 주소입니다. 접속자 IP를 따로 기록하려면 Nginx가 어떤 값을 넘겼는지, 앱이 그 값을 어떤 조건에서 읽는지 확인해야 합니다.

같은 요청, 두 로그의 IP
테스트 요청 한 건을 보내고 요청 시각과 경로를 기준으로 Nginx 액세스 로그와 앱 로그를 맞춰 봅니다. Nginx의 로그 형식에 $remote_addr가 들어 있고 Nginx가 외부 연결을 직접 받는다면, 이 값은 Nginx에 연결한 상대의 주소입니다. 반면 앱의 req.socket.remoteAddress는 앱과 TCP 연결을 맺은 Nginx 쪽 주소입니다. 같은 요청에서도 두 값이 달라질 수 있습니다. Nginx 공식 문서 · 액세스 로그와 기록 형식
앱에서 X-Forwarded-For도 함께 확인하면 점검 범위를 좁힐 수 있습니다. 해당 헤더를 Nginx에서 설정했는데 앱에 값이 도착하지 않으면, 요청을 실제로 처리한 location과 헤더 설정부터 살핍니다. 헤더에 기대한 주소가 들어 있는데 로그가 여전히 루프백 주소라면, 앱의 프록시 신뢰 설정과 로거가 읽는 필드를 확인할 차례입니다.
Nginx 한 대에서의 헤더 덮어쓰기
이 예시에서는 Nginx가 외부 연결과 HTTPS를 직접 받고, 같은 호스트의 Express 앱은 127.0.0.1:3000에만 바인딩합니다. Nginx 앞에는 CDN이나 로드밸런서가 없고 Real IP 주소 치환도 적용하지 않았습니다. 아래 설정은 앱으로 넘기는 location에서 사용할 수 있는 예시입니다.
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
X-Forwarded-For를 $remote_addr로 설정하면 외부에서 보내온 헤더 값을 Nginx가 관찰한 주소로 덮어씁니다. $proxy_add_x_forwarded_for를 쓰면 기존 헤더 뒤에 $remote_addr를 붙이므로, 기존 값에 접속자가 넣은 주소가 남을 수 있습니다. 하위 location에 proxy_set_header가 하나라도 있으면 상위의 같은 지시어 목록을 상속하지 않으므로, 경로별 헤더 설정도 함께 살핍니다. Nginx 공식 문서 · 프록시 전달 헤더
Express에서는 app.set('trust proxy', '127.0.0.1')로 이 예시의 연결 주소를 신뢰하도록 지정하고, 로거에서 req.ip를 읽습니다. Express는 먼저 소켓의 상대 주소가 신뢰 범위에 속하는지 확인합니다. 이 설정은 req.hostname과 req.protocol에도 영향을 주므로, 예시에서 두 전달 헤더도 Nginx가 설정했습니다. 같은 호스트의 다른 프로세스도 루프백 포트에 연결할 수 있으므로, 이 예시는 해당 호스트의 로컬 접속 주체를 신뢰할 수 있는 환경을 전제로 합니다. Express 공식 문서 · 프록시 뒤의 Express

CDN이나 로드밸런서가 앞에 있을 때
외부 요청이 로드밸런서를 거쳐 들어오면 Nginx에 직접 연결하는 쪽이 로드밸런서로 바뀝니다. 이때 위 설정을 그대로 쓰면 앱에 로드밸런서 IP를 전달할 수 있습니다. 먼저 앞단 장비가 어느 헤더를 어떤 규칙으로 생성하거나 갱신하는지 확인합니다. Nginx의 Real IP 모듈을 사용할 경우 set_real_ip_from에 실제로 관리하는 프록시의 주소나 대역을 지정하고, 검증한 헤더를 real_ip_header로 선택합니다. Nginx 공식 문서 · Real IP 모듈
여러 프록시가 X-Forwarded-For 목록을 유지하는 구성에서는 real_ip_recursive on이 신뢰한 프록시를 오른쪽부터 건너뛰고 오른쪽에서 처음 만나는 신뢰 범위 밖의 주소를 선택합니다. 앞단을 거치지 않고 원본 서버로 들어오는 경로가 있는지도 확인합니다. 장애 분석 중에는 모듈이 보존하는 $realip_remote_addr와 치환 후 $remote_addr를 함께 보면, Nginx에 연결한 장비와 선택된 접속자 주소를 구분할 수 있습니다. Nginx 공식 문서 · Real IP 모듈
임의 헤더를 넣은 요청으로 재검증
변경 전후의 차이는 테스트 환경에서 같은 경로를 반복 호출해 확인합니다. nginx -T로 서비스에 사용할 설정과 포함 파일을 확인하고, 변경 후에는 nginx -t로 문법과 참조 파일을 점검한 다음 해당 환경의 절차에 따라 다시 읽힙니다. Nginx 공식 문서 · 명령줄 옵션
- 정상 요청을 보냅니다. 단일 Nginx 예시에서 앱 로그의
req.ip는 Nginx의$remote_addr와 같아야 합니다. 앱의 소켓 상대 주소는 여전히 루프백입니다. - 같은 환경에서
X-Forwarded-For: 198.51.100.77을 넣어 다시 요청합니다. 앱이 이 예시 주소를 접속자 IP로 기록하는지 확인합니다. 이 예시의 기대값은 첫 요청과 같은 주소입니다. - 외부에서 앱 포트에 직접 연결할 수 있는지도 확인합니다. IP 기준 요청 제한을 별도 미들웨어에서 적용한다면, 그 미들웨어가 참조하는 값도 함께 대조합니다.

결론
로그에 프록시 IP가 남으면 먼저 문제가 헤더 전달에 있는지, 앱이 읽는 필드에 있는지 나눠 봅니다.
Nginx 한 대가 외부 연결을 받는 환경에서는 관찰한 주소를 헤더에 다시 쓰고, 앱이 신뢰할 연결 주소를 한정하는 방식으로 점검할 수 있습니다. 앞단 프록시가 있는 환경이라면 먼저 그 장비의 헤더 처리 규칙과 원본 서버의 접근 경로를 확인합니다.