본문 바로가기
서버구축 (WEB,DB)

Nginx Proxy 통한 Apache 서버로 요청 시 클라이언트 IP 전달

by 날으는물고기 2024. 5. 4.

Nginx Proxy 통한 Apache 서버로 요청 시 클라이언트 IP 전달

How a combination of Apache and nginx in proxy mode works

Nginx를 리버스 프록시로 사용하여 Apache2 (HTTPD) 서버로 요청을 전달할 때, 기본적으로 Apache2 서버는 요청이 Nginx 서버에서 온 것으로 인식합니다. 즉, Apache2의 접근 로그에는 클라이언트의 실제 IP 대신 Nginx 서버의 IP 주소가 기록됩니다. 클라이언트의 실제 IP 주소를 기반으로 Apache2에서 접근 제어를 하려면, 클라이언트의 원래 IP 주소를 Nginx에서 Apache2로 전달하고, Apache2가 이를 인식하도록 설정해야 합니다.

Nginx 설정 변경

Nginx 설정 파일에서 Apache2로 요청을 전달할 때 클라이언트의 실제 IP 주소를 포함시켜야 합니다. 이를 위해 proxy_set_header 지시어를 사용하여 X-Forwarded-For 헤더에 클라이언트의 IP 주소를 설정합니다.

 

Nginx의 서버 블록 혹은 로케이션 블록에 다음과 같은 설정을 추가합니다.

location / {
    proxy_pass http://apache_backend; # Apache2 서버의 주소
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Apache2 설정 변경

Apache2에서는 X-Forwarded-For 헤더를 사용하여 클라이언트의 실제 IP 주소를 인식하도록 설정해야 합니다. 이를 위해 mod_remoteip 모듈을 사용합니다. Apache 2.4 이상에서는 기본적으로 이 모듈이 포함되어 있지만, 활성화되어 있지 않을 수 있습니다.

  1. mod_remoteip 모듈 활성화: Apache2에서 mod_remoteip 모듈을 활성화합니다. 명령줄에서 다음 명령을 실행할 수 있습니다.
    a2enmod remoteip
  2. Apache2 설정 파일 수정: Apache2 설정 파일(예: /etc/apache2/apache2.conf 또는 /etc/apache2/conf-available/remoteip.conf)에 다음 지시어를 추가합니다.
    RemoteIPHeader X-Forwarded-For
    RemoteIPInternalProxy nginx_proxy_ip
    여기서 nginx_proxy_ip는 Nginx 서버의 IP 주소입니다. Nginx 서버가 로컬 네트워크에 있거나 고정된 공개 IP 주소를 가지고 있는 경우, 해당 IP 주소를 사용합니다.
  3. 설정 적용: 변경사항을 적용하기 위해 Apache2 서버를 재시작합니다.
    systemctl restart apache2

이 설정을 통해 Apache2는 X-Forwarded-For 헤더의 값을 실제 클라이언트 IP 주소로 인식하게 되며, 이를 기반으로 접근 제어 로직을 적용할 수 있습니다. Apache2의 접근 제어 설정(예: .htaccess 파일이나 Require ip 지시어)에서는 이제 X-Forwarded-For 헤더에 포함된 클라이언트의 실제 IP 주소를 사용하여 접근을 허용하거나 거부할 수 있습니다.

 

Nginx가 Docker 컨테이너에서 실행되고 있어 고정 IP 주소가 없는 경우, Apache의 RemoteIPInternalProxy 지시어에 Nginx 컨테이너의 정확한 IP 주소를 명시하는 것이 어려울 수 있습니다. 이 문제를 해결하기 위한 몇 가지 접근 방법이 있습니다.

1. Docker 네트워크 범위 사용

Nginx 컨테이너가 속한 Docker 네트워크의 IP 주소 범위를 RemoteIPInternalProxy 지시어에 설정할 수 있습니다. Docker 네트워크의 기본 범위는 보통 172.17.0.0/16, 172.18.0.0/16 등과 같이 설정됩니다. 이는 Docker 네트워크의 설정에 따라 달라질 수 있으므로, 해당 네트워크의 IP 범위를 확인하고 Apache 설정에 적용해야 합니다.

 

예를 들어, Docker 네트워크가 172.17.0.0/16 범위를 사용한다면, Apache 설정에 다음과 같이 추가합니다.

RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 172.17.0.0/16

2. Docker 컨테이너의 IP 주소 동적 할당 처리

Docker 컨테이너는 시작할 때마다 동적으로 IP 주소가 할당되므로, 시작 시 컨테이너의 IP 주소를 얻어서 Apache 설정을 자동으로 업데이트하는 스크립트를 사용할 수 있습니다. 이 스크립트는 Nginx 컨테이너가 시작할 때마다 실행되어야 합니다.

3. Docker 서비스의 호스트 이름 사용

Docker 컨테이너 간에는 Docker 내부 DNS를 통해 서로의 호스트 이름으로 통신할 수 있습니다. 하지만, RemoteIPInternalProxy 지시어는 IP 주소를 기반으로 작동하므로, 이 방법은 RemoteIPInternalProxy 설정에 직접 적용할 수 없습니다.

보안 고려사항

Docker 네트워크 범위를 넓게 설정할 경우, 해당 네트워크 내의 모든 요청이 신뢰할 수 있는 프록시로부터 온 것으로 간주됩니다. 이는 보안상의 리스크를 높일 수 있으므로, 신뢰할 수 있는 프록시만이 Apache 서버에 접근할 수 있도록 환경을 구성하는 것이 중요합니다.

 

위의 방법들을 적용할 때는 환경의 특성과 보안 요구사항을 고려하여 가장 적합한 방법을 선택해야 합니다. 가능하다면, Docker 컨테이너의 네트워크 설정을 조정하여 Nginx 컨테이너에 고정 IP 주소를 할당하는 방법도 고려할 수 있습니다.

 

특정 IP 주소의 경우에 원본 (사설) IP가 Apache 로그나 어플리케이션에서 그대로 표시되도록 설정하는 것은, 보통 신뢰할 수 있는 소스로부터 오는 요청을 구분하고, 이를 다르게 처리하고자 할 때 유용합니다. 이러한 설정은 특정 IP 주소나 네트워크 대역에서 오는 요청을 식별하고, 이를 통해 실제 클라이언트의 IP를 로그에 기록하거나 어플리케이션에서 사용할 수 있도록 하는 데 초점을 맞춥니다.

 

Apache에서 이를 구현하는 방법은 주로 mod_remoteip 모듈을 사용하는 것입니다. mod_remoteip는 클라이언트의 원본 IP 주소를 대체하기 위해, 리버스 프록시 또는 로드 밸런서로부터 전달된 요청의 X-Forwarded-For 헤더를 해석합니다. 그러나 특정 IP 주소에서 오는 요청에 대해서만 사설 IP를 그대로 표시하도록 설정하고자 한다면, Apache의 설정 파일에 조건부 로직을 적용할 수는 없습니다. 대신, 이런 동작을 구현하기 위해서는 리버스 프록시 (예: Nginx) 단에서 조건부 설정을 사용하는 것이 일반적입니다.

Nginx에서의 구현

Nginx를 사용하여 특정 소스 IP 주소로부터 오는 요청의 경우에만 사설 IP 주소를 Apache에 전달하도록 설정할 수 있습니다. 이를 위해 Nginx의 map 모듈을 사용하여 특정 조건에 따른 헤더 값을 설정할 수 있습니다.

 

예를 들어, 특정 IP 주소 1.2.3.4로부터 오는 요청의 경우에만 X-Forwarded-For 헤더를 전달하도록 Nginx 설정을 구성할 수 있습니다.

map $remote_addr $maybe_forwarded_for {
    default "";
    1.2.3.4 $proxy_add_x_forwarded_for;
}

server {
    location / {
        proxy_set_header X-Forwarded-For $maybe_forwarded_for;
        proxy_pass http://apache_backend; # Apache2 서버의 주소
        ...
    }
}

이 설정에서는 map 블록을 사용하여 $remote_addr (요청의 소스 IP)가 1.2.3.4일 경우에만 $proxy_add_x_forwarded_for 변수의 값을 사용하도록 합니다. 다른 모든 주소의 경우, 빈 문자열을 사용합니다. 그리고 이 값을 X-Forwarded-For 헤더로 설정하여 Apache로 전달합니다.

보안 고려사항

이 방법을 사용할 때는 보안상의 위험을 고려해야 합니다. X-Forwarded-For 헤더는 클라이언트나 중간의 프록시에 의해 쉽게 조작될 수 있으므로, 신뢰할 수 있는 네트워크 경로를 통해서만 이 헤더를 신뢰해야 합니다. 또한, 이 설정은 특정 IP 주소에 대해서만 적용되므로, 신뢰할 수 있는 IP 주소 목록을 정확하고 안전하게 관리해야 합니다.

 

10.10.1.0/24 대역이 아닌 경우에만 Nginx에서 X-Forwarded-For 헤더를 전달하도록 설정하려면, Nginx의 map 지시어를 사용하여 요청의 소스 IP 주소에 따라 조건부로 헤더 값을 설정할 수 있습니다. 이렇게 하면 특정 IP 대역에서 오는 요청은 X-Forwarded-For 헤더를 전달하지 않고, 그 외의 요청에 대해서는 헤더를 포함시킬 수 있습니다.

 

다음은 이를 구현하기 위한 Nginx 설정 예시입니다.

http {
    # 소스 IP 주소에 따라 $custom_x_forwarded_for 값을 설정
    map $remote_addr $custom_x_forwarded_for {
        # 10.10.1.0/24 대역에 속하는 경우 빈 값을 설정
        ~^10\.10\.1\. $remote_addr;
        # 그 외의 경우 기존 X-Forwarded-For 값을 사용하거나, 없으면 $remote_addr를 사용
        default $proxy_add_x_forwarded_for;
    }

    server {
        listen 80;

        location / {
            # 백엔드 서버로 요청을 전달
            proxy_pass http://backend_server;

            # $custom_x_forwarded_for 변수를 사용하여 X-Forwarded-For 헤더 설정
            proxy_set_header X-Forwarded-For $custom_x_forwarded_for;

            # 기타 필요한 proxy_set_header 지시어
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

이 설정에서 map 블록은 $remote_addr 변수(클라이언트의 IP 주소)를 기반으로 $custom_x_forwarded_for 변수의 값을 결정합니다. ~^10\.10\.1\. 패턴은 10.10.1.0/24 대역에 속하는 모든 IP 주소와 일치하며, 이 경우 $custom_x_forwarded_for에 빈 값을 설정합니다. 그 외의 모든 경우에는 기존의 X-Forwarded-For 값을 사용하거나, 그 값이 없는 경우 클라이언트의 현재 IP 주소($remote_addr)를 사용합니다.

 

proxy_set_header X-Forwarded-For $custom_x_forwarded_for; 지시어는 이렇게 설정된 $custom_x_forwarded_for 변수의 값을 사용하여 X-Forwarded-For 헤더를 설정하며, 이 헤더는 백엔드 서버로 전달됩니다. 이로써 10.10.1.0/24 대역에서 오는 요청은 X-Forwarded-For 헤더를 전달하지 않고, 다른 모든 IP 주소에서 오는 요청에 대해서는 해당 헤더를 포함시키게 됩니다.

 

proxy_add_x_forwarded_for 변수는 Nginx가 처리하는 요청의 X-Forwarded-For 헤더에 대한 값과, 요청을 하는 클라이언트의 IP 주소를 결합한 것입니다. 이 변수는 주로 리버스 프록시 설정에서 사용되어 클라이언트의 실제 IP 주소를 백엔드 서버에 전달하는 데 사용됩니다.

proxy_add_x_forwarded_for 변수에 포함되는 값

  1. 현재 요청의 X-Forwarded-For 헤더 값: 만약 클라이언트 요청이 이미 X-Forwarded-For 헤더를 포함하고 있다면, 해당 헤더의 값이 포함됩니다. 이는 주로 클라이언트가 이미 다른 프록시 서버를 통해 요청을 전송했을 경우에 해당하며, 이 헤더는 클라이언트의 원본 IP 주소 또는 그 이전 프록시의 IP 주소를 포함할 수 있습니다.
  2. 클라이언트의 현재 IP 주소: 요청을 하는 클라이언트의 IP 주소가 추가됩니다. 이 주소는 Nginx 서버에 직접 요청을 보내는 마지막 클라이언트 또는 프록시 서버의 IP 주소입니다.

Nginx가 리버스 프록시로서 작동할 때, proxy_set_header 지시어를 사용하여 X-Forwarded-For 헤더를 백엔드 서버로 전달할 수 있습니다. 이 때 proxy_add_x_forwarded_for 변수를 사용하면, 백엔드 서버는 최종 사용자의 실제 IP 주소와 요청 경로에 있는 모든 중간 프록시 서버의 IP 주소를 알 수 있게 됩니다.

location / {
    proxy_pass http://backend_server;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

이 구성을 통해 백엔드 서버는 클라이언트와 그 요청이 거쳐 온 모든 중간 프록시 서버의 IP 주소를 X-Forwarded-For 헤더를 통해 확인할 수 있습니다. 이 정보는 로깅, 디버깅, 보안 검사 등에 사용될 수 있습니다.

 

Nginx에서 Apache로 요청을 전달할 때 X-Forwarded-For 헤더에 호스트네임이 포함되어 Apache 로그에 IP 대신 호스트네임이 찍히는 경우가 발생할 수 있습니다. 이는 주로 X-Forwarded-For 헤더에 직접적으로 호스트네임이 설정되었거나, 혹은 Nginx나 Apache 설정에서 IP 주소를 호스트네임으로 해석하는 과정에서 발생할 수 있습니다.

 

Apache에서 클라이언트의 실제 IP 주소로만 로그를 남기도록 하려면, 다음과 같은 접근 방법을 사용할 수 있습니다.

1. Nginx 설정 확인

Nginx에서 proxy_set_header X-Forwarded-For $remote_addr;를 사용하여 오직 클라이언트의 IP 주소만 X-Forwarded-For 헤더에 설정하도록 해야 합니다. 이렇게 하면 호스트네임 대신 실제 IP 주소가 백엔드 서버로 전달됩니다.

location / {
    proxy_pass http://backend_server;
    proxy_set_header X-Forwarded-For $remote_addr;
}

2. Apache mod_remoteip 모듈 설정

Apache에서는 mod_remoteip 모듈을 사용하여 X-Forwarded-For 헤더의 값을 실제 클라이언트 IP 주소로 해석하고, 이를 로그에 기록할 수 있습니다. 이 모듈을 사용하려면, Apache가 mod_remoteip 모듈을 로드하도록 설정 파일을 구성해야 합니다.

LoadModule remoteip_module modules/mod_remoteip.so

그리고, mod_remoteip를 설정하여 X-Forwarded-For 헤더에서 IP 주소를 추출하고, 이를 클라이언트의 IP 주소로 사용하도록 합니다.

RemoteIPHeader X-Forwarded-For

3. 로그 포맷 설정

Apache의 로그 포맷을 mod_remoteip 모듈이 제공하는 클라이언트 IP 주소를 사용하도록 설정합니다. 기본적으로 %h 지시자는 원격 호스트의 IP 주소를 나타내는데, mod_remoteip 모듈을 사용할 경우, 이 지시자는 프록시 또는 로드 밸런서의 IP 주소 대신 실제 클라이언트의 IP 주소를 나타내게 됩니다.

 

로그 포맷을 설정하는 예시는 다음과 같습니다.

LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog logs/access_log common

이 설정들을 적용한 후 Apache 서버를 재시작합니다. 이렇게 하면 Nginx를 통해 전달되는 요청의 실제 클라이언트 IP 주소가 Apache 로그에 기록되며, 호스트네임 대신 IP 주소로만 기록되도록 할 수 있습니다. 설정을 변경한 후에는 반드시 Nginx와 Apache 서버를 재시작해야 변경사항이 적용됩니다.

728x90

댓글